initial commit

This commit is contained in:
2026-08-07 20:11:16 +05:30
commit a28cde3903
7 changed files with 380 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
*.py[codz]
__pycache__/
.mypy_cache/
.pytest_cache/
.ruff_cache/
.pdm-python
Generated
+90
View File
@@ -0,0 +1,90 @@
# This file is @generated by PDM.
# It is not intended for manual editing.
[metadata]
groups = ["default"]
strategy = ["inherit_metadata"]
lock_version = "4.5.0"
content_hash = "sha256:758d4d2ec35c05f925622890ce94547018729181f38472c8cd765765109d4eec"
[[metadata.targets]]
requires_python = "==3.14.*"
[[package]]
name = "numpy"
version = "2.4.4"
requires_python = ">=3.11"
summary = "Fundamental package for array computing in Python"
groups = ["default"]
files = [
{file = "numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0"},
{file = "numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a"},
{file = "numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a"},
{file = "numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b"},
{file = "numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a"},
{file = "numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d"},
{file = "numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252"},
{file = "numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f"},
{file = "numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc"},
{file = "numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74"},
{file = "numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb"},
{file = "numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e"},
{file = "numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113"},
{file = "numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d"},
{file = "numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d"},
{file = "numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f"},
{file = "numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0"},
{file = "numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150"},
{file = "numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871"},
{file = "numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e"},
{file = "numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7"},
{file = "numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0"},
]
[[package]]
name = "pypassive"
version = "0.0.1"
requires_python = ">=3.11"
summary = "A simple python package to compute p-y curve using log-spiral method and hyperbolic relationship."
groups = ["default"]
dependencies = [
"numpy>=1.26.2",
"scipy>=1.11.4",
]
files = [
{file = "pypassive-0.0.1-py3-none-any.whl", hash = "sha256:7c71a675459878117c7d02f232565e4ef549be9aafd4f01b707394a98c80f840"},
{file = "pypassive-0.0.1.tar.gz", hash = "sha256:40519cc33801cd37896c75f7a86ff3e50ecd765c077841a521d640539ee339a2"},
]
[[package]]
name = "scipy"
version = "1.17.1"
requires_python = ">=3.11"
summary = "Fundamental algorithms for scientific computing in Python"
groups = ["default"]
dependencies = [
"numpy<2.7,>=1.26.4",
]
files = [
{file = "scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717"},
{file = "scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9"},
{file = "scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b"},
{file = "scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866"},
{file = "scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350"},
{file = "scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118"},
{file = "scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068"},
{file = "scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118"},
{file = "scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19"},
{file = "scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293"},
{file = "scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6"},
{file = "scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1"},
{file = "scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39"},
{file = "scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca"},
{file = "scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad"},
{file = "scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a"},
{file = "scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4"},
{file = "scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2"},
{file = "scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484"},
{file = "scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21"},
{file = "scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0"},
]
+15
View File
@@ -0,0 +1,15 @@
[project]
name = "retain"
version = "0.1.0"
description = "Default template for PDM package"
authors = [
{name = "Alexander Rossmanith", email = ""},
]
dependencies = ["pypassive>=0.0.1"]
requires-python = "==3.14.*"
readme = "README.md"
license = {text = "MIT"}
[tool.pdm]
distribution = false
View File
+269
View File
@@ -0,0 +1,269 @@
import math
def main():
# --- Soil parameters ---
# phi = angle of internal friction: The angle that describes the shear strength of soil due to friction between particles. Unit: radians.
# gamma = unit weight: The weight of soil per unit volume. Unit: kilonewtons per cubic meter (kN/m³).
# c = cohesion: The shear strength of soil that comes from the bonding between particles, independent of normal stress. Unit: kilopascals (kPa).
# q_allow = allowable soil bearing capacity: The maximum pressure that the soil can safely support without risk of shear failure or excessive settlement. Unit: kN/m².
# q_allow should be confirmed with plate load test or SPT at foundation depth
#
# Sand: phi = 30-40°, gamma = 18-20 kN/m³
# Clay: phi = 15-25°, gamma = 17-19 kN/m³, c=10-50 kPa
# Silt: phi = 25-35°, gamma = 17-19 kN/m³
# Gravel: phi = 35-45°, gamma = 19-22 kN/m³
# Laterite/forest hill soils: Typically clayey with gravel inclusions, so φ ≈ 20°–28° is a reasonable assumption.
# If your site has compacted laterite with gravel, φ can be closer to 28°–32°.
phi = math.radians(30.0)
q_allow = 150.0 # kN/m² Allowable soil bearing capacity (typical for compacted laterite with gravel),
gamma = 18.0 # Soil unit weight (kN/m³)
c = 15.0 # Cohesion (kPa)
# --- Seismic parameters ---
kh = 0.05 # Seismic coefficient (Zone III)
# --- Wall parameters ---
Hw = 3.3 # Wall height (m)
Hf = 0.5 # Foundation depth (m)
H = Hw + Hf # Total height for earth pressure calculations
surcharge = 10.0 # Surcharge load (kN/m²)
delta = phi / 2 # Wall friction angle (radians)
beta = math.radians(0.0) # Backfill slope angle (radians)
base_width = 2.1 # m
batter = 1/3.5 # Wall batter (horizontal/vertical)
top_width = base_width - batter * H
print(f"Base width: {base_width:.2f} m, Top width: {top_width:.2f} m")
print("Height (H): {:.2f} m, Soil unit weight (γ): {:.2f} kN/m³, φ: {:.1f}°, Surcharge: {:.2f} kN/m²".format(H, gamma, math.degrees(phi), surcharge))
# --- Wall material properties ---
# "black stones" = basalt or dolerite rubble quarried locally.
wall_density = 30.0 # kN/m³
# --- EARTH PRESSURE COEFFICIENTS ---
Ka = rankine_Ka(phi)
Kp = rankine_Kp(phi)
# Ka = coulomb_Ka(phi, delta, beta)
# Kp = coulomb_Kp(phi, delta, beta)
# --- EARTH PRESSURES ---
Pa = 0.5 * gamma * H**2 * Ka + surcharge * H * Ka # Active pressure
Pp = 0.5 * gamma * H**2 * Kp # Passive resistance
print(f"Active pressure (Pa): {Pa:.2f} kN/m")
print(f"Passive resistance (Pp): {Pp:.2f} kN/m")
# --- STABILITY CHECKS ---
wall_weight = wall_density * trapezoidal_prism_volume(H, base_width, top_width)
FS_sliding = Pp / Pa
resisting_moment = wall_weight * (base_width/2)
driving_moment = Pa * (Hw/3)
FS_overturning = resisting_moment / driving_moment
q = wall_weight / base_width
print(f"Sliding FS: {FS_sliding:.2f} (required: 1.5)")
print(f"Overturning FS: {FS_overturning:.2f} (required: 2.0)")
print(f"Base pressure: {q:.2f} kN/m²")
# --- Bearing Check ---
M_net = resisting_moment - driving_moment
q_max, q_min, e, safe, suggestion = bearing_check(wall_weight, base_width, M_net, q_allow)
print(f"Eccentricity: {e:.3f} m")
print(f"Toe pressure (q_max): {q_max:.2f} kN/m²")
print(f"Heel pressure (q_min): {q_min:.2f} kN/m²")
print(f"Bearing check safe? {safe}")
if suggestion:
print("Suggestion:", suggestion)
# --- Bearing Check (Terzaghi + Meyerhof) ---
M_net = resisting_moment - driving_moment
# Location of resultant from toe
x_res = M_net / wall_weight
# Eccentricity = distance from centroid (B/2)
e = x_res - base_width / 2
q_ult, q_applied, FS_bearing, B_eff = bearing_capacity_terzaghi(phi, c, gamma, base_width, wall_weight, e)
middle_third_limit = base_width / 6
print(f"Eccentricity: {e:.3f} m")
print(f"Middle third limit: {middle_third_limit:.3f} m")
if abs(e) <= middle_third_limit:
print("✓ Resultant lies within middle third (no heel tension)")
else:
print("✗ Outside middle third (heel tension likely)")
print(f"Effective base width: {B_eff:.2f} m")
print(f"Applied pressure: {q_applied:.2f} kN/m²")
print(f"Ultimate capacity: {q_ult:.2f} kN/m²")
print(f"Bearing FS: {FS_bearing:.2f} (required: 2.5)")
# --- Volume and Material Estimation ---
volume = trapezoidal_prism_volume(H, base_width, top_width)
void_ratio = 0.1 # Assumed void ratio for rubble fill
material_volume = volume * (1 + void_ratio)
material_weight = material_volume * wall_density
print(f"Estimated material volume per meter of wall (including voids): {cubic_meters_to_cubic_feet(material_volume):.2f} ft³")
print(f"Estimated material weight per meter of wallin kg: {material_weight*1000/9.81:.0f} kg")
def rankine_Ka(phi):
# Rankine active earth pressure coefficient for vertical wall, horizontal backfill
return math.tan(math.pi/4 - phi/2)**2
def rankine_Kp(phi):
return math.tan(math.pi/4 + phi/2)**2
def coulomb_Ka(phi, delta, beta):
'''
Coulomb active earth pressure coefficient
Args:
phi: Soil friction angle (radians)
delta: Wall friction angle (radians)
beta: Backfill slope angle (radians)
Returns:
Ka: Active earth pressure coefficient
'''
num = math.cos(phi - beta)**2
den = math.cos(beta) * math.cos(delta + phi)
val = (math.sin(phi + delta) * math.sin(phi - beta)) / (math.cos(delta + phi) * math.cos(beta))
if val < 0:
raise ValueError("Invalid geometry")
return num / (den * (1 + math.sqrt(val))**2)
def coulomb_Kp(phi, delta, beta=0):
'''
Coulomb passive earth pressure coefficient
Args:
phi: Soil friction angle (radians)
delta: Wall friction angle (radians)
beta: Backfill slope angle (radians, default 0 for horizontal backfill)
Returns:
Kp: Passive earth pressure coefficient
'''
num = math.cos(phi + beta)**2
den = math.cos(beta) * math.cos(beta - delta)
val = (math.sin(phi + delta) * math.sin(phi - beta)) / (math.cos(beta - delta) * math.cos(beta + phi))
if val < 0:
raise ValueError("Invalid geometry")
return num / (den * (1 - math.sqrt(val))**2)
def mononobe_okabe_Ka(phi, delta, beta, kh, kv=0):
'''
Mononobe-Okabe seismic active earth pressure coefficient
Args:
phi: Soil friction angle (radians)
delta: Wall friction angle (radians)
beta: Backfill slope angle (radians)
kh: Horizontal seismic coefficient
kv: Vertical seismic coefficient (default 0)
Returns:
Ka: Seismic active earth pressure coefficient
'''
theta = math.atan(kh / (1 - kv))
num = math.cos(phi - theta)**2
den = math.cos(theta) * math.cos(delta + theta)
val = (math.sin(phi + delta) * math.sin(phi - beta - theta)) / (math.cos(delta + theta) * math.cos(beta + phi))
if val < 0:
raise ValueError("Invalid geometry")
return num / (den * (1 + math.sqrt(val))**2)
def bearing_capacity_terzaghi(phi, c, gamma_soil, B, W, e):
phi_rad = phi
Nq = math.exp(math.pi * math.tan(phi_rad)) * math.tan(math.pi/4 + phi_rad/2)**2
Nc = (Nq - 1) / math.tan(phi_rad)
Nγ = 2 * (Nq + 1) * math.tan(phi_rad)
# Effective width (Meyerhof correction)
B_eff = max(0.1, B - 2*abs(e))
# Shape factors (simplified)
sc = 1 + 0.2 * (B_eff / B)
sγ = 1 - 0.3 * (B_eff / B)
# Ultimate capacity
q_ult = c * Nc * sc + 0.5 * gamma_soil * B_eff * Nγ * sγ
q_applied = W / B_eff
FS_bearing = q_ult / q_applied
return q_ult, q_applied, FS_bearing, B_eff
def bearing_check(W, B, M, q_allow):
'''
Calculate bearing pressures and check against allowable soil capacity.
Also suggest base width adjustment if heel pressure is negative.
Args:
W: Total vertical load (kN)
B: Base width (m)
M: Net moment about toe (kN-m)
q_allow: Allowable soil bearing capacity (kN/m²)
Returns:
q_max: Pressure at toe (kN/m²)
q_min: Pressure at heel (kN/m²)
e: Eccentricity (m)
safe: Boolean indicating if bearing check is safe
suggestion: Text suggestion if unsafe
'''
e = M / W # eccentricity
q_avg = W / B
q_max = q_avg * (1 + 6*e/B)
q_min = q_avg * (1 - 6*e/B)
safe = True
suggestion = None
if q_min < 0:
safe = False
# Minimum base width to eliminate heel tension: B_min = 6e
B_min = 6 * e
suggestion = f"Increase base width to at least {B_min:.2f} m to avoid heel tension."
if q_max > q_allow:
safe = False
suggestion = f"Reduce pressure or increase base width; q_max exceeds allowable {q_allow:.2f} kN/m²."
return q_max, q_min, e, safe, suggestion
def trapezoidal_prism_volume(height, base_width, top_width, length=1.0):
"""
Calculate volume of a trapezoidal prism.
Args:
base_width: Average base thickness
height: Total wall height including foundation
top_width: Average top thickness
length: Wall length, default = 1 (per running metre)
Returns:
volume: Volume of the trapezoidal prism
"""
return (base_width + top_width) / 2 * height * length
def cubic_meters_to_cubic_feet(cubic_meters):
'''
Convert cubic meters to cubic feet.
Args:
cubic_meters: Volume in cubic meters
Returns:
Volume in cubic feet
'''
return cubic_meters * 35.3147
if __name__ == "__main__":
main()
View File
View File