def test_find_n_roots(): """test for find_n_roots""" #find_n_roots(func, args=(), n=1, x0=0.001, dx=0.001, p=1.0, fsolve_kwargs={}): assert_allclose(find_n_roots(math.sin, n=3, x0=0.1, dx=0.1, p=1.01), np.arange(1,4)*np.pi, atol=1e-5) #bessel roots from http://mathworld.wolfram.com/BesselFunctionZeros.html assert_allclose(find_n_roots(j0, n=3, x0=0.1, dx=0.1, p=1.01), np.array([2.4048, 5.5201, 8.6537]), atol=1e-4)
def test_find_n_roots(): """test for find_n_roots""" #find_n_roots(func, args=(), n=1, x0=0.001, dx=0.001, p=1.0, fsolve_kwargs={}): assert_allclose(find_n_roots(math.sin, n=3, x0=0.1, dx=0.1, p=1.01), np.arange(1, 4) * np.pi, atol=1e-5) #bessel roots from http://mathworld.wolfram.com/BesselFunctionZeros.html assert_allclose(find_n_roots(j0, n=3, x0=0.1, dx=0.1, p=1.01), np.array([2.4048, 5.5201, 8.6537]), atol=1e-4)
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 _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 _find_beta(self): """find the eigenvalues of the solution """ H = self.zlayer[-1] x0 = 0.1 / H**2 self._beta0 = np.empty(self.n, dtype=float) self._beta0[:] = find_n_roots(self._characteristic_eqn, n=self.n, x0=x0, dx=x0, p=1.01) return
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 _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 __init__(self, BC="SS", nterms=50, E=None, I=None, rho=None, A=None, L=None, k1=None, k3=None, mu=None, Fz=None, v=None, v_norm=None, kf=None, Fz_norm=None, mu_norm=None, k1_norm=None, k3_norm=None, nquad=30): self.BC = BC self.nterms = nterms self.E = E self.I = I self.rho = rho self.I = I self.A = A self.L = L self.k1 = k1 self.k3 = k3 self.mu = mu self.Fz = Fz self.v = v self.v_norm = v_norm self.kf = kf self.Fz_norm = Fz_norm self.mu_norm = mu_norm self.k1_norm = k1_norm self.k3_norm = k3_norm self.nquad = nquad # normalised parameters if kf is None: self.kf = 1 / self.L * np.sqrt(self.I / self.A) if v_norm is None: self.v_norm = self.v * np.sqrt(self.rho / self.E) if self.kf is None: self.kf = 1 / self.L * np.sqrt(self.I / self.A) if Fz_norm is None: self.Fz_norm = self.Fz / (self.E * self.A) if self.mu_norm is None: self.mu_norm = self.mu / self.A * np.sqrt(self.L**2 / (self.rho * self.E)) if self.k1_norm is None: self.k1_norm = self.k1 * self.L**2 / (self.E * self.A) if self.k3_norm is None: self.k3_norm = self.k3 * self.L**4 / (self.E* self.A) # phi, beta, and quadrature points if self.BC == "SS": self.phi = self.phiSS self.beta = np.pi * (np.arange(self.nterms) + 1) if not self.nquad is None: self.xj = 0.5 * (1 - np.cos(np.pi * np.arange(self.nquad) / (self.nquad - 1))) self.BC_coeff = 2 elif self.BC == "CC" or self.BC == "FF": def _f(beta): return 1 - np.cos(beta) * np.cosh(beta) self.beta = find_n_roots(_f, n=self.nterms, x0=0.001, dx=3.14159 / 10, p=1.1) if not self.nquad is None: self.xj = 0.5*(1 - np.cos(np.pi * np.arange(self.nquad)/(self.nquad - 3))) self.xj[0] = 0 self.xj[1] = 0.0001 self.xj[-2] = 0.0001 self.xj[-1] = 0 self.BC_coeff = 1 # Coefficeint to multiply Fz(vt) and k3*Integral terms by if self.BC == "CC": self.phi = self.phiCC if self.BC == "FF": self.phi = self.phiFF self.beta[1:] = self.beta[0:-1] self.beta[0] = 0.0 else: raise ValueError("only BC='SS', 'CC' and 'FF' have been implemented, you have {}".format(self.BC)) # quadrature weighting if not self.nquad is None: rhs = np.reciprocal(np.arange(self.nquad, dtype=float) + 1) lhs = self.xj[np.newaxis, :] ** np.arange(self.nquad)[:, np.newaxis] self.Ij = np.linalg.solve(lhs, rhs) self.vsvdot = np.zeros(2 * self.nterms) #vector of state values for odeint
def zhuandyin2012(z, t, alpha, p, q, drn=0, tpor=None, H = 1, kv0 = 1, mv0 = 0.1, gamw = 10, ui = 1, nterms = 20, plot_eigs=False): """Analysis and mathematical solutions for consolidation of a soil layer with depth-dependent parameters under confined compression. An implementation of Zhu and Yin (2012) [1]_. Features: - Single layer. - Permeability and volume compressibility can vary with depth with a power lay relationship. - Instant load uniform with depth. - PTIB ansd PTPB drainage conditions. - Pore pressure vs depth at variaous times - Degree of consolidation based on surface settlement vs time. - Settlement vs time. Parameters ---------- z : float or 1d array/list of float Depth. t : float or 1d array/list of float Time for degree of consolidation calcs. tpor : float or 1d array/list of float Time for pore pressure vs depth calcs. alpha, p, q : float Exponent in depth dependence of permeability and compressibility respectively. e.g. mv = mv0 * (1+alpha*z/H)**q. Note p/q cannot be 2; alpha cannot be zero. drn : [0,1], optional Drainage. drn=0 is pervious top pervious bottom. drn=1 is pervious bottom, impervious bottom. default drn=0. tpor : float or 1d array/list of float, optional Time values for pore pressure vs depth calcs. Default tpor=None i.e. time values will be taken from `t`. H : float, optional Drainage path length. default H=1. kv0 : float, optional Vertical coefficient of permeability. Default kv=1. mv0 : float, optional Volume compressibility. Default mv=0.1. gamw : float, optional Unit weight of water. Default gamw=10. ui : float, optional Initial uniform pore water pressure. Default ui=1. nterms : int, optional maximum number of series terms. default nterms=20. plot_eigs : True/False, optional If True then a plot of the characteristic curve and associated eigenvalues will be created. Use plt.show after runnning the program to display the curve. Use this to assess if the eigenvalues are correct. Default plot_eigs=False. Returns ------- por : 2d array of float Pore pressure at depth and time. ppress is an array of size (len(z), len(t)). doc : 1d array of float Degree of consolidation based on surface settlement. settlement : 1d array of float Surface settlement at time values Notes ----- kv = kv0 * (1+alp*z/H)**p mv = mv0 * (1+alp*z/H)**q References ---------- Code based on theroy in [1]_ ..[1] Zhu, G., and J. Yin. 2012. 'Analysis and Mathematical Solutions for Consolidation of a Soil Layer with Depth-Dependent Parameters under Confined Compression'. International Journal of Geomechanics 12 (4): 451-61. """ def Zmu(eta, mu, nu, b): """Depth fn""" return (bessely(nu, eta) * besselj(mu, eta * b) - besselj(nu, eta) * bessely(mu, eta * b)) def Zmu_(eta, mu, nu, b): """derivative of Zmu""" return ((besselj(mu - 1.0, eta * b)/2.0 - besselj(mu + 1.0, eta * b)/2.0)*bessely(nu, eta) - (bessely(mu - 1.0, eta * b)/2.0 - bessely(mu + 1.0, eta * b)/2.0)*besselj(nu, eta)) def drn1root(eta, mu, nu, b, p, n): """eigenvalue function""" return (1-p)/(2-n)*Zmu(eta, nu, nu, b) + eta * b * Zmu_(eta, nu, nu, b) z = np.atleast_1d(z) t = np.atleast_1d(t) if tpor is None: tpor = t else: tpor = np.atleast_1d(tpor) #derived parameters n = p-q b = (1 + alpha)**(1 - n/2) nu = abs((1 - p) / (2 - n)) # print('drn', drn) # print('p',p) # print('q', q) # print('n', n) # print('b', b) # print('nu', nu) # print('(1 - p) / (2 - n)',(1 - p) / (2 - n)) # plot_eigs=True if drn==0: etam = find_n_roots(Zmu, args=(nu, nu, b), n = nterms, p=1.01) if plot_eigs: fig=plt.figure(figsize=(20,5)) ax = fig.add_subplot('111') x = np.linspace(0.01,etam[-1],1000) y = Zmu(x, nu, nu, b) ax.plot(x, y, marker='.', markersize=3, ls='-') ax.plot(etam,np.zeros_like(etam), 'o', markersize=6, ) ax.set_ylim(-0.3,0.3) ax.set_xlabel('$\eta$') ax.set_ylabel('characteristic curve') ax.grid() fig.tight_layout() elif drn==1: etam = find_n_roots(drn1root, args=(nu, nu, b, p, n), n = nterms, p=1.01) if plot_eigs: fig=plt.figure(figsize=(20,5)) ax = fig.add_subplot('111') x = np.linspace(0.01,etam[-1],1000) y = drn1root(x, nu, nu, b, p, n) ax.plot(x, y, marker='.', markersize=3, ls='-') ax.plot(etam,np.zeros_like(etam), 'o', markersize=6, ) ax.set_ylim(-0.3,0.3) ax.set_xlabel('$\eta$') ax.set_ylabel('characteristic curve') ax.grid() fig.tight_layout() eta0=etam[0] etam = etam[np.newaxis, np.newaxis, :] cv0 = kv0 / (mv0 * gamw) dTv = cv0 * (2 - n)**2 * alpha**2 * eta0**2 / (np.pi**2 * H**2) y = (1 + alpha * z / H)**(1-n/2) y = y[:, np.newaxis, np.newaxis] T = dTv * tpor T = T[np.newaxis, :, np.newaxis] Tm = np.exp(-np.pi**2 * etam**2 / (4 * eta0**2) * T) # if np.allclose(tpor, t): # Tm_ = Tm.copy() Zm = Zmu(etam, nu, nu, y) if drn == 0: # if -nu == (p - 1) / (2 - n): if np.allclose(-nu, (p - 1) / (2 - n)): numer = 2*np.pi * (2 + np.pi * etam * b**(1-nu) * Zmu(etam, nu-1, nu, b)) denom = 4-(b * np.pi * etam * Zmu(etam, 1 + nu, nu, b))**2 Cm = numer/denom else: numer = 2*np.pi * (2 - np.pi * etam * b**(1+nu) * Zmu(etam, 1+nu, nu, b)) denom = 4-(b * np.pi * etam * Zmu(etam, 1 + nu, nu, b))**2 Cm = numer/denom elif drn == 1: numer = 4 * np.pi denom = 4 - (b * np.pi * etam * Zmu(etam, nu, nu, b))**2 Cm = numer / denom por = Cm*Zm*Tm por *= ui * y**((1 - p)/(2 - n)) por = np.sum(por, axis=2) #degree of consolidation etam = etam[0, :, :] # if np.allclose(tpor, t): # Tm=Tm_[0,:,:] # else: T = dTv * t T = T[:, np.newaxis] Tm = np.exp(-np.pi**2 * etam**2 / (4 * eta0**2) * T) if drn == 0: # if -nu == (p - 1) / (2 - n): if np.allclose(-nu, (p - 1) / (2 - n)): numer = (2 + np.pi * etam * b**(1-nu) * Zmu(etam, nu-1, nu, b))**2 denom = etam**2 * ((b * np.pi * etam * Zmu(etam, 1 + nu, nu, b))**2-4) Cm = numer/denom else: print('got here') numer = (2 - np.pi * etam * b**(1+nu) * Zmu(etam, 1 + nu, nu, b))**2 denom = etam**2 * ((b * np.pi * etam * Zmu(etam, 1 + nu, nu, b))**2-4) Cm = numer/denom elif drn == 1: numer = 1.0 denom = etam**2*((b * np.pi * etam * Zmu(etam, nu, nu, b))**2-4) Cm = numer / denom doc = np.sum(Cm*Tm,axis=1) if drn==0: numer = 4*(1+q) # numer_settle = 4 elif drn==1: numer = 16*(1+q) # numer_settle = 16 denom = (2 - n) * ((1+alpha)**(1 + q) - 1) # denom_settle = (2 - n) # settle = mv0*ui*(1 - (H/alpha*numer_settle / denom_settle) * doc) fr = numer / denom doc*= -fr doc += 1 settle = doc * ui* mv0*((1+alpha)**(1 + q) - 1)/(1+q)*H/alpha # print(",".join(['{:.3g}']*4).format((1 - p) / (2 - n), nu, t[0], doc[0])) return por, doc, settle