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.
@@ -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.bearing_capacity.ubc import UltimateBearingCapacity
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.bearing_capacity.ubc import UltimateBearingCapacity
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 geolysis.utils import enum_repr, inf, isclose, validators
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
- SHAPE: Shape
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
- return self.SHAPE
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
- SHAPE = Shape.STRIP
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
- SHAPE = Shape.CIRCLE
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
- SHAPE = Shape.SQUARE
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
- SHAPE = Shape.RECTANGLE
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) -> 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 ``width``, ``length``, and ``shape`` of 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 = } is not supported, Supported "
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)
@@ -15,7 +15,7 @@ Enums
15
15
  :toctree: _autosummary
16
16
  :nosignatures:
17
17
 
18
- CLF_TYPE
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__ = ["CLF_TYPE",
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 CLF_TYPE(enum.StrEnum):
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[CLF_TYPE | str] = None
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
- :type sand: float
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: CLF_TYPE | str
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 = } is not supported, Supported "
754
- f"types are: {list(CLF_TYPE)}")
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 = CLF_TYPE(str(clf_type).casefold())
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 == CLF_TYPE.AASHTO:
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)