geolysis 0.7.3__tar.gz → 0.9.0__tar.gz
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-0.7.3 → geolysis-0.9.0}/PKG-INFO +1 -2
- {geolysis-0.7.3 → geolysis-0.9.0}/README.md +0 -1
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/__init__.py +1 -1
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/abc/cohl/__init__.py +12 -11
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/abc/cohl/_core.py +4 -4
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/abc/cohl/bowles_abc.py +3 -3
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/abc/cohl/meyerhof_abc.py +3 -3
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/abc/cohl/terzaghi_abc.py +3 -3
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/ubc/__init__.py +8 -7
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/ubc/_core.py +6 -17
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/ubc/terzaghi_ubc.py +1 -1
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/foundation.py +47 -19
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/soil_classifier.py +24 -16
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/spt.py +37 -14
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/utils/__init__.py +6 -5
- geolysis-0.9.0/geolysis/utils/exceptions.py +65 -0
- geolysis-0.9.0/geolysis/utils/validators.py +119 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis.egg-info/PKG-INFO +1 -2
- {geolysis-0.7.3 → geolysis-0.9.0}/tests/test_foundation.py +4 -4
- {geolysis-0.7.3 → geolysis-0.9.0}/tests/test_soil_classifier.py +5 -1
- {geolysis-0.7.3 → geolysis-0.9.0}/tests/test_spt.py +28 -13
- geolysis-0.7.3/geolysis/utils/exceptions.py +0 -36
- geolysis-0.7.3/geolysis/utils/validators.py +0 -101
- {geolysis-0.7.3 → geolysis-0.9.0}/LICENSE.txt +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/__init__.py +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/abc/__init__.py +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/ubc/hansen_ubc.py +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis/bearing_capacity/ubc/vesic_ubc.py +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis.egg-info/SOURCES.txt +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis.egg-info/dependency_links.txt +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis.egg-info/requires.txt +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/geolysis.egg-info/top_level.txt +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/pyproject.toml +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/setup.cfg +0 -0
- {geolysis-0.7.3 → geolysis-0.9.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: geolysis
|
3
|
-
Version: 0.
|
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)
|
@@ -102,7 +102,6 @@ Here are brief descriptions of the `geolysis` projects:
|
|
102
102
|
|
103
103
|
- [Installation](#installation)
|
104
104
|
- [Usage Example](#usage-example)
|
105
|
-
- [Features](#features)
|
106
105
|
- [Documentation](#documentation)
|
107
106
|
- [Contributing](#contributing)
|
108
107
|
- [License](#license)
|
@@ -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
|
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 =
|
103
|
-
|
104
|
-
|
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
|
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
|
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 =
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
4
|
-
from geolysis.utils import validators
|
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:
|
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
|
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
|
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:
|
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:
|
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
|
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:
|
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:
|
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
|
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:
|
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:
|
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
|
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 =
|
120
|
-
|
121
|
-
|
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
|
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
|
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
|
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:
|
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:
|
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)
|
95
|
+
def load_angle(self):
|
101
96
|
"""Inclination of the applied load with the vertical."""
|
102
|
-
return self.
|
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:
|
@@ -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
|
8
|
+
from .utils.exceptions import ErrorMsg, ValidationError
|
9
9
|
|
10
10
|
__all__ = ["create_foundation",
|
11
|
-
"
|
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 =
|
35
|
-
|
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
|
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) ->
|
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 =
|
380
|
-
|
381
|
-
|
382
|
-
|
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(
|
393
|
-
|
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
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
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
|
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
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
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
|
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 =
|
717
|
-
|
718
|
-
|
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
|
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
|
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
|
740
|
-
|
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)
|
@@ -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,
|
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
|
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
|
-
|
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 =
|
562
|
-
|
563
|
-
|
564
|
-
|
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
|
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.
|
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
|
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:
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from collections import UserString
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
|
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}"
|
13
|
+
|
14
|
+
super().__init__(msg)
|
15
|
+
|
16
|
+
self.param_name = param_name
|
17
|
+
self.param_value = param_value
|
18
|
+
self.symbol = symbol
|
19
|
+
self.param_value_bound = param_value_bound
|
20
|
+
|
21
|
+
@property
|
22
|
+
def msg(self):
|
23
|
+
return self.data
|
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)
|
32
|
+
|
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)
|
40
|
+
|
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})"
|
46
|
+
|
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
|
+
}
|
55
|
+
|
56
|
+
|
57
|
+
class ValidationError(ValueError):
|
58
|
+
"""Exception raised when a validation error occurs."""
|
59
|
+
|
60
|
+
def __init__(self, error: ErrorMsg):
|
61
|
+
super().__init__(error)
|
62
|
+
self.error = error
|
63
|
+
|
64
|
+
def __repr__(self):
|
65
|
+
return f"ValidationError(error={self.error!r})"
|
@@ -0,0 +1,119 @@
|
|
1
|
+
"""validators"""
|
2
|
+
import operator
|
3
|
+
from functools import wraps
|
4
|
+
from typing import Any, Callable, Iterable, TypeAlias, List, Tuple, Sequence
|
5
|
+
|
6
|
+
from .exceptions import ErrorMsg, ValidationError
|
7
|
+
|
8
|
+
Number: TypeAlias = int | float
|
9
|
+
|
10
|
+
|
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):
|
28
|
+
@wraps(fn)
|
29
|
+
def wrapper(obj, val):
|
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
|
+
|
36
|
+
fn(obj, val)
|
37
|
+
|
38
|
+
return wrapper
|
39
|
+
|
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)
|
51
|
+
|
52
|
+
|
53
|
+
class _LenValidator(_Validator):
|
54
|
+
|
55
|
+
def __call__(self, fn):
|
56
|
+
@wraps(fn)
|
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)
|
66
|
+
fn(obj, val)
|
67
|
+
|
68
|
+
return wrapper
|
69
|
+
|
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)
|
85
|
+
|
86
|
+
|
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)
|
90
|
+
|
91
|
+
|
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)
|
95
|
+
|
96
|
+
|
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)
|
100
|
+
|
101
|
+
|
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)
|
105
|
+
|
106
|
+
|
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)
|
110
|
+
|
111
|
+
|
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)
|
115
|
+
|
116
|
+
|
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.
|
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)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import unittest
|
2
2
|
|
3
|
-
from geolysis.foundation import (CircularFooting,
|
3
|
+
from geolysis.foundation import (CircularFooting, Foundation,
|
4
4
|
RectangularFooting, Shape, SquareFooting,
|
5
5
|
StripFooting, create_foundation)
|
6
6
|
|
@@ -53,9 +53,9 @@ class TestFoundation(unittest.TestCase):
|
|
53
53
|
|
54
54
|
def test_foundation_size(self):
|
55
55
|
footing = StripFooting(width=2.0)
|
56
|
-
foundation =
|
57
|
-
|
58
|
-
|
56
|
+
foundation = Foundation(depth=1.5,
|
57
|
+
footing_size=footing,
|
58
|
+
eccentricity=0.1)
|
59
59
|
self.assertEqual(foundation.depth, 1.5)
|
60
60
|
self.assertEqual(foundation.width, 2.0)
|
61
61
|
self.assertEqual(foundation.length, float('inf'))
|
@@ -4,18 +4,21 @@ from geolysis.soil_classifier import (PSD, AtterbergLimits,
|
|
4
4
|
create_soil_classifier)
|
5
5
|
|
6
6
|
|
7
|
-
def
|
7
|
+
def test_create_soil_classifier_errors():
|
8
|
+
# Did not provide a classification (clf_type) value
|
8
9
|
with pytest.raises(ValueError):
|
9
10
|
create_soil_classifier(liquid_limit=30.4,
|
10
11
|
plastic_limit=15.9,
|
11
12
|
fines=40.20)
|
12
13
|
|
14
|
+
# Provided a wrong value for clf_type
|
13
15
|
with pytest.raises(ValueError):
|
14
16
|
create_soil_classifier(liquid_limit=30.4,
|
15
17
|
plastic_limit=15.9,
|
16
18
|
fines=40.20,
|
17
19
|
clf_type="IS")
|
18
20
|
|
21
|
+
# Did not provide sand for USCS classification
|
19
22
|
with pytest.raises(ValueError):
|
20
23
|
create_soil_classifier(liquid_limit=30.4,
|
21
24
|
plastic_limit=15.9,
|
@@ -54,6 +57,7 @@ class TestAtterbergLimits:
|
|
54
57
|
assert al.consistency_index(nmc=nmc) == pytest.approx(expected)
|
55
58
|
|
56
59
|
def test_errors(self):
|
60
|
+
# Plastic limit is greater than liquid limit
|
57
61
|
with pytest.raises(ValueError):
|
58
62
|
AtterbergLimits(liquid_limit=15.0, plastic_limit=25.0)
|
59
63
|
|
@@ -1,18 +1,18 @@
|
|
1
1
|
import pytest
|
2
2
|
|
3
|
-
from geolysis.spt import (
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
from geolysis.spt import (DilatancyCorrection, EnergyCorrection, HammerType,
|
4
|
+
SamplerType, SPTNDesign,
|
5
|
+
create_overburden_pressure_correction)
|
6
|
+
from geolysis.utils.exceptions import ValidationError
|
7
7
|
|
8
8
|
|
9
9
|
def test_create_spt_correction_errors():
|
10
|
-
with pytest.raises(
|
10
|
+
with pytest.raises(ValidationError):
|
11
11
|
create_overburden_pressure_correction(std_spt_n_value=34,
|
12
12
|
eop=100, opc_type="TERZAGHI")
|
13
13
|
|
14
14
|
|
15
|
-
class
|
15
|
+
class TestSPTNDesign:
|
16
16
|
|
17
17
|
def test_spt_n_design(self):
|
18
18
|
spt_design = SPTNDesign([7.0, 15.0, 18], method="min")
|
@@ -24,20 +24,26 @@ class TestSPTDesign:
|
|
24
24
|
assert spt_design.n_design() == pytest.approx(9.4)
|
25
25
|
|
26
26
|
def test_errors(self):
|
27
|
-
|
27
|
+
# Provided an empty value for corrected_spt_n_values
|
28
|
+
with pytest.raises(ValidationError):
|
28
29
|
SPTNDesign(corrected_spt_n_values=[])
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
spt_design.n_design()
|
31
|
+
# Provided an invalid method
|
32
|
+
with pytest.raises(ValidationError):
|
33
|
+
SPTNDesign(corrected_spt_n_values=[7.0, 15.0, 18], method="max")
|
34
34
|
|
35
|
-
|
35
|
+
# corrected_spt_n_values is greater than 100
|
36
|
+
with pytest.raises(ValidationError):
|
36
37
|
SPTNDesign(corrected_spt_n_values=[22, 44, 120])
|
37
38
|
|
38
|
-
|
39
|
+
# corrected_spt_n_values is 0.0
|
40
|
+
with pytest.raises(ValidationError):
|
39
41
|
SPTNDesign(corrected_spt_n_values=[0.0, 15.0, 18])
|
40
42
|
|
43
|
+
# corrected_spt_n_values is less than 0.0
|
44
|
+
with pytest.raises(ValidationError):
|
45
|
+
SPTNDesign(corrected_spt_n_values=[-10, 15.0, 18])
|
46
|
+
|
41
47
|
|
42
48
|
class TestEnergyCorrection:
|
43
49
|
|
@@ -66,6 +72,15 @@ class TestEnergyCorrection:
|
|
66
72
|
assert energy_corr.standardized_spt_n_value() == pytest.approx(
|
67
73
|
expected)
|
68
74
|
|
75
|
+
def test_errors(self):
|
76
|
+
# Provided an invalid value for hammer_type
|
77
|
+
with pytest.raises(ValidationError):
|
78
|
+
EnergyCorrection(recorded_spt_n_value=22, hammer_type="manual")
|
79
|
+
|
80
|
+
# Provided an invalid value for sampler_type
|
81
|
+
with pytest.raises(ValidationError):
|
82
|
+
EnergyCorrection(recorded_spt_n_value=22, sampler_type="std")
|
83
|
+
|
69
84
|
|
70
85
|
class TestGibbsHoltzOPC:
|
71
86
|
|
@@ -1,36 +0,0 @@
|
|
1
|
-
from typing import Unpack, TypedDict, NotRequired, Any, Optional
|
2
|
-
|
3
|
-
|
4
|
-
class _ErrorParams(TypedDict):
|
5
|
-
param_name: NotRequired[str]
|
6
|
-
param_value: NotRequired[Any]
|
7
|
-
param_type: NotRequired[Any]
|
8
|
-
|
9
|
-
|
10
|
-
class ErrorMsg(str):
|
11
|
-
|
12
|
-
@staticmethod
|
13
|
-
def __new__(cls, msg):
|
14
|
-
return super().__new__(cls, msg)
|
15
|
-
|
16
|
-
|
17
|
-
class EnumErrorMsg(ErrorMsg):
|
18
|
-
|
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'])}")
|
25
|
-
|
26
|
-
return super().__new__(cls, err_msg)
|
27
|
-
|
28
|
-
|
29
|
-
class ValidationError(ValueError):
|
30
|
-
"""Exception raised when a validation error occurs."""
|
31
|
-
|
32
|
-
|
33
|
-
class SettlementError(ValueError):
|
34
|
-
"""Raised when tolerable settlement is greater than the maximum
|
35
|
-
allowable settlement.
|
36
|
-
"""
|
@@ -1,101 +0,0 @@
|
|
1
|
-
"""validators"""
|
2
|
-
import operator
|
3
|
-
from typing import Callable, TypeAlias, Optional
|
4
|
-
from functools import wraps
|
5
|
-
|
6
|
-
from .exceptions import ValidationError
|
7
|
-
|
8
|
-
Number: TypeAlias = int | float
|
9
|
-
|
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):
|
17
|
-
@wraps(fn)
|
18
|
-
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)
|
22
|
-
fn(obj, val)
|
23
|
-
|
24
|
-
return wrapper
|
25
|
-
|
26
|
-
return dec
|
27
|
-
|
28
|
-
|
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):
|
35
|
-
@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)
|
41
|
-
fn(obj, val)
|
42
|
-
|
43
|
-
return wrapper
|
44
|
-
|
45
|
-
return dec
|
46
|
-
|
47
|
-
|
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)
|
54
|
-
|
55
|
-
|
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)
|
62
|
-
|
63
|
-
|
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)
|
70
|
-
|
71
|
-
|
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)
|
78
|
-
|
79
|
-
|
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)
|
86
|
-
|
87
|
-
|
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)
|
94
|
-
|
95
|
-
|
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)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|