diff --git a/01_DATAVIZ_TOOL.ipynb b/01_DATAVIZ_TOOL.ipynb
index c114475..2cbfc7c 100644
--- a/01_DATAVIZ_TOOL.ipynb
+++ b/01_DATAVIZ_TOOL.ipynb
@@ -1,1247 +1,1242 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 1. Wall structural behaviour\n",
"\n",
"This script reproduces the results of the shear-compression tests, focusing on the structural behaviour of the walls. Part of the results that are reproduced by the script are contained in the journal article: \n",
"\n",
"Godio M., Vanin F., Zhang S. & Beyer K. (2019) \"Quasi-static shear-compression tests on stone masonry walls with plaster: Influence of load history and axial load ratio\". Engineering Structures. https://doi.org/10.1016/j.engstruct.2019.04.041"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`Created by: M. Godio (EESD @ EPFL) on: August 3 2019 - \n",
"Last modification by: M.Godio on: August 14 2019`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Import libraries"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section imports the Python libraries needed to run this script"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" Libraries have been imported\n"
]
}
],
"source": [
"# libraries to import\n",
"import os\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import scipy.io as sio\n",
"\n",
"from matplotlib import rc\n",
"from scipy.signal import find_peaks\n",
"from tabulate import tabulate\n",
"from scipy.interpolate import interp1d\n",
"\n",
"# to install a library from the anaconda prompt, run a command of the kind:\n",
"# pip install numpy\n",
"\n",
"print(\" Libraries have been imported\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Define classes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section defines the classes used in this script"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" Classes have been defined\n"
]
}
],
"source": [
"\"\"\" \n",
"These classe contain the test data from shear-compression tests:\n",
"F = horizontal force (kN)\n",
"u = horizontal displacement (mm)\n",
"N = vertical force (kN)\n",
"v = vertical displacement (mm)\n",
"ss = sampling step \n",
"\"\"\"\n",
"class Dataset_sc():\n",
" \"\"\"Import the dataset contained in the -mat file.\"\"\"\n",
" \n",
" def __init__(self):\n",
" \"\"\"Initialize variables.\"\"\" \n",
" self.dataset = {}\n",
" \n",
" def get_mat_sc(self, pwd, nameset, test_num):\n",
" \"\"\"import mat file and create dictionary out of it.\"\"\"\n",
" dataset={}\n",
" sio.loadmat(pwd + os.sep + nameset + '.mat',mdict=dataset);\n",
" for test in range(test_num):\n",
" self.dataset['Test' + str(test)] = {}\n",
" F = []\n",
" u = []\n",
" N = []\n",
" v = []\n",
" ss = []\n",
" for dataId in range(len(dataset['TESTS'][0][test][0])):\n",
" F.append(dataset['TESTS'][0][test][0][dataId][0])\n",
" u.append(dataset['TESTS'][0][test][2][dataId][0])\n",
" N.append(dataset['TESTS'][0][test][1][dataId][0])\n",
" v.append(dataset['TESTS'][0][test][3][dataId][0])\n",
" ss.append(dataId+1)\n",
" self.dataset['Test' + str(test)]['F'] = F\n",
" self.dataset['Test' + str(test)]['u'] = u\n",
" self.dataset['Test' + str(test)]['N'] = N\n",
" self.dataset['Test' + str(test)]['v'] = v\n",
" self.dataset['Test' + str(test)]['ss'] = ss\n",
" print(\"The dataset \" + nameset + \" has been imported.\")\n",
" \n",
"print(\" Classes have been defined\")\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Define functions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section defines the functions used in this script"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" Functions have been defined\n"
]
}
],
"source": [
"\"\"\"\n",
"This function gives an xy line plot on a defined domain\n",
"\"\"\"\n",
"def plot_one(setname,x,y,col,lab_x,lab_y,leg_lab,leg_pos,x_lim_lw,x_lim_up,y_lim_lw,y_lim_up,if_grid,f_size,x_size,y_size,if_show):\n",
" \n",
" rc('text', usetex=True) \n",
" # change font gloabally\n",
" plt.rcParams[\"font.family\"] = \"Times New Roman\"\n",
" \n",
" # plot function\n",
" plt.figure(figsize=(x_size,y_size))\n",
" plt.plot(x, y, color = col)\n",
"\n",
" # config the graph\n",
" plt.xlabel(lab_x, fontsize=f_size-1)\n",
" plt.ylabel(lab_y, fontsize=f_size-1)\n",
" plt.tick_params(axis='both', labelsize=f_size)\n",
" plt.ylim([y_lim_lw, y_lim_up])\n",
" plt.xlim([x_lim_lw, x_lim_up])\n",
" plt.grid(if_grid)\n",
" plt.legend([leg_lab], loc=leg_pos, fontsize = f_size-1, frameon = False)\n",
" \n",
" # save\n",
" plt.savefig(setname + '.pdf',bbox_inches='tight')\n",
" \n",
" # show the graph\n",
" if if_show == True:\n",
" plt.show()\n",
" else:\n",
" plt.close()\n",
" \n",
"\"\"\"\n",
"This function gives multiple xy line plots on the defined domain\n",
"\"\"\"\n",
"def plot_multi(setname,x,y,col,lab_x,lab_y,leg_lab,leg_pos,x_lim_lw,x_lim_up,y_lim_lw,y_lim_up,if_grid,f_size,x_size,y_size,if_show):\n",
" \n",
" rc('text', usetex=True) \n",
" # change font gloabally\n",
" plt.rcParams[\"font.family\"] = \"Times New Roman\"\n",
" \n",
" # plot function\n",
" plt.figure(figsize=(x_size,y_size))\n",
" for plot_index in range(len(x)):\n",
" plt.plot(x[plot_index], y[plot_index], color = col[plot_index])\n",
"\n",
" # config the graph\n",
" plt.xlabel(lab_x, fontsize=f_size-1)\n",
" plt.ylabel(lab_y, fontsize=f_size-1)\n",
" plt.tick_params(axis='both', labelsize=f_size)\n",
" plt.ylim([y_lim_lw, y_lim_up])\n",
" plt.xlim([x_lim_lw, x_lim_up])\n",
" plt.grid(if_grid)\n",
" plt.legend(leg_lab, loc=leg_pos, fontsize = f_size-1, frameon = False)\n",
" \n",
" # save\n",
" plt.savefig(setname + '.pdf',bbox_inches='tight')\n",
" \n",
" # show the graph\n",
" if if_show == True:\n",
" plt.show()\n",
" else:\n",
" plt.close()\n",
" \n",
"\"\"\"\n",
"This function gives the test label\n",
"\"\"\"\n",
"def test_unit(i):\n",
" switcher={\n",
" 0:'SC1',\n",
" 1:'SC2',\n",
" 2:'SC4',\n",
" 3:'SC5',\n",
" 4:'SC6',\n",
" 5:'SC7'\n",
" }\n",
" return switcher.get(i)\n",
"\n",
"\"\"\"\n",
"This function calcultes the envelope force-displacement curve starting from a cyclic one\n",
"input: u = displacement array\n",
" V = force array \n",
" oddindex = 1 for positive envelope\n",
" = 2 for negative envelope\n",
"Note: the first peak in the negative envelope will be skipped \n",
"not to obtain me too high values of initial stiffness\n",
"\n",
"Created by B. Wilding (EESD @ EPFL) in Matlab format\n",
"Modified, and implemented in Python, by M. Godio (EESD @ EPFL)\n",
"\"\"\"\n",
"def fEnvelope(u,V,oddindex):\n",
" \n",
" # find peak position and value\n",
" nPE, _ = find_peaks(u) #,distance=2) #,height=0.05,distance=2)\n",
" uPE = u[nPE]\n",
" nPE = np.append(nPE,len(u))\n",
" uPE = np.append(uPE,u[len(u)-1])\n",
" \n",
" # decide from where to start in calculating the envelope\n",
" if oddindex == 1:\n",
" startfrom = 2 - 1\n",
" else:\n",
" startfrom = 3 - 1\n",
"\n",
" # calculate envelope only if input is cyclic response\n",
" if len(nPE) == 0 or len(nPE) == 1:\n",
" uE = u\n",
" VE = V\n",
" else:\n",
" uE = 0\n",
" VE = 0\n",
" # take the origin plus the first valid point - only for positive envelope\n",
" if oddindex == 1:\n",
" uE = np.append(uE,u[0:nPE[0]])\n",
" VE = np.append(VE,V[0:nPE[0]])\n",
" for C in range(startfrom,len(nPE)):\n",
" # if current peak > previous peak\n",
" if uPE[C] > uPE[C-1]:\n",
" ulap = u[nPE[C-1]+1:len(u)]\n",
" if C == 1:\n",
" max_prev = uPE[0]\n",
" else:\n",
" max_prev = max(uPE[0:C]) # this was C-1 and has changed to match matlab\n",
" for ulap_index in range(len(ulap)):\n",
" # look for first time value greater than peak ever seen\n",
" if ulap[ulap_index] > max_prev:\n",
" n_first = ulap_index\n",
" break\n",
" else:\n",
" n_first = 1000\n",
" init_pos_tmp = n_first + nPE[C-1] + 1 # nPE[C-1] in matlab\n",
" end_pos_tmp = nPE[C] + 1 # nPE[C] in matlab\n",
" if init_pos_tmp == end_pos_tmp: # new part in Python\n",
" addu = u[init_pos_tmp:end_pos_tmp+1]\n",
" addV = V[init_pos_tmp:end_pos_tmp+1]\n",
" else:\n",
" addu = u[init_pos_tmp:end_pos_tmp]\n",
" addV = V[init_pos_tmp:end_pos_tmp]\n",
" uE = np.append(uE, addu)\n",
" VE = np.append(VE, addV)\n",
" \n",
" return uE, VE\n",
"\n",
"print(\" Functions have been defined\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Define working directories"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section defines the working directories used in the script:\n",
"\n",
"
\n",
" - cwd = current working directory
\n",
" - where_to_import = directory from where importing the dataset
\n",
" - where_to_save_pic = directory where plots are saved
\n",
"
"
]
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 2,
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'os' is not defined",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)",
- "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m# get current working directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mcwd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetcwd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;31m# define other working directories\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mwhere_to_import\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcwd\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msep\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m\"01_WALL_STRUCTURAL_BEHAVIOUR\"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msep\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m\"INPUT_DATASET\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m# get current working directory\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mcwd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mgetcwd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;31m# define other working directories\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mwhere_to_import\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcwd\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msep\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m\"01_WALL_STRUCTURAL_BEHAVIOUR\"\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msep\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m\"INPUT_DATASET\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mNameError\u001b[0m: name 'os' is not defined"
]
}
],
"source": [
"# get current working directory\n",
"cwd = os.getcwd()\n",
"\n",
"# define other working directories\n",
"where_to_import = cwd + os.sep + \"01_WALL_STRUCTURAL_BEHAVIOUR\" + os.sep + \"INPUT_DATASET\"\n",
"\n",
"print(\" Working directories have been defined\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.1 Define wall properties"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section defines the geometry and material properties of the test wall units tested in shear-compression: SC1, SC2, SC4, SC5, SC6, SC7. The variable test_number gives the number of tests performed. The dictionary wall containing the following variables is created:\n",
"\n",
"\n",
" - height = wall height [mm]
\n",
" - length = wall length [mm]
\n",
" - thickness = wall thickness [mm]
\n",
" - b = wall aspect ratio
\n",
" - H0 = wall shear span [mm]
\n",
" - N = axial load [kN]
\n",
" - alr = axial load ratio
\n",
" - LH = load history - for labels
\n",
" - LHn = load history - for plots
\n",
" - density = stone density [kg/m3]
\n",
" - porosity = stone porosity [%]
\n",
" - W = wall body weight [kN]
\n",
" - fcm = masonry compressive strength [Mpa]
\n",
" - fb = stone compressive strength [Mpa]
\n",
" - fbt = stone tensile strength [MPa]
\n",
" \n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" Wall properties have been imported for all test units\n"
]
}
],
"source": [
"test_number = 6\n",
"\n",
"wall = {\n",
" 'height': [900, 900, 900, 900, 900, 900],\n",
" 'length': [900, 900, 900, 900, 900, 900],\n",
" 'thickness': [200, 200, 200, 200, 200, 200],\n",
" 'b': {},\n",
" 'H0': [450, 450, 450, 450, 450, 450],\n",
" 'N': {},\n",
" 'alr': [7.5, 10., 15., 11.5, 11.5, 11.5],\n",
" 'LH': ['$LH1$', '$LH1$', '$LH1$', '$LH1$', '$LH2$', 'monotonic'],\n",
" 'LHn':[1, 1, 1, 1, 2, 0],\n",
" 'density': 2688,\n",
" 'porosity': 7,\n",
" 'W': {},\n",
" 'fcm': 10, \n",
" 'fb': 65.60, \n",
" 'fbt': 8\n",
"}\n",
"\n",
"for test in range(test_number):\n",
" wall['N'][test] = wall['alr'][test]/100*wall['fcm']*wall['thickness'][test]*wall['length'][test]/1000\n",
" wall['b'][test] = wall['height'][test]/wall['length'][test]\n",
" wall['W'][test] = wall['height'][test]/1000*wall['length'][test]/1000*wall['thickness'][test]/1000*wall['density']*9.81/1000\n",
"\n",
"print(\" Wall properties have been imported for all test units\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.2 Import test data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section imports the dataset related to the structural behaviour of the walls. Tha data is contained in the corresponding TESTS MAT-file and is imported in the dictionary test which includes the following variables:\n",
"\n",
" - F = horizontal - shear - force
\n",
" - u = horizontal displacement
\n",
" - N = vertical - axial - force
\n",
" - v = vertical displacement
\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The dataset TESTS has been imported.\n"
]
}
],
"source": [
"sc_tests = Dataset_sc()\n",
"sc_tests.get_mat_sc(where_to_import,'TESTS',6)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.8 Calculate envelope curves"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section computes the F-u envelope curves starting from the experimental curves. The envelopes are save in the dictionary envelope having the following structure:\n",
"\n",
" - envelope.positive = including the positive envelope
\n",
" - envelope.negative = including the negative envelope
\n",
"
\n",
"Inside the dictionaries positive and negative the following variables are contained:\n",
"\n",
" - F = horizontal force
\n",
" - u = horizontal displacement
\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" Envelope curves have been calculated for all test units\n"
]
}
],
"source": [
"# loop over the test units\n",
"envelope = {}\n",
"for test in range(test_number):\n",
" \n",
" # initialize\n",
" envelope['Test' + str(test)] = {\n",
" 'positive': {},\n",
" 'negative': {} \n",
" }\n",
" u = []; V = []\n",
" uPos = []; VPos = []; indPos = []\n",
" uNeg = []; VNeg = []; indNeg = []\n",
" uEPos = []; VEPos = [] \n",
" uENeg = []; VENeg = []\n",
" \n",
" # tmp arrays used for brevity in the notation\n",
" u = np.array(sc_tests.dataset['Test' + str(test)]['u'])\n",
" V = np.array(sc_tests.dataset['Test' + str(test)]['F'])\n",
"\n",
" # define type of loading\n",
" if test == 5:\n",
" # monotonic\n",
" type = 1 \n",
" else:\n",
" # cyclic\n",
" type = 0 \n",
" \n",
" # calculate envelope response\n",
" if type == 1:\n",
" uEPos, VEPos = fEnvelope(u,V,1)\n",
" uENeg = uEPos \n",
" VENeg = VEPos\n",
" else:\n",
" #positive response\n",
" uPos = np.array([val for val in u if val >= 0])\n",
" indPos = [ind for ind in range(len(u)) if u[ind] >= 0]\n",
" VPos = np.array([V[ind] for ind in indPos])\n",
" # negative response\n",
" uNeg = np.array([val for val in u if val <= 0])\n",
" indNeg = [ind for ind in range(len(u)) if u[ind] <= 0]\n",
" VNeg = np.array([V[ind] for ind in indNeg])\n",
" # envelopes\n",
" uEPos, VEPos = fEnvelope(uPos,VPos,1)\n",
" uENeg, VENeg = fEnvelope(-uNeg,-VNeg,2)\n",
" \n",
" # apply corrections\n",
" if test == 0:\n",
" uEPosTmp = []\n",
" VEPosTmp = []\n",
" oo = 0;\n",
" jobdone = 0;\n",
" for kk in range(len(uEPos)):\n",
" if kk > 44 and kk < 56:\n",
" if jobdone == 0:\n",
" oo += 1\n",
" uEPosTmp = np.append(uEPosTmp,1.05)\n",
" VEPosTmp = np.append(VEPosTmp,66.03)\n",
" jobdone = 1\n",
" else:\n",
" oo += 1\n",
" uEPosTmp = np.append(uEPosTmp,uEPos[kk]);\n",
" VEPosTmp = np.append(VEPosTmp,VEPos[kk]);\n",
" uEPos = []\n",
" VEPos = []\n",
" uEPos = uEPosTmp\n",
" VEPos = VEPosTmp\n",
"\n",
" # save in dictionary\n",
" envelope['Test' + str(test)]['positive']['F'] = VEPos\n",
" envelope['Test' + str(test)]['positive']['u'] = uEPos\n",
" envelope['Test' + str(test)]['negative']['F'] = VENeg\n",
" envelope['Test' + str(test)]['negative']['u'] = uENeg\n",
" \n",
"print(\" Envelope curves have been calculated for all test units\")\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.10 Calculate key parameters"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This section computes the key parameters of the wall structural behaviour. The results contained in Table 3 and Table 4 of Godio et al. (2019) are reproduced. The parameters are appended to the key dictionary. Inside the dictionary the following variables are added:\n",
"\n",
" - peak_force = peak shear force, $V_\\text{max}$
\n",
" - initial_stiffness = initial stiffness calculated as secant stiffness at 15% the peak force, $K_\\text{init}$
\n",
" - delta_cracking = drift corresponding at the onset of cracking in the masonry, $\\delta_\\text{cr}$
\n",
" - delta_yielding = drift at the yielding point of the bi-linear curve, $\\delta_\\text{y}$
\n",
" - delta_max = drift measured when the peak force is reached, $\\delta_\\text{max}$
\n",
" - delta_SD = drift at the Severe Damage (SD) limit state, $\\delta_\\text{SD}$
\n",
" - delta_ultimate = ultimate drift, $\\delta_\\text{u}$
\n",
" - delta_collapse = drift at collapse, $\\delta_\\text{c}$
\n",
"
\n",
"Each variable contains values for both the positive and the negative envelopes, e.g. peak_force.positive and peak_force.pegative, plus the average value peak_force.average\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# initialize the key dictionary\n",
"key = {}\n",
"for test in range(test_number):\n",
" \n",
" key['Test' + str(test)] = {\n",
" 'peak_force':{},\n",
" 'initial_stiffness':{},\n",
" 'delta_cracking':{},\n",
" 'delta_yielding':{},\n",
" 'delta_max':{},\n",
" 'delta_SD':{},\n",
" 'delta_ultimate':{},\n",
" 'delta_collapse':{},\n",
" }\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Peak force"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"# initialize\n",
"tmp_table = []\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # save in dictionary\n",
" key['Test' + str(test)]['peak_force']['positive'] = max(envelope['Test' + str(test)]['positive']['F'])\n",
" key['Test' + str(test)]['peak_force']['negative'] = max(envelope['Test' + str(test)]['negative']['F'])\n",
" key['Test' + str(test)]['peak_force']['average'] = (key['Test' + str(test)]['peak_force']['positive'] + key['Test' + str(test)]['peak_force']['negative'])/2\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Initial stiffness"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# initialize\n",
"tmp_table = []\n",
"beta = 0.15\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive value\n",
" u = []; F = []; f = []; u_pre = []; F_pre = []; ind_15_pos = []\n",
" u = envelope['Test' + str(test)]['positive']['u']\n",
" F = envelope['Test' + str(test)]['positive']['F']\n",
" F_15_pos = beta*key['Test' + str(test)]['peak_force']['positive']\n",
" ind_15_pos = [ind for ind in range(len(F)) if F[ind] >= F_15_pos]\n",
" F_pre = F[0:ind_15_pos[0]+1]\n",
" u_pre = u[0:ind_15_pos[0]+1]\n",
" f = interp1d(F_pre, u_pre)\n",
" u_15_pos = f(F_15_pos)\n",
" key['Test' + str(test)]['initial_stiffness']['positive'] = F_15_pos/u_15_pos\n",
"\n",
" # negative value\n",
" u = []; F = []; f = []; u_pre = []; F_pre = []; ind_15_neg = []\n",
" u = envelope['Test' + str(test)]['negative']['u']\n",
" F = envelope['Test' + str(test)]['negative']['F']\n",
" F_15_neg = beta*key['Test' + str(test)]['peak_force']['negative']\n",
" ind_15_neg = [ind for ind in range(len(F)) if F[ind] >= F_15_neg]\n",
" F_pre = F[0:ind_15_neg[0]+1]\n",
" u_pre = u[0:ind_15_neg[0]+1]\n",
" f = interp1d(F_pre, u_pre)\n",
" u_15_neg = f(F_15_neg)\n",
" key['Test' + str(test)]['initial_stiffness']['negative'] = F_15_neg/u_15_neg\n",
" \n",
" # average value\n",
" key['Test' + str(test)]['initial_stiffness']['average'] = (key['Test' + str(test)]['initial_stiffness']['positive'] + key['Test' + str(test)]['initial_stiffness']['negative'])/2\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Drift at masonry craking"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# initialize\n",
"tmp_table = []\n",
"\n",
"# displacement values measured after visual inspection + DIC check\n",
"def disp_cracking_positive(i):\n",
" switcher={\n",
" 0:1.0145,\n",
" 1:0.8284,\n",
" 2:0.6674,\n",
" 3:1.0204,\n",
" 4:0.9239,\n",
" 5:1.48\n",
" }\n",
" return switcher.get(i)\n",
"def disp_cracking_negative(i):\n",
" switcher={\n",
" 0:0.8821,\n",
" 1:0.6767,\n",
" 2:0.514,\n",
" 3:1.29,\n",
" 4:1.0567,\n",
" 5:1.48\n",
" }\n",
" return switcher.get(i)\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive negative and average values\n",
" key['Test' + str(test)]['delta_cracking']['positive'] = disp_cracking_positive(test)/wall['height'][test]*100\n",
" key['Test' + str(test)]['delta_cracking']['negative'] = disp_cracking_negative(test)/wall['height'][test]*100\n",
" key['Test' + str(test)]['delta_cracking']['average'] = (key['Test' + str(test)]['delta_cracking']['positive'] + key['Test' + str(test)]['delta_cracking']['negative'])/2\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Drift at yielding"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"# note: I use here the interp function which is the closest to matlab interp1 function\n",
"# initialize \n",
"tmp_table = []\n",
"beta = 0.70\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive value\n",
" u = []; F = []; u_pre = []; F_pre = []; ind_70_pos = []\n",
" u = envelope['Test' + str(test)]['positive']['u']\n",
" F = envelope['Test' + str(test)]['positive']['F']\n",
" F_70_pos = beta*key['Test' + str(test)]['peak_force']['positive']\n",
" ind_70_pos = [ind for ind in range(len(F)) if F[ind] >= F_70_pos]\n",
" F_pre = F[0:ind_70_pos[0]+1]\n",
" u_pre = u[0:ind_70_pos[0]+1]\n",
" key['Test' + str(test)]['delta_yielding']['positive'] = np.interp(F_70_pos, F_pre, u_pre)/wall['height'][test]*100\n",
"\n",
" # negative value\n",
" u = []; F = []; u_pre = []; F_pre = []; ind_70_neg = []\n",
" u = envelope['Test' + str(test)]['negative']['u']\n",
" F = envelope['Test' + str(test)]['negative']['F']\n",
" F_70_neg = beta*key['Test' + str(test)]['peak_force']['negative']\n",
" ind_70_neg = [ind for ind in range(len(F)) if F[ind] >= F_70_neg]\n",
" F_pre = F[0:ind_70_neg[0]+1]\n",
" u_pre = u[0:ind_70_neg[0]+1]\n",
" key['Test' + str(test)]['delta_yielding']['negative'] = np.interp(F_70_neg, F_pre, u_pre)/wall['height'][test]*100\n",
"\n",
" # average value\n",
" key['Test' + str(test)]['delta_yielding']['average'] = (key['Test' + str(test)]['delta_yielding']['positive'] + key['Test' + str(test)]['delta_yielding']['negative'])/2\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Drift at peak"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# initialize\n",
"tmp_table = []\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive value\n",
" u = []; F = []\n",
" u = envelope['Test' + str(test)]['positive']['u']\n",
" F = envelope['Test' + str(test)]['positive']['F']\n",
" ind_peak = [ind for ind in range(len(F)) if F[ind] >= key['Test' + str(test)]['peak_force']['positive']]\n",
" key['Test' + str(test)]['delta_max']['positive'] = u[ind_peak[0]]/wall['height'][test]*100\n",
" \n",
" # negative value\n",
" u = []; F = []\n",
" u = envelope['Test' + str(test)]['negative']['u']\n",
" F = envelope['Test' + str(test)]['negative']['F']\n",
" ind_peak = [ind for ind in range(len(F)) if F[ind] >= key['Test' + str(test)]['peak_force']['negative']]\n",
" key['Test' + str(test)]['delta_max']['negative'] = u[ind_peak[0]]/wall['height'][test]*100\n",
"\n",
" # average value\n",
" key['Test' + str(test)]['delta_max']['average'] = (key['Test' + str(test)]['delta_max']['positive'] + key['Test' + str(test)]['delta_max']['negative'])/2\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Drift at SD limit state"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"# initialize\n",
"tmp_table = []\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive value\n",
" key['Test' + str(test)]['delta_SD']['positive'] = min(3*key['Test' + str(test)]['delta_cracking']['positive'],key['Test' + str(test)]['delta_max']['positive'])\n",
" \n",
" # negative value\n",
" key['Test' + str(test)]['delta_SD']['negative'] = min(3*key['Test' + str(test)]['delta_cracking']['negative'],key['Test' + str(test)]['delta_max']['negative'])\n",
"\n",
" # average value\n",
" key['Test' + str(test)]['delta_SD']['average'] = min(3*key['Test' + str(test)]['delta_cracking']['average'],key['Test' + str(test)]['delta_max']['average'])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Ultimate drift"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# note: I use here the interp function which is the closest to matlab interp1 function\n",
"# initialize \n",
"tmp_table = []\n",
"beta = 0.80\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive value\n",
" u = []; F = []; u_post = []; F_post = [];\n",
" u = envelope['Test' + str(test)]['positive']['u']\n",
" F = envelope['Test' + str(test)]['positive']['F']\n",
" ind_peak = [ind for ind in range(len(F)) if F[ind] >= key['Test' + str(test)]['peak_force']['positive']][0]\n",
" F_post = F[ind_peak:len(F)]\n",
" u_post = u[ind_peak:len(u)]\n",
" F_80 = beta*key['Test' + str(test)]['peak_force']['positive']\n",
" if F[-1] < F_80:\n",
" ind_80 = ind_peak + [ind for ind in range(len(F_post)) if F_post[ind] <= F_80][0] \n",
" key['Test' + str(test)]['delta_ultimate']['positive'] = u[ind_80]/wall['height'][test]*100\n",
" else:\n",
" ind_80 = len(F)\n",
" key['Test' + str(test)]['delta_ultimate']['positive'] = u[-1]/wall['height'][test]*100\n",
" \n",
" # negative value\n",
" u = []; F = []; u_post = []; F_post = [];\n",
" u = envelope['Test' + str(test)]['negative']['u']\n",
" F = envelope['Test' + str(test)]['negative']['F']\n",
" ind_peak = [ind for ind in range(len(F)) if F[ind] >= key['Test' + str(test)]['peak_force']['negative']][0]\n",
" F_post = F[ind_peak:len(F)]\n",
" u_post = u[ind_peak:len(u)]\n",
" F_80 = beta*key['Test' + str(test)]['peak_force']['negative']\n",
" if F[-1] < F_80:\n",
" ind_80 = ind_peak + [ind for ind in range(len(F_post)) if F_post[ind] <= F_80][0] \n",
" key['Test' + str(test)]['delta_ultimate']['negative'] = u[ind_80]/wall['height'][test]*100\n",
" else:\n",
" ind_80 = len(F)\n",
" key['Test' + str(test)]['delta_ultimate']['negative'] = u[-1]/wall['height'][test]*100\n",
"\n",
" # minimum value\n",
" if test == 4:\n",
" key['Test' + str(test)]['delta_ultimate']['minimum'] = max(key['Test' + str(test)]['delta_ultimate']['positive'],key['Test' + str(test)]['delta_ultimate']['negative'])\n",
" else:\n",
" key['Test' + str(test)]['delta_ultimate']['minimum'] = min(key['Test' + str(test)]['delta_ultimate']['positive'],key['Test' + str(test)]['delta_ultimate']['negative'])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Drift at collapse"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"# initialize\n",
"tmp_table = []\n",
"\n",
"# displacement values measured after visual inspection + DIC check\n",
"def disp_collapse_positive(i):\n",
" switcher={\n",
" 0:40.63,\n",
" 1:10.06,\n",
" 2:11.51,\n",
" 3:15.93,\n",
" 4:2.1,\n",
" 5:111.8860\n",
" }\n",
" return switcher.get(i)\n",
"def disp_collapse_negative(i):\n",
" switcher={\n",
" 0:22.19,\n",
" 1:21.93,\n",
" 2:13.71,\n",
" 3:21.84,\n",
" 4:10.44,\n",
" 5:111.8860\n",
" }\n",
" return switcher.get(i)\n",
"\n",
"# loop over the test units\n",
"for test in range(test_number):\n",
" \n",
" # positive negative and average values\n",
" key['Test' + str(test)]['delta_collapse']['positive'] = disp_collapse_positive(test)/wall['height'][test]*100\n",
" key['Test' + str(test)]['delta_collapse']['negative'] = disp_collapse_negative(test)/wall['height'][test]*100\n",
" if test == 4:\n",
" key['Test' + str(test)]['delta_collapse']['minimum'] = max(key['Test' + str(test)]['delta_collapse']['positive'],key['Test' + str(test)]['delta_collapse']['negative'])\n",
" else:\n",
" key['Test' + str(test)]['delta_collapse']['minimum'] = min(key['Test' + str(test)]['delta_collapse']['positive'],key['Test' + str(test)]['delta_collapse']['negative'])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1.11 Data Visualization Tool for Wall Structural Behaviour"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Import libraries"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
- "# Import libraries\n",
+ "# Import additional libraries for the dataviz tool\n",
"import ipywidgets as widgets\n",
- "\n",
"from ipywidgets import FloatSlider\n",
"from ipywidgets import interact, interactive, fixed, interact_manual, interactive_output, Text\n",
- "\n",
"from IPython.display import display\n",
- "import matplotlib.pyplot as plt\n",
- "import numpy as np\n",
- "\n",
"import pandas as pd\n",
"\n",
"%matplotlib nbagg\n",
"%matplotlib inline\n",
"\n",
"# to be able to use widgets I need to install this through the anaconda prompt\n",
"# conda install -c conda-forge nodejs\n",
"# conda install -c conda-forge ipywidgets\n",
"# jupyter labextension install @jupyter-widgets/jupyterlab-manager\n",
"# jupyter nbextension enable --py widgetsnbextension\n",
"# useful youtube video: https://www.youtube.com/watch?v=rkBPgTL-D3Y"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "e78e4835eaec41fabd4fad5fd434eeb7",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(VBox(children=(ToggleButtons(button_style='success', description='Test unit', index=2, options=…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7797c14c689c4f91864e5c06f7f63dcb",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Output()"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def select_units(i):\n",
" switcher={\n",
" 'F':'Horizontal Force (kN)',\n",
" 'N':'Vertical Force (kN)',\n",
" 'u':'Horizontal Displacement (mm)',\n",
" 'v':'Vertical Displacement (mm)',\n",
" }\n",
" return switcher.get(i)\n",
"\n",
"def select_add(i):\n",
" switcher={\n",
" 'None':None,\n",
" 'Positive Envelope':print('ciao'),\n",
" 'Negative Envelope':None,\n",
" }\n",
" return switcher.get(i)\n",
"\n",
"def update_plot(test, xaxis, yaxis, add_PosEnv, add_NegEnv, colour, f_size, if_grid, what_to_save, where_to_save):\n",
" \"\"\"\n",
" this function gets called to update the plot\n",
" \"\"\"\n",
" if not where_to_save.strip():\n",
" where_to_save = 'C:\\Temp'\n",
" \n",
" test_ind = [ind for ind in range(len(w_test.options)) if w_test.options[ind] == w_test.value][0]\n",
"\n",
" x = sc_tests.dataset['Test' + str(test_ind)][xaxis]\n",
" y = sc_tests.dataset['Test' + str(test_ind)][yaxis]\n",
" \n",
" plt.figure(figsize=(8,6))\n",
" plt.plot(x,y, color = colour)\n",
" \n",
" if add_PosEnv == True:\n",
" plt.plot(envelope['Test' + str(test_ind)]['positive']['u'], envelope['Test' + str(test_ind)]['positive']['F'], color = \"blue\" )\n",
" if add_NegEnv == True:\n",
" plt.plot(-envelope['Test' + str(test_ind)]['negative']['u'], -envelope['Test' + str(test_ind)]['negative']['F'], color = \"red\" )\n",
" \n",
" x_lim_lw = 1.2*min(sc_tests.dataset['Test' + str(test_ind)][xaxis])\n",
" x_lim_up = 1.2*max(sc_tests.dataset['Test' + str(test_ind)][xaxis])\n",
" y_lim_lw = 1.2*min(sc_tests.dataset['Test' + str(test_ind)][yaxis])\n",
" y_lim_up = 1.2*max(sc_tests.dataset['Test' + str(test_ind)][yaxis])\n",
" plt.xlim([x_lim_lw, x_lim_up])\n",
" plt.ylim([y_lim_lw, y_lim_up])\n",
" plt.xlabel(select_units(xaxis), fontsize = f_size-1)\n",
" plt.ylabel(select_units(yaxis), fontsize = f_size-1)\n",
" \n",
" plt.tick_params(axis='both', labelsize = f_size)\n",
" if if_grid == True:\n",
" plt.grid(if_grid)\n",
" \n",
" if what_to_save == \"Figure\":\n",
" plt.savefig(where_to_save + '\\Test_' + test + '_' + xaxis + '-' + yaxis + '.pdf', bbox_inches = 'tight')\n",
" print('Plots have been saved in ' + where_to_save)\n",
" \n",
" if what_to_save == \"Data\":\n",
" data_x1 = pd.DataFrame({xaxis: sc_tests.dataset['Test' + str(test_ind)][xaxis]})\n",
" data_y1 = pd.DataFrame({yaxis: sc_tests.dataset['Test' + str(test_ind)][yaxis]})\n",
" data_t = data_x1.join(data_y1)\n",
" if add_PosEnv == True:\n",
" data_x2 = pd.DataFrame({'u, Pos. Env': envelope['Test' + str(test_ind)]['positive']['u']})\n",
" data_y2 = pd.DataFrame({'F, Pos. Env.': envelope['Test' + str(test_ind)]['positive']['F']})\n",
" data_t = data_t.join(data_x2)\n",
" data_t = data_t.join(data_y2)\n",
" if add_NegEnv == True:\n",
" data_x3 = pd.DataFrame({'u, Neg. Env': - envelope['Test' + str(test_ind)]['negative']['u']})\n",
" data_y3 = pd.DataFrame({'F, Neg. Env.': - envelope['Test' + str(test_ind)]['negative']['F']})\n",
" data_t = data_t.join(data_x3)\n",
" data_t = data_t.join(data_y3)\n",
" data_t.to_csv(where_to_save + '\\Test_' + test + '_' + xaxis + '-' + yaxis + '.csv', index = False)\n",
" print('Data have been saved in ' + where_to_save)\n",
"\n",
"w_test = widgets.ToggleButtons(\n",
" options = ['SC1', 'SC2', 'SC4', 'SC5', 'SC6', 'SC7'],\n",
" value = 'SC4',\n",
" description = 'Test unit',\n",
" disabled = False,\n",
" button_style = 'success',\n",
")\n",
"\n",
"w_xaxis = widgets.ToggleButtons(\n",
" options = ['F', 'N', 'u', 'v'],\n",
" value = 'u',\n",
" description = 'X axis',\n",
" disabled = False,\n",
")\n",
"\n",
"w_yaxis = widgets.ToggleButtons(\n",
" options = ['F', 'N', 'u', 'v'],\n",
" value = 'F',\n",
" description = 'Y axis',\n",
" disabled = False,\n",
")\n",
"\n",
"w_colour = widgets.ColorPicker(\n",
" concise = False,\n",
" description = 'Plot options',\n",
" value = 'black',\n",
" disabled = False\n",
")\n",
"\n",
"w_add_PosEnvelope = widgets.Checkbox(\n",
" value = False,\n",
" description = 'Add positive envelope (for F-u)',\n",
" disabled = False\n",
")\n",
"\n",
"w_add_NegEnvelope = widgets.Checkbox(\n",
" value = False,\n",
" description = 'Add negative envelope (for F-u)',\n",
" disabled = False\n",
")\n",
"\n",
"w_f_size = widgets.IntSlider(\n",
" value = 28,\n",
" min = 2,\n",
" max = 50,\n",
" step = 1,\n",
" description = 'Font size',\n",
" disabled = False,\n",
" continuous_update = False,\n",
" orientation = 'horizontal',\n",
" readout = True,\n",
" readout_format = '.1f',\n",
")\n",
"\n",
"w_if_grid = widgets.Checkbox(\n",
" value = True,\n",
" description = 'Grid',\n",
" disabled = False\n",
")\n",
"\n",
"w_save = widgets.ToggleButtons(\n",
" options = ['Figure', 'Data'],\n",
" value = None,\n",
" description = 'Save',\n",
" disabled = False,\n",
" tooltips = ['Save plot in PDF-format','Save data in CSV-format'],\n",
" button_style = 'warning',\n",
")\n",
"\n",
"w_path = widgets.Textarea(\n",
" value='',\n",
" placeholder='Folder where to save plots and tables',\n",
" description='',\n",
" disabled=False\n",
")\n",
"\n",
"out = interactive_output(update_plot, {\"test\":w_test, \"xaxis\":w_xaxis, \"yaxis\":w_yaxis, \"add_PosEnv\":w_add_PosEnvelope, \"add_NegEnv\":w_add_NegEnvelope, \n",
" \"colour\":w_colour, \"f_size\":w_f_size, \"if_grid\":w_if_grid, \"what_to_save\":w_save, \"where_to_save\": w_path})\n",
"\n",
"hbox1 = widgets.VBox([w_test, w_yaxis, w_xaxis])\n",
"hbox2 = widgets.HBox([w_add_PosEnvelope, w_add_NegEnvelope])\n",
"hbox21 = widgets.HBox([widgets.HTML(value=\"\",description='',)])\n",
"hbox3 = widgets.HBox([w_colour, w_f_size, w_if_grid])\n",
"hbox4 = widgets.HBox([w_save, w_path])\n",
"ui = widgets.VBox([hbox1, hbox2, hbox3, hbox4])\n",
"\n",
"display(ui, out)\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}