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.
@@ -1,53 +1,74 @@
1
- import enum
2
- from abc import abstractmethod
3
- from typing import Protocol
4
- from typing import NamedTuple, Optional, Sequence
1
+ """ Soil classification module.
5
2
 
6
- from geolysis import validators
7
- from geolysis.utils import isclose, round_
3
+ Exceptions
4
+ ==========
8
5
 
9
- __all__ = ["CLF_TYPE", "AtterbergLimits", "PSD", "AASHTO", "USCS",
10
- "SizeDistribution", "create_soil_classifier"]
6
+ .. autosummary::
7
+ :toctree: _autosummary
11
8
 
9
+ SizeDistError
12
10
 
13
- class SizeDistError(ZeroDivisionError):
14
- """Exception raised when size distribution is not provided."""
15
- pass
11
+ Enums
12
+ =====
16
13
 
14
+ .. autosummary::
15
+ :toctree: _autosummary
16
+ :nosignatures:
17
17
 
18
- class SoilClf(NamedTuple):
19
- symbol: str
20
- description: str
18
+ CLF_TYPE
19
+ USCSSymbol
20
+ AASHTOSymbol
21
21
 
22
+ Classes
23
+ =======
22
24
 
23
- class SoilClassifier(Protocol):
25
+ .. autosummary::
26
+ :toctree: _autosummary
24
27
 
25
- @abstractmethod
26
- def classify(self) -> SoilClf: ...
28
+ AtterbergLimits
29
+ PSD
30
+ AASHTO
31
+ USCS
27
32
 
33
+ Functions
34
+ =========
28
35
 
29
- class CLF_TYPE(enum.StrEnum):
30
- """Enumeration of soil classification types."""
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
- class _Clf(enum.Enum):
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 clf_symbol(self) -> str:
67
+ def symbol(self) -> str:
47
68
  return self.value[0]
48
69
 
49
70
  @property
50
- def clf_description(self) -> str:
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 minimum
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 content at
135
- which soil can be rolled into a thread 3mm thick.
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 SizeDistribution:
229
- """Features obtained from the Particle Size Distribution graph."""
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
- size_dist: Optional[SizeDistribution] = None):
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 percentage of
286
- soil sample passing through No. 200 sieve (0.075mm).
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 size_dist: Particle size distribution of soil sample.
293
- :type size_dist: SizeDistribution
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.gravel = 100.0 - (fines + sand)
298
- self.size_dist = size_dist if size_dist else SizeDistribution()
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
- Coefficient of curvature :math:`(C_c)` is given by the formula:
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
- Coefficient of uniformity :math:`(C_u)` is given by the formula:
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 graded
331
- for gravels and sands respectively. When :math:`C_u` is less than 4, it
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 the soil.
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 of
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.clf_symbol, soil_clf.clf_description
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.clf_symbol, soil_clf.clf_description)
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.clf_symbol},{second_clf.clf_symbol}"
548
- comb_desc = f"{first_clf.clf_description},{second_clf.clf_description}"
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
- def create_soil_classifier(liquid_limit: float, plastic_limit: float,
646
- fines: float, sand: Optional[float] = None,
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, organic: bool = False,
649
- clf_type: CLF_TYPE | str | None = None
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 moisture
655
- content at which a soil flows upon application of a
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. (mm)
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. (mm)
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. (mm)
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: ClfType, optional
747
+ :type clf_type: CLF_TYPE | str
693
748
 
694
- :raises ValueError: Raises ValueError if ``clf_type`` is ``None`` or
695
- invalid
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("clf_type must be specified")
758
+ raise ValueError(msg)
699
759
 
700
- # raises ValueError if clf_type is not supported
701
- if isinstance(clf_type, str):
702
- clf_type = CLF_TYPE(clf_type.casefold())
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
- al = AtterbergLimits(liquid_limit=liquid_limit, plastic_limit=plastic_limit)
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=al, fines=fines,
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
- size_dist = SizeDistribution(d_10=d_10, d_30=d_30, d_60=d_60)
716
- psd = PSD(fines=fines, sand=sand, size_dist=size_dist)
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