geolysis 0.4.4__py3-none-any.whl → 0.4.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geolysis/__init__.py +1 -1
- geolysis/bearing_capacity/abc/cohl/__init__.py +30 -90
- geolysis/bearing_capacity/abc/cohl/_core.py +55 -0
- geolysis/bearing_capacity/abc/cohl/bowles_abc.py +1 -1
- geolysis/bearing_capacity/abc/cohl/meyerhof_abc.py +1 -1
- geolysis/bearing_capacity/abc/cohl/terzaghi_abc.py +1 -1
- geolysis/bearing_capacity/ubc/__init__.py +42 -219
- geolysis/bearing_capacity/ubc/_core.py +192 -0
- geolysis/bearing_capacity/ubc/hansen_ubc.py +3 -2
- geolysis/bearing_capacity/ubc/terzaghi_ubc.py +2 -1
- geolysis/bearing_capacity/ubc/vesic_ubc.py +4 -3
- geolysis/foundation.py +51 -17
- geolysis/soil_classifier.py +24 -22
- geolysis/spt.py +195 -73
- {geolysis-0.4.4.dist-info → geolysis-0.4.5.dist-info}/METADATA +3 -3
- geolysis-0.4.5.dist-info/RECORD +23 -0
- {geolysis-0.4.4.dist-info → geolysis-0.4.5.dist-info}/WHEEL +1 -1
- geolysis-0.4.4.dist-info/RECORD +0 -21
- {geolysis-0.4.4.dist-info → geolysis-0.4.5.dist-info/licenses}/LICENSE.txt +0 -0
- {geolysis-0.4.4.dist-info → geolysis-0.4.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,192 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
from geolysis.foundation import FoundationSize
|
4
|
+
from geolysis.utils import arctan, round_, tan, validators
|
5
|
+
|
6
|
+
|
7
|
+
class UltimateBearingCapacity(ABC):
|
8
|
+
def __init__(self, friction_angle: float,
|
9
|
+
cohesion: float,
|
10
|
+
moist_unit_wgt: float,
|
11
|
+
foundation_size: FoundationSize,
|
12
|
+
load_angle=0.0,
|
13
|
+
apply_local_shear=False) -> None:
|
14
|
+
r"""
|
15
|
+
:param friction_angle: Internal angle of friction for general shear
|
16
|
+
failure (degrees).
|
17
|
+
:type friction_angle: float
|
18
|
+
|
19
|
+
:param cohesion: Cohesion of soil (:math:`kPa`).
|
20
|
+
:type cohesion: float
|
21
|
+
|
22
|
+
:param moist_unit_wgt: Moist unit weight of soil (:math:`kN/m^3`).
|
23
|
+
:type moist_unit_wgt: float
|
24
|
+
|
25
|
+
:param foundation_size: Size of the foundation.
|
26
|
+
:type foundation_size: FoundationSize
|
27
|
+
|
28
|
+
:param load_angle: Inclination of the applied load with the vertical
|
29
|
+
(:math:`\alpha^{\circ}`), defaults to 0.0.
|
30
|
+
:type load_angle: float, optional
|
31
|
+
|
32
|
+
:param apply_local_shear: Indicate whether bearing capacity failure is
|
33
|
+
general shear or local shear failure,
|
34
|
+
defaults to False.
|
35
|
+
:type apply_local_shear: bool, optional
|
36
|
+
"""
|
37
|
+
self.friction_angle = friction_angle
|
38
|
+
self.cohesion = cohesion
|
39
|
+
self.moist_unit_wgt = moist_unit_wgt
|
40
|
+
self.load_angle = load_angle
|
41
|
+
self.foundation_size = foundation_size
|
42
|
+
self.apply_local_shear = apply_local_shear
|
43
|
+
|
44
|
+
@property
|
45
|
+
def friction_angle(self) -> float:
|
46
|
+
"""Return friction angle for local shear in the case of local shear
|
47
|
+
failure or general shear in the case of general shear failure.
|
48
|
+
"""
|
49
|
+
if self.apply_local_shear:
|
50
|
+
return arctan((2 / 3) * tan(self._friction_angle))
|
51
|
+
return self._friction_angle
|
52
|
+
|
53
|
+
@friction_angle.setter
|
54
|
+
@validators.ge(0.0)
|
55
|
+
def friction_angle(self, val: float):
|
56
|
+
self._friction_angle = val
|
57
|
+
|
58
|
+
@property
|
59
|
+
def cohesion(self) -> float:
|
60
|
+
"""Return cohesion for local shear in the case of local shear failure
|
61
|
+
or general shear in the case of general shear failure.
|
62
|
+
"""
|
63
|
+
if self.apply_local_shear:
|
64
|
+
return (2.0 / 3.0) * self._cohesion
|
65
|
+
return self._cohesion
|
66
|
+
|
67
|
+
@cohesion.setter
|
68
|
+
@validators.ge(0.0)
|
69
|
+
def cohesion(self, val: float):
|
70
|
+
self._cohesion = val
|
71
|
+
|
72
|
+
@property
|
73
|
+
def moist_unit_wgt(self) -> float:
|
74
|
+
"""Moist unit weight of soil (:math:`kN/m^3`)."""
|
75
|
+
return self._moist_unit_wgt
|
76
|
+
|
77
|
+
@moist_unit_wgt.setter
|
78
|
+
@validators.gt(0.0)
|
79
|
+
def moist_unit_wgt(self, val: float):
|
80
|
+
self._moist_unit_wgt = val
|
81
|
+
|
82
|
+
@property
|
83
|
+
def load_angle(self) -> float:
|
84
|
+
"""Inclination of the applied load with the vertical."""
|
85
|
+
return self._load_angle
|
86
|
+
|
87
|
+
@load_angle.setter
|
88
|
+
@validators.le(90.0)
|
89
|
+
@validators.ge(0.0)
|
90
|
+
def load_angle(self, val: float):
|
91
|
+
self._load_angle = val
|
92
|
+
|
93
|
+
@property
|
94
|
+
def s_c(self) -> float:
|
95
|
+
"""Shape factor :math:`S_c`"""
|
96
|
+
return 1.0
|
97
|
+
|
98
|
+
@property
|
99
|
+
def s_q(self) -> float:
|
100
|
+
"""Shape factor :math:`S_q`"""
|
101
|
+
return 1.0
|
102
|
+
|
103
|
+
@property
|
104
|
+
def s_gamma(self) -> float:
|
105
|
+
r"""Shape factor :math:`S_{\gamma}`"""
|
106
|
+
return 1.0
|
107
|
+
|
108
|
+
@property
|
109
|
+
def d_c(self) -> float:
|
110
|
+
"""Depth factor :math:`d_c`"""
|
111
|
+
return 1.0
|
112
|
+
|
113
|
+
@property
|
114
|
+
def d_q(self) -> float:
|
115
|
+
"""Depth factor :math:`d_q`"""
|
116
|
+
return 1.0
|
117
|
+
|
118
|
+
@property
|
119
|
+
def d_gamma(self) -> float:
|
120
|
+
r"""Depth factor :math:`d_{\gamma}`"""
|
121
|
+
return 1.0
|
122
|
+
|
123
|
+
@property
|
124
|
+
def i_c(self) -> float:
|
125
|
+
"""Inclination factor :math:`i_c`"""
|
126
|
+
return 1.0
|
127
|
+
|
128
|
+
@property
|
129
|
+
def i_q(self) -> float:
|
130
|
+
"""Inclination factor :math:`i_q`"""
|
131
|
+
return 1.0
|
132
|
+
|
133
|
+
@property
|
134
|
+
def i_gamma(self) -> float:
|
135
|
+
r"""Inclination factor :math:`i_{\gamma}`"""
|
136
|
+
return 1.0
|
137
|
+
|
138
|
+
def _cohesion_term(self, coef: float = 1.0) -> float:
|
139
|
+
return coef * self.cohesion * self.n_c * self.s_c * self.d_c * self.i_c
|
140
|
+
|
141
|
+
def _surcharge_term(self) -> float:
|
142
|
+
depth = self.foundation_size.depth
|
143
|
+
water_level = self.foundation_size.ground_water_level
|
144
|
+
|
145
|
+
if water_level is None:
|
146
|
+
water_corr = 1.0 # water correction
|
147
|
+
else:
|
148
|
+
# water level above the base of the foundation
|
149
|
+
a = max(depth - water_level, 0.0)
|
150
|
+
water_corr = min(1 - 0.5 * a / depth, 1)
|
151
|
+
|
152
|
+
# effective overburden pressure (surcharge)
|
153
|
+
eop = self.moist_unit_wgt * depth
|
154
|
+
return eop * self.n_q * self.s_q * self.d_q * self.i_q * water_corr
|
155
|
+
|
156
|
+
def _embedment_term(self, coef: float = 0.5) -> float:
|
157
|
+
depth = self.foundation_size.depth
|
158
|
+
width = self.foundation_size.effective_width
|
159
|
+
water_level = self.foundation_size.ground_water_level
|
160
|
+
|
161
|
+
if water_level is None:
|
162
|
+
# water correction
|
163
|
+
water_corr = 1.0
|
164
|
+
else:
|
165
|
+
#: b -> water level below the base of the foundation
|
166
|
+
b = max(water_level - depth, 0)
|
167
|
+
water_corr = min(0.5 + 0.5 * b / width, 1)
|
168
|
+
|
169
|
+
return (coef * self.moist_unit_wgt * width * self.n_gamma
|
170
|
+
* self.s_gamma * self.d_gamma * self.i_gamma * water_corr)
|
171
|
+
|
172
|
+
@round_
|
173
|
+
def bearing_capacity(self):
|
174
|
+
"""Calculates the ultimate bearing capacity."""
|
175
|
+
return (self._cohesion_term(1.0)
|
176
|
+
+ self._surcharge_term()
|
177
|
+
+ self._embedment_term(0.5))
|
178
|
+
|
179
|
+
@property
|
180
|
+
@abstractmethod
|
181
|
+
def n_c(self) -> float:
|
182
|
+
...
|
183
|
+
|
184
|
+
@property
|
185
|
+
@abstractmethod
|
186
|
+
def n_q(self) -> float:
|
187
|
+
...
|
188
|
+
|
189
|
+
@property
|
190
|
+
@abstractmethod
|
191
|
+
def n_gamma(self) -> float:
|
192
|
+
...
|
@@ -8,10 +8,11 @@ Classes
|
|
8
8
|
|
9
9
|
HansenUltimateBearingCapacity
|
10
10
|
"""
|
11
|
-
from geolysis.
|
12
|
-
from geolysis.foundation import FoundationSize, Shape
|
11
|
+
from geolysis.foundation import Shape
|
13
12
|
from geolysis.utils import cos, cot, exp, isclose, pi, round_, sin, tan
|
14
13
|
|
14
|
+
from ._core import UltimateBearingCapacity
|
15
|
+
|
15
16
|
__all__ = ["HansenUltimateBearingCapacity"]
|
16
17
|
|
17
18
|
|
@@ -13,9 +13,10 @@ Classes
|
|
13
13
|
"""
|
14
14
|
from abc import ABC
|
15
15
|
|
16
|
-
from geolysis.bearing_capacity.ubc import UltimateBearingCapacity
|
17
16
|
from geolysis.utils import cos, cot, deg2rad, exp, isclose, pi, round_, tan
|
18
17
|
|
18
|
+
from ._core import UltimateBearingCapacity
|
19
|
+
|
19
20
|
__all__ = ["TerzaghiUBC4StripFooting",
|
20
21
|
"TerzaghiUBC4CircularFooting",
|
21
22
|
"TerzaghiUBC4SquareFooting",
|
@@ -8,11 +8,12 @@ Classes
|
|
8
8
|
|
9
9
|
VesicUltimateBearingCapacity
|
10
10
|
"""
|
11
|
-
from geolysis.
|
12
|
-
from geolysis.bearing_capacity.ubc import hansen_ubc
|
13
|
-
from geolysis.foundation import FoundationSize, Shape
|
11
|
+
from geolysis.foundation import Shape
|
14
12
|
from geolysis.utils import isclose, round_, sin, tan
|
15
13
|
|
14
|
+
from . import hansen_ubc
|
15
|
+
from ._core import UltimateBearingCapacity
|
16
|
+
|
16
17
|
__all__ = ["VesicUltimateBearingCapacity"]
|
17
18
|
|
18
19
|
|
geolysis/foundation.py
CHANGED
@@ -35,7 +35,7 @@ import enum
|
|
35
35
|
from abc import ABC, abstractmethod
|
36
36
|
from typing import Optional, TypeVar
|
37
37
|
|
38
|
-
from
|
38
|
+
from .utils import enum_repr, inf, isclose, validators
|
39
39
|
|
40
40
|
__all__ = ["create_foundation",
|
41
41
|
"FoundationSize",
|
@@ -66,7 +66,7 @@ class FoundationType(enum.StrEnum):
|
|
66
66
|
|
67
67
|
|
68
68
|
class FootingSize(ABC):
|
69
|
-
|
69
|
+
_SHAPE: Shape
|
70
70
|
|
71
71
|
@property
|
72
72
|
@abstractmethod
|
@@ -88,13 +88,14 @@ class FootingSize(ABC):
|
|
88
88
|
|
89
89
|
@property
|
90
90
|
def shape(self) -> Shape:
|
91
|
-
|
91
|
+
"""Return the shape of the foundation footing."""
|
92
|
+
return self._SHAPE
|
92
93
|
|
93
94
|
|
94
95
|
class StripFooting(FootingSize):
|
95
96
|
"""A class representation of strip footing."""
|
96
97
|
|
97
|
-
|
98
|
+
_SHAPE = Shape.STRIP
|
98
99
|
|
99
100
|
def __init__(self, width: float, length: float = inf) -> None:
|
100
101
|
"""
|
@@ -109,6 +110,7 @@ class StripFooting(FootingSize):
|
|
109
110
|
|
110
111
|
@property
|
111
112
|
def width(self) -> float:
|
113
|
+
"""Width of foundation footing (m)."""
|
112
114
|
return self._width
|
113
115
|
|
114
116
|
@width.setter
|
@@ -118,6 +120,7 @@ class StripFooting(FootingSize):
|
|
118
120
|
|
119
121
|
@property
|
120
122
|
def length(self) -> float:
|
123
|
+
"""Length of foundation footing (m)."""
|
121
124
|
return self._length
|
122
125
|
|
123
126
|
@length.setter
|
@@ -136,7 +139,7 @@ class CircularFooting(FootingSize):
|
|
136
139
|
square and rectangular footing follow.
|
137
140
|
"""
|
138
141
|
|
139
|
-
|
142
|
+
_SHAPE = Shape.CIRCLE
|
140
143
|
|
141
144
|
def __init__(self, diameter: float):
|
142
145
|
"""
|
@@ -146,6 +149,7 @@ class CircularFooting(FootingSize):
|
|
146
149
|
|
147
150
|
@property
|
148
151
|
def diameter(self) -> float:
|
152
|
+
"""Diameter of foundation footing (m)."""
|
149
153
|
return self._diameter
|
150
154
|
|
151
155
|
@diameter.setter
|
@@ -155,6 +159,7 @@ class CircularFooting(FootingSize):
|
|
155
159
|
|
156
160
|
@property
|
157
161
|
def width(self):
|
162
|
+
"""Diameter of foundation footing (m)."""
|
158
163
|
return self.diameter
|
159
164
|
|
160
165
|
@width.setter
|
@@ -163,6 +168,7 @@ class CircularFooting(FootingSize):
|
|
163
168
|
|
164
169
|
@property
|
165
170
|
def length(self):
|
171
|
+
"""Diameter of foundation footing (m)."""
|
166
172
|
return self.diameter
|
167
173
|
|
168
174
|
@length.setter
|
@@ -173,7 +179,7 @@ class CircularFooting(FootingSize):
|
|
173
179
|
class SquareFooting(FootingSize):
|
174
180
|
"""A class representation of square footing."""
|
175
181
|
|
176
|
-
|
182
|
+
_SHAPE = Shape.SQUARE
|
177
183
|
|
178
184
|
def __init__(self, width: float):
|
179
185
|
"""
|
@@ -183,6 +189,7 @@ class SquareFooting(FootingSize):
|
|
183
189
|
|
184
190
|
@property
|
185
191
|
def width(self):
|
192
|
+
"""Width of foundation footing (m)."""
|
186
193
|
return self._width
|
187
194
|
|
188
195
|
@width.setter
|
@@ -192,6 +199,7 @@ class SquareFooting(FootingSize):
|
|
192
199
|
|
193
200
|
@property
|
194
201
|
def length(self):
|
202
|
+
"""Width of foundation footing (m)."""
|
195
203
|
return self.width
|
196
204
|
|
197
205
|
@length.setter
|
@@ -202,7 +210,7 @@ class SquareFooting(FootingSize):
|
|
202
210
|
class RectangularFooting(FootingSize):
|
203
211
|
"""A class representation of rectangular footing."""
|
204
212
|
|
205
|
-
|
213
|
+
_SHAPE = Shape.RECTANGLE
|
206
214
|
|
207
215
|
def __init__(self, width: float, length: float):
|
208
216
|
"""
|
@@ -217,6 +225,7 @@ class RectangularFooting(FootingSize):
|
|
217
225
|
|
218
226
|
@property
|
219
227
|
def width(self) -> float:
|
228
|
+
"""Width of foundation footing (m)."""
|
220
229
|
return self._width
|
221
230
|
|
222
231
|
@width.setter
|
@@ -226,6 +235,7 @@ class RectangularFooting(FootingSize):
|
|
226
235
|
|
227
236
|
@property
|
228
237
|
def length(self) -> float:
|
238
|
+
"""Length of foundation footing (m)."""
|
229
239
|
return self._length
|
230
240
|
|
231
241
|
@length.setter
|
@@ -240,7 +250,8 @@ class FoundationSize:
|
|
240
250
|
def __init__(self, depth: float,
|
241
251
|
footing_size: FootingSize,
|
242
252
|
eccentricity: float = 0.0,
|
243
|
-
ground_water_level: Optional[float] = None
|
253
|
+
ground_water_level: Optional[float] = None,
|
254
|
+
foundation_type: FoundationType = FoundationType.PAD) -> None:
|
244
255
|
"""
|
245
256
|
:param depth: Depth of foundation (m).
|
246
257
|
:type depth: float
|
@@ -258,14 +269,21 @@ class FoundationSize:
|
|
258
269
|
:param ground_water_level: Depth of the water below ground level (m),
|
259
270
|
defaults to inf.
|
260
271
|
:type ground_water_level: float, optional
|
272
|
+
|
273
|
+
:param foundation_type: Type of foundation, defaults to
|
274
|
+
:attr:`FoundationType.PAD`
|
275
|
+
:type foundation_type: FoundationType, optional
|
261
276
|
"""
|
262
277
|
self.depth = depth
|
263
278
|
self.footing_size = footing_size
|
264
279
|
self.eccentricity = eccentricity
|
280
|
+
|
265
281
|
self._ground_water_level = ground_water_level
|
282
|
+
self._foundation_type = foundation_type
|
266
283
|
|
267
284
|
@property
|
268
285
|
def depth(self) -> float:
|
286
|
+
"""Depth of foundation (m)."""
|
269
287
|
return self._depth
|
270
288
|
|
271
289
|
@depth.setter
|
@@ -274,7 +292,8 @@ class FoundationSize:
|
|
274
292
|
self._depth = val
|
275
293
|
|
276
294
|
@property
|
277
|
-
def width(self):
|
295
|
+
def width(self) -> float:
|
296
|
+
"""Width of foundation footing (m)."""
|
278
297
|
return self.footing_size.width
|
279
298
|
|
280
299
|
@width.setter
|
@@ -282,7 +301,8 @@ class FoundationSize:
|
|
282
301
|
self.footing_size.width = val
|
283
302
|
|
284
303
|
@property
|
285
|
-
def length(self):
|
304
|
+
def length(self) -> float:
|
305
|
+
"""Length of foundation footing (m)."""
|
286
306
|
return self.footing_size.length
|
287
307
|
|
288
308
|
@length.setter
|
@@ -290,11 +310,15 @@ class FoundationSize:
|
|
290
310
|
self.footing_size.length = val
|
291
311
|
|
292
312
|
@property
|
293
|
-
def footing_shape(self):
|
313
|
+
def footing_shape(self) -> Shape:
|
314
|
+
"""Shape of foundation footing."""
|
294
315
|
return self.footing_size.shape
|
295
316
|
|
296
317
|
@property
|
297
318
|
def eccentricity(self) -> float:
|
319
|
+
"""The deviation of the foundation load from the center of gravity of
|
320
|
+
the foundation footing.
|
321
|
+
"""
|
298
322
|
return self._eccentricity
|
299
323
|
|
300
324
|
@eccentricity.setter
|
@@ -304,6 +328,7 @@ class FoundationSize:
|
|
304
328
|
|
305
329
|
@property
|
306
330
|
def ground_water_level(self) -> Optional[float]:
|
331
|
+
"""Depth of the water below ground level (m)."""
|
307
332
|
return self._ground_water_level
|
308
333
|
|
309
334
|
@ground_water_level.setter
|
@@ -311,16 +336,19 @@ class FoundationSize:
|
|
311
336
|
def ground_water_level(self, val: float) -> None:
|
312
337
|
self._ground_water_level = val
|
313
338
|
|
339
|
+
@property
|
340
|
+
def foundation_type(self) -> FoundationType:
|
341
|
+
"""Type of foundation."""
|
342
|
+
return self._foundation_type
|
343
|
+
|
314
344
|
@property
|
315
345
|
def effective_width(self) -> float:
|
316
346
|
"""Returns the effective width of the foundation footing."""
|
317
347
|
return self.width - 2.0 * self.eccentricity
|
318
348
|
|
319
349
|
def footing_params(self) -> tuple[float, float, Shape]:
|
320
|
-
"""Returns the
|
321
|
-
foundation footing.
|
322
|
-
|
323
|
-
.. note:: "width" is the effective width of the foundation footing.
|
350
|
+
"""Returns the :attr:`effective_width`, :attr:`length`, and
|
351
|
+
:attr:`footing_shape` of the foundation footing.
|
324
352
|
"""
|
325
353
|
width, length, shape = self.effective_width, self.length, self.footing_shape
|
326
354
|
|
@@ -335,6 +363,7 @@ def create_foundation(depth: float,
|
|
335
363
|
length: Optional[float] = None,
|
336
364
|
eccentricity: float = 0.0,
|
337
365
|
ground_water_level: Optional[float] = None,
|
366
|
+
foundation_type: FoundationType = FoundationType.PAD,
|
338
367
|
shape: Shape | str = Shape.SQUARE) -> FoundationSize:
|
339
368
|
"""A factory function that encapsulate the creation of a foundation.
|
340
369
|
|
@@ -359,8 +388,12 @@ def create_foundation(depth: float,
|
|
359
388
|
defaults to None.
|
360
389
|
:type ground_water_level: float, optional
|
361
390
|
|
391
|
+
:param foundation_type: Type of foundation footing, defaults to
|
392
|
+
FoundationType.PAD.
|
393
|
+
:type foundation_type: FoundationType, optional
|
394
|
+
|
362
395
|
:param shape: Shape of foundation footing, defaults to :class:`Shape.SQUARE`
|
363
|
-
:type shape: Shape | str
|
396
|
+
:type shape: Shape | str, optional
|
364
397
|
|
365
398
|
:raises ValueError: Raised when length is not provided for a rectangular
|
366
399
|
footing.
|
@@ -371,7 +404,7 @@ def create_foundation(depth: float,
|
|
371
404
|
try:
|
372
405
|
shape = Shape(shape)
|
373
406
|
except ValueError as e:
|
374
|
-
msg = (f"{shape
|
407
|
+
msg = (f"{shape=} is not supported, Supported "
|
375
408
|
f"types are: {list(Shape)}")
|
376
409
|
|
377
410
|
raise ValueError(msg) from e
|
@@ -390,4 +423,5 @@ def create_foundation(depth: float,
|
|
390
423
|
return FoundationSize(depth=depth,
|
391
424
|
eccentricity=eccentricity,
|
392
425
|
ground_water_level=ground_water_level,
|
426
|
+
foundation_type=foundation_type,
|
393
427
|
footing_size=footing_size)
|
geolysis/soil_classifier.py
CHANGED
@@ -15,7 +15,7 @@ Enums
|
|
15
15
|
:toctree: _autosummary
|
16
16
|
:nosignatures:
|
17
17
|
|
18
|
-
|
18
|
+
ClfType
|
19
19
|
USCSSymbol
|
20
20
|
AASHTOSymbol
|
21
21
|
|
@@ -44,7 +44,7 @@ from typing import NamedTuple, Optional, Protocol, Sequence
|
|
44
44
|
|
45
45
|
from .utils import enum_repr, isclose, round_, validators
|
46
46
|
|
47
|
-
__all__ = ["
|
47
|
+
__all__ = ["ClfType",
|
48
48
|
"AtterbergLimits",
|
49
49
|
"PSD",
|
50
50
|
"AASHTO",
|
@@ -162,6 +162,7 @@ class AtterbergLimits:
|
|
162
162
|
|
163
163
|
@property
|
164
164
|
def liquid_limit(self) -> float:
|
165
|
+
"""Water content beyond which soils flows under their own weight (%)."""
|
165
166
|
return self._liquid_limit
|
166
167
|
|
167
168
|
@liquid_limit.setter
|
@@ -171,6 +172,7 @@ class AtterbergLimits:
|
|
171
172
|
|
172
173
|
@property
|
173
174
|
def plastic_limit(self) -> float:
|
175
|
+
"""Water content at which plastic deformation can be initiated (%)."""
|
174
176
|
return self._plastic_limit
|
175
177
|
|
176
178
|
@plastic_limit.setter
|
@@ -195,9 +197,7 @@ class AtterbergLimits:
|
|
195
197
|
|
196
198
|
@property
|
197
199
|
def fine_material_type(self) -> USCSSymbol:
|
198
|
-
"""
|
199
|
-
Checks whether the soil is either clay or silt.
|
200
|
-
"""
|
200
|
+
"""Checks whether the soil is either clay or silt."""
|
201
201
|
return USCSSymbol.CLAY if self.above_A_LINE() else USCSSymbol.SILT
|
202
202
|
|
203
203
|
def above_A_LINE(self) -> bool:
|
@@ -439,6 +439,7 @@ class AASHTO:
|
|
439
439
|
|
440
440
|
@property
|
441
441
|
def fines(self) -> float:
|
442
|
+
"""Percentage of fines in soil sample (%)."""
|
442
443
|
return self._fines
|
443
444
|
|
444
445
|
@fines.setter
|
@@ -682,18 +683,18 @@ class USCS:
|
|
682
683
|
f"{coarse_material_type}{fine_material_type}")
|
683
684
|
|
684
685
|
|
686
|
+
class SoilClassifier(Protocol):
|
687
|
+
@abstractmethod
|
688
|
+
def classify(self) -> SoilClf: ...
|
689
|
+
|
690
|
+
|
685
691
|
@enum_repr
|
686
|
-
class
|
692
|
+
class ClfType(enum.StrEnum):
|
687
693
|
"""Enumeration of soil classification types."""
|
688
694
|
AASHTO = enum.auto()
|
689
695
|
USCS = enum.auto()
|
690
696
|
|
691
697
|
|
692
|
-
class SoilClassifier(Protocol):
|
693
|
-
@abstractmethod
|
694
|
-
def classify(self) -> SoilClf: ...
|
695
|
-
|
696
|
-
|
697
698
|
def create_soil_classifier(liquid_limit: float,
|
698
699
|
plastic_limit: float,
|
699
700
|
fines: float,
|
@@ -701,7 +702,7 @@ def create_soil_classifier(liquid_limit: float,
|
|
701
702
|
d_10: float = 0, d_30: float = 0, d_60: float = 0,
|
702
703
|
add_group_idx: bool = True,
|
703
704
|
organic: bool = False,
|
704
|
-
clf_type: Optional[
|
705
|
+
clf_type: Optional[ClfType | str] = None
|
705
706
|
) -> SoilClassifier:
|
706
707
|
""" A factory function that encapsulates the creation of a soil classifier.
|
707
708
|
|
@@ -721,17 +722,18 @@ def create_soil_classifier(liquid_limit: float,
|
|
721
722
|
soil sample passing through No. 200 sieve (0.075mm).
|
722
723
|
:type fines: float
|
723
724
|
|
724
|
-
:param sand: Percentage of sand in soil sample (%).
|
725
|
-
|
725
|
+
:param sand: Percentage of sand in soil sample (%). This is optional for
|
726
|
+
:class:`AASHTO` classification.
|
727
|
+
:type sand: float, optional
|
726
728
|
|
727
729
|
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
728
|
-
:type d_10: float
|
730
|
+
:type d_10: float, optional
|
729
731
|
|
730
732
|
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
731
|
-
:type d_30: float
|
733
|
+
:type d_30: float, optional
|
732
734
|
|
733
735
|
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
734
|
-
:type d_60: float
|
736
|
+
:type d_60: float, optional
|
735
737
|
|
736
738
|
:param add_group_idx: Used to indicate whether the group index should
|
737
739
|
be added to the classification or not, defaults to
|
@@ -743,28 +745,28 @@ def create_soil_classifier(liquid_limit: float,
|
|
743
745
|
|
744
746
|
:param clf_type: Used to indicate which type of soil classifier should be
|
745
747
|
used, defaults to None.
|
746
|
-
:type clf_type:
|
748
|
+
:type clf_type: ClfType | str
|
747
749
|
|
748
750
|
:raises ValueError: Raises ValueError if ``clf_type`` is not supported or
|
749
751
|
None
|
750
752
|
:raises ValueError: Raises ValueError if ``sand`` is not provided for
|
751
753
|
:class:`USCS` classification.
|
752
754
|
"""
|
753
|
-
msg = (f"{clf_type
|
754
|
-
f"types are: {list(
|
755
|
+
msg = (f"{clf_type=} is not supported, Supported "
|
756
|
+
f"types are: {list(ClfType)}")
|
755
757
|
|
756
758
|
if clf_type is None:
|
757
759
|
raise ValueError(msg)
|
758
760
|
|
759
761
|
try:
|
760
|
-
clf_type =
|
762
|
+
clf_type = ClfType(str(clf_type).casefold())
|
761
763
|
except ValueError as e:
|
762
764
|
raise ValueError(msg) from e
|
763
765
|
|
764
766
|
atterberg_lmts = AtterbergLimits(liquid_limit=liquid_limit,
|
765
767
|
plastic_limit=plastic_limit)
|
766
768
|
|
767
|
-
if clf_type ==
|
769
|
+
if clf_type == ClfType.AASHTO:
|
768
770
|
clf = AASHTO(atterberg_limits=atterberg_lmts,
|
769
771
|
fines=fines,
|
770
772
|
add_group_idx=add_group_idx)
|