geolysis 0.11.0__py3-none-any.whl → 0.13.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 +1 -1
- geolysis/bearing_capacity/abc/_cohl/__init__.py +31 -43
- geolysis/bearing_capacity/abc/_cohl/_core.py +42 -19
- geolysis/bearing_capacity/abc/_cohl/bowles_abc.py +11 -11
- geolysis/bearing_capacity/abc/_cohl/meyerhof_abc.py +11 -11
- geolysis/bearing_capacity/abc/_cohl/terzaghi_abc.py +16 -16
- geolysis/bearing_capacity/ubc/__init__.py +25 -28
- geolysis/bearing_capacity/ubc/_core.py +139 -76
- geolysis/bearing_capacity/ubc/_terzaghi_ubc.py +48 -65
- geolysis/bearing_capacity/ubc/_vesic_ubc.py +90 -46
- geolysis/foundation.py +104 -75
- geolysis/soil_classifier.py +47 -50
- geolysis/spt.py +87 -76
- geolysis/{utils.py → utils/__init__.py} +15 -53
- geolysis/utils/math.py +59 -0
- {geolysis-0.11.0.dist-info → geolysis-0.13.0.dist-info}/METADATA +47 -39
- geolysis-0.13.0.dist-info/RECORD +22 -0
- geolysis/bearing_capacity/ubc/_hansen_ubc.py +0 -188
- geolysis-0.11.0.dist-info/RECORD +0 -22
- {geolysis-0.11.0.dist-info → geolysis-0.13.0.dist-info}/WHEEL +0 -0
- {geolysis-0.11.0.dist-info → geolysis-0.13.0.dist-info}/licenses/LICENSE.txt +0 -0
- {geolysis-0.11.0.dist-info → geolysis-0.13.0.dist-info}/top_level.txt +0 -0
geolysis/soil_classifier.py
CHANGED
@@ -2,9 +2,9 @@ import enum
|
|
2
2
|
from dataclasses import dataclass
|
3
3
|
from typing import Annotated, Sequence
|
4
4
|
|
5
|
-
from func_validator import
|
5
|
+
from func_validator import validate_params, MustBeNonNegative
|
6
6
|
|
7
|
-
from .utils import isclose, round_
|
7
|
+
from .utils import isclose, round_, nan, isnan
|
8
8
|
|
9
9
|
__all__ = [
|
10
10
|
"AtterbergLimits",
|
@@ -256,9 +256,9 @@ class AtterbergLimits:
|
|
256
256
|
return self._liquid_limit
|
257
257
|
|
258
258
|
@liquid_limit.setter
|
259
|
-
@
|
260
|
-
def liquid_limit(self,
|
261
|
-
self._liquid_limit =
|
259
|
+
@validate_params
|
260
|
+
def liquid_limit(self, liquid_limit: Annotated[float, MustBeNonNegative]):
|
261
|
+
self._liquid_limit = liquid_limit
|
262
262
|
|
263
263
|
@property
|
264
264
|
def plastic_limit(self) -> float:
|
@@ -268,16 +268,16 @@ class AtterbergLimits:
|
|
268
268
|
return self._plastic_limit
|
269
269
|
|
270
270
|
@plastic_limit.setter
|
271
|
-
@
|
272
|
-
def plastic_limit(self,
|
273
|
-
if self.liquid_limit <
|
271
|
+
@validate_params
|
272
|
+
def plastic_limit(self, plastic_limit: Annotated[float, MustBeNonNegative]):
|
273
|
+
if self.liquid_limit < plastic_limit:
|
274
274
|
msg = (
|
275
|
-
f"plastic_limit: {
|
275
|
+
f"plastic_limit: {plastic_limit} cannot be greater than "
|
276
276
|
f"liquid_limit: {self.liquid_limit}"
|
277
277
|
)
|
278
278
|
raise ValueError(msg)
|
279
279
|
|
280
|
-
self._plastic_limit =
|
280
|
+
self._plastic_limit = plastic_limit
|
281
281
|
|
282
282
|
@property
|
283
283
|
@round_(2)
|
@@ -353,8 +353,7 @@ class _SizeDistribution:
|
|
353
353
|
Features obtained from the Particle Size Distribution graph.
|
354
354
|
"""
|
355
355
|
|
356
|
-
def __init__(self, d_10: float
|
357
|
-
d_60: float = 0.0):
|
356
|
+
def __init__(self, d_10: float, d_30: float, d_60: float):
|
358
357
|
self.d_10 = d_10
|
359
358
|
self.d_30 = d_30
|
360
359
|
self.d_60 = d_60
|
@@ -364,7 +363,7 @@ class _SizeDistribution:
|
|
364
363
|
|
365
364
|
@property
|
366
365
|
def coeff_of_curvature(self) -> float:
|
367
|
-
return (self.d_30
|
366
|
+
return (self.d_30**2.0) / (self.d_60 * self.d_10)
|
368
367
|
|
369
368
|
@property
|
370
369
|
def coeff_of_uniformity(self) -> float:
|
@@ -390,6 +389,12 @@ class _SizeDistribution:
|
|
390
389
|
grade = USCSSymbol.POORLY_GRADED
|
391
390
|
return grade
|
392
391
|
|
392
|
+
def has_particle_sizes(self) -> bool:
|
393
|
+
"""Checks if particle sizes are provided."""
|
394
|
+
if isnan(self.d_10) or isnan(self.d_30) or isnan(self.d_60):
|
395
|
+
return False
|
396
|
+
return True
|
397
|
+
|
393
398
|
|
394
399
|
class PSD:
|
395
400
|
"""Quantitative proportions by mass of various sizes of particles
|
@@ -397,12 +402,12 @@ class PSD:
|
|
397
402
|
"""
|
398
403
|
|
399
404
|
def __init__(
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
405
|
+
self,
|
406
|
+
fines: float,
|
407
|
+
sand: float,
|
408
|
+
d_10: float = nan,
|
409
|
+
d_30: float = nan,
|
410
|
+
d_60: float = nan,
|
406
411
|
):
|
407
412
|
"""
|
408
413
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
@@ -460,7 +465,7 @@ class PSD:
|
|
460
465
|
|
461
466
|
def has_particle_sizes(self) -> bool:
|
462
467
|
"""Checks if soil sample has particle sizes."""
|
463
|
-
return
|
468
|
+
return self.size_dist.has_particle_sizes()
|
464
469
|
|
465
470
|
def grade(self) -> USCSSymbol:
|
466
471
|
r"""Return the grade of the soil sample, either well graded or
|
@@ -474,7 +479,7 @@ class PSD:
|
|
474
479
|
return self.size_dist.grade(coarse_soil=self.coarse_material_type)
|
475
480
|
|
476
481
|
|
477
|
-
@dataclass
|
482
|
+
@dataclass(frozen=True, slots=True)
|
478
483
|
class AASHTOResult:
|
479
484
|
symbol: str
|
480
485
|
symbol_no_group_idx: str
|
@@ -528,9 +533,9 @@ class AASHTO:
|
|
528
533
|
return self._fines
|
529
534
|
|
530
535
|
@fines.setter
|
531
|
-
@
|
532
|
-
def fines(self,
|
533
|
-
self._fines =
|
536
|
+
@validate_params
|
537
|
+
def fines(self, fines: Annotated[float, MustBeNonNegative]):
|
538
|
+
self._fines = fines
|
534
539
|
|
535
540
|
@round_(ndigits=0)
|
536
541
|
def group_index(self) -> float:
|
@@ -620,7 +625,7 @@ class AASHTO:
|
|
620
625
|
return soil_clf
|
621
626
|
|
622
627
|
|
623
|
-
@dataclass
|
628
|
+
@dataclass(frozen=True, slots=True)
|
624
629
|
class USCSResult:
|
625
630
|
symbol: str
|
626
631
|
description: str
|
@@ -649,10 +654,10 @@ class USCS:
|
|
649
654
|
"""
|
650
655
|
|
651
656
|
def __init__(
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
657
|
+
self,
|
658
|
+
atterberg_limits: AtterbergLimits,
|
659
|
+
psd: PSD,
|
660
|
+
organic=False,
|
656
661
|
):
|
657
662
|
"""
|
658
663
|
:param atterberg_limits: Atterberg limits of the soil.
|
@@ -673,7 +678,8 @@ class USCS:
|
|
673
678
|
|
674
679
|
if isinstance(soil_clf, USCSSymbol):
|
675
680
|
soil_clf = USCSResult(
|
676
|
-
symbol=soil_clf.symbol,
|
681
|
+
symbol=soil_clf.symbol,
|
682
|
+
description=soil_clf.description,
|
677
683
|
)
|
678
684
|
else:
|
679
685
|
# Handling tuple or list case for dual classification
|
@@ -779,9 +785,9 @@ class USCS:
|
|
779
785
|
|
780
786
|
|
781
787
|
def create_aashto_classifier(
|
782
|
-
|
783
|
-
|
784
|
-
|
788
|
+
liquid_limit: float,
|
789
|
+
plastic_limit: float,
|
790
|
+
fines: float,
|
785
791
|
) -> AASHTO:
|
786
792
|
"""A helper function that encapsulates the creation of a AASHTO
|
787
793
|
classifier.
|
@@ -791,12 +797,10 @@ def create_aashto_classifier(
|
|
791
797
|
the minimum moisture content at which a soil
|
792
798
|
flows upon application of a very small shear
|
793
799
|
force.
|
794
|
-
|
795
800
|
:param plastic_limit: Water content at which plastic deformation can
|
796
801
|
be initiated (%). It is also the minimum water
|
797
802
|
content at which soil can be rolled into a
|
798
803
|
thread 3mm thick (molded without breaking).
|
799
|
-
|
800
804
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
801
805
|
percentage of soil sample passing through No. 200
|
802
806
|
sieve (0.075mm).
|
@@ -806,14 +810,14 @@ def create_aashto_classifier(
|
|
806
810
|
|
807
811
|
|
808
812
|
def create_uscs_classifier(
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
813
|
+
liquid_limit: float,
|
814
|
+
plastic_limit: float,
|
815
|
+
fines: float,
|
816
|
+
sand: float,
|
817
|
+
d_10: float = nan,
|
818
|
+
d_30: float = nan,
|
819
|
+
d_60: float = nan,
|
820
|
+
organic: bool = False,
|
817
821
|
):
|
818
822
|
"""A helper function that encapsulates the creation of a USCS
|
819
823
|
classifier.
|
@@ -823,24 +827,17 @@ def create_uscs_classifier(
|
|
823
827
|
the minimum moisture content at which a soil
|
824
828
|
flows upon application of a very small shear
|
825
829
|
force.
|
826
|
-
|
827
830
|
:param plastic_limit: Water content at which plastic deformation can
|
828
831
|
be initiated (%). It is also the minimum water
|
829
832
|
content at which soil can be rolled into a
|
830
833
|
thread 3mm thick. (molded without breaking)
|
831
|
-
|
832
834
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
833
835
|
percentage of soil sample passing through No. 200
|
834
836
|
sieve (0.075mm).
|
835
|
-
|
836
837
|
:param sand: Percentage of sand in soil sample (%).
|
837
|
-
|
838
838
|
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
839
|
-
|
840
839
|
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
841
|
-
|
842
840
|
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
843
|
-
|
844
841
|
:param organic: Indicates whether soil is organic or not.
|
845
842
|
"""
|
846
843
|
atterberg_lmts = AtterbergLimits(liquid_limit, plastic_limit)
|
geolysis/spt.py
CHANGED
@@ -3,7 +3,7 @@ from abc import abstractmethod
|
|
3
3
|
from typing import Annotated, Final, Sequence
|
4
4
|
|
5
5
|
from func_validator import (
|
6
|
-
|
6
|
+
validate_params,
|
7
7
|
MustBeBetween,
|
8
8
|
MustBePositive,
|
9
9
|
MustBeMemberOf,
|
@@ -61,9 +61,9 @@ class SPT:
|
|
61
61
|
"""
|
62
62
|
|
63
63
|
def __init__(
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
self,
|
65
|
+
corrected_spt_n_values: Sequence[float],
|
66
|
+
method: SPTDesignMethod.WEIGHTED = "wgt",
|
67
67
|
):
|
68
68
|
"""
|
69
69
|
:param corrected_spt_n_values: Corrected SPT N-values within the
|
@@ -80,14 +80,14 @@ class SPT:
|
|
80
80
|
return self._corrected_spt_n_values
|
81
81
|
|
82
82
|
@corrected_spt_n_values.setter
|
83
|
-
@
|
83
|
+
@validate_params
|
84
84
|
def corrected_spt_n_values(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
91
|
) -> None:
|
92
92
|
self._corrected_spt_n_values = corrected_spt_n_values
|
93
93
|
|
@@ -96,9 +96,9 @@ class SPT:
|
|
96
96
|
return self._method
|
97
97
|
|
98
98
|
@method.setter
|
99
|
-
@
|
100
|
-
def method(self,
|
101
|
-
self._method =
|
99
|
+
@validate_params
|
100
|
+
def method(self, method: Annotated[str, MustBeMemberOf(SPTDesignMethod)]):
|
101
|
+
self._method = method
|
102
102
|
|
103
103
|
@staticmethod
|
104
104
|
def _avg_spt_n_design(vals) -> float:
|
@@ -111,15 +111,15 @@ class SPT:
|
|
111
111
|
@staticmethod
|
112
112
|
def _wgt_spt_n_design(vals):
|
113
113
|
|
114
|
-
|
115
|
-
|
114
|
+
total_wgted_spt = 0.0
|
115
|
+
total_wgt = 0.0
|
116
116
|
|
117
117
|
for i, corr_spt_n_val in enumerate(vals, start=1):
|
118
|
-
wgt = 1 / i
|
119
|
-
|
120
|
-
|
118
|
+
wgt = 1 / i**2
|
119
|
+
total_wgted_spt += wgt * corr_spt_n_val
|
120
|
+
total_wgt += wgt
|
121
121
|
|
122
|
-
return
|
122
|
+
return total_wgted_spt / total_wgt
|
123
123
|
|
124
124
|
@round_(ndigits=1)
|
125
125
|
def n_design(self):
|
@@ -220,14 +220,14 @@ class EnergyCorrection:
|
|
220
220
|
}
|
221
221
|
|
222
222
|
def __init__(
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
231
|
):
|
232
232
|
"""
|
233
233
|
:param recorded_spt_n_value: Recorded SPT N-value from field.
|
@@ -252,12 +252,12 @@ class EnergyCorrection:
|
|
252
252
|
return self._recorded_spt_value
|
253
253
|
|
254
254
|
@recorded_spt_n_value.setter
|
255
|
-
@
|
255
|
+
@validate_params
|
256
256
|
def recorded_spt_n_value(
|
257
|
-
|
258
|
-
|
257
|
+
self,
|
258
|
+
recorded_spt_n_value: Annotated[int, MustBeBetween(min_value=0, max_value=100)],
|
259
259
|
) -> None:
|
260
|
-
self._recorded_spt_value =
|
260
|
+
self._recorded_spt_value = recorded_spt_n_value
|
261
261
|
|
262
262
|
@property
|
263
263
|
def energy_percentage(self) -> float:
|
@@ -265,12 +265,14 @@ class EnergyCorrection:
|
|
265
265
|
return self._energy_percentage
|
266
266
|
|
267
267
|
@energy_percentage.setter
|
268
|
-
@
|
268
|
+
@validate_params
|
269
269
|
def energy_percentage(
|
270
|
-
|
271
|
-
|
270
|
+
self,
|
271
|
+
energy_percentage: Annotated[
|
272
|
+
float, MustBeBetween(min_value=0.0, max_value=1.0)
|
273
|
+
],
|
272
274
|
) -> None:
|
273
|
-
self._energy_percentage =
|
275
|
+
self._energy_percentage = energy_percentage
|
274
276
|
|
275
277
|
@property
|
276
278
|
def borehole_diameter(self) -> float:
|
@@ -278,12 +280,14 @@ class EnergyCorrection:
|
|
278
280
|
return self._borehole_diameter
|
279
281
|
|
280
282
|
@borehole_diameter.setter
|
281
|
-
@
|
283
|
+
@validate_params
|
282
284
|
def borehole_diameter(
|
283
|
-
|
284
|
-
|
285
|
+
self,
|
286
|
+
borehole_diameter: Annotated[
|
287
|
+
float, MustBeBetween(min_value=65.0, max_value=200.0)
|
288
|
+
],
|
285
289
|
) -> None:
|
286
|
-
self._borehole_diameter =
|
290
|
+
self._borehole_diameter = borehole_diameter
|
287
291
|
|
288
292
|
@property
|
289
293
|
def rod_length(self) -> float:
|
@@ -291,19 +295,19 @@ class EnergyCorrection:
|
|
291
295
|
return self._rod_length
|
292
296
|
|
293
297
|
@rod_length.setter
|
294
|
-
@
|
295
|
-
def rod_length(self,
|
296
|
-
self._rod_length =
|
298
|
+
@validate_params
|
299
|
+
def rod_length(self, rod_length: Annotated[float, MustBePositive]):
|
300
|
+
self._rod_length = rod_length
|
297
301
|
|
298
302
|
@property
|
299
303
|
def hammer_type(self) -> HammerType:
|
300
304
|
return self._hammer_type
|
301
305
|
|
302
306
|
@hammer_type.setter
|
303
|
-
@
|
307
|
+
@validate_params
|
304
308
|
def hammer_type(
|
305
|
-
|
306
|
-
|
309
|
+
self,
|
310
|
+
hammer_type: Annotated[HammerType, MustBeMemberOf(HammerType)],
|
307
311
|
):
|
308
312
|
self._hammer_type = hammer_type
|
309
313
|
|
@@ -312,10 +316,11 @@ class EnergyCorrection:
|
|
312
316
|
return self._sampler_type
|
313
317
|
|
314
318
|
@sampler_type.setter
|
315
|
-
@
|
316
|
-
def sampler_type(
|
317
|
-
|
318
|
-
|
319
|
+
@validate_params
|
320
|
+
def sampler_type(
|
321
|
+
self, sampler_type: Annotated[SamplerType, MustBeMemberOf(SamplerType)]
|
322
|
+
):
|
323
|
+
self._sampler_type = sampler_type
|
319
324
|
|
320
325
|
@property
|
321
326
|
def hammer_efficiency(self) -> float:
|
@@ -362,10 +367,10 @@ class EnergyCorrection:
|
|
362
367
|
`ENERGY`: 0.6, 0.55, etc
|
363
368
|
"""
|
364
369
|
numerator = (
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
370
|
+
self.hammer_efficiency
|
371
|
+
* self.borehole_diameter_correction
|
372
|
+
* self.sampler_correction
|
373
|
+
* self.rod_length_correction
|
369
374
|
)
|
370
375
|
return numerator / self.energy_percentage
|
371
376
|
|
@@ -393,10 +398,10 @@ class OPC:
|
|
393
398
|
return self._eop
|
394
399
|
|
395
400
|
@eop.setter
|
396
|
-
@
|
397
|
-
def eop(self,
|
401
|
+
@validate_params
|
402
|
+
def eop(self, eop: Annotated[float, MustBeNonNegative]):
|
398
403
|
"""Effective overburden pressure ($kPa$)."""
|
399
|
-
self._eop =
|
404
|
+
self._eop = eop
|
400
405
|
|
401
406
|
@property
|
402
407
|
def std_spt_n_value(self) -> float:
|
@@ -404,12 +409,14 @@ class OPC:
|
|
404
409
|
return self._std_spt_n_value
|
405
410
|
|
406
411
|
@std_spt_n_value.setter
|
407
|
-
@
|
412
|
+
@validate_params
|
408
413
|
def std_spt_n_value(
|
409
|
-
|
410
|
-
|
414
|
+
self,
|
415
|
+
std_spt_n_value: Annotated[
|
416
|
+
float, MustBeBetween(min_value=0.0, max_value=100.0)
|
417
|
+
],
|
411
418
|
):
|
412
|
-
self._std_spt_n_value =
|
419
|
+
self._std_spt_n_value = std_spt_n_value
|
413
420
|
|
414
421
|
@round_(ndigits=1)
|
415
422
|
def corrected_spt_n_value(self) -> float:
|
@@ -435,10 +442,12 @@ class GibbsHoltzOPC(OPC):
|
|
435
442
|
return self._eop
|
436
443
|
|
437
444
|
@eop.setter
|
438
|
-
@
|
439
|
-
def eop(
|
440
|
-
|
441
|
-
|
445
|
+
@validate_params
|
446
|
+
def eop(
|
447
|
+
self,
|
448
|
+
eop: Annotated[float, MustBeBetween(min_value=0.0, max_value=280.0)],
|
449
|
+
):
|
450
|
+
self._eop = eop
|
442
451
|
|
443
452
|
def correction(self) -> float:
|
444
453
|
r"""SPT Correction."""
|
@@ -476,9 +485,9 @@ class PeckOPC(OPC):
|
|
476
485
|
return self._eop
|
477
486
|
|
478
487
|
@eop.setter
|
479
|
-
@
|
480
|
-
def eop(self,
|
481
|
-
self._eop =
|
488
|
+
@validate_params
|
489
|
+
def eop(self, eop: Annotated[float, MustBeGreaterThanOrEqual(24.0)]):
|
490
|
+
self._eop = eop
|
482
491
|
|
483
492
|
def correction(self) -> float:
|
484
493
|
r"""SPT Correction."""
|
@@ -527,12 +536,14 @@ class DilatancyCorrection:
|
|
527
536
|
return self._corr_spt_n_value
|
528
537
|
|
529
538
|
@corr_spt_n_value.setter
|
530
|
-
@
|
539
|
+
@validate_params
|
531
540
|
def corr_spt_n_value(
|
532
|
-
|
533
|
-
|
541
|
+
self,
|
542
|
+
corr_spt_n_value: Annotated[
|
543
|
+
float, MustBeBetween(min_value=0.0, max_value=100.0)
|
544
|
+
],
|
534
545
|
):
|
535
|
-
self._corr_spt_n_value =
|
546
|
+
self._corr_spt_n_value = corr_spt_n_value
|
536
547
|
|
537
548
|
@round_(ndigits=1)
|
538
549
|
def corrected_spt_n_value(self) -> float:
|
@@ -574,11 +585,11 @@ _opctypes = {
|
|
574
585
|
}
|
575
586
|
|
576
587
|
|
577
|
-
@
|
588
|
+
@validate_params
|
578
589
|
def create_overburden_pressure_correction(
|
579
|
-
|
580
|
-
|
581
|
-
|
590
|
+
std_spt_n_value: float,
|
591
|
+
eop: float,
|
592
|
+
opc_type: Annotated[OPCType | str, MustBeMemberOf(OPCType)] = "gibbs",
|
582
593
|
):
|
583
594
|
"""A factory function that encapsulates the creation of overburden
|
584
595
|
pressure correction.
|
@@ -1,31 +1,11 @@
|
|
1
1
|
import enum
|
2
2
|
import functools
|
3
|
-
import math
|
4
|
-
from math import exp, inf, isclose, log10, pi, sqrt
|
5
|
-
from statistics import fmean as mean
|
6
3
|
from typing import Callable
|
7
4
|
|
8
|
-
from
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
"ValidationError",
|
13
|
-
"inf",
|
14
|
-
"pi",
|
15
|
-
"deg2rad",
|
16
|
-
"rad2deg",
|
17
|
-
"tan",
|
18
|
-
"cot",
|
19
|
-
"sin",
|
20
|
-
"cos",
|
21
|
-
"arctan",
|
22
|
-
"round_",
|
23
|
-
"mean",
|
24
|
-
"exp",
|
25
|
-
"isclose",
|
26
|
-
"log10",
|
27
|
-
"sqrt",
|
28
|
-
]
|
5
|
+
from .math import *
|
6
|
+
from . import math as m
|
7
|
+
|
8
|
+
__all__ = ["AbstractStrEnum", "ValidationError", "add_repr", "round_"] + m.__all__
|
29
9
|
|
30
10
|
|
31
11
|
class StrEnumMeta(enum.EnumMeta):
|
@@ -46,39 +26,21 @@ class AbstractStrEnum(enum.StrEnum, metaclass=StrEnumMeta):
|
|
46
26
|
"""
|
47
27
|
|
48
28
|
|
49
|
-
def
|
50
|
-
"""
|
51
|
-
return math.radians(x)
|
52
|
-
|
53
|
-
|
54
|
-
def rad2deg(x: float, /) -> float:
|
55
|
-
"""Convert angle x from radians to degrees."""
|
56
|
-
return math.degrees(x)
|
57
|
-
|
58
|
-
|
59
|
-
def tan(x: float, /) -> float:
|
60
|
-
"""Return the tangent of x (measured in degrees)."""
|
61
|
-
return math.tan(deg2rad(x))
|
62
|
-
|
63
|
-
|
64
|
-
def cot(x: float, /) -> float:
|
65
|
-
"""Return the cotangent of x (measured in degrees)."""
|
66
|
-
return 1 / tan(x)
|
67
|
-
|
68
|
-
|
69
|
-
def sin(x: float, /) -> float:
|
70
|
-
"""Return the sine of x (measured in degrees)."""
|
71
|
-
return math.sin(deg2rad(x))
|
29
|
+
def add_repr(cls):
|
30
|
+
"""A class decorator that adds a __repr__ method to the class."""
|
72
31
|
|
32
|
+
def __repr__(self) -> str:
|
33
|
+
inst_attrs = self.__dict__
|
34
|
+
attrs = (f"{key.strip('_')}={val}" for key, val in inst_attrs.items())
|
35
|
+
return f"{type(self).__name__}({', '.join(attrs)})"
|
73
36
|
|
74
|
-
def
|
75
|
-
|
76
|
-
return math.cos(deg2rad(x))
|
37
|
+
def __str__(self) -> str:
|
38
|
+
return repr(self)
|
77
39
|
|
40
|
+
cls.__repr__ = __repr__
|
41
|
+
cls.__str__ = __str__
|
78
42
|
|
79
|
-
|
80
|
-
"""Return the arc tangent (measured in degrees) of x."""
|
81
|
-
return rad2deg(math.atan(x))
|
43
|
+
return cls
|
82
44
|
|
83
45
|
|
84
46
|
def round_(ndigits: int) -> Callable:
|
geolysis/utils/math.py
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
import math
|
2
|
+
from math import exp, inf, isclose, log10, pi, sqrt, isinf, atan, nan, isnan
|
3
|
+
from statistics import fmean as mean
|
4
|
+
|
5
|
+
__all__ = [
|
6
|
+
"atan",
|
7
|
+
"inf",
|
8
|
+
"isinf",
|
9
|
+
"pi",
|
10
|
+
"deg2rad",
|
11
|
+
"rad2deg",
|
12
|
+
"tandeg",
|
13
|
+
"cotdeg",
|
14
|
+
"sindeg",
|
15
|
+
"cosdeg",
|
16
|
+
"arctandeg",
|
17
|
+
"mean",
|
18
|
+
"exp",
|
19
|
+
"isclose",
|
20
|
+
"log10",
|
21
|
+
"sqrt",
|
22
|
+
"nan",
|
23
|
+
"isnan",
|
24
|
+
]
|
25
|
+
|
26
|
+
|
27
|
+
def deg2rad(x: float, /) -> float:
|
28
|
+
"""Convert angle x from degrees to radians."""
|
29
|
+
return math.radians(x)
|
30
|
+
|
31
|
+
|
32
|
+
def rad2deg(x: float, /) -> float:
|
33
|
+
"""Convert angle x from radians to degrees."""
|
34
|
+
return math.degrees(x)
|
35
|
+
|
36
|
+
|
37
|
+
def tandeg(x: float, /) -> float:
|
38
|
+
"""Return the tangent of x (measured in degrees)."""
|
39
|
+
return math.tan(deg2rad(x))
|
40
|
+
|
41
|
+
|
42
|
+
def cotdeg(x: float, /) -> float:
|
43
|
+
"""Return the cotangent of x (measured in degrees)."""
|
44
|
+
return 1 / tandeg(x)
|
45
|
+
|
46
|
+
|
47
|
+
def sindeg(x: float, /) -> float:
|
48
|
+
"""Return the sine of x (measured in degrees)."""
|
49
|
+
return math.sin(deg2rad(x))
|
50
|
+
|
51
|
+
|
52
|
+
def cosdeg(x: float, /) -> float:
|
53
|
+
"""Return the cosine of x (measured in degrees)."""
|
54
|
+
return math.cos(deg2rad(x))
|
55
|
+
|
56
|
+
|
57
|
+
def arctandeg(x: float, /) -> float:
|
58
|
+
"""Return the arc tangent (measured in degrees) of x."""
|
59
|
+
return rad2deg(math.atan(x))
|