geolysis 0.7.3__py3-none-any.whl → 0.9.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 CHANGED
@@ -1,5 +1,5 @@
1
1
  from . import foundation, soil_classifier, spt
2
2
 
3
- __version__ = "0.7.3"
3
+ __version__ = "0.9.0"
4
4
 
5
5
  __all__ = ["foundation", "soil_classifier", "spt"]
@@ -3,12 +3,11 @@ allowable bearing capacity calculations using methods like Bowles, Meyerhof,
3
3
  and Terzaghi for various foundation types and shapes.
4
4
  """
5
5
  import enum
6
- from codecs import backslashreplace_errors
7
6
  from typing import Optional
8
7
 
9
8
  from geolysis.foundation import FoundationType, Shape, create_foundation
10
9
  from geolysis.utils import enum_repr, inf
11
- from geolysis.utils.exceptions import EnumErrorMsg
10
+ from geolysis.utils.exceptions import ErrorMsg, ValidationError
12
11
 
13
12
  from ._core import AllowableBearingCapacity
14
13
  from .bowles_abc import BowlesABC4MatFoundation, BowlesABC4PadFoundation
@@ -99,25 +98,27 @@ def create_allowable_bearing_capacity(corrected_spt_n_value: float,
99
98
  :raises ValueError: Raised if an invalid footing ``shape`` is provided.
100
99
  """
101
100
 
102
- msg = EnumErrorMsg(param_name="abc_type",
103
- param_value=abc_type,
104
- param_type=ABCType)
101
+ msg = ErrorMsg(param_name="abc_type",
102
+ param_value=abc_type,
103
+ symbol="in",
104
+ param_value_bound=list(ABCType))
105
105
 
106
106
  if abc_type is None:
107
- raise ValueError(msg)
107
+ raise ValidationError(msg)
108
108
 
109
109
  try:
110
110
  abc_type = ABCType(str(abc_type).casefold())
111
111
  except ValueError as e:
112
- raise ValueError(msg) from e
112
+ raise ValidationError(msg) from e
113
113
 
114
114
  try:
115
115
  foundation_type = FoundationType(str(foundation_type).casefold())
116
116
  except ValueError as e:
117
- msg = EnumErrorMsg(param_name="foundation_type",
118
- param_value=foundation_type,
119
- param_type=FoundationType)
120
- raise ValueError(msg) from e
117
+ msg = ErrorMsg(param_name="foundation_type",
118
+ param_value=foundation_type,
119
+ symbol="in",
120
+ param_value_bound=list(FoundationType))
121
+ raise ValidationError(msg) from e
121
122
 
122
123
  # exception from create_foundation will automaatically propagate
123
124
  # no need to catch and handle it.
@@ -1,7 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
- from geolysis.foundation import FoundationSize
4
- from geolysis.utils import validators, exceptions as exc
3
+ from geolysis.foundation import Foundation
4
+ from geolysis.utils import validators
5
5
 
6
6
 
7
7
  class AllowableBearingCapacity(ABC):
@@ -10,7 +10,7 @@ class AllowableBearingCapacity(ABC):
10
10
 
11
11
  def __init__(self, corrected_spt_n_value: float,
12
12
  tol_settlement: float,
13
- foundation_size: FoundationSize) -> None:
13
+ foundation_size: Foundation) -> None:
14
14
  self.corrected_spt_n_value = corrected_spt_n_value
15
15
  self.tol_settlement = tol_settlement
16
16
  self.foundation_size = foundation_size
@@ -31,7 +31,7 @@ class AllowableBearingCapacity(ABC):
31
31
  return self._tol_settlement
32
32
 
33
33
  @tol_settlement.setter
34
- @validators.le(25.4, exc_type=exc.SettlementError)
34
+ @validators.le(25.4)
35
35
  def tol_settlement(self, tol_settlement: float) -> None:
36
36
  self._tol_settlement = tol_settlement
37
37
 
@@ -1,4 +1,4 @@
1
- from geolysis.foundation import FoundationSize
1
+ from geolysis.foundation import Foundation
2
2
  from geolysis.utils import round_
3
3
 
4
4
  from ._core import AllowableBearingCapacity
@@ -34,7 +34,7 @@ class BowlesABC4PadFoundation(AllowableBearingCapacity):
34
34
 
35
35
  def __init__(self, corrected_spt_n_value: float,
36
36
  tol_settlement: float,
37
- foundation_size: FoundationSize) -> None:
37
+ foundation_size: Foundation) -> None:
38
38
  """
39
39
  :param corrected_spt_n_value: Statistical average of corrected SPT
40
40
  N-value (55% energy with overburden
@@ -46,7 +46,7 @@ class BowlesABC4PadFoundation(AllowableBearingCapacity):
46
46
  :type tol_settlement: float
47
47
 
48
48
  :param foundation_size: Size of the foundation.
49
- :type foundation_size: FoundationSize
49
+ :type foundation_size: Foundation
50
50
  """
51
51
  super().__init__(corrected_spt_n_value=corrected_spt_n_value,
52
52
  tol_settlement=tol_settlement,
@@ -1,4 +1,4 @@
1
- from geolysis.foundation import FoundationSize
1
+ from geolysis.foundation import Foundation
2
2
  from geolysis.utils import round_
3
3
 
4
4
  from ._core import AllowableBearingCapacity
@@ -33,7 +33,7 @@ class MeyerhofABC4PadFoundation(AllowableBearingCapacity):
33
33
 
34
34
  def __init__(self, corrected_spt_n_value: float,
35
35
  tol_settlement: float,
36
- foundation_size: FoundationSize):
36
+ foundation_size: Foundation):
37
37
  """
38
38
  :param corrected_spt_n_value: Average uncorrected SPT N-value (60%
39
39
  energy with dilatancy (water) correction
@@ -46,7 +46,7 @@ class MeyerhofABC4PadFoundation(AllowableBearingCapacity):
46
46
  :type tol_settlement: float
47
47
 
48
48
  :param foundation_size: Size of the foundation.
49
- :type foundation_size: FoundationSize
49
+ :type foundation_size: Foundation
50
50
  """
51
51
  super().__init__(corrected_spt_n_value=corrected_spt_n_value,
52
52
  tol_settlement=tol_settlement,
@@ -1,4 +1,4 @@
1
- from geolysis.foundation import FoundationSize
1
+ from geolysis.foundation import Foundation
2
2
  from geolysis.utils import round_
3
3
 
4
4
  from ._core import AllowableBearingCapacity
@@ -40,7 +40,7 @@ class TerzaghiABC4PadFoundation(AllowableBearingCapacity):
40
40
 
41
41
  def __init__(self, corrected_spt_n_value: float,
42
42
  tol_settlement: float,
43
- foundation_size: FoundationSize) -> None:
43
+ foundation_size: Foundation) -> None:
44
44
  """
45
45
  :param corrected_spt_n_value: Lowest (or average) uncorrected SPT
46
46
  N-value (60% energy) within the foundation
@@ -52,7 +52,7 @@ class TerzaghiABC4PadFoundation(AllowableBearingCapacity):
52
52
  :type tol_settlement: float
53
53
 
54
54
  :param foundation_size: Size of the foundation.
55
- :type foundation_size: FoundationSize
55
+ :type foundation_size: Foundation
56
56
  """
57
57
  super().__init__(corrected_spt_n_value=corrected_spt_n_value,
58
58
  tol_settlement=tol_settlement,
@@ -8,7 +8,7 @@ from typing import Optional
8
8
 
9
9
  from geolysis.foundation import Shape, create_foundation
10
10
  from geolysis.utils import enum_repr
11
- from geolysis.utils.exceptions import EnumErrorMsg
11
+ from geolysis.utils.exceptions import ErrorMsg, ValidationError
12
12
 
13
13
  from ._core import UltimateBearingCapacity
14
14
  from .hansen_ubc import HansenUltimateBearingCapacity
@@ -116,17 +116,18 @@ def create_ultimate_bearing_capacity(friction_angle: float,
116
116
  :raises ValueError: Raised if an invalid footing shape is provided.
117
117
  """
118
118
 
119
- msg = EnumErrorMsg(param_name="ubc_type",
120
- param_value=ubc_type,
121
- param_type=UBCType)
119
+ msg = ErrorMsg(param_name="ubc_type",
120
+ param_value=ubc_type,
121
+ symbol="in",
122
+ param_value_bound=list(UBCType))
122
123
 
123
124
  if ubc_type is None:
124
- raise ValueError(msg)
125
+ raise ValidationError(msg)
125
126
 
126
127
  try:
127
128
  ubc_type = UBCType(str(ubc_type).casefold())
128
129
  except ValueError as e:
129
- raise ValueError(msg) from e
130
+ raise ValidationError(msg) from e
130
131
 
131
132
  # exception from create_foundation will automatically propagate
132
133
  # no need to catch and handle it.
@@ -134,6 +135,7 @@ def create_ultimate_bearing_capacity(friction_angle: float,
134
135
  width=width,
135
136
  length=length,
136
137
  eccentricity=eccentricity,
138
+ load_angle=load_angle,
137
139
  ground_water_level=ground_water_level,
138
140
  shape=shape)
139
141
 
@@ -146,6 +148,5 @@ def create_ultimate_bearing_capacity(friction_angle: float,
146
148
  cohesion=cohesion,
147
149
  moist_unit_wgt=moist_unit_wgt,
148
150
  foundation_size=fnd_size,
149
- load_angle=load_angle,
150
151
  apply_local_shear=apply_local_shear)
151
152
  return ubc
@@ -1,6 +1,6 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
- from geolysis.foundation import FoundationSize
3
+ from geolysis.foundation import Foundation
4
4
  from geolysis.utils import arctan, round_, tan, validators
5
5
 
6
6
 
@@ -8,8 +8,8 @@ class UltimateBearingCapacity(ABC):
8
8
  def __init__(self, friction_angle: float,
9
9
  cohesion: float,
10
10
  moist_unit_wgt: float,
11
- foundation_size: FoundationSize,
12
- load_angle: float = 0.0,
11
+ foundation_size: Foundation,
12
+ # load_angle: float = 0.0,
13
13
  apply_local_shear: bool = False) -> None:
14
14
  r"""
15
15
  :param friction_angle: Internal angle of friction for general shear
@@ -23,11 +23,7 @@ class UltimateBearingCapacity(ABC):
23
23
  :type moist_unit_wgt: float
24
24
 
25
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
26
+ :type foundation_size: Foundation
31
27
 
32
28
  :param apply_local_shear: Indicate whether bearing capacity failure is
33
29
  general shear or local shear failure,
@@ -37,7 +33,6 @@ class UltimateBearingCapacity(ABC):
37
33
  self.friction_angle = friction_angle
38
34
  self.cohesion = cohesion
39
35
  self.moist_unit_wgt = moist_unit_wgt
40
- self.load_angle = load_angle
41
36
  self.foundation_size = foundation_size
42
37
  self.apply_local_shear = apply_local_shear
43
38
 
@@ -97,15 +92,9 @@ class UltimateBearingCapacity(ABC):
97
92
  self._moist_unit_wgt = val
98
93
 
99
94
  @property
100
- def load_angle(self) -> float:
95
+ def load_angle(self):
101
96
  """Inclination of the applied load with the vertical."""
102
- return self._load_angle
103
-
104
- @load_angle.setter
105
- @validators.le(90.0)
106
- @validators.ge(0.0)
107
- def load_angle(self, val: float):
108
- self._load_angle = val
97
+ return self.foundation_size.load_angle
109
98
 
110
99
  @property
111
100
  def s_c(self) -> float:
@@ -60,7 +60,7 @@ class TerzaghiUltimateBearingCapacity(UltimateBearingCapacity, ABC):
60
60
 
61
61
  :Equation:
62
62
 
63
- .. math:: N_{\gamma} &= (N_q - 1) \cdot \tan(1.4\phi)
63
+ .. math:: N_{\gamma} = (N_q - 1) \cdot \tan(1.4\phi)
64
64
  """
65
65
  return n_gamma(self.friction_angle)
66
66
 
geolysis/foundation.py CHANGED
@@ -5,10 +5,10 @@ from abc import ABC, abstractmethod
5
5
  from typing import Optional, TypeVar
6
6
 
7
7
  from .utils import enum_repr, inf, isclose, validators
8
- from .utils.exceptions import EnumErrorMsg, ErrorMsg
8
+ from .utils.exceptions import ErrorMsg, ValidationError
9
9
 
10
10
  __all__ = ["create_foundation",
11
- "FoundationSize",
11
+ "Foundation",
12
12
  "FoundationType",
13
13
  "Shape",
14
14
  "StripFooting",
@@ -31,8 +31,10 @@ class Shape(enum.StrEnum):
31
31
  @enum_repr
32
32
  class FoundationType(enum.StrEnum):
33
33
  """Enumeration of foundation types."""
34
- PAD = ISOLATED = enum.auto()
35
- MAT = RAFT = enum.auto()
34
+ PAD = enum.auto()
35
+ ISOLATED = PAD
36
+ MAT = enum.auto()
37
+ RAFT = MAT
36
38
 
37
39
 
38
40
  class FootingSize(ABC):
@@ -214,15 +216,16 @@ class RectangularFooting(FootingSize):
214
216
  self._length = val
215
217
 
216
218
 
217
- class FoundationSize:
219
+ class Foundation:
218
220
  """A simple class representing a foundation structure."""
219
221
 
220
222
  def __init__(self, depth: float,
221
223
  footing_size: FootingSize,
222
224
  eccentricity: float = 0.0,
225
+ load_angle: float = 0.0,
223
226
  ground_water_level: Optional[float] = None,
224
227
  foundation_type: FoundationType = FoundationType.PAD) -> None:
225
- """
228
+ r"""
226
229
  :param depth: Depth of foundation (m).
227
230
  :type depth: float
228
231
 
@@ -236,6 +239,10 @@ class FoundationSize:
236
239
  foundation footing.
237
240
  :type eccentricity: float, optional
238
241
 
242
+ :param load_angle: Inclination of the applied load with the vertical
243
+ (:math:`\alpha^{\circ}`), defaults to 0.0.
244
+ :type load_angle: float, optional
245
+
239
246
  :param ground_water_level: Depth of the water below ground level (m),
240
247
  defaults to None.
241
248
  :type ground_water_level: float, optional
@@ -247,6 +254,7 @@ class FoundationSize:
247
254
  self.depth = depth
248
255
  self.footing_size = footing_size
249
256
  self.eccentricity = eccentricity
257
+ self.load_angle = load_angle
250
258
 
251
259
  self._ground_water_level = ground_water_level
252
260
  self._foundation_type = foundation_type
@@ -296,6 +304,17 @@ class FoundationSize:
296
304
  def eccentricity(self, val: float) -> None:
297
305
  self._eccentricity = val
298
306
 
307
+ @property
308
+ def load_angle(self) -> float:
309
+ """Inclination of the applied load with the vertical."""
310
+ return self._load_angle
311
+
312
+ @load_angle.setter
313
+ @validators.le(90.0)
314
+ @validators.ge(0.0)
315
+ def load_angle(self, val: float):
316
+ self._load_angle = val
317
+
299
318
  @property
300
319
  def ground_water_level(self) -> Optional[float]:
301
320
  """Depth of the water below ground level (m)."""
@@ -334,10 +353,11 @@ def create_foundation(depth: float,
334
353
  width: float,
335
354
  length: Optional[float] = None,
336
355
  eccentricity: float = 0.0,
356
+ load_angle: float = 0.0,
337
357
  ground_water_level: Optional[float] = None,
338
358
  foundation_type: FoundationType = FoundationType.PAD,
339
- shape: Shape | str = Shape.SQUARE) -> FoundationSize:
340
- """A factory function that encapsulate the creation of a foundation.
359
+ shape: Shape | str = Shape.SQUARE) -> Foundation:
360
+ r"""A factory function that encapsulate the creation of a foundation.
341
361
 
342
362
  :param depth: Depth of foundation (m).
343
363
  :type depth: float
@@ -356,6 +376,10 @@ def create_foundation(depth: float,
356
376
  foundation footing .
357
377
  :type eccentricity: float, optional
358
378
 
379
+ :param load_angle: Inclination of the applied load with the vertical
380
+ (:math:`\alpha^{\circ}`), defaults to 0.0.
381
+ :type load_angle: float, optional
382
+
359
383
  :param ground_water_level: Depth of the water below ground level (m),
360
384
  defaults to None.
361
385
  :type ground_water_level: float, optional
@@ -376,10 +400,11 @@ def create_foundation(depth: float,
376
400
  try:
377
401
  shape = Shape(str(shape).casefold())
378
402
  except ValueError as e:
379
- msg = EnumErrorMsg(param_name="shape",
380
- param_value=shape,
381
- param_type=Shape)
382
- raise ValueError(msg) from e
403
+ msg = ErrorMsg(param_name="shape",
404
+ param_value=shape,
405
+ symbol="in",
406
+ param_value_bound=list(Shape))
407
+ raise ValidationError(msg) from e
383
408
 
384
409
  if shape is Shape.STRIP:
385
410
  footing_size = StripFooting(width=width)
@@ -389,12 +414,15 @@ def create_foundation(depth: float,
389
414
  footing_size = CircularFooting(diameter=width)
390
415
  else: # RECTANGLE
391
416
  if not length:
392
- msg = ErrorMsg(msg="Length of footing must be provided.")
393
- raise ValueError(msg)
417
+ msg = ErrorMsg(param_name="length",
418
+ param_value=length,
419
+ msg="Length of footing must be provided.")
420
+ raise ValidationError(msg)
394
421
  footing_size = RectangularFooting(width=width, length=length)
395
422
 
396
- return FoundationSize(depth=depth,
397
- eccentricity=eccentricity,
398
- ground_water_level=ground_water_level,
399
- foundation_type=foundation_type,
400
- footing_size=footing_size)
423
+ return Foundation(depth=depth,
424
+ eccentricity=eccentricity,
425
+ load_angle=load_angle,
426
+ ground_water_level=ground_water_level,
427
+ foundation_type=foundation_type,
428
+ footing_size=footing_size)
@@ -5,7 +5,7 @@ import enum
5
5
  from typing import NamedTuple, Optional, Sequence
6
6
 
7
7
  from .utils import enum_repr, isclose, round_, validators
8
- from .utils.exceptions import EnumErrorMsg, ErrorMsg
8
+ from .utils.exceptions import ErrorMsg, ValidationError
9
9
 
10
10
  __all__ = ["ClfType",
11
11
  "AtterbergLimits",
@@ -117,9 +117,6 @@ class AtterbergLimits:
117
117
  3mm thick. (molded without breaking)
118
118
  :type plastic_limit: float
119
119
  """
120
- if liquid_limit < plastic_limit:
121
- raise ValueError("liquid_limit cannot be less than plastic_limit")
122
-
123
120
  self.liquid_limit = liquid_limit
124
121
  self.plastic_limit = plastic_limit
125
122
 
@@ -141,6 +138,14 @@ class AtterbergLimits:
141
138
  @plastic_limit.setter
142
139
  @validators.ge(0.0)
143
140
  def plastic_limit(self, val: float) -> None:
141
+ if self.liquid_limit < val:
142
+ msg = ErrorMsg(param_name="plastic_limit",
143
+ param_value=val,
144
+ param_value_bound=f"<{self.liquid_limit}",
145
+ msg=f"plastic_limit: {val} cannot be greater than "
146
+ f"liquid_limit: {self.liquid_limit}")
147
+ raise ValidationError(msg)
148
+
144
149
  self._plastic_limit = val
145
150
 
146
151
  @property
@@ -421,12 +426,12 @@ class AASHTO:
421
426
  plasticity_idx = self.atterberg_limits.plasticity_index
422
427
  fines = self.fines
423
428
 
424
- var_a = 1.0 if (x_0 := fines - 35.0) < 0.0 else min(x_0, 40.0)
425
- var_b = 1.0 if (x_0 := liquid_lmt - 40.0) < 0.0 else min(x_0, 20.0)
426
- var_c = 1.0 if (x_0 := fines - 15.0) < 0.0 else min(x_0, 40.0)
427
- var_d = 1.0 if (x_0 := plasticity_idx - 10.0) < 0.0 else min(x_0, 20.0)
429
+ x_1 = 1.0 if (x_0 := fines - 35.0) < 0.0 else min(x_0, 40.0)
430
+ x_2 = 1.0 if (x_0 := liquid_lmt - 40.0) < 0.0 else min(x_0, 20.0)
431
+ x_3 = 1.0 if (x_0 := fines - 15.0) < 0.0 else min(x_0, 40.0)
432
+ x_4 = 1.0 if (x_0 := plasticity_idx - 10.0) < 0.0 else min(x_0, 20.0)
428
433
 
429
- return var_a * (0.2 + 0.005 * var_b) + 0.01 * var_c * var_d
434
+ return x_1 * (0.2 + 0.005 * x_2) + 0.01 * x_3 * x_4
430
435
 
431
436
  def classify(self) -> SoilClf:
432
437
  """Return the AASHTO classification of the soil."""
@@ -713,17 +718,18 @@ def create_soil_classifier(liquid_limit: float,
713
718
  :raises ValueError: Raises ValueError if ``sand`` is not provided for
714
719
  :class:`USCS` classification.
715
720
  """
716
- msg = EnumErrorMsg(param_name="clf_type",
717
- param_value=clf_type,
718
- param_type=ClfType)
721
+ msg = ErrorMsg(param_name="clf_type",
722
+ param_value=clf_type,
723
+ symbol="in",
724
+ param_value_bound=list(ClfType))
719
725
 
720
726
  if clf_type is None:
721
- raise ValueError(msg)
727
+ raise ValidationError(msg)
722
728
 
723
729
  try:
724
730
  clf_type = ClfType(str(clf_type).casefold())
725
731
  except ValueError as e:
726
- raise ValueError(msg) from e
732
+ raise ValidationError(msg) from e
727
733
 
728
734
  atterberg_lmts = AtterbergLimits(liquid_limit=liquid_limit,
729
735
  plastic_limit=plastic_limit)
@@ -736,8 +742,10 @@ def create_soil_classifier(liquid_limit: float,
736
742
 
737
743
  # USCS classification
738
744
  if not sand:
739
- msg = ErrorMsg("sand must be specified for USCS classification")
740
- raise ValueError(msg)
745
+ msg = ErrorMsg(param_name="sand",
746
+ param_value=sand,
747
+ msg="sand must be specified for USCS classification")
748
+ raise ValidationError(msg)
741
749
 
742
750
  psd = PSD(fines=fines, sand=sand, d_10=d_10, d_30=d_30, d_60=d_60)
743
751
  clf = USCS(atterberg_limits=atterberg_lmts, psd=psd, organic=organic)
geolysis/spt.py CHANGED
@@ -4,10 +4,10 @@ as well as calculating design N-values.
4
4
  """
5
5
  import enum
6
6
  from abc import abstractmethod
7
- from typing import Final, Sequence, Literal
7
+ from typing import Final, Literal, Sequence
8
8
 
9
9
  from .utils import enum_repr, isclose, log10, mean, round_, sqrt, validators
10
- from .utils.exceptions import EnumErrorMsg, ErrorMsg, ValidationError
10
+ from .utils.exceptions import ErrorMsg, ValidationError
11
11
 
12
12
  __all__ = ["SPTNDesign",
13
13
  "HammerType",
@@ -51,14 +51,21 @@ class SPTNDesign:
51
51
  return self._corrected_spt_n_values
52
52
 
53
53
  @corrected_spt_n_values.setter
54
+ @validators.le(100.0)
55
+ @validators.gt(0.0)
54
56
  @validators.min_len(1)
55
57
  def corrected_spt_n_values(self, val: Sequence[float]) -> None:
56
- for v in val:
57
- if v <= 0.0 or v > 100:
58
- raise ValidationError(
59
- "SPT N-values must be between 0.0 and 100.")
60
58
  self._corrected_spt_n_values = val
61
59
 
60
+ @property
61
+ def method(self):
62
+ return self._method
63
+
64
+ @method.setter
65
+ @validators.in_(("min", "avg", "wgt"))
66
+ def method(self, val: str) -> None:
67
+ self._method = val
68
+
62
69
  @staticmethod
63
70
  def _avg_spt_n_design(vals) -> float:
64
71
  return mean(vals)
@@ -105,11 +112,8 @@ class SPTNDesign:
105
112
  return self._min_spt_n_design(self.corrected_spt_n_values)
106
113
  elif self.method == "avg":
107
114
  return self._avg_spt_n_design(self.corrected_spt_n_values)
108
- elif self.method == "wgt":
115
+ else: # method="wgt"
109
116
  return self._wgt_spt_n_design(self.corrected_spt_n_values)
110
- else:
111
- msg = ErrorMsg("method must be 'min', 'avg', or 'wgt'")
112
- raise ValueError(msg)
113
117
 
114
118
 
115
119
  @enum_repr
@@ -227,6 +231,24 @@ class EnergyCorrection:
227
231
  def rod_length(self, val: float) -> None:
228
232
  self._rod_length = val
229
233
 
234
+ @property
235
+ def hammer_type(self) -> HammerType:
236
+ return self._hammer_type
237
+
238
+ @hammer_type.setter
239
+ @validators.in_(tuple(HammerType))
240
+ def hammer_type(self, val: HammerType) -> None:
241
+ self._hammer_type = val
242
+
243
+ @property
244
+ def sampler_type(self) -> SamplerType:
245
+ return self._sampler_type
246
+
247
+ @sampler_type.setter
248
+ @validators.in_(tuple(SamplerType))
249
+ def sampler_type(self, val: SamplerType) -> None:
250
+ self._sampler_type = val
251
+
230
252
  @property
231
253
  def hammer_efficiency(self) -> float:
232
254
  """Hammer efficiency correction factor."""
@@ -558,10 +580,11 @@ def create_overburden_pressure_correction(std_spt_n_value: float, eop,
558
580
  try:
559
581
  opc_type = OPCType(str(opc_type).casefold())
560
582
  except ValueError as e:
561
- msg = EnumErrorMsg(param_name="opc_type",
562
- param_value=opc_type,
563
- param_type=OPCType)
564
- raise ValueError(msg) from e
583
+ msg = ErrorMsg(param_name="opc_type",
584
+ param_value=opc_type,
585
+ symbol="in",
586
+ param_value_bound=list(OPCType))
587
+ raise ValidationError(msg) from e
565
588
 
566
589
  opc_class = _opctypes[opc_type]
567
590
  opc_corr = opc_class(std_spt_n_value=std_spt_n_value, eop=eop)
@@ -67,18 +67,19 @@ def enum_repr(cls):
67
67
  return cls
68
68
 
69
69
 
70
- def round_(ndigits: int | Callable[..., SupportsRound]) -> Callable:
70
+ def round_(ndigits: int) -> Callable:
71
71
  """A decorator that rounds the result of a callable to a specified number
72
72
  of decimal places.
73
73
 
74
74
  The returned value of the callable should support the ``__round__`` dunder
75
- method and should be a numeric value. ``ndigits`` can either be an int
76
- which will indicate the number of decimal places to round to or a
77
- callable. If ``ndigits`` is callable the default decimal places is 2.
75
+ method and should be a numeric value.
78
76
 
79
- TypeError is raised when ``ndigits`` is neither an int nor a callable.
77
+ TypeError is raised when ``ndigits`` is not an int.
80
78
  """
81
79
 
80
+ if not isinstance(ndigits, int):
81
+ raise TypeError("ndigits must be an int")
82
+
82
83
  def dec(fn) -> Callable[..., float]:
83
84
  @functools.wraps(fn)
84
85
  def wrapper(*args, **kwargs) -> float:
@@ -1,36 +1,65 @@
1
- from typing import Unpack, TypedDict, NotRequired, Any, Optional
1
+ from collections import UserString
2
+ from typing import Any
2
3
 
3
4
 
4
- class _ErrorParams(TypedDict):
5
- param_name: NotRequired[str]
6
- param_value: NotRequired[Any]
7
- param_type: NotRequired[Any]
5
+ class ErrorMsg(UserString):
6
+ def __init__(self, *, param_name: str = None,
7
+ param_value: Any = None,
8
+ symbol: str = None,
9
+ param_value_bound: Any = None,
10
+ msg: str = None):
11
+ if not msg:
12
+ msg = f"{param_name}: {param_value!r} must be {symbol} {param_value_bound}"
8
13
 
14
+ super().__init__(msg)
9
15
 
10
- class ErrorMsg(str):
16
+ self.param_name = param_name
17
+ self.param_value = param_value
18
+ self.symbol = symbol
19
+ self.param_value_bound = param_value_bound
11
20
 
12
- @staticmethod
13
- def __new__(cls, msg):
14
- return super().__new__(cls, msg)
21
+ @property
22
+ def msg(self):
23
+ return self.data
15
24
 
25
+ def __add__(self, other):
26
+ msg = self.msg + str(other)
27
+ return self.__class__(param_name=self.param_name,
28
+ param_value=self.param_value,
29
+ symbol=self.symbol,
30
+ param_value_bound=self.param_value_bound,
31
+ msg=msg)
16
32
 
17
- class EnumErrorMsg(ErrorMsg):
33
+ def __radd__(self, other):
34
+ msg = str(other) + self.msg
35
+ return self.__class__(param_name=self.param_name,
36
+ param_value=self.param_value,
37
+ symbol=self.symbol,
38
+ param_value_bound=self.param_value_bound,
39
+ msg=msg)
18
40
 
19
- @staticmethod
20
- def __new__(cls, *args, msg: Optional[str] = None,
21
- **kwargs: Unpack[_ErrorParams]):
22
- err_msg = msg if msg else (
23
- f"Invalid value for {kwargs['param_name']}: {kwargs['param_value']}, "
24
- f"Supported types are: {list(kwargs['param_type'])}")
41
+ def __repr__(self) -> str:
42
+ return f"ErrorMsg(param_name={self.param_name}, " \
43
+ f"param_value={self.param_value}, " \
44
+ f"symbol={self.symbol}, " \
45
+ f"param_value_bound={self.param_value_bound}, msg={self.msg!r})"
25
46
 
26
- return super().__new__(cls, err_msg)
47
+ def to_dict(self) -> dict:
48
+ return {
49
+ "param_name": self.param_name,
50
+ "param_value": self.param_value,
51
+ "symbol": self.symbol,
52
+ "param_value_bound": self.param_value_bound,
53
+ "message": self.msg
54
+ }
27
55
 
28
56
 
29
57
  class ValidationError(ValueError):
30
58
  """Exception raised when a validation error occurs."""
31
59
 
60
+ def __init__(self, error: ErrorMsg):
61
+ super().__init__(error)
62
+ self.error = error
32
63
 
33
- class SettlementError(ValueError):
34
- """Raised when tolerable settlement is greater than the maximum
35
- allowable settlement.
36
- """
64
+ def __repr__(self):
65
+ return f"ValidationError(error={self.error!r})"
@@ -1,101 +1,119 @@
1
1
  """validators"""
2
2
  import operator
3
- from typing import Callable, TypeAlias, Optional
4
3
  from functools import wraps
4
+ from typing import Any, Callable, Iterable, TypeAlias, List, Tuple, Sequence
5
5
 
6
- from .exceptions import ValidationError
6
+ from .exceptions import ErrorMsg, ValidationError
7
7
 
8
8
  Number: TypeAlias = int | float
9
9
 
10
10
 
11
- def _num_validator(bound: float, /, *,
12
- compare_symbol: str,
13
- compare_fn: Callable,
14
- exc_type: Callable,
15
- err_msg: str):
16
- def dec(fn):
11
+ class _Validator:
12
+
13
+ def __init__(self, bound: Any, /, *,
14
+ symbol: str,
15
+ check: Callable,
16
+ exc_type: Callable,
17
+ err_msg: str):
18
+ self.bound = bound
19
+ self.symbol = symbol
20
+ self.check = check
21
+ self.exc_type = exc_type
22
+ self.err_msg = err_msg
23
+
24
+ def check_val(self, val, fname: str):
25
+ raise NotImplementedError
26
+
27
+ def __call__(self, fn):
17
28
  @wraps(fn)
18
29
  def wrapper(obj, val):
19
- if not compare_fn(val, bound):
20
- msg = f"{fn.__name__} must be {compare_symbol} {bound}"
21
- raise exc_type(err_msg if err_msg else msg)
30
+ if isinstance(val, List | Tuple):
31
+ for v in val:
32
+ self.check_val(v, fn.__name__)
33
+ else:
34
+ self.check_val(val, fn.__name__)
35
+
22
36
  fn(obj, val)
23
37
 
24
38
  return wrapper
25
39
 
26
- return dec
40
+
41
+ class _NumValidator(_Validator):
42
+
43
+ def check_val(self, v: Number, fname: str):
44
+ if not self.check(v, self.bound):
45
+ msg = ErrorMsg(msg=self.err_msg,
46
+ param_name=fname,
47
+ param_value=v,
48
+ symbol=self.symbol,
49
+ param_value_bound=self.bound)
50
+ raise self.exc_type(msg)
27
51
 
28
52
 
29
- def _len_validator(bound: float, /, *,
30
- compare_symbol: str,
31
- compare_fn: Callable,
32
- exc_type: Callable,
33
- err_msg: str):
34
- def dec(fn):
53
+ class _LenValidator(_Validator):
54
+
55
+ def __call__(self, fn):
35
56
  @wraps(fn)
36
- def wrapper(obj, val):
37
- _len = len(val)
38
- if not compare_fn(_len, bound):
39
- msg = f"Length of '{fn.__name__}' must be {compare_symbol} {bound}"
40
- raise exc_type(err_msg if err_msg else msg)
57
+ def wrapper(obj, val: Sequence):
58
+ if not self.check(len(val), self.bound):
59
+ msg = ErrorMsg(msg=self.err_msg,
60
+ param_name=fn.__name__,
61
+ param_value=val,
62
+ symbol=self.symbol,
63
+ param_value_bound=self.bound)
64
+ msg = "Length of " + msg
65
+ raise self.exc_type(msg)
41
66
  fn(obj, val)
42
67
 
43
68
  return wrapper
44
69
 
45
- return dec
70
+
71
+ class _InValidator(_Validator):
72
+ def check_val(self, v, fname):
73
+ if not self.check(self.bound, v):
74
+ msg = ErrorMsg(msg=self.err_msg,
75
+ param_name=fname,
76
+ param_value=v,
77
+ symbol=self.symbol,
78
+ param_value_bound=self.bound)
79
+ raise self.exc_type(msg)
80
+
81
+
82
+ def in_(bound: Iterable[Any], /, *, exc_type=ValidationError, err_msg=None):
83
+ return _InValidator(bound, symbol="in", check=operator.contains,
84
+ exc_type=exc_type, err_msg=err_msg)
46
85
 
47
86
 
48
- def min_len(m_len: int, /, *,
49
- exc_type=ValidationError,
50
- err_msg: Optional[str] = None):
51
- return _len_validator(m_len, compare_symbol=">=",
52
- compare_fn=operator.ge,
53
- exc_type=exc_type, err_msg=err_msg)
87
+ def min_len(bound: int, /, *, exc_type=ValidationError, err_msg=None):
88
+ return _LenValidator(bound, symbol=">=", check=operator.ge,
89
+ exc_type=exc_type, err_msg=err_msg)
54
90
 
55
91
 
56
- def lt(val: Number, /, *, exc_type=ValidationError,
57
- err_msg: Optional[str] = None):
58
- return _num_validator(val, compare_symbol="<",
59
- compare_fn=operator.lt,
60
- exc_type=exc_type,
61
- err_msg=err_msg)
92
+ def lt(bound: Number, /, *, exc_type=ValidationError, err_msg=None):
93
+ return _NumValidator(bound, symbol="<", check=operator.lt,
94
+ exc_type=exc_type, err_msg=err_msg)
62
95
 
63
96
 
64
- def le(val: Number, /, *, exc_type=ValidationError,
65
- err_msg: Optional[str] = None):
66
- return _num_validator(val, compare_symbol="<=",
67
- compare_fn=operator.le,
68
- exc_type=exc_type,
69
- err_msg=err_msg)
97
+ def le(bound: Number, /, *, exc_type=ValidationError, err_msg=None):
98
+ return _NumValidator(bound, symbol="<=", check=operator.le,
99
+ exc_type=exc_type, err_msg=err_msg)
70
100
 
71
101
 
72
- def eq(val: Number, /, *, exc_type=ValidationError,
73
- err_msg: Optional[str] = None):
74
- return _num_validator(val, compare_symbol="==",
75
- compare_fn=operator.eq,
76
- exc_type=exc_type,
77
- err_msg=err_msg)
102
+ def eq(bound: Number, /, *, exc_type=ValidationError, err_msg=None):
103
+ return _NumValidator(bound, symbol="==", check=operator.eq,
104
+ exc_type=exc_type, err_msg=err_msg)
78
105
 
79
106
 
80
- def ne(val: Number, /, *, exc_type=ValidationError,
81
- err_msg: Optional[str] = None):
82
- return _num_validator(val, compare_symbol="!=",
83
- compare_fn=operator.ne,
84
- exc_type=exc_type,
85
- err_msg=err_msg)
107
+ def ne(bound: Number, /, *, exc_type=ValidationError, err_msg=None):
108
+ return _NumValidator(bound, symbol="!=", check=operator.ne,
109
+ exc_type=exc_type, err_msg=err_msg)
86
110
 
87
111
 
88
- def ge(val: Number, /, *, exc_type=ValidationError,
89
- err_msg: Optional[str] = None):
90
- return _num_validator(val, compare_symbol=">=",
91
- compare_fn=operator.ge,
92
- exc_type=exc_type,
93
- err_msg=err_msg)
112
+ def ge(bound: Number, /, *, exc_type=ValidationError, err_msg=None):
113
+ return _NumValidator(bound, symbol=">=", check=operator.ge,
114
+ exc_type=exc_type, err_msg=err_msg)
94
115
 
95
116
 
96
- def gt(val: Number, /, *, exc_type=ValidationError,
97
- err_msg: Optional[str] = None):
98
- return _num_validator(val, compare_symbol=">",
99
- compare_fn=operator.gt,
100
- exc_type=exc_type,
101
- err_msg=err_msg)
117
+ def gt(bound: Number, /, *, exc_type=ValidationError, err_msg=None):
118
+ return _NumValidator(bound, symbol=">", check=operator.gt,
119
+ exc_type=exc_type, err_msg=err_msg)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geolysis
3
- Version: 0.7.3
3
+ Version: 0.9.0
4
4
  Summary: geolysis is an opensource software for geotechnical engineering analysis and modeling.
5
5
  Author-email: Patrick Boateng <boatengpato.pb@gmail.com>
6
6
  License: MIT License
@@ -134,7 +134,6 @@ Here are brief descriptions of the `geolysis` projects:
134
134
 
135
135
  - [Installation](#installation)
136
136
  - [Usage Example](#usage-example)
137
- - [Features](#features)
138
137
  - [Documentation](#documentation)
139
138
  - [Contributing](#contributing)
140
139
  - [License](#license)
@@ -0,0 +1,24 @@
1
+ geolysis/__init__.py,sha256=kFx0nIRRC4FkGDiad710EjGzxkIbTO7HgbwZ9DRgrXc,122
2
+ geolysis/foundation.py,sha256=tnoDycRLMl0W_6QDM2fwPmosrxVwhGH3b88PIy0zPks,12661
3
+ geolysis/soil_classifier.py,sha256=J4N_0jmOcrPJZop_CyIlAk1hDqfFO-AdBi_TtpQLRNw,27274
4
+ geolysis/spt.py,sha256=ix0kHhOXeaIRhfqxq3CTueDpLRlPCfeSz8KyqQSwF8k,18208
5
+ geolysis/bearing_capacity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ geolysis/bearing_capacity/abc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ geolysis/bearing_capacity/abc/cohl/__init__.py,sha256=En8EQMz8LV0rCy8EZZXHkUOfBe7KBnw2Kz-Q8SpU7HM,5454
8
+ geolysis/bearing_capacity/abc/cohl/_core.py,sha256=C1sZM5kVwXv_dqZfKdd7OHNH-q44pz87GNI2vcmdzYI,1570
9
+ geolysis/bearing_capacity/abc/cohl/bowles_abc.py,sha256=7oet6fhiMHI9dPV9EYFNaW_-RPeGGlFuJnpWFOEoI2I,4084
10
+ geolysis/bearing_capacity/abc/cohl/meyerhof_abc.py,sha256=1JUuCCrsh374ZltTl9OQmFsCYmVm2_8-jlZlFHbwWuE,4044
11
+ geolysis/bearing_capacity/abc/cohl/terzaghi_abc.py,sha256=_EKKVh7WWx76fBNFtDcby6Dwtzg3H0kaVxjkVuBr_Xc,5296
12
+ geolysis/bearing_capacity/ubc/__init__.py,sha256=bJryzgkY5DvjCU0YKzAsCp_rxO3E2lNpUqP9QE6ro0I,6052
13
+ geolysis/bearing_capacity/ubc/_core.py,sha256=fee8DNd8QmcMv55u3dXR4iYAa0xHIGCbYNz1ixpsg_4,5802
14
+ geolysis/bearing_capacity/ubc/hansen_ubc.py,sha256=exkYLUG4W8AecJVbYC4lnE58KbssVUsjI0lJ7Mu5pqw,7170
15
+ geolysis/bearing_capacity/ubc/terzaghi_ubc.py,sha256=TokZUUlP62R9zFtokzZVY57M6cEoKy1-T5wy0hvQxGU,6513
16
+ geolysis/bearing_capacity/ubc/vesic_ubc.py,sha256=zlFI26tY_L1LCb6T7q4NY4E0pTivdjYyTttp-VcIlvk,7405
17
+ geolysis/utils/__init__.py,sha256=PTfn4PLXmGASjuFEUFCDbled8MjD9BwNsvgGoW_DaG0,2200
18
+ geolysis/utils/exceptions.py,sha256=PPOQRujje053r1jHzjpiwy11P98LGhm9t1dlfzR11is,2165
19
+ geolysis/utils/validators.py,sha256=yePaIt7eo5rjlCb18WJfQGjgbSD5DHeyz0ztNTpwS7s,3899
20
+ geolysis-0.9.0.dist-info/licenses/LICENSE.txt,sha256=ap6sMs3lT7ICbEXBhgihwH1BTCVcjmCQkIkwVnil1Ak,1065
21
+ geolysis-0.9.0.dist-info/METADATA,sha256=spL4OqYV4oW1TzJiBrJ-X_VCTNn3LVuAopyayas3O9s,7211
22
+ geolysis-0.9.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
23
+ geolysis-0.9.0.dist-info/top_level.txt,sha256=9mnQgOaCRr11dtXff8X-q3FfXjRONd6kHseSy5q2y8g,9
24
+ geolysis-0.9.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,24 +0,0 @@
1
- geolysis/__init__.py,sha256=tB9wh0D84gDFP-Qawiw-tgXqyYB_apapJ9hJj6uGP1U,122
2
- geolysis/foundation.py,sha256=gxI6bLbUrxQNhoKJis5glDysnI6PgqBkMM9m5CQztsg,11695
3
- geolysis/soil_classifier.py,sha256=2C-4hpgXNo2DUgXKcokUh3qjAH70qvgOCnxsL_NnmTw,26880
4
- geolysis/spt.py,sha256=B9tR4GapKVFHsGHkcFHW68-K2w7szLmtBC9Ejmhz0lY,17736
5
- geolysis/bearing_capacity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- geolysis/bearing_capacity/abc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- geolysis/bearing_capacity/abc/cohl/__init__.py,sha256=sWhQJj5klrenbwgaBAWRM23BQCcudZM4Ztwg8auxNw8,5399
8
- geolysis/bearing_capacity/abc/cohl/_core.py,sha256=ZQrjK4d89OMNhLRg9PczRpwkT6xiRRcn2sq603Fsobc,1627
9
- geolysis/bearing_capacity/abc/cohl/bowles_abc.py,sha256=kUAZWR5exvRNoOB6pXoxmyOiQorPNtnZwBoaXCk9z0I,4096
10
- geolysis/bearing_capacity/abc/cohl/meyerhof_abc.py,sha256=3iriC_pQCKRf_4QtDm8163lnKNZUvJ9M7c7ZyRRrID8,4056
11
- geolysis/bearing_capacity/abc/cohl/terzaghi_abc.py,sha256=EOGfA7_IM0vCa5gLBaBOiEgop4nKBtghoA5EZC7k9dM,5308
12
- geolysis/bearing_capacity/ubc/__init__.py,sha256=Q9VJhjgcz1heFjj0zgvASUFekNS683_BZBfTJsfxPcE,5983
13
- geolysis/bearing_capacity/ubc/_core.py,sha256=xia-ygcbjF3a9eVh6hzp61LPVJfHHCiztb1J8_W2apE,6177
14
- geolysis/bearing_capacity/ubc/hansen_ubc.py,sha256=exkYLUG4W8AecJVbYC4lnE58KbssVUsjI0lJ7Mu5pqw,7170
15
- geolysis/bearing_capacity/ubc/terzaghi_ubc.py,sha256=zoTf2pVTd1zN_6-yuNK9njo-8rn4o3CSccAEiivc2AE,6514
16
- geolysis/bearing_capacity/ubc/vesic_ubc.py,sha256=zlFI26tY_L1LCb6T7q4NY4E0pTivdjYyTttp-VcIlvk,7405
17
- geolysis/utils/__init__.py,sha256=713rJNWVFLrP4CNon4i-xUf5rF5eA40Ydg-F1UV8o-0,2339
18
- geolysis/utils/exceptions.py,sha256=ivuyxqz0B7nmA5sXMfw4o7KPnQHoaGbLHmJCEiCEaAc,929
19
- geolysis/utils/validators.py,sha256=g18NIlLaNSIjlBwRLkUQr68qcYnwzo5qcfY5y_GoO1Y,3205
20
- geolysis-0.7.3.dist-info/licenses/LICENSE.txt,sha256=ap6sMs3lT7ICbEXBhgihwH1BTCVcjmCQkIkwVnil1Ak,1065
21
- geolysis-0.7.3.dist-info/METADATA,sha256=x-9PiEkGWxqWKrTjQZ4VnHlZ8OfkQPjGlOwkxMn_kaU,7235
22
- geolysis-0.7.3.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
23
- geolysis-0.7.3.dist-info/top_level.txt,sha256=9mnQgOaCRr11dtXff8X-q3FfXjRONd6kHseSy5q2y8g,9
24
- geolysis-0.7.3.dist-info/RECORD,,