geolysis 0.8.0__py3-none-any.whl → 0.10.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.
Files changed (32) hide show
  1. geolysis/__init__.py +3 -3
  2. geolysis/bearing_capacity/abc/__init__.py +21 -0
  3. geolysis/bearing_capacity/abc/_cohl/__init__.py +109 -0
  4. geolysis/bearing_capacity/abc/{cohl → _cohl}/_core.py +20 -10
  5. geolysis/bearing_capacity/abc/_cohl/bowles_abc.py +103 -0
  6. geolysis/bearing_capacity/abc/_cohl/meyerhof_abc.py +100 -0
  7. geolysis/bearing_capacity/abc/_cohl/terzaghi_abc.py +143 -0
  8. geolysis/bearing_capacity/ubc/__init__.py +107 -128
  9. geolysis/bearing_capacity/ubc/_core.py +68 -66
  10. geolysis/bearing_capacity/ubc/_hansen_ubc.py +271 -0
  11. geolysis/bearing_capacity/ubc/_terzaghi_ubc.py +178 -0
  12. geolysis/bearing_capacity/ubc/_vesic_ubc.py +253 -0
  13. geolysis/foundation.py +160 -127
  14. geolysis/soil_classifier.py +386 -285
  15. geolysis/spt.py +323 -257
  16. geolysis/{utils/__init__.py → utils.py} +48 -36
  17. geolysis-0.10.0.dist-info/METADATA +181 -0
  18. geolysis-0.10.0.dist-info/RECORD +22 -0
  19. {geolysis-0.8.0.dist-info → geolysis-0.10.0.dist-info}/WHEEL +1 -1
  20. geolysis/bearing_capacity/abc/cohl/__init__.py +0 -137
  21. geolysis/bearing_capacity/abc/cohl/bowles_abc.py +0 -96
  22. geolysis/bearing_capacity/abc/cohl/meyerhof_abc.py +0 -96
  23. geolysis/bearing_capacity/abc/cohl/terzaghi_abc.py +0 -131
  24. geolysis/bearing_capacity/ubc/hansen_ubc.py +0 -287
  25. geolysis/bearing_capacity/ubc/terzaghi_ubc.py +0 -246
  26. geolysis/bearing_capacity/ubc/vesic_ubc.py +0 -293
  27. geolysis/utils/exceptions.py +0 -52
  28. geolysis/utils/validators.py +0 -129
  29. geolysis-0.8.0.dist-info/METADATA +0 -206
  30. geolysis-0.8.0.dist-info/RECORD +0 -24
  31. {geolysis-0.8.0.dist-info → geolysis-0.10.0.dist-info}/licenses/LICENSE.txt +0 -0
  32. {geolysis-0.8.0.dist-info → geolysis-0.10.0.dist-info}/top_level.txt +0 -0
geolysis/spt.py CHANGED
@@ -1,69 +1,103 @@
1
- """This module provides classes for performing Standard Penetration Test (SPT)
2
- corrections, including energy, overburden pressure, and dilatancy corrections,
3
- as well as calculating design N-values.
4
- """
5
1
  import enum
6
2
  from abc import abstractmethod
7
- from typing import Final, Literal, Sequence
8
-
9
- from .utils import enum_repr, isclose, log10, mean, round_, sqrt, validators
10
- from .utils.exceptions import ErrorMsg, ValidationError
11
-
12
- __all__ = ["SPTNDesign",
13
- "HammerType",
14
- "SamplerType",
15
- "EnergyCorrection",
16
- "GibbsHoltzOPC",
17
- "BazaraaPeckOPC",
18
- "PeckOPC",
19
- "LiaoWhitmanOPC",
20
- "SkemptonOPC",
21
- "DilatancyCorrection",
22
- "OPCType",
23
- "create_overburden_pressure_correction"]
24
-
25
-
26
- class SPTNDesign:
3
+ from typing import Annotated, Final, Sequence
4
+
5
+ from func_validator import (
6
+ validate_func_args,
7
+ MustBeBetween,
8
+ MustBePositive,
9
+ MustBeMemberOf,
10
+ MustBeNonNegative,
11
+ MustBeGreaterThanOrEqual,
12
+ MustHaveLengthGreaterThan,
13
+ MustHaveValuesBetween,
14
+ )
15
+
16
+ from .utils import AbstractStrEnum, isclose, log10, mean, round_, sqrt
17
+
18
+ __all__ = [
19
+ "SPT",
20
+ "HammerType",
21
+ "SamplerType",
22
+ "EnergyCorrection",
23
+ "GibbsHoltzOPC",
24
+ "BazaraaPeckOPC",
25
+ "PeckOPC",
26
+ "LiaoWhitmanOPC",
27
+ "SkemptonOPC",
28
+ "DilatancyCorrection",
29
+ "OPCType",
30
+ "create_overburden_pressure_correction",
31
+ ]
32
+
33
+
34
+ class SPTDesignMethod(AbstractStrEnum):
35
+ """Enumeration of Standard Penetration Test (SPT) design methods.
36
+
37
+ Each member represents a different method for interpreting SPT
38
+ results in geotechnical design calculations.
39
+ """
40
+
41
+ MINIMUM = "min"
42
+ """Use the minimum SPT value."""
43
+
44
+ AVERAGE = "avg"
45
+ """Use the average SPT value."""
46
+
47
+ WEIGHTED = "wgt"
48
+ """Use the weighted SPT value."""
49
+
50
+
51
+ class SPT:
27
52
  """SPT Design Calculations.
28
53
 
29
- Due to uncertainty in field procedure in standard penetration test and also
30
- to consider all the N-value in the influence zone of a foundation, a method
31
- was suggested to calculate the design N-value which should be used in
32
- calculating the allowable bearing capacity of shallow foundation rather
33
- than using a particular N-value. All the N-value from the influence zone is
34
- taken under consideration by giving the highest weightage to the closest
35
- N-value from the base.
54
+ Due to uncertainty in field procedure in standard penetration test
55
+ and also to consider all the N-value in the influence zone of a
56
+ foundation, a method was suggested to calculate the design N-value
57
+ which should be used in calculating the allowable bearing capacity
58
+ of shallow foundation rather than using a particular N-value. All
59
+ the N-value from the influence zone is taken under consideration by
60
+ giving the highest weightage to the closest N-value from the base.
36
61
  """
37
62
 
38
- def __init__(self, corrected_spt_n_values: Sequence[float],
39
- method: Literal["min", "avg", "wgt"] = "wgt") -> None:
63
+ def __init__(
64
+ self,
65
+ corrected_spt_n_values: Sequence[float],
66
+ method: SPTDesignMethod.WEIGHTED = "wgt",
67
+ ):
40
68
  """
41
69
  :param corrected_spt_n_values: Corrected SPT N-values within the
42
70
  foundation influence zone.
43
- :type corrected_spt_n_values: Sequence[float]
44
71
  """
45
72
  self.corrected_spt_n_values = corrected_spt_n_values
46
73
  self.method = method
47
74
 
48
75
  @property
49
76
  def corrected_spt_n_values(self) -> Sequence[float]:
50
- """Corrected SPT N-values within the foundation influence zone."""
77
+ """
78
+ Corrected SPT N-values within the foundation influence zone.
79
+ """
51
80
  return self._corrected_spt_n_values
52
81
 
53
82
  @corrected_spt_n_values.setter
54
- @validators.le(100.0)
55
- @validators.gt(0.0)
56
- @validators.min_len(1)
57
- def corrected_spt_n_values(self, val: Sequence[float]) -> None:
58
- self._corrected_spt_n_values = val
83
+ @validate_func_args
84
+ def corrected_spt_n_values(
85
+ self,
86
+ corrected_spt_n_values: Annotated[
87
+ Sequence[float],
88
+ MustHaveLengthGreaterThan(1),
89
+ MustHaveValuesBetween(min_value=1.0, max_value=100.0),
90
+ ],
91
+ ) -> None:
92
+ self._corrected_spt_n_values = corrected_spt_n_values
59
93
 
60
94
  @property
61
95
  def method(self):
62
96
  return self._method
63
97
 
64
98
  @method.setter
65
- @validators.in_(("min", "avg", "wgt"))
66
- def method(self, val: str) -> None:
99
+ @validate_func_args
100
+ def method(self, val: Annotated[str, MustBeMemberOf(SPTDesignMethod)]):
67
101
  self._method = val
68
102
 
69
103
  @staticmethod
@@ -89,97 +123,121 @@ class SPTNDesign:
89
123
 
90
124
  @round_(ndigits=1)
91
125
  def n_design(self):
92
- r"""Calculates the SPT N-design within the foundation influence zone.
126
+ r"""Calculates the SPT N-design within the foundation influence
127
+ zone.
93
128
 
94
- If ``method="min"``, it returns the minimum N-value within the foundation
95
- influence zone as the SPT N-design value. This approach was suggested
96
- by ``Terzaghi & Peck (1948)``.
129
+ If `method="min"`, it returns the minimum N-value within the
130
+ foundation influence zone as the SPT N-design value. This
131
+ approach was suggested by `Terzaghi & Peck (1948)`.
97
132
 
98
- if ``method="avg"``, it returns the average N-value within the foundation
99
- influence zone as the SPT N-design value.
100
-
101
- if ``method="wgt"``, it returns the weighted average N-value within the
133
+ if `method="avg"`, it returns the average N-value within the
102
134
  foundation influence zone as the SPT N-design value.
103
135
 
104
- :Equation:
136
+ if `method="wgt"`, it returns the weighted average N-value
137
+ within the foundation influence zone as the SPT N-design value.
105
138
 
106
- .. math::
107
139
 
108
- N_{design} = \dfrac{\sum_{i=1}^{n} \frac{N_i}{i^2}}
109
- {\sum_{i=1}^{n}\frac{1}{i^2}}
140
+ $$
141
+ N_{design} = \dfrac{\sum_{i=1}^{n} \frac{N_i}{i^2}}
142
+ {\sum_{i=1}^{n}\frac{1}{i^2}}
143
+ $$
110
144
  """
111
145
  if self.method == "min":
112
- return self._min_spt_n_design(self.corrected_spt_n_values)
146
+ _n_design = self._min_spt_n_design
113
147
  elif self.method == "avg":
114
- return self._avg_spt_n_design(self.corrected_spt_n_values)
115
- else: # method="wgt"
116
- return self._wgt_spt_n_design(self.corrected_spt_n_values)
148
+ _n_design = self._avg_spt_n_design
149
+ else:
150
+ _n_design = self._wgt_spt_n_design
117
151
 
152
+ return _n_design(self.corrected_spt_n_values)
153
+
154
+
155
+ class HammerType(AbstractStrEnum):
156
+ """Enumeration of hammer types used in geotechnical testing.
157
+
158
+ Each member represents a different type of hammer used for
159
+ Standard Penetration Test (SPT) or other soil testing methods.
160
+ """
118
161
 
119
- @enum_repr
120
- class HammerType(enum.StrEnum):
121
- """Enumeration of hammer types."""
122
162
  AUTOMATIC = enum.auto()
163
+ """Automatic hammer."""
164
+
123
165
  DONUT_1 = enum.auto()
166
+ """Donut-type hammer, variant 1."""
167
+
124
168
  DONUT_2 = enum.auto()
169
+ """Donut-type hammer, variant 2."""
170
+
125
171
  SAFETY = enum.auto()
172
+ """Safety hammer."""
173
+
126
174
  DROP = enum.auto()
175
+ """Drop hammer."""
176
+
127
177
  PIN = enum.auto()
178
+ """Pin-type hammer."""
179
+
128
180
 
181
+ class SamplerType(AbstractStrEnum):
182
+ """Enumeration of soil sampler types.
183
+
184
+ Each member represents a different type of sampler used in
185
+ Standard Penetration Tests (SPT) or other geotechnical sampling
186
+ methods.
187
+ """
129
188
 
130
- @enum_repr
131
- class SamplerType(enum.StrEnum):
132
- """Enumeration of sampler types."""
133
189
  STANDARD = enum.auto()
190
+ """Standard sampler."""
191
+
134
192
  NON_STANDARD = enum.auto()
193
+ """Non-standard sampler."""
135
194
 
136
195
 
137
196
  class EnergyCorrection:
138
197
  r"""SPT N-value standardized for field procedures.
139
198
 
140
- On the basis of field observations, it appears reasonable to standardize
141
- the field SPT N-value as a function of the input driving energy and its
142
- dissipation around the sampler around the surrounding soil. The variations
143
- in testing procedures may be at least partially compensated by converting
144
- the measured N-value to :math:`N_{60}` assuming 60% hammer energy being
145
- transferred to the tip of the standard split spoon.
199
+ On the basis of field observations, it appears reasonable to
200
+ standardize the field SPT N-value as a function of the input driving
201
+ energy and its dissipation around the sampler around the surrounding
202
+ soil. The variations in testing procedures may be at least partially
203
+ compensated by converting the measured N-value to $N_{60}$
204
+ assuming 60% hammer energy being transferred to the tip of the
205
+ standard split spoon.
146
206
  """
147
207
 
148
- _HAMMER_EFFICIENCY_FACTORS = {HammerType.AUTOMATIC: 0.70,
149
- HammerType.DONUT_1: 0.60,
150
- HammerType.DONUT_2: 0.50,
151
- HammerType.SAFETY: 0.55,
152
- HammerType.DROP: 0.45,
153
- HammerType.PIN: 0.45}
154
-
155
- _SAMPLER_CORRECTION_FACTORS = {SamplerType.STANDARD: 1.00,
156
- SamplerType.NON_STANDARD: 1.20}
157
-
158
- def __init__(self, recorded_spt_n_value: int, *,
159
- energy_percentage=0.6,
160
- borehole_diameter=65.0,
161
- rod_length=3.0,
162
- hammer_type=HammerType.DONUT_1,
163
- sampler_type=SamplerType.STANDARD):
208
+ _HAMMER_EFFICIENCY_FACTORS = {
209
+ HammerType.AUTOMATIC: 0.70,
210
+ HammerType.DONUT_1: 0.60,
211
+ HammerType.DONUT_2: 0.50,
212
+ HammerType.SAFETY: 0.55,
213
+ HammerType.DROP: 0.45,
214
+ HammerType.PIN: 0.45,
215
+ }
216
+
217
+ _SAMPLER_CORRECTION_FACTORS = {
218
+ SamplerType.STANDARD: 1.00,
219
+ SamplerType.NON_STANDARD: 1.20,
220
+ }
221
+
222
+ def __init__(
223
+ self,
224
+ recorded_spt_n_value: int,
225
+ *,
226
+ energy_percentage=0.6,
227
+ borehole_diameter=65.0,
228
+ rod_length=3.0,
229
+ hammer_type=HammerType.DONUT_1,
230
+ sampler_type=SamplerType.STANDARD,
231
+ ):
164
232
  """
165
233
  :param recorded_spt_n_value: Recorded SPT N-value from field.
166
- :type recorded_spt_n_value: int
167
-
168
- :param energy_percentage: Energy percentage reaching the tip of the
169
- sampler, defaults to 0.6
170
- :type energy_percentage: float, optional
171
-
172
- :param borehole_diameter: Borehole diameter (mm), defaults to 65.0.
173
- :type borehole_diameter: float, optional
174
234
 
175
- :param rod_length: Length of SPT rod, defaults to 3.0. (m)
176
- :type rod_length: float, optional
177
-
178
- :param hammer_type: Hammer type, defaults to :py:enum:mem:`~HammerType.DONUT_1`
179
- :type hammer_type: HammerType, optional
180
-
181
- :param sampler_type: Sampler type, defaults to :py:enum:mem:`~SamplerType.STANDARD`
182
- :type sampler_type: SamplerType, optional
235
+ :param energy_percentage: Energy percentage reaching the tip of
236
+ the sampler.
237
+ :param borehole_diameter: Borehole diameter (mm).
238
+ :param rod_length: Length of SPT rod, defaults to 3.0 (m).
239
+ :param hammer_type: Hammer type.
240
+ :param sampler_type: Sampler type.
183
241
  """
184
242
  self.recorded_spt_n_value = int(recorded_spt_n_value)
185
243
  self.energy_percentage = energy_percentage
@@ -194,9 +252,11 @@ class EnergyCorrection:
194
252
  return self._recorded_spt_value
195
253
 
196
254
  @recorded_spt_n_value.setter
197
- @validators.le(100)
198
- @validators.gt(0)
199
- def recorded_spt_n_value(self, val: int) -> None:
255
+ @validate_func_args
256
+ def recorded_spt_n_value(
257
+ self,
258
+ val: Annotated[int, MustBeBetween(min_value=0, max_value=100)]
259
+ ) -> None:
200
260
  self._recorded_spt_value = val
201
261
 
202
262
  @property
@@ -205,9 +265,11 @@ class EnergyCorrection:
205
265
  return self._energy_percentage
206
266
 
207
267
  @energy_percentage.setter
208
- @validators.le(1.0)
209
- @validators.gt(0.0)
210
- def energy_percentage(self, val: float) -> None:
268
+ @validate_func_args
269
+ def energy_percentage(
270
+ self,
271
+ val: Annotated[float, MustBeBetween(min_value=0.0, max_value=1.0)]
272
+ ) -> None:
211
273
  self._energy_percentage = val
212
274
 
213
275
  @property
@@ -216,9 +278,11 @@ class EnergyCorrection:
216
278
  return self._borehole_diameter
217
279
 
218
280
  @borehole_diameter.setter
219
- @validators.le(200.0)
220
- @validators.ge(65.0)
221
- def borehole_diameter(self, val: float) -> None:
281
+ @validate_func_args
282
+ def borehole_diameter(
283
+ self, val: Annotated[
284
+ float, MustBeBetween(min_value=65.0, max_value=200.0)]
285
+ ) -> None:
222
286
  self._borehole_diameter = val
223
287
 
224
288
  @property
@@ -227,8 +291,8 @@ class EnergyCorrection:
227
291
  return self._rod_length
228
292
 
229
293
  @rod_length.setter
230
- @validators.gt(0.0)
231
- def rod_length(self, val: float) -> None:
294
+ @validate_func_args
295
+ def rod_length(self, val: Annotated[float, MustBePositive]):
232
296
  self._rod_length = val
233
297
 
234
298
  @property
@@ -236,17 +300,21 @@ class EnergyCorrection:
236
300
  return self._hammer_type
237
301
 
238
302
  @hammer_type.setter
239
- @validators.in_(tuple(HammerType))
240
- def hammer_type(self, val: HammerType) -> None:
241
- self._hammer_type = val
303
+ @validate_func_args
304
+ def hammer_type(
305
+ self,
306
+ hammer_type: Annotated[HammerType, MustBeMemberOf(HammerType)]
307
+ ):
308
+ self._hammer_type = hammer_type
242
309
 
243
310
  @property
244
311
  def sampler_type(self) -> SamplerType:
245
312
  return self._sampler_type
246
313
 
247
314
  @sampler_type.setter
248
- @validators.in_(tuple(SamplerType))
249
- def sampler_type(self, val: SamplerType) -> None:
315
+ @validate_func_args
316
+ def sampler_type(self,
317
+ val: Annotated[SamplerType, MustBeMemberOf(SamplerType)]):
250
318
  self._sampler_type = val
251
319
 
252
320
  @property
@@ -286,18 +354,19 @@ class EnergyCorrection:
286
354
  def correction(self) -> float:
287
355
  r"""Energy correction factor.
288
356
 
289
- :Equation:
290
-
291
- .. math::
357
+ $$
358
+ N_{ENERGY} = \dfrac{E_H \cdot C_B \cdot C_S
359
+ \cdot C_R \cdot N}{ENERGY}
360
+ $$
292
361
 
293
- N_{ENERGY} = \dfrac{E_H \cdot C_B \cdot C_S \cdot C_R \cdot N}{ENERGY}
294
-
295
- ``ENERGY``: 0.6, 0.55, etc
362
+ `ENERGY`: 0.6, 0.55, etc
296
363
  """
297
- numerator = (self.hammer_efficiency
298
- * self.borehole_diameter_correction
299
- * self.sampler_correction
300
- * self.rod_length_correction)
364
+ numerator = (
365
+ self.hammer_efficiency
366
+ * self.borehole_diameter_correction
367
+ * self.sampler_correction
368
+ * self.rod_length_correction
369
+ )
301
370
  return numerator / self.energy_percentage
302
371
 
303
372
  @round_(ndigits=1)
@@ -309,41 +378,52 @@ class EnergyCorrection:
309
378
  class OPC:
310
379
  """Base class for Overburden Pressure Correction (OPC)."""
311
380
 
312
- def __init__(self, std_spt_n_value: float, eop: float) -> None:
381
+ def __init__(self, std_spt_n_value: float, eop: float):
313
382
  """
314
- :param std_spt_n_value: SPT N-value standardized for field procedures.
315
- :type std_spt_n_value: float
316
-
317
- :param eop: Effective overburden pressure (:math:`kPa`).
318
- :type eop: float
383
+ :param std_spt_n_value: SPT N-value standardized for field
384
+ procedures.
385
+ :param eop: Effective overburden pressure ($kPa$).
319
386
  """
320
387
  self.std_spt_n_value = std_spt_n_value
321
388
  self.eop = eop
322
389
 
390
+ @property
391
+ def eop(self) -> float:
392
+ """Effective overburden pressure ($kPa$)."""
393
+ return self._eop
394
+
395
+ @eop.setter
396
+ @validate_func_args
397
+ def eop(self, val: Annotated[float, MustBeNonNegative]):
398
+ """Effective overburden pressure ($kPa$)."""
399
+ self._eop = val
400
+
323
401
  @property
324
402
  def std_spt_n_value(self) -> float:
325
403
  """SPT N-value standardized for field procedures."""
326
404
  return self._std_spt_n_value
327
405
 
328
406
  @std_spt_n_value.setter
329
- @validators.le(100)
330
- @validators.gt(0.0)
331
- def std_spt_n_value(self, val: float) -> None:
407
+ @validate_func_args
408
+ def std_spt_n_value(
409
+ self, val: Annotated[
410
+ float, MustBeBetween(min_value=0.0, max_value=100.0)]
411
+ ):
332
412
  self._std_spt_n_value = val
333
413
 
334
414
  @round_(ndigits=1)
335
415
  def corrected_spt_n_value(self) -> float:
336
416
  r"""Corrected SPT N-value.
337
417
 
338
- :Equation:
339
-
340
- .. math:: (N_1)_{60} = C_N \cdot N_{60}
418
+ $$
419
+ (N_1)_{60} = C_N \cdot N_{60}
420
+ $$
341
421
 
342
- .. note::
422
+ !!! note
343
423
 
344
- ``60`` is used in this case to represent ``60%`` hammer efficiency
345
- and can be any percentage of hammer efficiency e.g :math:`N_{55}`
346
- for ``55%`` hammer efficiency.
424
+ `60` is used in this case to represent `60%` hammer
425
+ efficiency and can be any percentage of hammer efficiency
426
+ e.g. $N_{55}$ for `55%` hammer efficiency.
347
427
  """
348
428
  corrected_spt = self.correction() * self.std_spt_n_value
349
429
  # Corrected SPT should not be more
@@ -356,67 +436,61 @@ class OPC:
356
436
 
357
437
 
358
438
  class GibbsHoltzOPC(OPC):
359
- """Overburden Pressure Correction according to ``Gibbs & Holtz (1957)``."""
439
+ """Overburden Pressure Correction according to
440
+ `Gibbs & Holtz (1957)`.
441
+ """
360
442
 
361
443
  @property
362
444
  def eop(self) -> float:
363
- """Effective overburden pressure (:math:`kpa`)."""
445
+ """Effective overburden pressure ($kPa$)."""
364
446
  return self._eop
365
447
 
366
448
  @eop.setter
367
- @validators.le(280.0)
368
- @validators.gt(0.0)
369
- def eop(self, val: float) -> None:
449
+ @validate_func_args
450
+ def eop(self, val: Annotated[
451
+ float, MustBeBetween(min_value=0.0, max_value=280.0)]):
370
452
  self._eop = val
371
453
 
372
454
  def correction(self) -> float:
373
455
  r"""SPT Correction.
374
456
 
375
- :Equation:
376
-
377
- .. math:: C_N = \dfrac{350}{\sigma_o + 70} \, \sigma_o \le 280kN/m^2
457
+ $$
458
+ C_N = \dfrac{350}{\sigma_o + 70} \, \sigma_o \le 280kN/m^2
459
+ $$
378
460
 
379
- :math:`\frac{N_c}{N_{60}}` should lie between 0.45 and 2.0, if
380
- :math:`\frac{N_c}{N_{60}}` is greater than 2.0, :math:`N_c` should be
381
- divided by 2.0 to obtain the design value used in finding the bearing
382
- capacity of the soil.
461
+ $\frac{N_c}{N_{60}}$ should lie between 0.45 and 2.0, if
462
+ $\frac{N_c}{N_{60}}$ is greater than 2.0, :math:`N_c` should be
463
+ divided by 2.0 to obtain the design value used in finding the
464
+ bearing capacity of the soil.
383
465
  """
384
466
  corr = 350.0 / (self.eop + 70.0)
385
467
  return corr / 2.0 if corr > 2.0 else corr
386
468
 
387
469
 
388
470
  class BazaraaPeckOPC(OPC):
389
- """Overburden Pressure Correction according to ``Bazaraa (1967)``, and
390
- also by ``Peck and Bazaraa (1969)``.
471
+ """Overburden Pressure Correction according to `Bazaraa (1967)`, and
472
+ also by `Peck and Bazaraa (1969)`.
391
473
  """
392
474
 
393
475
  #: Maximum effective overburden pressure (:math:`kPa`).
394
476
  STD_PRESSURE: Final = 71.8
395
477
 
396
- @property
397
- def eop(self) -> float:
398
- """Effective overburden pressure (:math:`kPa`)."""
399
- return self._eop
400
-
401
- @eop.setter
402
- @validators.ge(0.0)
403
- def eop(self, val: float) -> None:
404
- """Effective overburden pressure (:math:`kPa`)."""
405
- self._eop = val
406
-
407
478
  def correction(self) -> float:
408
479
  r"""SPT Correction.
409
480
 
410
- :Equation:
411
-
412
- .. math::
481
+ $$
482
+ C_N = \dfrac{4}{1 + 0.0418 \cdot \sigma_o}, \,
483
+ \sigma_o \lt 71.8kN/m^2
484
+ $$
413
485
 
414
- C_N &= \dfrac{4}{1 + 0.0418 \cdot \sigma_o}, \, \sigma_o \lt 71.8kN/m^2
486
+ $$
487
+ C_N = \dfrac{4}{3.25 + 0.0104 \cdot \sigma_o},
488
+ \, \sigma_o \gt 71.8kN/m^2
489
+ $$
415
490
 
416
- C_N &= \dfrac{4}{3.25 + 0.0104 \cdot \sigma_o},
417
- \, \sigma_o \gt 71.8kN/m^2
418
-
419
- C_N &= 1 \, , \, \sigma_o = 71.8kN/m^2
491
+ $$
492
+ C_N = 1 \, , \, \sigma_o = 71.8kN/m^2
493
+ $$
420
494
  """
421
495
  if isclose(self.eop, self.STD_PRESSURE, rel_tol=0.01):
422
496
  corr = 1.0
@@ -428,165 +502,157 @@ class BazaraaPeckOPC(OPC):
428
502
 
429
503
 
430
504
  class PeckOPC(OPC):
431
- """Overburden Pressure Correction according to ``Peck et al. (1974)``."""
505
+ """Overburden Pressure Correction according to
506
+ `Peck et al. (1974)`.
507
+ """
432
508
 
433
509
  @property
434
510
  def eop(self) -> float:
435
- """Effective overburden pressure (:math:`kPa`)."""
511
+ """Effective overburden pressure ($kPa$)."""
436
512
  return self._eop
437
513
 
438
514
  @eop.setter
439
- @validators.ge(24.0)
440
- def eop(self, val: float) -> None:
515
+ @validate_func_args
516
+ def eop(self, val: Annotated[float, MustBeGreaterThanOrEqual(24.0)]):
441
517
  self._eop = val
442
518
 
443
519
  def correction(self) -> float:
444
520
  r"""SPT Correction.
445
521
 
446
- :Equation:
447
-
448
- .. math:: C_N = 0.77 \log \left(\dfrac{2000}{\sigma_o} \right)
522
+ $$
523
+ C_N = 0.77 \log \left(\dfrac{2000}{\sigma_o} \right)
524
+ $$
449
525
  """
450
526
  return 0.77 * log10(2000.0 / self.eop)
451
527
 
452
528
 
453
529
  class LiaoWhitmanOPC(OPC):
454
- """Overburden Pressure Correction according to ``Liao & Whitman (1986)``.
530
+ """Overburden Pressure Correction according to
531
+ `Liao & Whitman (1986)`.
455
532
  """
456
533
 
457
- @property
458
- def eop(self) -> float:
459
- """Effective overburden pressure (:math:`kPa`)."""
460
- return self._eop
461
-
462
- @eop.setter
463
- @validators.gt(0.0)
464
- def eop(self, val: float) -> None:
465
- self._eop = val
466
-
467
534
  def correction(self) -> float:
468
535
  r"""SPT Correction.
469
536
 
470
- :Equation:
471
-
472
- .. math:: C_N = \sqrt{\dfrac{100}{\sigma_o}}
537
+ $$
538
+ C_N = \sqrt{\dfrac{100}{\sigma_o}}
539
+ $$
473
540
  """
474
541
  return sqrt(100.0 / self.eop)
475
542
 
476
543
 
477
544
  class SkemptonOPC(OPC):
478
- """Overburden Pressure Correction according to ``Skempton (1986)``."""
479
-
480
- @property
481
- def eop(self) -> float:
482
- """Effective overburden pressure (:math:`kPa`)."""
483
- return self._eop
484
-
485
- @eop.setter
486
- @validators.ge(0.0)
487
- def eop(self, val: float) -> None:
488
- self._eop = val
545
+ """Overburden Pressure Correction according to `Skempton (1986)`."""
489
546
 
490
547
  def correction(self) -> float:
491
548
  r"""SPT Correction.
492
549
 
493
- :Equation:
494
-
495
- .. math:: C_N = \dfrac{2}{1 + 0.01044 \cdot \sigma_o}
550
+ $$
551
+ C_N = \dfrac{2}{1 + 0.01044 \cdot \sigma_o}
552
+ $$
496
553
  """
497
554
  return 2.0 / (1.0 + 0.01044 * self.eop)
498
555
 
499
556
 
500
557
  class DilatancyCorrection:
501
- """Dilatancy SPT Correction according to ``Terzaghi & Peck (1948)``.
558
+ """Dilatancy SPT Correction according to `Terzaghi & Peck (1948)`.
502
559
 
503
560
  For coarse sand, this correction is not required. In applying this
504
561
  correction, overburden pressure correction is applied first and then
505
562
  dilatancy correction is applied.
506
563
  """
507
564
 
508
- def __init__(self, corr_spt_n_value: float) -> None:
565
+ def __init__(self, corr_spt_n_value: float):
509
566
  """
510
- :param corr_spt_n_value: SPT N-value standardized for field procedures
511
- and/or corrected for overburden pressure.
512
- :type corr_spt_n_value: float
567
+ :param corr_spt_n_value: SPT N-value standardized for field
568
+ procedures and/or corrected for
569
+ overburden pressure.
513
570
  """
514
571
  self.corr_spt_n_value = corr_spt_n_value
515
572
 
516
573
  @property
517
574
  def corr_spt_n_value(self) -> float:
518
- """SPT N-value standardized for field procedures and/or corrected for
519
- overburden pressure.
575
+ """SPT N-value standardized for field procedures and/or corrected
576
+ for overburden pressure.
520
577
  """
521
578
  return self._corr_spt_n_value
522
579
 
523
580
  @corr_spt_n_value.setter
524
- @validators.le(100.0)
525
- @validators.gt(0.0)
526
- def corr_spt_n_value(self, val: float) -> None:
581
+ @validate_func_args
582
+ def corr_spt_n_value(
583
+ self, val: Annotated[
584
+ float, MustBeBetween(min_value=0.0, max_value=100.0)]
585
+ ):
527
586
  self._corr_spt_n_value = val
528
587
 
529
588
  @round_(ndigits=1)
530
589
  def corrected_spt_n_value(self) -> float:
531
590
  r"""Corrected SPT N-value.
532
591
 
533
- :Equation:
534
-
535
- .. math::
592
+ $$
593
+ (N_1)_{60} = 15 + \dfrac{1}{2}((N_1)_{60} - 15) \, , \,
594
+ (N_1)_{60} \gt 15
595
+ $$
536
596
 
537
- (N_1)_{60} &= 15 + \dfrac{1}{2}((N_1)_{60} - 15) \, , \,
538
- (N_1)_{60} \gt 15
539
-
540
- (N_1)_{60} &= (N_1)_{60} \, , \, (N_1)_{60} \le 15
597
+ $$
598
+ (N_1)_{60} = (N_1)_{60} \, , \, (N_1)_{60} \le 15
599
+ $$
541
600
  """
542
601
  if self.corr_spt_n_value <= 15.0:
543
602
  return self.corr_spt_n_value
544
603
  return 15.0 + 0.5 * (self.corr_spt_n_value - 15.0)
545
604
 
546
605
 
547
- @enum_repr
548
- class OPCType(enum.StrEnum):
549
- """Enumeration of overburden pressure correction types."""
606
+ class OPCType(AbstractStrEnum):
607
+ """
608
+ Enumeration of overburden pressure correction (OPC) methods.
609
+
610
+ Each member represents a method used to correct SPT results
611
+ for the effects of overburden pressure in geotechnical design.
612
+ """
613
+
550
614
  GIBBS = enum.auto()
615
+ """Gibbs method for overburden pressure correction."""
616
+
551
617
  BAZARAA = enum.auto()
618
+ """Bazaraa method for overburden pressure correction."""
619
+
552
620
  PECK = enum.auto()
621
+ """Peck method for overburden pressure correction."""
622
+
553
623
  LIAO = enum.auto()
624
+ """Liao method for overburden pressure correction."""
625
+
554
626
  SKEMPTON = enum.auto()
627
+ """Skempton method for overburden pressure correction."""
555
628
 
556
629
 
557
- _opctypes = {OPCType.GIBBS: GibbsHoltzOPC,
558
- OPCType.BAZARAA: BazaraaPeckOPC,
559
- OPCType.PECK: PeckOPC,
560
- OPCType.LIAO: LiaoWhitmanOPC,
561
- OPCType.SKEMPTON: SkemptonOPC}
630
+ _opctypes = {
631
+ OPCType.GIBBS: GibbsHoltzOPC,
632
+ OPCType.BAZARAA: BazaraaPeckOPC,
633
+ OPCType.PECK: PeckOPC,
634
+ OPCType.LIAO: LiaoWhitmanOPC,
635
+ OPCType.SKEMPTON: SkemptonOPC,
636
+ }
562
637
 
563
638
 
564
- def create_overburden_pressure_correction(std_spt_n_value: float, eop,
565
- opc_type: OPCType | str = OPCType.GIBBS) -> OPC:
639
+ @validate_func_args
640
+ def create_overburden_pressure_correction(
641
+ std_spt_n_value: float,
642
+ eop: float,
643
+ opc_type: Annotated[OPCType | str, MustBeMemberOf(OPCType)] = "gibbs",
644
+ ):
566
645
  """A factory function that encapsulates the creation of overburden
567
646
  pressure correction.
568
647
 
569
- :param std_spt_n_value: SPT N-value standardized for field procedures.
570
- :type std_spt_n_value: float
648
+ :param std_spt_n_value: SPT N-value standardized for field
649
+ procedures.
571
650
 
572
- :param eop: Effective overburden pressure (:math:`kPa`).
573
- :type eop: float
651
+ :param eop: Effective overburden pressure ($kPa$).
574
652
 
575
- :param opc_type: Overburden Pressure Correction type to apply,
576
- defaults to :py:enum:mem:`~OPCType.GIBBS`
577
- :type opc_type: OPCType, optional
653
+ :param opc_type: Overburden Pressure Correction type to apply.
578
654
  """
579
-
580
- try:
581
- opc_type = OPCType(str(opc_type).casefold())
582
- except ValueError as 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
588
-
655
+ opc_type = OPCType(opc_type)
589
656
  opc_class = _opctypes[opc_type]
590
657
  opc_corr = opc_class(std_spt_n_value=std_spt_n_value, eop=eop)
591
-
592
658
  return opc_corr