Source code for pypassive.alqarawi_et_al_2021
import math
from typing import Any
from scipy.optimize import minimize_scalar
[docs]
class AlqarawiLogSpiral:
"""Compute passive pressure on retaining wall.
ref: Alqarawi, A. S., Leo, C. J., Liyanapathirana, D. S., Sigdel, L., Lu, M., and Hu, P. (2012).
A spreadsheet-based technique to calculate the passive soil pressure based on log-spiral method.
Computers and Geotechnics 130.
"""
def __init__(self, soil_layer, retaining_wall):
"""Initialize the log spiral method for passive pressure with soil_layer and foundation.
:param soil_layer: a class defined with soil layer properties
:type: :class:SoilLayer
:param retaining_wall: a class defined with retaining wall dimensions and surcharge loading.
:type: :class:RetainingWall
"""
self._c: float = soil_layer.c
self._phi: float = math.radians(soil_layer.phi)
self._gamma: float = soil_layer.gamma
self._delta: float = math.radians(soil_layer.delta)
self._h: float = retaining_wall.h
self._omega: float = math.radians(retaining_wall.omega)
self._beta: float = math.radians(retaining_wall.beta)
self._q: float = retaining_wall.q
# Eqn 6, Wall height is the vertical projection so no need for Eqn 5
# |ab| = H/cos(omega)
self._ab = retaining_wall.h / math.cos(self._omega)
# Eqn 7
self._xhat: float = retaining_wall.h * math.tan(self._omega)
# Eqn 1
self._alpha1: float = self.calc_alpha1()
# Eqn 2
self._alpha2: float = self.calc_alpha2()
# Eqn 7
self._eta: float = self._alpha1 - self._beta
# Eqn 31
self._nu: float = self._eta - self._delta + self._omega
# rest of the coordinates and lengths/distances
self._xa: float = 0
self._ya: float = 0
self._xb: float = 0
self._yb: float = 0
self._xg: float = 0
self._yg: float = 0
self._rg: float = 0
self._xf: float = 0
self._yf: float = 0
self._ag: float = 0
self._fg: float = 0
# Moments
self._Mrw: float = 0
self._Mqh: float = 0
self._Mobg: float = 0
self._Moba: float = 0
self._Mabg: float = 0
self._Mq: float = 0
self._Magfp: float = 0
self._l1: float = 0
# passive ford
self._Pp: float = 0
[docs]
def calc_alpha1(self) -> float:
"""Eq 1"""
return (
math.pi / 4
- self._phi / 2
+ 0.5 * math.asin(math.sin(self._beta) / math.sin(self._phi))
- self._beta / 2
)
[docs]
def calc_alpha2(self) -> float:
"""Eq 2"""
return (
math.pi / 4
- self._phi / 2
- 0.5 * math.asin(math.sin(self._beta) / math.sin(self._phi))
+ self._beta / 2
)
[docs]
def calc_coords(self, zeta: float) -> None:
"""Coordinates that define salient points"""
# Eqn 9
self._xa = abs(zeta) * math.cos(self._eta)
# Eqn 10
self._ya = abs(zeta) * math.sin(self._eta)
# Eqn 11
self._ro = math.sqrt((self._h + self._ya) ** 2 + (self._xa + self._xhat) ** 2)
# Eqn 12
self._xb = self._xa + abs(self._xhat)
# Eqn 13
self._yb = self._ya + self._h
# Eqn 14
self._thetag = math.asin(self._yb / self._ro) - self._eta
# Eqn 3
self._rg = self._ro * math.exp(self._thetag * math.tan(self._phi))
# Eqn 15
self._xg = self._rg * math.cos(self._eta)
# Eqn 16
self._yg = self._rg * math.sin(self._eta)
# Eqn 17
self._ag = self._rg - abs(zeta)
# Eqn 18
self._fg = self._ag * math.sin(self._alpha1)
# Eqn 19
self._xf = self._xg - self._fg * math.sin(self._beta)
# Eqn 20
self._yf = self._yg - self._fg * math.cos(self._beta)
# angle between the ro and the vertical
self._lambda = math.atan(self._xb / self._yb)
[docs]
def calc_Mobg(self) -> float:
# Eqn 27
t1 = (
(self._ro**3 * math.cos(self._lambda))
/ (3 * (1 + 9 * math.tan(self._phi) ** 2))
* (
1
+ math.exp(3 * self._thetag * math.tan(self._phi))
* (
3 * math.tan(self._phi) * math.sin(self._thetag)
- math.cos(self._thetag)
)
)
)
t2 = (
(self._ro**3 * math.sin(self._lambda))
/ (3 * (1 + 9 * math.tan(self._phi) ** 2))
* (
math.exp(3 * self._thetag * math.tan(self._phi))
* (
math.sin(self._thetag)
+ 3 * math.tan(self._phi) * math.cos(self._thetag)
)
- 3 * math.tan(self._phi)
)
)
return t1 + t2
[docs]
def calc_Moba(self) -> float:
# Eqn 29
return (
1 / 6 * (self._xa * self._yb - self._xb * self._ya) * (self._xa + self._xb)
)
[docs]
def calc_Mabg(self) -> float:
# Eqn 30
self._Mobg = self.calc_Mobg()
self._Moba = self.calc_Moba()
return (self._Mobg - self._Moba) * self._gamma
[docs]
def calc_l1(self, zeta: float) -> float:
# Eq 32, 33, and 34
return abs(zeta) * math.sin(self._nu) + 2 / 3 * self._ab * math.cos(self._delta)
[docs]
def calc_afp(self) -> None:
# Eqn 38
af = abs(self._xf - self._xa) / math.cos(self._beta)
# Eqn 37
return af + self._fg * math.tan(self._beta)
[docs]
def calc_Mq(self) -> float:
# Eqn 38
afp = self.calc_afp()
# Eqn 36
surcharge_load = self._q * afp
return surcharge_load * (self._xa + (self._xg - self._xa) / 2)
[docs]
def calc_Mrw(self) -> float:
kp = self.calc_kp()
# Eqn 41
hrw = self._fg / math.cos(self._beta)
# Eqn 35
lrw = self._rg * math.sin(self._alpha1) - 1 / 3 * self._fg
prw = 1 / 2 * kp * self._gamma * hrw**2 * math.cos(self._beta)
return prw * lrw
[docs]
def calc_Mqh(self) -> float:
# Eqn 41
hrw = self._fg / math.cos(self._beta)
# Eqn 42
kp = self.calc_kp()
fq = self._q * math.cos(self._beta) * kp * hrw
lq = self._rg * math.sin(self._alpha1) - self._fg / 2
return fq * lq
[docs]
def calc_Magfp(self):
afp = self.calc_afp()
# Eq 43
return 1 / 6 * afp * self._fg * self._gamma * (self._xa + self._xg + self._xg)
[docs]
def calc_kp(self) -> float:
"""Rankine's passive pressure coefficient for sloped backfill."""
# Eqn 42
return (
math.cos(self._beta)
+ math.sqrt(math.cos(self._beta) ** 2 - math.cos(self._phi) ** 2)
) / (
math.cos(self._beta)
- math.sqrt(math.cos(self._beta) ** 2 - math.cos(self._phi) ** 2)
)
[docs]
def calc_moments(self) -> None:
self._Mabg = self.calc_Mabg()
self._Mq = self.calc_Mq()
self._Mqh = self.calc_Mqh()
self._Mrw = self.calc_Mrw()
self._Magfp = self.calc_Magfp()
[docs]
def calc_passive_force_all(self, zeta: float) -> float:
"""Determine the total passive force from moment equilibrium."""
self.calc_coords(zeta)
self.calc_moments()
self._l1 = self.calc_l1(zeta)
return 1 / self._l1 * (self._Mrw + self._Mqh + self._Mabg + self._Mq + self._Magfp)
[docs]
def passive_force(self) -> float:
"""Minize the passive force by changing, zeta, the center of the log spiral"""
bnds = (-3.0 * self._h, 0 * self._h)
res = minimize_scalar(
self.calc_passive_force_all,
bounds=bnds,
method="bounded",
)
self._zeta = res.x
self._Ep = res.fun
return res