geolysis 0.4.2__py3-none-any.whl → 0.4.3__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 -3
- geolysis/foundation.py +165 -98
- geolysis/soil_classifier.py +161 -99
- geolysis/spt.py +89 -44
- {geolysis-0.4.2.dist-info → geolysis-0.4.3.dist-info}/METADATA +43 -78
- geolysis-0.4.3.dist-info/RECORD +9 -0
- {geolysis-0.4.2.dist-info → geolysis-0.4.3.dist-info}/WHEEL +1 -1
- geolysis/utils.py +0 -78
- geolysis/validators.py +0 -54
- geolysis-0.4.2.dist-info/RECORD +0 -11
- {geolysis-0.4.2.dist-info → geolysis-0.4.3.dist-info}/LICENSE.txt +0 -0
- {geolysis-0.4.2.dist-info → geolysis-0.4.3.dist-info}/top_level.txt +0 -0
geolysis/soil_classifier.py
CHANGED
@@ -1,53 +1,74 @@
|
|
1
|
-
|
2
|
-
from abc import abstractmethod
|
3
|
-
from typing import Protocol
|
4
|
-
from typing import NamedTuple, Optional, Sequence
|
1
|
+
""" Soil classification module.
|
5
2
|
|
6
|
-
|
7
|
-
|
3
|
+
Exceptions
|
4
|
+
==========
|
8
5
|
|
9
|
-
|
10
|
-
|
6
|
+
.. autosummary::
|
7
|
+
:toctree: _autosummary
|
11
8
|
|
9
|
+
SizeDistError
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
pass
|
11
|
+
Enums
|
12
|
+
=====
|
16
13
|
|
14
|
+
.. autosummary::
|
15
|
+
:toctree: _autosummary
|
16
|
+
:nosignatures:
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
CLF_TYPE
|
19
|
+
USCSSymbol
|
20
|
+
AASHTOSymbol
|
21
21
|
|
22
|
+
Classes
|
23
|
+
=======
|
22
24
|
|
23
|
-
|
25
|
+
.. autosummary::
|
26
|
+
:toctree: _autosummary
|
24
27
|
|
25
|
-
|
26
|
-
|
28
|
+
AtterbergLimits
|
29
|
+
PSD
|
30
|
+
AASHTO
|
31
|
+
USCS
|
27
32
|
|
33
|
+
Functions
|
34
|
+
=========
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
AASHTO = enum.auto()
|
32
|
-
USCS = enum.auto()
|
36
|
+
.. autosummary::
|
37
|
+
:toctree: _autosummary
|
33
38
|
|
39
|
+
create_soil_classifier
|
40
|
+
"""
|
41
|
+
import enum
|
42
|
+
from abc import abstractmethod
|
43
|
+
from typing import Protocol
|
44
|
+
from typing import NamedTuple, Optional, Sequence
|
34
45
|
|
35
|
-
|
46
|
+
from geolysis.utils import enum_repr, isclose, round_, validators
|
47
|
+
|
48
|
+
__all__ = ["CLF_TYPE",
|
49
|
+
"AtterbergLimits",
|
50
|
+
"PSD",
|
51
|
+
"AASHTO",
|
52
|
+
"USCS",
|
53
|
+
"create_soil_classifier"]
|
54
|
+
|
55
|
+
|
56
|
+
class SizeDistError(ZeroDivisionError):
|
57
|
+
"""Exception raised when size distribution is not provided."""
|
58
|
+
|
59
|
+
|
60
|
+
@enum_repr
|
61
|
+
class _Clf(tuple, enum.Enum):
|
36
62
|
|
37
63
|
def __str__(self) -> str:
|
38
64
|
return self.name
|
39
65
|
|
40
|
-
def __eq__(self, value: object) -> bool:
|
41
|
-
if isinstance(value, str):
|
42
|
-
return self.clf_symbol == value
|
43
|
-
return super().__eq__(value)
|
44
|
-
|
45
66
|
@property
|
46
|
-
def
|
67
|
+
def symbol(self) -> str:
|
47
68
|
return self.value[0]
|
48
69
|
|
49
70
|
@property
|
50
|
-
def
|
71
|
+
def description(self) -> str:
|
51
72
|
return self.value[1]
|
52
73
|
|
53
74
|
|
@@ -112,30 +133,31 @@ class AtterbergLimits:
|
|
112
133
|
"""
|
113
134
|
|
114
135
|
class __A_LINE:
|
115
|
-
"""The ``A-line`` is used to determine if a soil is clayey or silty.
|
116
|
-
|
117
|
-
.. math:: A = 0.73(LL - 20.0)
|
118
|
-
"""
|
119
136
|
|
120
137
|
def __get__(self, obj, objtype=None) -> float:
|
121
138
|
return 0.73 * (obj.liquid_limit - 20.0)
|
122
139
|
|
140
|
+
#: The ``A-line`` determines if a soil is clayey or silty.
|
141
|
+
#: :math:`A = 0.73(LL - 20.0)`
|
123
142
|
A_LINE = __A_LINE()
|
124
143
|
|
125
144
|
def __init__(self, liquid_limit: float, plastic_limit: float):
|
126
145
|
"""
|
127
146
|
:param liquid_limit: Water content beyond which soils flows under their
|
128
|
-
own weight. It can also be defined as the
|
129
|
-
moisture content at which a soil flows upon
|
130
|
-
application of a very small shear force.
|
147
|
+
own weight (%). It can also be defined as the
|
148
|
+
minimum moisture content at which a soil flows upon
|
149
|
+
application of a very small shear force.
|
131
150
|
:type liquid_limit: float
|
132
151
|
|
133
152
|
:param plastic_limit: Water content at which plastic deformation can be
|
134
|
-
initiated. It is also the minimum water
|
135
|
-
which soil can be rolled into a thread
|
136
|
-
(molded without breaking)
|
153
|
+
initiated (%). It is also the minimum water
|
154
|
+
content at which soil can be rolled into a thread
|
155
|
+
3mm thick. (molded without breaking)
|
137
156
|
:type plastic_limit: float
|
138
157
|
"""
|
158
|
+
if liquid_limit < plastic_limit:
|
159
|
+
raise ValueError("liquid_limit cannot be less than plastic_limit")
|
160
|
+
|
139
161
|
self.liquid_limit = liquid_limit
|
140
162
|
self.plastic_limit = plastic_limit
|
141
163
|
|
@@ -166,6 +188,8 @@ class AtterbergLimits:
|
|
166
188
|
It is also the numerical difference between the liquid limit and
|
167
189
|
plastic limit of the soil.
|
168
190
|
|
191
|
+
:Equation:
|
192
|
+
|
169
193
|
.. math:: PI = LL - PL
|
170
194
|
"""
|
171
195
|
return self.liquid_limit - self.plastic_limit
|
@@ -199,6 +223,8 @@ class AtterbergLimits:
|
|
199
223
|
|
200
224
|
:param float nmc: Moisture contents of the soil in natural condition.
|
201
225
|
|
226
|
+
:Equation:
|
227
|
+
|
202
228
|
.. math:: I_l = \dfrac{w - PL}{PI} \cdot 100
|
203
229
|
"""
|
204
230
|
return ((nmc - self.plastic_limit) / self.plasticity_index) * 100.0
|
@@ -220,20 +246,20 @@ class AtterbergLimits:
|
|
220
246
|
|
221
247
|
:param float nmc: Moisture contents of the soil in natural condition.
|
222
248
|
|
249
|
+
:Equation:
|
250
|
+
|
223
251
|
.. math:: I_c = \dfrac{LL - w}{PI} \cdot 100
|
224
252
|
"""
|
225
253
|
return ((self.liquid_limit - nmc) / self.plasticity_index) * 100.0
|
226
254
|
|
227
255
|
|
228
|
-
class
|
229
|
-
"""
|
256
|
+
class _SizeDistribution:
|
257
|
+
"""Particle size distribution of soil sample.
|
258
|
+
|
259
|
+
Features obtained from the Particle Size Distribution graph.
|
260
|
+
"""
|
230
261
|
|
231
262
|
def __init__(self, d_10: float = 0, d_30: float = 0, d_60: float = 0):
|
232
|
-
"""
|
233
|
-
:param float d_10: Diameter at which 10% of the soil by weight is finer.
|
234
|
-
:param float d_30: Diameter at which 30% of the soil by weight is finer.
|
235
|
-
:param float d_60: Diameter at which 60% of the soil by weight is finer.
|
236
|
-
"""
|
237
263
|
self.d_10 = d_10
|
238
264
|
self.d_30 = d_30
|
239
265
|
self.d_60 = d_60
|
@@ -256,9 +282,6 @@ class SizeDistribution:
|
|
256
282
|
:param coarse_soil: Coarse fraction of the soil sample. Valid arguments
|
257
283
|
are ``USCSSymbol.GRAVEL`` and ``USCSSymbol.SAND``.
|
258
284
|
"""
|
259
|
-
if not (coarse_soil in (USCSSymbol.GRAVEL, USCSSymbol.SAND)):
|
260
|
-
raise NotImplementedError
|
261
|
-
|
262
285
|
if coarse_soil is USCSSymbol.GRAVEL:
|
263
286
|
if 1 < self.coeff_of_curvature < 3 and self.coeff_of_uniformity >= 4:
|
264
287
|
grade = USCSSymbol.WELL_GRADED
|
@@ -280,22 +303,31 @@ class PSD:
|
|
280
303
|
"""
|
281
304
|
|
282
305
|
def __init__(self, fines: float, sand: float,
|
283
|
-
|
306
|
+
d_10: float = 0, d_30: float = 0, d_60: float = 0):
|
284
307
|
"""
|
285
|
-
:param fines: Percentage of fines in soil sample i.e. The
|
286
|
-
soil sample passing through No. 200 sieve
|
308
|
+
:param fines: Percentage of fines in soil sample (%) i.e. The
|
309
|
+
percentage of soil sample passing through No. 200 sieve
|
310
|
+
(0.075mm).
|
287
311
|
:type fines: float
|
288
312
|
|
289
|
-
:param sand: Percentage of sand in soil sample.
|
313
|
+
:param sand: Percentage of sand in soil sample (%).
|
290
314
|
:type sand: float
|
291
315
|
|
292
|
-
:param
|
293
|
-
:type
|
316
|
+
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
317
|
+
:type d_10: float
|
318
|
+
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
319
|
+
:type d_30: float
|
320
|
+
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
321
|
+
:type d_60: float
|
294
322
|
"""
|
295
323
|
self.fines = fines
|
296
324
|
self.sand = sand
|
297
|
-
self.
|
298
|
-
|
325
|
+
self.size_dist = _SizeDistribution(d_10=d_10, d_30=d_30, d_60=d_60)
|
326
|
+
|
327
|
+
@property
|
328
|
+
def gravel(self):
|
329
|
+
"""Percentage of gravel in soil sample (%)."""
|
330
|
+
return 100.0 - (self.fines + self.sand)
|
299
331
|
|
300
332
|
@property
|
301
333
|
def coarse_material_type(self) -> USCSSymbol:
|
@@ -309,7 +341,7 @@ class PSD:
|
|
309
341
|
def coeff_of_curvature(self) -> float:
|
310
342
|
r"""Coefficient of curvature of soil sample.
|
311
343
|
|
312
|
-
|
344
|
+
:Equation:
|
313
345
|
|
314
346
|
.. math:: C_c = \dfrac{D^2_{30}}{D_{60} \cdot D_{10}}
|
315
347
|
|
@@ -323,13 +355,13 @@ class PSD:
|
|
323
355
|
def coeff_of_uniformity(self) -> float:
|
324
356
|
r"""Coefficient of uniformity of soil sample.
|
325
357
|
|
326
|
-
|
358
|
+
:Equation:
|
327
359
|
|
328
360
|
.. math:: C_u = \dfrac{D_{60}}{D_{10}}
|
329
361
|
|
330
|
-
:math:`C_u` value greater than 4 to 6 classifies the soil as well
|
331
|
-
for gravels and sands respectively. When :math:`C_u` is less
|
332
|
-
is classified as poorly graded or uniformly graded soil.
|
362
|
+
:math:`C_u` value greater than 4 to 6 classifies the soil as well
|
363
|
+
graded for gravels and sands respectively. When :math:`C_u` is less
|
364
|
+
than 4, it is classified as poorly graded or uniformly graded soil.
|
333
365
|
|
334
366
|
Higher values of :math:`C_u` indicates that the soil mass consists of
|
335
367
|
soil particles with different size ranges.
|
@@ -346,12 +378,19 @@ class PSD:
|
|
346
378
|
|
347
379
|
Conditions for a well-graded soil:
|
348
380
|
|
381
|
+
:Equation:
|
382
|
+
|
349
383
|
- :math:`1 \lt C_c \lt 3` and :math:`C_u \ge 4` (for gravels)
|
350
384
|
- :math:`1 \lt C_c \lt 3` and :math:`C_u \ge 6` (for sands)
|
351
385
|
"""
|
352
386
|
return self.size_dist.grade(coarse_soil=self.coarse_material_type)
|
353
387
|
|
354
388
|
|
389
|
+
class SoilClf(NamedTuple):
|
390
|
+
symbol: str
|
391
|
+
description: str
|
392
|
+
|
393
|
+
|
355
394
|
class AASHTO:
|
356
395
|
r"""American Association of State Highway and Transportation Officials
|
357
396
|
(AASHTO) classification system.
|
@@ -373,6 +412,8 @@ class AASHTO:
|
|
373
412
|
The ``GI`` must be mentioned even when it is zero, to indicate that the
|
374
413
|
soil has been classified as per AASHTO system.
|
375
414
|
|
415
|
+
:Equation:
|
416
|
+
|
376
417
|
.. math::
|
377
418
|
|
378
419
|
GI = (F_{200} - 35)[0.2 + 0.005(LL - 40)] + 0.01(F_{200} - 15)(PI - 10)
|
@@ -381,11 +422,11 @@ class AASHTO:
|
|
381
422
|
def __init__(self, atterberg_limits: AtterbergLimits,
|
382
423
|
fines: float, add_group_idx=True):
|
383
424
|
"""
|
384
|
-
:param atterberg_limits: Atterberg limits of
|
425
|
+
:param atterberg_limits: Atterberg limits of soil sample.
|
385
426
|
:type atterberg_limits: AtterbergLimits
|
386
427
|
|
387
|
-
:param fines: Percentage of fines in soil sample i.e. The percentage
|
388
|
-
soil sample passing through No. 200 sieve (0.075mm).
|
428
|
+
:param fines: Percentage of fines in soil sample (%) i.e. The percentage
|
429
|
+
of soil sample passing through No. 200 sieve (0.075mm).
|
389
430
|
:type fines: float
|
390
431
|
|
391
432
|
:param add_group_idx: Used to indicate whether the group index should
|
@@ -425,7 +466,7 @@ class AASHTO:
|
|
425
466
|
"""Return the AASHTO classification of the soil."""
|
426
467
|
soil_clf = self._classify()
|
427
468
|
|
428
|
-
symbol, description = soil_clf.
|
469
|
+
symbol, description = soil_clf.symbol, soil_clf.description
|
429
470
|
|
430
471
|
if self.add_group_idx:
|
431
472
|
symbol = f"{symbol}({self.group_index():.0f})"
|
@@ -513,7 +554,7 @@ class USCS:
|
|
513
554
|
termed as Peat. (:math:`P_t`)
|
514
555
|
"""
|
515
556
|
|
516
|
-
def __init__(self, atterberg_limits: AtterbergLimits,
|
557
|
+
def __init__(self, atterberg_limits: AtterbergLimits,
|
517
558
|
psd: PSD, organic=False):
|
518
559
|
"""
|
519
560
|
:param atterberg_limits: Atterberg limits of the soil.
|
@@ -539,13 +580,13 @@ class USCS:
|
|
539
580
|
soil_clf = USCSSymbol[soil_clf]
|
540
581
|
|
541
582
|
if isinstance(soil_clf, USCSSymbol):
|
542
|
-
return SoilClf(soil_clf.
|
583
|
+
return SoilClf(soil_clf.symbol, soil_clf.description)
|
543
584
|
|
544
585
|
# Handling tuple or list case for dual classification
|
545
586
|
first_clf, second_clf = map(lambda clf: USCSSymbol[clf], soil_clf)
|
546
587
|
|
547
|
-
comb_symbol = f"{first_clf.
|
548
|
-
comb_desc = f"{first_clf.
|
588
|
+
comb_symbol = f"{first_clf.symbol},{second_clf.symbol}"
|
589
|
+
comb_desc = f"{first_clf.description},{second_clf.description}"
|
549
590
|
|
550
591
|
return SoilClf(comb_symbol, comb_desc)
|
551
592
|
|
@@ -642,40 +683,55 @@ class USCS:
|
|
642
683
|
f"{coarse_material_type}{fine_material_type}")
|
643
684
|
|
644
685
|
|
645
|
-
|
646
|
-
|
686
|
+
@enum_repr
|
687
|
+
class CLF_TYPE(enum.StrEnum):
|
688
|
+
"""Enumeration of soil classification types."""
|
689
|
+
AASHTO = enum.auto()
|
690
|
+
USCS = enum.auto()
|
691
|
+
|
692
|
+
|
693
|
+
class SoilClassifier(Protocol):
|
694
|
+
@abstractmethod
|
695
|
+
def classify(self) -> SoilClf: ...
|
696
|
+
|
697
|
+
|
698
|
+
def create_soil_classifier(liquid_limit: float,
|
699
|
+
plastic_limit: float,
|
700
|
+
fines: float,
|
701
|
+
sand: Optional[float] = None,
|
647
702
|
d_10: float = 0, d_30: float = 0, d_60: float = 0,
|
648
|
-
add_group_idx: bool = True,
|
649
|
-
|
703
|
+
add_group_idx: bool = True,
|
704
|
+
organic: bool = False,
|
705
|
+
clf_type: Optional[CLF_TYPE | str] = None
|
650
706
|
) -> SoilClassifier:
|
651
707
|
""" A factory function that encapsulates the creation of a soil classifier.
|
652
708
|
|
653
709
|
:param liquid_limit: Water content beyond which soils flows under their own
|
654
|
-
weight. It can also be defined as the minimum
|
655
|
-
content at which a soil flows upon application
|
656
|
-
very small shear force.
|
710
|
+
weight (%). It can also be defined as the minimum
|
711
|
+
moisture content at which a soil flows upon application
|
712
|
+
of a very small shear force.
|
657
713
|
:type liquid_limit: float
|
658
714
|
|
659
715
|
:param plastic_limit: Water content at which plastic deformation can be
|
660
|
-
initiated. It is also the minimum water content at
|
716
|
+
initiated (%). It is also the minimum water content at
|
661
717
|
which soil can be rolled into a thread 3mm thick.
|
662
|
-
(molded without breaking)
|
718
|
+
(molded without breaking)
|
663
719
|
:type plastic_limit: float
|
664
720
|
|
665
|
-
:param fines: Percentage of fines in soil sample i.e. The percentage of
|
666
|
-
soil sample passing through No. 200 sieve (0.075mm).
|
721
|
+
:param fines: Percentage of fines in soil sample (%) i.e. The percentage of
|
722
|
+
soil sample passing through No. 200 sieve (0.075mm).
|
667
723
|
:type fines: float
|
668
724
|
|
669
|
-
:param sand: Percentage of sand in soil sample
|
725
|
+
:param sand: Percentage of sand in soil sample (%).
|
670
726
|
:type sand: float
|
671
727
|
|
672
|
-
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
728
|
+
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
673
729
|
:type d_10: float
|
674
730
|
|
675
|
-
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
731
|
+
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
676
732
|
:type d_30: float
|
677
733
|
|
678
|
-
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
734
|
+
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
679
735
|
:type d_60: float
|
680
736
|
|
681
737
|
:param add_group_idx: Used to indicate whether the group index should
|
@@ -683,28 +739,35 @@ def create_soil_classifier(liquid_limit: float, plastic_limit: float,
|
|
683
739
|
True.
|
684
740
|
:type add_group_idx: bool, optional
|
685
741
|
|
686
|
-
:param organic: Indicates whether soil is organic or not, defaults to
|
687
|
-
False.
|
742
|
+
:param organic: Indicates whether soil is organic or not, defaults to False.
|
688
743
|
:type organic: bool, optional
|
689
744
|
|
690
745
|
:param clf_type: Used to indicate which type of soil classifier should be
|
691
746
|
used, defaults to None.
|
692
|
-
:type clf_type:
|
747
|
+
:type clf_type: CLF_TYPE | str
|
693
748
|
|
694
|
-
:raises ValueError: Raises ValueError if ``clf_type`` is
|
695
|
-
|
749
|
+
:raises ValueError: Raises ValueError if ``clf_type`` is not supported or
|
750
|
+
None
|
751
|
+
:raises ValueError: Raises ValueError if ``sand`` is not provided for
|
752
|
+
:class:`USCS` classification.
|
696
753
|
"""
|
754
|
+
msg = (f"{clf_type = } is not supported, Supported "
|
755
|
+
f"types are: {list(CLF_TYPE)}")
|
756
|
+
|
697
757
|
if clf_type is None:
|
698
|
-
raise ValueError(
|
758
|
+
raise ValueError(msg)
|
699
759
|
|
700
|
-
|
701
|
-
|
702
|
-
|
760
|
+
try:
|
761
|
+
clf_type = CLF_TYPE(str(clf_type).casefold())
|
762
|
+
except ValueError as e:
|
763
|
+
raise ValueError(msg) from e
|
703
764
|
|
704
|
-
|
765
|
+
atterberg_lmts = AtterbergLimits(liquid_limit=liquid_limit,
|
766
|
+
plastic_limit=plastic_limit)
|
705
767
|
|
706
768
|
if clf_type == CLF_TYPE.AASHTO:
|
707
|
-
clf = AASHTO(atterberg_limits=
|
769
|
+
clf = AASHTO(atterberg_limits=atterberg_lmts,
|
770
|
+
fines=fines,
|
708
771
|
add_group_idx=add_group_idx)
|
709
772
|
return clf
|
710
773
|
|
@@ -712,8 +775,7 @@ def create_soil_classifier(liquid_limit: float, plastic_limit: float,
|
|
712
775
|
if sand is None:
|
713
776
|
raise ValueError("sand must be specified for USCS classification")
|
714
777
|
|
715
|
-
|
716
|
-
|
717
|
-
clf = USCS(atterberg_limits=al, psd=psd, organic=organic)
|
778
|
+
psd = PSD(fines=fines, sand=sand, d_10=d_10, d_30=d_30, d_60=d_60)
|
779
|
+
clf = USCS(atterberg_limits=atterberg_lmts, psd=psd, organic=organic)
|
718
780
|
|
719
781
|
return clf
|