geolysis 0.12.0__py3-none-any.whl → 0.14.0__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 +31 -43
- geolysis/bearing_capacity/abc/_cohl/_core.py +15 -9
- geolysis/bearing_capacity/abc/_cohl/terzaghi_abc.py +5 -5
- geolysis/bearing_capacity/ubc/__init__.py +21 -31
- geolysis/bearing_capacity/ubc/_core.py +25 -20
- geolysis/bearing_capacity/ubc/_terzaghi_ubc.py +17 -13
- geolysis/bearing_capacity/ubc/_vesic_ubc.py +19 -4
- geolysis/foundation.py +69 -73
- geolysis/soil_classifier.py +31 -33
- geolysis/spt.py +62 -43
- geolysis/utils/__init__.py +2 -3
- geolysis/utils/math.py +3 -1
- {geolysis-0.12.0.dist-info → geolysis-0.14.0.dist-info}/METADATA +2 -2
- geolysis-0.14.0.dist-info/RECORD +22 -0
- geolysis/bearing_capacity/ubc/_hansen_ubc.py +0 -200
- geolysis-0.12.0.dist-info/RECORD +0 -23
- {geolysis-0.12.0.dist-info → geolysis-0.14.0.dist-info}/WHEEL +0 -0
- {geolysis-0.12.0.dist-info → geolysis-0.14.0.dist-info}/licenses/LICENSE.txt +0 -0
- {geolysis-0.12.0.dist-info → geolysis-0.14.0.dist-info}/top_level.txt +0 -0
geolysis/foundation.py
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
import enum
|
2
|
-
import math
|
3
2
|
from abc import ABC, abstractmethod
|
4
|
-
from
|
5
|
-
from typing import Optional, TypeVar, Annotated
|
3
|
+
from typing import Optional, TypeAlias, TypeVar, Annotated
|
6
4
|
|
7
5
|
from func_validator import (
|
8
|
-
|
6
|
+
validate_params,
|
9
7
|
MustBePositive,
|
10
8
|
MustBeNonNegative,
|
11
9
|
MustBeBetween,
|
12
10
|
MustBeMemberOf,
|
11
|
+
DependsOn,
|
13
12
|
)
|
14
13
|
|
15
|
-
from .utils import AbstractStrEnum, inf, isclose, pi, round_, add_repr
|
14
|
+
from .utils import AbstractStrEnum, inf, isclose, pi, round_, add_repr, isinf
|
16
15
|
|
17
16
|
__all__ = [
|
18
17
|
"create_foundation",
|
@@ -82,7 +81,7 @@ class FootingSize(ABC):
|
|
82
81
|
raise NotImplementedError
|
83
82
|
|
84
83
|
@width.setter
|
85
|
-
def width(self,
|
84
|
+
def width(self, width: float):
|
86
85
|
raise NotImplementedError
|
87
86
|
|
88
87
|
@property
|
@@ -91,7 +90,7 @@ class FootingSize(ABC):
|
|
91
90
|
raise NotImplementedError
|
92
91
|
|
93
92
|
@length.setter
|
94
|
-
def length(self,
|
93
|
+
def length(self, length: float):
|
95
94
|
raise NotImplementedError
|
96
95
|
|
97
96
|
def area(self) -> float:
|
@@ -123,9 +122,8 @@ class StripFooting(FootingSize):
|
|
123
122
|
return self._width
|
124
123
|
|
125
124
|
@width.setter
|
126
|
-
|
127
|
-
|
128
|
-
self._width = val
|
125
|
+
def width(self, width: float) -> None:
|
126
|
+
self._width = width
|
129
127
|
|
130
128
|
@property
|
131
129
|
def length(self) -> float:
|
@@ -133,13 +131,12 @@ class StripFooting(FootingSize):
|
|
133
131
|
return self._length
|
134
132
|
|
135
133
|
@length.setter
|
136
|
-
|
137
|
-
|
138
|
-
self._length = val
|
134
|
+
def length(self, length: float) -> None:
|
135
|
+
self._length = length
|
139
136
|
|
140
137
|
def area(self) -> float:
|
141
138
|
"""Area of strip footing ($m \text{or} m^2$)."""
|
142
|
-
if
|
139
|
+
if isinf(self.length):
|
143
140
|
return self.width
|
144
141
|
return self.width * self.length
|
145
142
|
|
@@ -169,9 +166,8 @@ class CircularFooting(FootingSize):
|
|
169
166
|
return self._diameter
|
170
167
|
|
171
168
|
@diameter.setter
|
172
|
-
|
173
|
-
|
174
|
-
self._diameter = val
|
169
|
+
def diameter(self, diameter: float) -> None:
|
170
|
+
self._diameter = diameter
|
175
171
|
|
176
172
|
@property
|
177
173
|
def width(self):
|
@@ -180,8 +176,8 @@ class CircularFooting(FootingSize):
|
|
180
176
|
|
181
177
|
# Not checking for positive as diameter setter already does that
|
182
178
|
@width.setter
|
183
|
-
def width(self,
|
184
|
-
self.diameter =
|
179
|
+
def width(self, width: float):
|
180
|
+
self.diameter = width
|
185
181
|
|
186
182
|
# Not checking for positive as diameter setter already does that
|
187
183
|
@property
|
@@ -190,8 +186,8 @@ class CircularFooting(FootingSize):
|
|
190
186
|
return self.diameter
|
191
187
|
|
192
188
|
@length.setter
|
193
|
-
def length(self,
|
194
|
-
self.diameter =
|
189
|
+
def length(self, length: float):
|
190
|
+
self.diameter = length
|
195
191
|
|
196
192
|
def area(self) -> float:
|
197
193
|
"""Area of circular footing ($m^2$)."""
|
@@ -216,9 +212,8 @@ class SquareFooting(FootingSize):
|
|
216
212
|
return self._width
|
217
213
|
|
218
214
|
@width.setter
|
219
|
-
|
220
|
-
|
221
|
-
self._width = val
|
215
|
+
def width(self, width: float) -> None:
|
216
|
+
self._width = width
|
222
217
|
|
223
218
|
@property
|
224
219
|
def length(self):
|
@@ -227,8 +222,8 @@ class SquareFooting(FootingSize):
|
|
227
222
|
|
228
223
|
# Not checking for positive as width setter already does that
|
229
224
|
@length.setter
|
230
|
-
def length(self,
|
231
|
-
self.width =
|
225
|
+
def length(self, length: float):
|
226
|
+
self.width = length
|
232
227
|
|
233
228
|
def area(self) -> float:
|
234
229
|
"""Area of square footing ($m^2$)."""
|
@@ -255,9 +250,8 @@ class RectangularFooting(FootingSize):
|
|
255
250
|
return self._width
|
256
251
|
|
257
252
|
@width.setter
|
258
|
-
|
259
|
-
|
260
|
-
self._width = val
|
253
|
+
def width(self, width: float) -> None:
|
254
|
+
self._width = width
|
261
255
|
|
262
256
|
@property
|
263
257
|
def length(self) -> float:
|
@@ -265,9 +259,8 @@ class RectangularFooting(FootingSize):
|
|
265
259
|
return self._length
|
266
260
|
|
267
261
|
@length.setter
|
268
|
-
|
269
|
-
|
270
|
-
self._length = val
|
262
|
+
def length(self, length: float) -> None:
|
263
|
+
self._length = length
|
271
264
|
|
272
265
|
def area(self) -> float:
|
273
266
|
"""Area of rectangular footing ($m^2$)."""
|
@@ -284,7 +277,7 @@ class Foundation:
|
|
284
277
|
footing_size: FootingSize,
|
285
278
|
eccentricity: float = 0.0,
|
286
279
|
load_angle: float = 0.0,
|
287
|
-
ground_water_level: Optional[float] =
|
280
|
+
ground_water_level: Optional[float] = inf,
|
288
281
|
foundation_type: FoundationType = FoundationType.PAD,
|
289
282
|
) -> None:
|
290
283
|
r"""
|
@@ -304,7 +297,7 @@ class Foundation:
|
|
304
297
|
self.eccentricity = eccentricity
|
305
298
|
self.load_angle = load_angle
|
306
299
|
|
307
|
-
self.
|
300
|
+
self.ground_water_level = ground_water_level
|
308
301
|
self.foundation_type = foundation_type
|
309
302
|
|
310
303
|
@property
|
@@ -313,9 +306,9 @@ class Foundation:
|
|
313
306
|
return self._depth
|
314
307
|
|
315
308
|
@depth.setter
|
316
|
-
@
|
317
|
-
def depth(self,
|
318
|
-
self._depth =
|
309
|
+
@validate_params
|
310
|
+
def depth(self, depth: Annotated[float, MustBePositive]) -> None:
|
311
|
+
self._depth = depth
|
319
312
|
|
320
313
|
@property
|
321
314
|
def width(self) -> float:
|
@@ -323,8 +316,8 @@ class Foundation:
|
|
323
316
|
return self.footing_size.width
|
324
317
|
|
325
318
|
@width.setter
|
326
|
-
def width(self,
|
327
|
-
self.footing_size.width =
|
319
|
+
def width(self, width: Annotated[float, MustBePositive]):
|
320
|
+
self.footing_size.width = width
|
328
321
|
|
329
322
|
@property
|
330
323
|
def length(self) -> float:
|
@@ -332,8 +325,8 @@ class Foundation:
|
|
332
325
|
return self.footing_size.length
|
333
326
|
|
334
327
|
@length.setter
|
335
|
-
def length(self,
|
336
|
-
self.footing_size.length =
|
328
|
+
def length(self, length: Annotated[float, MustBePositive]):
|
329
|
+
self.footing_size.length = length
|
337
330
|
|
338
331
|
@property
|
339
332
|
def footing_shape(self) -> Shape:
|
@@ -348,9 +341,10 @@ class Foundation:
|
|
348
341
|
return self._eccentricity
|
349
342
|
|
350
343
|
@eccentricity.setter
|
351
|
-
@
|
352
|
-
def eccentricity(self,
|
353
|
-
|
344
|
+
@validate_params
|
345
|
+
def eccentricity(self, eccentricity: Annotated[
|
346
|
+
float, MustBeNonNegative]) -> None:
|
347
|
+
self._eccentricity = eccentricity
|
354
348
|
|
355
349
|
@property
|
356
350
|
def load_angle(self) -> float:
|
@@ -358,12 +352,13 @@ class Foundation:
|
|
358
352
|
return self._load_angle
|
359
353
|
|
360
354
|
@load_angle.setter
|
361
|
-
@
|
355
|
+
@validate_params
|
362
356
|
def load_angle(
|
363
357
|
self,
|
364
|
-
|
358
|
+
load_angle: Annotated[
|
359
|
+
float, MustBeBetween(min_value=0.0, max_value=90.0)],
|
365
360
|
) -> None:
|
366
|
-
self._load_angle =
|
361
|
+
self._load_angle = load_angle
|
367
362
|
|
368
363
|
@property
|
369
364
|
def ground_water_level(self) -> Optional[float]:
|
@@ -371,9 +366,12 @@ class Foundation:
|
|
371
366
|
return self._ground_water_level
|
372
367
|
|
373
368
|
@ground_water_level.setter
|
374
|
-
@
|
375
|
-
def ground_water_level(
|
376
|
-
|
369
|
+
@validate_params
|
370
|
+
def ground_water_level(
|
371
|
+
self,
|
372
|
+
ground_water_level: Annotated[float, MustBePositive],
|
373
|
+
):
|
374
|
+
self._ground_water_level = ground_water_level
|
377
375
|
|
378
376
|
@property
|
379
377
|
def foundation_type(self) -> FoundationType:
|
@@ -381,12 +379,13 @@ class Foundation:
|
|
381
379
|
return self._foundation_type
|
382
380
|
|
383
381
|
@foundation_type.setter
|
384
|
-
@
|
382
|
+
@validate_params
|
385
383
|
def foundation_type(
|
386
384
|
self,
|
387
|
-
|
385
|
+
foundation_type: Annotated[
|
386
|
+
FoundationType, MustBeMemberOf(FoundationType)],
|
388
387
|
):
|
389
|
-
self._foundation_type =
|
388
|
+
self._foundation_type = foundation_type
|
390
389
|
|
391
390
|
@round_(2)
|
392
391
|
def foundation_area(self) -> float:
|
@@ -403,7 +402,10 @@ class Foundation:
|
|
403
402
|
of the foundation footing.
|
404
403
|
"""
|
405
404
|
width, length, shape = (
|
406
|
-
|
405
|
+
self.effective_width,
|
406
|
+
self.length,
|
407
|
+
self.footing_shape,
|
408
|
+
)
|
407
409
|
|
408
410
|
if not isclose(width, length) and shape != Shape.STRIP:
|
409
411
|
shape = Shape.RECTANGLE
|
@@ -411,11 +413,11 @@ class Foundation:
|
|
411
413
|
return width, length, shape
|
412
414
|
|
413
415
|
|
414
|
-
@
|
416
|
+
@validate_params
|
415
417
|
def create_foundation(
|
416
418
|
depth: float,
|
417
419
|
width: float,
|
418
|
-
length: float =
|
420
|
+
length: Annotated[float, DependsOn(shape=Shape.RECTANGLE)] = None,
|
419
421
|
eccentricity: float = 0.0,
|
420
422
|
load_angle: float = 0.0,
|
421
423
|
ground_water_level: Optional[float] = inf,
|
@@ -434,31 +436,25 @@ def create_foundation(
|
|
434
436
|
load aligns with the center of gravity of the
|
435
437
|
foundation footing .
|
436
438
|
:param load_angle: Inclination of the applied load with the vertical
|
437
|
-
|
438
|
-
:param ground_water_level: Depth of the water below ground level (m)
|
439
|
-
|
440
|
-
:param
|
441
|
-
|
442
|
-
:
|
443
|
-
|
444
|
-
:raises ValueError: Raised when length is not provided for a
|
445
|
-
rectangular footing.
|
446
|
-
:raises ValidationError: Raised if an invalid footing shape is
|
439
|
+
(:math:`\alpha^{\circ}`).
|
440
|
+
:param ground_water_level: Depth of the water below ground level (m)
|
441
|
+
:param foundation_type: Type of foundation footing.
|
442
|
+
:param shape: Shape of foundation footing
|
443
|
+
|
444
|
+
:raises ValidationError: Raised when length is not provided for a
|
445
|
+
rectangular footing or an invalid shape is
|
447
446
|
provided.
|
448
447
|
"""
|
449
|
-
|
448
|
+
footing_size: FootingSize
|
450
449
|
shape = Shape(str(shape).casefold())
|
451
450
|
|
452
|
-
if shape
|
451
|
+
if shape == Shape.STRIP:
|
453
452
|
footing_size = StripFooting(width=width)
|
454
|
-
elif shape
|
453
|
+
elif shape == Shape.SQUARE:
|
455
454
|
footing_size = SquareFooting(width=width)
|
456
|
-
elif shape
|
455
|
+
elif shape == Shape.CIRCLE:
|
457
456
|
footing_size = CircularFooting(diameter=width)
|
458
457
|
else: # RECTANGLE
|
459
|
-
if isinf(length):
|
460
|
-
msg = "Length of rectangular footing must be provided."
|
461
|
-
raise ValueError(msg)
|
462
458
|
footing_size = RectangularFooting(width=width, length=length)
|
463
459
|
|
464
460
|
return Foundation(
|
geolysis/soil_classifier.py
CHANGED
@@ -2,9 +2,9 @@ import enum
|
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from typing import Annotated, Sequence
|
4
4
|
|
5
|
-
from func_validator import
|
5
|
+
from func_validator import validate_params, MustBeNonNegative
|
6
6
|
|
7
|
-
from .utils import isclose, round_
|
7
|
+
from .utils import isclose, round_, nan, isnan
|
8
8
|
|
9
9
|
__all__ = [
|
10
10
|
"AtterbergLimits",
|
@@ -256,9 +256,9 @@ class AtterbergLimits:
|
|
256
256
|
return self._liquid_limit
|
257
257
|
|
258
258
|
@liquid_limit.setter
|
259
|
-
@
|
260
|
-
def liquid_limit(self,
|
261
|
-
self._liquid_limit =
|
259
|
+
@validate_params
|
260
|
+
def liquid_limit(self, liquid_limit: Annotated[float, MustBeNonNegative]):
|
261
|
+
self._liquid_limit = liquid_limit
|
262
262
|
|
263
263
|
@property
|
264
264
|
def plastic_limit(self) -> float:
|
@@ -268,16 +268,16 @@ class AtterbergLimits:
|
|
268
268
|
return self._plastic_limit
|
269
269
|
|
270
270
|
@plastic_limit.setter
|
271
|
-
@
|
272
|
-
def plastic_limit(self,
|
273
|
-
if self.liquid_limit <
|
271
|
+
@validate_params
|
272
|
+
def plastic_limit(self, plastic_limit: Annotated[float, MustBeNonNegative]):
|
273
|
+
if self.liquid_limit < plastic_limit:
|
274
274
|
msg = (
|
275
|
-
f"plastic_limit: {
|
275
|
+
f"plastic_limit: {plastic_limit} cannot be greater than "
|
276
276
|
f"liquid_limit: {self.liquid_limit}"
|
277
277
|
)
|
278
278
|
raise ValueError(msg)
|
279
279
|
|
280
|
-
self._plastic_limit =
|
280
|
+
self._plastic_limit = plastic_limit
|
281
281
|
|
282
282
|
@property
|
283
283
|
@round_(2)
|
@@ -353,7 +353,7 @@ class _SizeDistribution:
|
|
353
353
|
Features obtained from the Particle Size Distribution graph.
|
354
354
|
"""
|
355
355
|
|
356
|
-
def __init__(self, d_10: float
|
356
|
+
def __init__(self, d_10: float, d_30: float, d_60: float):
|
357
357
|
self.d_10 = d_10
|
358
358
|
self.d_30 = d_30
|
359
359
|
self.d_60 = d_60
|
@@ -389,6 +389,12 @@ class _SizeDistribution:
|
|
389
389
|
grade = USCSSymbol.POORLY_GRADED
|
390
390
|
return grade
|
391
391
|
|
392
|
+
def has_particle_sizes(self) -> bool:
|
393
|
+
"""Checks if particle sizes are provided."""
|
394
|
+
if isnan(self.d_10) or isnan(self.d_30) or isnan(self.d_60):
|
395
|
+
return False
|
396
|
+
return True
|
397
|
+
|
392
398
|
|
393
399
|
class PSD:
|
394
400
|
"""Quantitative proportions by mass of various sizes of particles
|
@@ -399,9 +405,9 @@ class PSD:
|
|
399
405
|
self,
|
400
406
|
fines: float,
|
401
407
|
sand: float,
|
402
|
-
d_10: float =
|
403
|
-
d_30: float =
|
404
|
-
d_60: float =
|
408
|
+
d_10: float = nan,
|
409
|
+
d_30: float = nan,
|
410
|
+
d_60: float = nan,
|
405
411
|
):
|
406
412
|
"""
|
407
413
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
@@ -459,7 +465,7 @@ class PSD:
|
|
459
465
|
|
460
466
|
def has_particle_sizes(self) -> bool:
|
461
467
|
"""Checks if soil sample has particle sizes."""
|
462
|
-
return
|
468
|
+
return self.size_dist.has_particle_sizes()
|
463
469
|
|
464
470
|
def grade(self) -> USCSSymbol:
|
465
471
|
r"""Return the grade of the soil sample, either well graded or
|
@@ -473,7 +479,7 @@ class PSD:
|
|
473
479
|
return self.size_dist.grade(coarse_soil=self.coarse_material_type)
|
474
480
|
|
475
481
|
|
476
|
-
@dataclass
|
482
|
+
@dataclass(frozen=True, slots=True)
|
477
483
|
class AASHTOResult:
|
478
484
|
symbol: str
|
479
485
|
symbol_no_group_idx: str
|
@@ -527,9 +533,9 @@ class AASHTO:
|
|
527
533
|
return self._fines
|
528
534
|
|
529
535
|
@fines.setter
|
530
|
-
@
|
531
|
-
def fines(self,
|
532
|
-
self._fines =
|
536
|
+
@validate_params
|
537
|
+
def fines(self, fines: Annotated[float, MustBeNonNegative]):
|
538
|
+
self._fines = fines
|
533
539
|
|
534
540
|
@round_(ndigits=0)
|
535
541
|
def group_index(self) -> float:
|
@@ -619,7 +625,7 @@ class AASHTO:
|
|
619
625
|
return soil_clf
|
620
626
|
|
621
627
|
|
622
|
-
@dataclass
|
628
|
+
@dataclass(frozen=True, slots=True)
|
623
629
|
class USCSResult:
|
624
630
|
symbol: str
|
625
631
|
description: str
|
@@ -672,7 +678,8 @@ class USCS:
|
|
672
678
|
|
673
679
|
if isinstance(soil_clf, USCSSymbol):
|
674
680
|
soil_clf = USCSResult(
|
675
|
-
symbol=soil_clf.symbol,
|
681
|
+
symbol=soil_clf.symbol,
|
682
|
+
description=soil_clf.description,
|
676
683
|
)
|
677
684
|
else:
|
678
685
|
# Handling tuple or list case for dual classification
|
@@ -790,12 +797,10 @@ def create_aashto_classifier(
|
|
790
797
|
the minimum moisture content at which a soil
|
791
798
|
flows upon application of a very small shear
|
792
799
|
force.
|
793
|
-
|
794
800
|
:param plastic_limit: Water content at which plastic deformation can
|
795
801
|
be initiated (%). It is also the minimum water
|
796
802
|
content at which soil can be rolled into a
|
797
803
|
thread 3mm thick (molded without breaking).
|
798
|
-
|
799
804
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
800
805
|
percentage of soil sample passing through No. 200
|
801
806
|
sieve (0.075mm).
|
@@ -809,9 +814,9 @@ def create_uscs_classifier(
|
|
809
814
|
plastic_limit: float,
|
810
815
|
fines: float,
|
811
816
|
sand: float,
|
812
|
-
d_10: float =
|
813
|
-
d_30: float =
|
814
|
-
d_60: float =
|
817
|
+
d_10: float = nan,
|
818
|
+
d_30: float = nan,
|
819
|
+
d_60: float = nan,
|
815
820
|
organic: bool = False,
|
816
821
|
):
|
817
822
|
"""A helper function that encapsulates the creation of a USCS
|
@@ -822,24 +827,17 @@ def create_uscs_classifier(
|
|
822
827
|
the minimum moisture content at which a soil
|
823
828
|
flows upon application of a very small shear
|
824
829
|
force.
|
825
|
-
|
826
830
|
:param plastic_limit: Water content at which plastic deformation can
|
827
831
|
be initiated (%). It is also the minimum water
|
828
832
|
content at which soil can be rolled into a
|
829
833
|
thread 3mm thick. (molded without breaking)
|
830
|
-
|
831
834
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
832
835
|
percentage of soil sample passing through No. 200
|
833
836
|
sieve (0.075mm).
|
834
|
-
|
835
837
|
:param sand: Percentage of sand in soil sample (%).
|
836
|
-
|
837
838
|
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
838
|
-
|
839
839
|
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
840
|
-
|
841
840
|
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
842
|
-
|
843
841
|
:param organic: Indicates whether soil is organic or not.
|
844
842
|
"""
|
845
843
|
atterberg_lmts = AtterbergLimits(liquid_limit, plastic_limit)
|