Source code for geotecha.consolidation.nogamiandli2003

# geotecha - A software suite for geotechncial engineering
# Copyright (C) 2018  Rohan T. Walker (rtrwalker@gmail.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses/gpl.html.

"""
Nogami and Li (2003) 'Consolidation of Clay with a System of Vertical and
Horizontal Drains'.

"""
from __future__ import print_function, division

import numpy as np
import matplotlib.pyplot as plt
import matplotlib

import geotecha.inputoutput.inputoutput as inputoutput
import math
import textwrap
import scipy.optimize
import geotecha.piecewise.piecewise_linear_1d as pwise
import cmath
import time
from geotecha.mathematics.root_finding import find_n_roots
import geotecha.plotting.one_d
import scipy.special
#from scipy.special import j0, y0, j1, y1

besselj = scipy.special.jn
bessely = scipy.special.yn

from geotecha.inputoutput.inputoutput import GenericInputFileArgParser


[docs]class NogamiAndLi2003(inputoutput.InputFileLoaderCheckerSaver): """Multi-layer vertical and radial consolidation using matrix transfer Partially implements the article by Nogami and Li (2003) [1]_. While the article includes special treatment for sand layers and geotextile layers, this implementation only considers 'soil' layers. (Sand layers are just normal layers with high kv and low mv). The coding is not of high quality. The main use is for verification of speccon models noting that Nogami and Li (2003) use rigourous methods where as speccon uses equal-strain assumptions for the radial flow part. Features: - Multiple layers. - Vertical flow and radial flow to a central drain (no smear zone). - Load is uniform with depth but varies piecewise-linear with time. - No assumptions on radial distribution of strain (i.e. NOT equal-strain). - pore pressure vs depth at various times. Either at a particular radial coordinate or averaged in the radial direction. - Average pore pressure vs time. Average is over the entire soil layer. .. warning:: The 'Parameters' and 'Attributes' sections below require further explanation. The parameters listed below are not used to explicitly initialize the object. Rather they are defined in either a multi-line string or a file-like object using python syntax. It is the file object or string object that is used to initialize the object. Each 'parameter' will be turned into an attribute that can be accessed using conventional python dot notation, after the object has been initialised. The attributes listed below are calculated values (i.e. they could be interpreted as results) which are accessible using dot notation after all calculations are complete. Parameters ---------- z : list/array of float Depth to calc pore pressure at. t : list/array of float Time values to calc average pore pressure at. tpor : list/array of float Time values to calc pore pressure profiles at. h : list/array of float Layer thicknesses. nv, nh : tuple of 2 int, optional Number of series terms to use in vertical and horizontal direction. Default nv=nh=5. kv, kh : list/array of float Layer vertical and horizontal permeability divided by unit weight of water. mv : list/array of float Layer volume compressibility. bctop, bcbot : [0, 1] Boundary condition. bctop=0 is free draining, bctop=1 is impervious. surcharge_vs_time : PolyLine Piecewise linear variation of surcharge with time r1, r0 : float optional drain influence zone and drain radius. If either is none then only vertical drainage will be considered. rcalc : float, optional Radial coordinate at which to calc pore pressure. Default rcalc=None i.e. pore pressure is averaged in the radial direction. radial_roots_x0 : float, optional Starting point for finding radial eigenvalues. Default radial_roots_x0=1e-3. radial_roots_dx : float, optional Starting increment for finding radial eigenvalues. Default radial_roots_dx=1e-3. radial_roots_p : float, optional Succesive increment length increase factor for finding radial eigenvalues. default radial_roots_p=1.05. vertical_roots_x0 : float, optional Starting point for finding vertical eigenvalues. Default vertical_roots_x0=1e-7. vertical_roots_dx : float, optional Starting increment for finding vertical eigenvalues. Default vertical_roots_dx=1e-7. vertical_roots_p : float, optional Succesive increment lenght increase factor for finding vertical eigenvalues. Default vertical_roots_p=1.05. max_iter : int, optional Max iterations when searching for eigenvalue intervals. Default max_iter=10000 show_vert_eigs : True/False, optional If true a vertical eigen value plot will be made. Default show_vert_eigs=False plot_properties : dict of dict, optional dictionary that overrides some of the plot properties. Each member of `plot_properties` will correspond to one of the plots. ================== ============================================ plot_properties description ================== ============================================ por dict of prop to pass to pore pressure plot. avp dict of prop to pass to average pore pressure plot. set dict of prop to pass to settlement plot. ================== ============================================ see geotecha.plotting.one_d.plot_vs_depth and geotecha.plotting.one_d.plot_vs_time for options to specify in each plot dict. save_data_to_file : True/False, optional If True data will be saved to file. Default save_data_to_file=False save_figures_to_file : True/False If True then figures will be saved to file. Default save_figures_to_file=False show_figures : True/False, optional If True the after calculation figures will be shown on screen. Default show_figures=False. directory : string, optional Path to directory where files should be stored. Default directory=None which will use the current working directory. Note if you keep getting directory does not exist errors then try putting an r before the string definition. i.e. directory = r'C:\\Users\\...' overwrite : True/False, optional If True then existing files will be overwritten. Default overwrite=False. prefix : string, optional Filename prefix for all output files. Default prefix= 'out' create_directory : True/Fase, optional If True a new sub-folder with name based on `prefix` and an incremented number will contain the output files. Default create_directory=True. data_ext : string, optional File extension for data files. Default data_ext='.csv' input_ext : string, optional File extension for original and parsed input files. default = ".py" figure_ext : string, optional File extension for figures. Can be any valid matplotlib option for savefig. Default figure_ext=".eps". Others include 'pdf', 'png'. title : str, optional A title for the input file. This will appear at the top of data files. Default title=None, i.e. no title. author : str, optional Author of analysis. Default='unknown'. Attributes ---------- por : array of shape (len(z), len(tpor)) Pore pressure vs depth at various times. Only present if tpor defined. If rcalc defined then porepressure will be at r=rcalc. If rcalc is not defined then pore pressure is averaged radially avp : array of shape (1, len(t)) Averge pore pressure of profile various times. Only present if t defined. If rcalc defined then pore pressure will be at r=rcalc. If rcalc is not defined then pore pressure is averaged radially set : array of shape (1, len(t)) Surface settlement at various times. Only present if t defined. If rcalc defined then settlement will be at r=rcalc. If `rcalc` is not defined then settlement is averaged radially. Notes ----- It is possbile to initialize the object without a file-like object or multi-line string, i.e. using the default reader=None. This is not recommended because you have to explicitly set each attribute. It will most likely be easier to use a string or file object and then do any custom modifications to the attributes afterwards. This program relies on numerical root finding, which can be extremely troublesome in for the vertical eigenvalue case here (Mainly because I never figured out how to normalise in the z direction... but that is another story). You will probably need to fine tune the vertical_roots parameters to ensure the correct eigenvalues have been found, so: 1. Run the program with the defaults. If it actually excecutes go to step 3. 2. Increase a combo of `vertical_roots_dx`, `vertical_roots_p` and `max_iter` untill the program excecutes. 3. Does your pore pressure vs depth plots look ok. If yes, then possibly accept the results. But better to check eigen values in step 4. 4. Run the method `_plot_vert_roots` with enough points to smoothly show the characteristic curve. zoom in on the roots and check if all the roots are found (usually the problems occur with leftmost line. If not alter `vertical_roots_dx`, `vertical_roots_p` and `max_iter` untill all roots are captured. Basically if you choose `vertical_roots_dx` tiny, `vertical_roots_p`=1, and `max_iter` huge then you will find all the roots but it may take a long time. Root finding is very hard when there are clumps of closely spaced roots but the clumps themselves are far apart. Also note that there are errors in eq.24a and eq.24b in the published article of Nogami and Li. Also I could never get the vertical normalisation to work. Also I've done my own normalising for the radial part. See Also -------- geotecha.piecewise.piecewise_linear_1d.PolyLine : How to specify loadings References ---------- .. [1] Nogami, Toyoaki, and Maoxin Li. 'Consolidation of Clay with a System of Vertical and Horizontal Drains'. Journal of Geotechnical and Geoenvironmental Engineering 129, no. 9 (2003): 838-48. doi:10.1061/(ASCE)1090-0241(2003)129:9(838). """ def _setup(self): """This method overwrites the _setup method in inputoutput.InputFileLoaderCheckerSaver """ self._attribute_defaults = {'bctop': 0, 'bcbot': 0, 'radial_roots_x0': 1e-3, 'radial_roots_dx': 1e-3, 'radial_roots_p': 1.05, 'vertical_roots_x0': 1e-7, 'vertical_roots_dx': 1e-7, 'vertical_roots_p': 1.05, 'max_iter': 10000, 'prefix': 'nl2003_', 'show_vert_eigs': False} self._attributes = ('z t tpor nv nh h kv kh mv bctop bcbot ' 'surcharge_vs_time r0 r1 rcalc ' 'radial_roots_x0 radial_roots_dx radial_roots_p ' 'vertical_roots_x0 vertical_roots_dx vertical_roots_p ' 'max_iter show_vert_eigs' ).split() self._attributes_that_should_have_same_len_pairs = [ 'h kv'.split(), 'kv mv'.split(), 'h mv'.split(), 'h kh'.split(), 'h kv'.split(), 'h mv'.split()] #pairs that should have the same length self._attributes_that_should_be_lists= [] self._attributes_that_should_have_same_x_limits = [] self.z = None self.t = None self.tpor = None self.nv = self._attribute_defaults.get('nv', None) self.nh = self._attribute_defaults.get('nh', None) self.h = None self.kv = None self.kh = None self.mv = None self.bctop = self._attribute_defaults.get('bctop', None) self.bcbot = self._attribute_defaults.get('bcbot', None) self.r0 = None self.r1 = None self.rcalc = None self.radial_roots_x0 = self._attribute_defaults.get('radial_roots_x0', None) self.radial_roots_dx = self._attribute_defaults.get('radial_roots_dx', None) self.radial_roots_p = self._attribute_defaults.get('radial_roots_p', None) self.vertical_roots_x0 = self._attribute_defaults.get('vertical_roots_x0', None) self.vertical_roots_dx = self._attribute_defaults.get('vertical_roots_dx', None) self.vertical_roots_p = self._attribute_defaults.get('vertical_roots_p', None) self.max_iter = self._attribute_defaults.get('max_iter', None) self.show_vert_eigs=self._attribute_defaults.get('show_vert_eigs', None) self.surcharge_vs_time = None self._zero_or_all = [ 'h kv mv'.split(), 'r0 r1'.split()] self._at_least_one = [ ['mv'], ['surcharge_vs_time'], 'kv kh'.split(), 'tpor t'.split(),] self._one_implies_others = ['r0 r1 kh nh'.split(), 'r1 r0 kh nh'.split(), 'kh r0 r1 nh'.split(), 'nh kh r0 r1'.split()] def _calc_derived_properties(self): """Calculate properties/ratios derived from input""" self.check_input_attributes() # if self.rcalc is None: # self.rcalc=self.r1 if not self.t is None: self.t = np.asarray(self.t) self.z = np.asarray(self.z) self.kv = np.asarray(self.kv) self.mv = np.asarray(self.mv) if not self.kh is None: self.kh = np.asarray(self.kh) self.ch = self.kh / self.mv else: self.nh = 1 self.ch = np.zeros_like(self.mv) self.h = np.asarray(self.h) self.nlayers = len(self.kv) self.zlayer = np.cumsum(self.h) self.cv = self.kv / self.mv # self.use_normalised = True #use_normalised is only relevant fot the radial component. #I couldn't get non-normalised to work, hence why it is hard coded in #rather than a user variable. I could never get the vertical #normalisation working so I gave up trying if self.bctop == 0: self.phia0 = np.array([0.0, 1.0]) elif self.bctop == 1: self.phia0 = np.array([1.0, 0.0]) #index of phib at bottom to check if self.bcbot == 0: self.phi_i_check = 0 elif self.bcbot == 1: self.phi_i_check = 1
[docs] def un_normalised_average(self,s): """u(r) part of u(r, z, t) = u(r) * phi(z) * T(t), averaged betw r0 r1 """ r0 = self.r0 r1 = self.r1 nn = r1/r0 return -self.un_normalised(r0,s,1)*2 / (nn**2-1)/s
[docs] def un_normalised(self, r, s, order): """u(r) part of u(r, z, t) = u(r) * phi(z) * T(t) This version is normalised w.r.t. r0 """ r0 = self.r0 r1 = self.r1 return besselj(order, r/r0*s)*bessely(0, s) - besselj(0, s)*bessely(order, r/r0*s)
def _radial_characteristic_curve(self, s): """Zeros of this function provide the radial eigenvalues""" r0 = self.r0 r1 = self.r1 return self.un_normalised(r1, s, 1) def _find_sn(self): """Find the radial eigenvalues""" if self.kh is None: self._sn=np.array([0]) else: self._sn = find_n_roots(self._radial_characteristic_curve, n=self.nh,x0=self.radial_roots_x0, dx=self.radial_roots_dx, p = self.radial_roots_p, max_iter=self.max_iter) def _beta(self, alp, s): """beta from alp**2 = cv*beta**2 + cr * s**2 / r0**2""" if self.r0 is None: r0=1 else: r0 = self.r0 a = 1/self.cv * alp**2 -(self.ch/self.cv)*s**2/r0**2 return np.sqrt(np.array(a, dtype=complex)) def _calc_phia_and_phidota(self): """Determine the pore pressure and pore pressure gradient at top of each layer Can only be done after finding alp """ sin = cmath.sin cos = cmath.cos self._phia = np.zeros((self.nh, self.nv, self.nlayers), dtype=float) self._phidota = np.zeros((self.nh, self.nv, self.nlayers), dtype=float) self._phia[:,:,0] = self.phia0[0] self._phidota[:,:,0] = self.phia0[1] # print('o'*40) for i in range(self.nh): s = self._sn[i] square = np.zeros((2,2), dtype=complex) for j in range(self.nv): alp = self._alp[i, j] phia = np.array([self.phia0[0], self.phia0[1]], dtype=complex) # print(i, 's=', s) # print(j, 'alp=', alp) for k in range(self.nlayers): h = self.h[k] beta = self._betamn[i, j, k] if cmath.polar(beta)[0]==0: phib = np.array([phia[0],0], dtype=complex) # phib[0] = phia[0] # phib[1] = 0+0j else: square[0,0] = cos(beta*h) square[0,1] = sin(beta*h) / beta square[1,0] = -beta*sin(beta*h) square[1,1] = cos(beta*h) phib = np.dot(square, phia) # print(k, beta, phia, phib) if k != self.nlayers-1: # we are not in the last layer # transfer phib to next layers phia phia[0] = phib[0] phia[1] = phib[1] * self.kv[k] / self.kv[k+1] self._phia[i,j,k + 1] = phia[0].real self._phidota[i, j, k+1] = phia[1].real#phib[1] * self.kv[i] / self.kv[i+1] #check # print('_', alp, 's', phib.real) if abs(phib[self.phi_i_check].real)>0.1: pass print('bottom BC not satisfied. ih=',i,'jv=', j ) # raise ValueError('Bottom BC not satisfied') def _vertical_characteristic_curve(self, alp, s): """the roots of this function will give the vertical eigenvalues Parameters ---------- alp : float alp common for all layers s : float radial eigen value """ sin = cmath.sin cos = cmath.cos phia = np.array([self.phia0[0], self.phia0[1]], dtype=complex) square = np.zeros((2,2), dtype=complex) beta = self._beta(alp, s) # print("*", 's=', s) # print('alp=', alp) for i, h in enumerate(self.h): if cmath.polar(beta[i])[0]==0: phib = np.array([phia[0], 0], dtype=complex) # phib[0] = phia[0] # phib[1] = 0+0j else: square[0,0] = cos(beta[i]*h) square[0,1] = sin(beta[i]*h) / beta[i] square[1,0] = -beta[i]* sin(beta[i]*h) square[1,1] = cos(beta[i]*h) phib = np.dot(square, phia) # print(i, beta[i], phia, phib) if i != self.nlayers - 1: # we are not in the last layer #transfer phib to the next layer phia phia[0]= phib[0] phia[1] = phib[1] * self.kv[i] / self.kv[i+1] ret = phib[self.phi_i_check].real return ret def _find_alp(self): """find alp by matrix transfer method""" self._alp = np.zeros((self.nh, self.nv), dtype=float) for n, s in enumerate(self._sn): if s==0: alp_start_offset = min(1e-7, self.vertical_roots_dx) else: alp_start_offset = 0 if n==0: alp=self.vertical_roots_x0 else: alp = self._alp[n-1,0] self._alp[n,:] = find_n_roots(self._vertical_characteristic_curve, args=(s,),n= self.nv, x0 = alp+alp_start_offset, dx = self.vertical_roots_dx, p = self.vertical_roots_p, max_iter=self.max_iter, fsolve_kwargs={}) def _calc_Cn(self): """Calc Cn part of the coefficient Cmn""" self._Cn = np.zeros(self.nh, dtype=float) if self.kh is None: self._Cn[:]=1 return r0 = self.r0 r1 = self.r1 for n, s in enumerate(self._sn): numer = -r0**2/s * self.un_normalised(r0, s, 1) denom = r0**2/2 * (r1**2/r0**2 * self.un_normalised(r1, s, 0)**2 - self.un_normalised(r0, s, 1)**2) self._Cn[n] = numer / denom def _calc_betamn(self): """calc beta for each layer and each eigenvalue combination""" self._betamn = np.zeros((self.nh, self.nv, self.nlayers), dtype=complex) for i in range(self.nh): s = self._sn[i] for j in range(self.nv): alp = self._alp[i, j] self._betamn[i,j,:] = self._beta(alp, s) def _calc_Amn_and_Bmn(self): """calc coefficeints Amn and Bmn for each layer and eigenvalue combination""" sin = cmath.sin cos = cmath.cos self._Amn = np.zeros((self.nh, self.nv, self.nlayers), dtype=complex) self._Bmn = np.zeros((self.nh, self.nv, self.nlayers), dtype=complex) for i in range(self.nh): s = self._sn[i] square = np.zeros((2,2), dtype=float) for j in range(self.nv): alp = self._alp[i, j] phia = self.phia0 for k in range(self.nlayers): h = self.h[k] bet = self._betamn[i, j, k] phi_a = self._phia[i, j, k] phi_a_dot = self._phidota[i, j, k] if cmath.polar(bet)[0]==0: self._Amn[i,j,k] = h*phi_a self._Bmn[i,j,k] = h*phi_a**2 else: self._Amn[i,j,k] = (phi_a*sin(bet*h)/bet - phi_a_dot*cos(bet*h)/bet**2 + phi_a_dot/bet**2) self._Bmn[i,j,k] = (h*phi_a**2*sin(bet*h)**2/2 + h*phi_a**2*cos(bet*h)**2/2 + phi_a**2*sin(bet*h)*cos(bet*h)/(2*bet) + h*phi_a_dot**2*sin(bet*h)**2/(2*bet**2) + h*phi_a_dot**2*cos(bet*h)**2/(2*bet**2) - phi_a*phi_a_dot*cos(bet*h)**2/bet**2 + phi_a*phi_a_dot/bet**2 - phi_a_dot**2*sin(bet*h)*cos(bet*h)/(2*bet**3)) def _calc_Cm(self): """Calc Cm part of the coefficient Cmn""" self._calc_Amn_and_Bmn() self._Cm = np.zeros((self.nh, self.nv), dtype=complex) for i in range(self.nh): s = self._sn[i] for j in range(self.nv): alp = self._alp[i, j] # phia = self.phia0 numer = 0.0 denom = 0.0 for k in range(self.nlayers): h = self.h[k] mv = self.mv[k] Amn = self._Amn[i,j,k] Bmn = self._Bmn[i,j,k] numer += mv*Amn denom += mv*Bmn self._Cm[i,j] = numer / denom def _calc_Cmn(self): """calc the coefficient Cmn = Cm * Cn""" self._calc_Cn() self._calc_Cm() self._Cmn = np.zeros((self.nh, self.nv), dtype=complex) for i in range(self.nh): Cn = self._Cn[i] for j in range(self.nv): Cm = self._Cm[i,j] self._Cmn[i,j] = Cm * Cn
[docs] def calc(self): """Perform all calculations""" self._calc_derived_properties() self._find_sn() self._find_alp() self._calc_betamn() self._calc_phia_and_phidota() self._calc_Cmn() self._calc_por() return
[docs] def make_all(self): """Check input, make_output produce files and plots""" self.check_input_attributes() self.make_output() if getattr(self, 'save_data_to_file', False): self._save_data() if (getattr(self, 'save_figures_to_file', False) or getattr(self, 'show_figures', False)): self.produce_plots() if getattr(self, 'save_figures_to_file', False): self._save_figures() if getattr(self, 'show_figures', False): plt.show()
[docs] def make_output(self): """make all output""" self._calc_derived_properties() self._find_sn() self._find_alp() self._calc_betamn() self._calc_phia_and_phidota() self._calc_Cmn() # self._calc_por() header1 = "program: nogamiandli2003; geotecha version: {}; author: {}; date: {}\n".format(self.version, self.author, time.strftime('%Y/%m/%d %H:%M:%S')) if not self.title is None: header1 += "{}\n".format(self.title) if not self.rcalc is None: extra = " at r={0:.3g}".format(self.rcalc) else: extra="" self._grid_data_dicts = [] if not self.tpor is None: self._calc_por() labels = ['{:.3g}'.format(v) for v in self.z] d = {'name': '_data_por', 'data': self.por.T, 'row_labels': self.tpor, 'row_labels_label': 'Time', 'column_labels': labels, 'header': header1 + 'Pore pressure at depth'+extra} self._grid_data_dicts.append(d) if not self.t is None: self._calc_avp() labels = ['{:.3g} to {:.3g}'.format(0, sum(self.h))] d = {'name': '_data_avp', 'data': self.avp.T, 'row_labels': self.t, 'row_labels_label': 'Time', 'column_labels': labels, 'header': header1 + 'Average pore pressure between depths' + extra} self._grid_data_dicts.append(d) labels = ['{:.3g} to {:.3g}'.format(0, sum(self.h))] d = {'name': '_data_set', 'data': self.avp.T, 'row_labels': self.t, 'row_labels_label': 'Time', 'column_labels': labels, 'header': header1 + 'settlement between depths' + extra} self._grid_data_dicts.append(d) return
[docs] def produce_plots(self): """produce plots of analysis""" # geotecha.plotting.one_d.pleasing_defaults() # matplotlib.rcParams['figure.dpi'] = 80 # matplotlib.rcParams['savefig.dpi'] = 80 matplotlib.rcParams.update({'font.size': 11}) matplotlib.rcParams.update({'font.family': 'serif'}) self._figures=[] #por if not self.tpor is None: f=self._plot_por() title = 'fig_por' f.set_label(title) f.canvas.manager.set_window_title(title) self._figures.append(f) if not self.t is None: f=self._plot_avp() title = 'fig_avp' f.set_label(title) f.canvas.manager.set_window_title(title) self._figures.append(f) f=self._plot_set() title = 'fig_set' f.set_label(title) f.canvas.manager.set_window_title(title) self._figures.append(f) if self.show_vert_eigs: f = self._plot_vert_roots(1000) title = 'vertical characteristic curve and eigs' f.set_label(title) f.canvas.manager.set_window_title(title) self._figures.append(f)
def _plot_por(self): """plot depth vs pore pressure for various times """ if not self.rcalc is None: extra = " at r={0:.3g}".format(self.rcalc) else: extra=" (radial average)" t = self.tpor line_labels = ['{:.3g}'.format(v) for v in t] por_prop = self.plot_properties.pop('por', dict()) if not 'xlabel' in por_prop: por_prop['xlabel'] = 'Pore pressure'+extra #to do fig_por = geotecha.plotting.one_d.plot_vs_depth(self.por, self.z, line_labels=line_labels, prop_dict=por_prop) return fig_por def _plot_avp(self): """plot average pore pressure of profile""" if not self.rcalc is None: extra = " at r={0:.3g}".format(self.rcalc) else: extra=" (radial average)" t = self.t line_labels = ['{:.3g} to {:.3g}'.format(0, sum(self.h))] avp_prop = self.plot_properties.pop('avp', dict()) if not 'ylabel' in avp_prop: avp_prop['ylabel'] = 'Average pore pressure'+extra fig_avp = geotecha.plotting.one_d.plot_vs_time(t, self.avp.T, line_labels=line_labels, prop_dict=avp_prop) return fig_avp def _plot_set(self): """plot surface settlement""" if not self.rcalc is None: extra = " at r={0:.3g}".format(self.rcalc) else: extra=" (radial average)" t = self.t line_labels = ['{:.3g} to {:.3g}'.format(0, sum(self.h))] set_prop = self.plot_properties.pop('set', dict()) if not 'ylabel' in set_prop: set_prop['ylabel'] = 'surface settlement'+extra fig_set = geotecha.plotting.one_d.plot_vs_time(t, self.set.T, line_labels=line_labels, prop_dict=set_prop) fig_set.gca().invert_yaxis() return fig_set def _calc_Tm(self, alp, t): """calculate the Tm expression at a given time Parameters ---------- alp : float eigenvalue for layer t : float time value Returns ------- Tm: float time dependant function """ loadmag = self.surcharge_vs_time.y loadtim = self.surcharge_vs_time.x (ramps_less_than_t, constants_less_than_t, steps_less_than_t, ramps_containing_t, constants_containing_t) = pwise.segment_containing_also_segments_less_than_xi(loadtim, loadmag, t, steps_or_equal_to = True) exp = math.exp Tm=0 cv = 1 # I copied the Tm function from SchiffmanAndStein1970 i=0 #only one time value for k in steps_less_than_t[i]: sig1 = loadmag[k] sig2 = loadmag[k+1] Tm += (sig2-sig1)*exp(-cv * alp**2 * (t-loadtim[k])) for k in ramps_containing_t[i]: sig1 = loadmag[k] sig2 = loadmag[k+1] t1 = loadtim[k] t2 = loadtim[k+1] # Tm += (-sig1 + sig2)/(alp**2*cv*(-t1 + t2)) - (-sig1 + sig2)*exp(-alp**2*cv*t)*exp(alp**2*cv*t1)/(alp**2*cv*(-t1 + t2)) Tm += (-sig1 + sig2)/(alp**2*cv*(-t1 + t2)) - (-sig1 + sig2)*exp(-alp**2*cv*(t-t1))/(alp**2*cv*(-t1 + t2)) for k in ramps_less_than_t[i]: sig1 = loadmag[k] sig2 = loadmag[k+1] t1 = loadtim[k] t2 = loadtim[k+1] # Tm += -(-sig1 + sig2)*exp(-alp**2*cv*t)*exp(alp**2*cv*t1)/(alp**2*cv*(-t1 + t2)) + (-sig1 + sig2)*exp(-alp**2*cv*t)*exp(alp**2*cv*t2)/(alp**2*cv*(-t1 + t2)) Tm += -(-sig1 + sig2)*exp(-alp**2*cv*(t-t1))/(alp**2*cv*(-t1 + t2)) + (-sig1 + sig2)*exp(-alp**2*cv*(t-t2))/(alp**2*cv*(-t1 + t2)) return Tm def _calc_un(self): """u(r) part of u(r, z, t) = u(r) * phi(z) * T(t)""" self._un = np.ones_like(self._sn) if not self.kh is None: for i, s in enumerate(self._sn): if not self.rcalc is None: self._un[i] = self.un_normalised(self.rcalc, s, 0) else: self._un[i] = self.un_normalised_average(s) def _calc_por(self): """calculate the pore pressure""" sin = cmath.sin cos = cmath.cos # if self.tpor is None: # self.tpor==self.t if self.tpor is None: return self.por = np.zeros((len(self.z), len(self.tpor)), dtype=float) z_in_layer = np.searchsorted(self.zlayer, self.z) self._calc_un() for p, t in enumerate(self.tpor): for i in range(self.nh): s = self._sn[i] un = self._un[i] for j in range(self.nv): alp = self._alp[i, j] Tm = self._calc_Tm(alp, t) for k, z in enumerate(self.z): layer = z_in_layer[k] zlay = z - (self.zlayer[layer] - self.h[layer]) bet = self._betamn[i, j, layer] Cmn = self._Cmn[i, j].real phi_a = self._phia[i, j, layer] phi_a_dot = self._phidota[i, j, layer] phi = (cos(bet * zlay) * phi_a + sin(bet * zlay)/bet * phi_a_dot) self.por[k, p] += Cmn * un * phi.real * Tm def _calc_avp(self): """calculate the average pore pressure""" sin = cmath.sin cos = cmath.cos h_all = sum(self.h) if self.t is None: return self.avp = np.zeros((1, len(self.t)), dtype=float) self.set = np.zeros((1, len(self.t)), dtype=float) z_in_layer = np.searchsorted(self.zlayer, self.z) self._calc_un() for p, t in enumerate(self.t): for i in range(self.nh): s = self._sn[i] un = self._un[i] for j in range(self.nv): alp = self._alp[i, j] Tm = self._calc_Tm(alp, t) load = pwise.pinterp_x_y(self.surcharge_vs_time, t) for layer, h in enumerate(self.h): # layer = z_in_layer[k] # zlay = z - (self.zlayer[layer] - self.h[layer]) bet = self._betamn[i, j, layer] Cmn = self._Cmn[i, j].real phi_a = self._phia[i, j, layer] phi_a_dot = self._phidota[i, j, layer] phi = (sin(bet * h) / bet * phi_a + (1-cos(bet * h))/bet**2*phi_a_dot) self.avp[0, p] += Cmn * un * phi.real / h_all * Tm self.set[0, p] += self.mv[layer] * (load * h /self.nh/self.nv - Cmn * un * phi.real * Tm) def _plot_vert_roots(self, npt=200): """Plot the vertical characteristic curve and it's roots After a 'successful' run, use this to check the validity of the calculated vertical eigenvalues and ensure none are missing Parameters ---------- npt : int, optional number of points to plot. default=200 """ fig = plt.figure(figsize=(40, 8)) ax = fig.add_subplot('111') for i in range(self.nh): s = self._sn[i] # amin=self._alp_min()[i] # amin=0.001 amin = 0.3*self._alp[i,0] x = np.linspace(amin, self._alp[i,-1], npt) y = np.zeros_like(x) for j,_x in enumerate(x): y[j] = self._vertical_characteristic_curve(_x, s) # print(x[i],y[i]) # print(y) ax.plot(x, y, ls='-', marker='.', markersize=3) c = ax.get_lines()[-1].get_color() ax.set_ylim((-1,1)) ax.plot(self._alp[i,:], np.zeros_like(self._alp[i,:]), 'o', color=c) ax.set_title('vertical_roots_x0={}, vertical_roots_dx={}, vertical_roots_p={}'.format(self.vertical_roots_x0, self.vertical_roots_dx, self.vertical_roots_p)) ax.set_xlabel('beta') ax.set_ylabel('value of characterisrtic curve') ax.grid() fig.tight_layout() return fig
[docs]def main(): """Run nogamiandli2003 as script""" a = GenericInputFileArgParser(obj=NogamiAndLi2003, methods=[('make_all', [], {})], pass_open_file=True) a.main()
if __name__ == '__main__': # import nose # nose.runmodule(argv=['nose', '--verbosity=3', '--with-doctest']) ## nose.runmodule(argv=['nose', '--verbosity=3']) main()