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.
- geolysis/__init__.py +3 -3
- geolysis/bearing_capacity/abc/__init__.py +21 -0
- geolysis/bearing_capacity/abc/_cohl/__init__.py +109 -0
- geolysis/bearing_capacity/abc/{cohl → _cohl}/_core.py +20 -10
- geolysis/bearing_capacity/abc/_cohl/bowles_abc.py +103 -0
- geolysis/bearing_capacity/abc/_cohl/meyerhof_abc.py +100 -0
- geolysis/bearing_capacity/abc/_cohl/terzaghi_abc.py +143 -0
- geolysis/bearing_capacity/ubc/__init__.py +107 -128
- geolysis/bearing_capacity/ubc/_core.py +68 -66
- geolysis/bearing_capacity/ubc/_hansen_ubc.py +271 -0
- geolysis/bearing_capacity/ubc/_terzaghi_ubc.py +178 -0
- geolysis/bearing_capacity/ubc/_vesic_ubc.py +253 -0
- geolysis/foundation.py +160 -127
- geolysis/soil_classifier.py +386 -285
- geolysis/spt.py +323 -257
- geolysis/{utils/__init__.py → utils.py} +48 -36
- geolysis-0.10.0.dist-info/METADATA +181 -0
- geolysis-0.10.0.dist-info/RECORD +22 -0
- {geolysis-0.8.0.dist-info → geolysis-0.10.0.dist-info}/WHEEL +1 -1
- geolysis/bearing_capacity/abc/cohl/__init__.py +0 -137
- geolysis/bearing_capacity/abc/cohl/bowles_abc.py +0 -96
- geolysis/bearing_capacity/abc/cohl/meyerhof_abc.py +0 -96
- geolysis/bearing_capacity/abc/cohl/terzaghi_abc.py +0 -131
- geolysis/bearing_capacity/ubc/hansen_ubc.py +0 -287
- geolysis/bearing_capacity/ubc/terzaghi_ubc.py +0 -246
- geolysis/bearing_capacity/ubc/vesic_ubc.py +0 -293
- geolysis/utils/exceptions.py +0 -52
- geolysis/utils/validators.py +0 -129
- geolysis-0.8.0.dist-info/METADATA +0 -206
- geolysis-0.8.0.dist-info/RECORD +0 -24
- {geolysis-0.8.0.dist-info → geolysis-0.10.0.dist-info}/licenses/LICENSE.txt +0 -0
- {geolysis-0.8.0.dist-info → geolysis-0.10.0.dist-info}/top_level.txt +0 -0
geolysis/soil_classifier.py
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
"""This module provides classes for soil classification using systems like
|
2
|
-
USCS and AASHTO, based on particle size distribution and Atterberg limits.
|
3
|
-
"""
|
4
1
|
import enum
|
5
|
-
from
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Annotated, Sequence
|
6
4
|
|
7
|
-
from
|
8
|
-
from .utils.exceptions import ErrorMsg, ValidationError
|
5
|
+
from func_validator import validate_func_args, MustBeNonNegative
|
9
6
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
from .utils import isclose, round_
|
8
|
+
|
9
|
+
__all__ = [
|
10
|
+
"AtterbergLimits",
|
11
|
+
"PSD",
|
12
|
+
"AASHTO",
|
13
|
+
"USCS",
|
14
|
+
"create_aashto_classifier",
|
15
|
+
"create_uscs_classifier",
|
16
|
+
]
|
16
17
|
|
17
18
|
|
18
19
|
class SizeDistError(ZeroDivisionError):
|
19
20
|
"""Exception raised when size distribution is not provided."""
|
20
21
|
|
21
22
|
|
22
|
-
@enum_repr
|
23
23
|
class _Clf(tuple, enum.Enum):
|
24
24
|
|
25
25
|
def __str__(self) -> str:
|
@@ -35,63 +35,191 @@ class _Clf(tuple, enum.Enum):
|
|
35
35
|
|
36
36
|
|
37
37
|
class USCSSymbol(_Clf):
|
38
|
-
"""
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
38
|
+
"""
|
39
|
+
Unified Soil Classification System (USCS) symbols and descriptions.
|
40
|
+
|
41
|
+
Each member represents a USCS soil type, grading, or plasticity symbol.
|
42
|
+
Aliases are provided where applicable.
|
43
|
+
"""
|
44
|
+
|
45
|
+
# General soil types
|
46
|
+
G = ("G", "Gravel")
|
47
|
+
"""Gravel"""
|
48
|
+
|
49
|
+
GRAVEL = G
|
50
|
+
|
51
|
+
S = ("S", "Sand")
|
52
|
+
"""Sand"""
|
53
|
+
|
54
|
+
SAND = S
|
55
|
+
|
56
|
+
M = ("M", "Silt")
|
57
|
+
"""Silt"""
|
58
|
+
|
59
|
+
SILT = M
|
60
|
+
|
61
|
+
C = ("C", "Clay")
|
62
|
+
"""Clay"""
|
63
|
+
|
64
|
+
CLAY = C
|
65
|
+
|
66
|
+
O = ("O", "Organic")
|
67
|
+
"""Organic soil"""
|
68
|
+
|
69
|
+
ORGANIC = O
|
70
|
+
|
71
|
+
# Grading descriptors
|
72
|
+
W = ("W", "Well graded")
|
73
|
+
"""Well graded"""
|
74
|
+
|
75
|
+
WELL_GRADED = W
|
76
|
+
|
77
|
+
P = ("P", "Poorly graded")
|
78
|
+
"""Poorly graded"""
|
79
|
+
|
80
|
+
POORLY_GRADED = P
|
81
|
+
|
82
|
+
# Plasticity descriptors
|
83
|
+
L = ("L", "Low plasticity")
|
84
|
+
"""Low plasticity"""
|
85
|
+
|
86
|
+
LOW_PLASTICITY = L
|
87
|
+
|
88
|
+
H = ("H", "High plasticity")
|
89
|
+
"""High plasticity"""
|
90
|
+
|
91
|
+
HIGH_PLASTICITY = H
|
92
|
+
|
93
|
+
# Gravels
|
48
94
|
GW = ("GW", "Well graded gravels")
|
95
|
+
"""Well graded gravels"""
|
96
|
+
|
49
97
|
GP = ("GP", "Poorly graded gravels")
|
98
|
+
"""Poorly graded gravels"""
|
99
|
+
|
50
100
|
GM = ("GM", "Silty gravels")
|
101
|
+
"""Silty gravels"""
|
102
|
+
|
51
103
|
GC = ("GC", "Clayey gravels")
|
104
|
+
"""Clayey gravels"""
|
105
|
+
|
52
106
|
GM_GC = ("GM-GC", "Gravelly clayey silt")
|
107
|
+
"""Gravelly clayey silt"""
|
108
|
+
|
53
109
|
GW_GM = ("GW-GM", "Well graded gravel with silt")
|
110
|
+
"""Well graded gravel with silt"""
|
111
|
+
|
54
112
|
GP_GM = ("GP-GM", "Poorly graded gravel with silt")
|
113
|
+
"""Poorly graded gravel with silt"""
|
114
|
+
|
55
115
|
GW_GC = ("GW-GC", "Well graded gravel with clay")
|
116
|
+
"""Well graded gravel with clay"""
|
117
|
+
|
56
118
|
GP_GC = ("GP-GC", "Poorly graded gravel with clay")
|
119
|
+
"""Poorly graded gravel with clay"""
|
120
|
+
|
121
|
+
# Sands
|
57
122
|
SW = ("SW", "Well graded sands")
|
123
|
+
"""Well graded sands"""
|
124
|
+
|
58
125
|
SP = ("SP", "Poorly graded sands")
|
126
|
+
"""Poorly graded sands"""
|
127
|
+
|
59
128
|
SM = ("SM", "Silty sands")
|
129
|
+
"""Silty sands"""
|
130
|
+
|
60
131
|
SC = ("SC", "Clayey sands")
|
132
|
+
"""Clayey sands"""
|
133
|
+
|
61
134
|
SM_SC = ("SM-SC", "Sandy clayey silt")
|
135
|
+
"""Sandy clayey silt"""
|
136
|
+
|
62
137
|
SW_SM = ("SW-SM", "Well graded sand with silt")
|
138
|
+
"""Well graded sand with silt"""
|
139
|
+
|
63
140
|
SP_SM = ("SP-SM", "Poorly graded sand with silt")
|
141
|
+
"""Poorly graded sand with silt"""
|
142
|
+
|
64
143
|
SW_SC = ("SW-SC", "Well graded sand with clay")
|
144
|
+
"""Well graded sand with clay"""
|
145
|
+
|
65
146
|
SP_SC = ("SP-SC", "Poorly graded sand with clay")
|
147
|
+
"""Poorly graded sand with clay"""
|
148
|
+
|
149
|
+
# Silts and clays
|
66
150
|
ML = ("ML", "Inorganic silts with low plasticity")
|
151
|
+
"""Inorganic silts with low plasticity"""
|
152
|
+
|
67
153
|
CL = ("CL", "Inorganic clays with low plasticity")
|
154
|
+
"""Inorganic clays with low plasticity"""
|
155
|
+
|
68
156
|
ML_CL = ("ML-CL", "Clayey silt with low plasticity")
|
157
|
+
"""Clayey silt with low plasticity"""
|
158
|
+
|
69
159
|
OL = ("OL", "Organic clays with low plasticity")
|
160
|
+
"""Organic clays with low plasticity"""
|
161
|
+
|
70
162
|
MH = ("MH", "Inorganic silts with high plasticity")
|
163
|
+
"""Inorganic silts with high plasticity"""
|
164
|
+
|
71
165
|
CH = ("CH", "Inorganic clays with high plasticity")
|
166
|
+
"""Inorganic clays with high plasticity"""
|
167
|
+
|
72
168
|
OH = ("OH", "Organic silts with high plasticity")
|
169
|
+
"""Organic silts with high plasticity"""
|
170
|
+
|
73
171
|
Pt = ("Pt", "Highly organic soils")
|
172
|
+
"""Highly organic soils"""
|
74
173
|
|
75
174
|
|
76
175
|
class AASHTOSymbol(_Clf):
|
77
|
-
"""
|
176
|
+
"""
|
177
|
+
AASHTO soil classification symbols and descriptions.
|
178
|
+
|
179
|
+
Each member represents a standard AASHTO soil class used in
|
180
|
+
pavement and highway engineering.
|
181
|
+
"""
|
182
|
+
|
78
183
|
A_1_a = ("A-1-a", "Stone fragments, gravel, and sand")
|
184
|
+
"""Stone fragments, gravel, and sand"""
|
185
|
+
|
79
186
|
A_1_b = ("A-1-b", "Stone fragments, gravel, and sand")
|
187
|
+
"""Stone fragments, gravel, and sand"""
|
188
|
+
|
80
189
|
A_3 = ("A-3", "Fine sand")
|
190
|
+
"""Fine sand"""
|
191
|
+
|
81
192
|
A_2_4 = ("A-2-4", "Silty or clayey gravel and sand")
|
193
|
+
"""Silty or clayey gravel and sand"""
|
194
|
+
|
82
195
|
A_2_5 = ("A-2-5", "Silty or clayey gravel and sand")
|
196
|
+
"""Silty or clayey gravel and sand"""
|
197
|
+
|
83
198
|
A_2_6 = ("A-2-6", "Silty or clayey gravel and sand")
|
199
|
+
"""Silty or clayey gravel and sand"""
|
200
|
+
|
84
201
|
A_2_7 = ("A-2-7", "Silty or clayey gravel and sand")
|
202
|
+
"""Silty or clayey gravel and sand"""
|
203
|
+
|
85
204
|
A_4 = ("A-4", "Silty soils")
|
205
|
+
"""Silty soils"""
|
206
|
+
|
86
207
|
A_5 = ("A-5", "Silty soils")
|
208
|
+
"""Silty soils"""
|
209
|
+
|
87
210
|
A_6 = ("A-6", "Clayey soils")
|
211
|
+
"""Clayey soils"""
|
212
|
+
|
88
213
|
A_7_5 = ("A-7-5", "Clayey soils")
|
214
|
+
"""Clayey soils"""
|
215
|
+
|
89
216
|
A_7_6 = ("A-7-6", "Clayey soils")
|
217
|
+
"""Clayey soils"""
|
90
218
|
|
91
219
|
|
92
220
|
class AtterbergLimits:
|
93
|
-
"""Represents the water contents at which soil changes from one state
|
94
|
-
the other.
|
221
|
+
"""Represents the water contents at which soil changes from one state
|
222
|
+
to the other.
|
95
223
|
"""
|
96
224
|
|
97
225
|
class __A_LINE:
|
@@ -99,62 +227,69 @@ class AtterbergLimits:
|
|
99
227
|
def __get__(self, obj, objtype=None) -> float:
|
100
228
|
return 0.73 * (obj.liquid_limit - 20.0)
|
101
229
|
|
102
|
-
#: The ``A-line`` determines if a soil is clayey or silty.
|
103
|
-
#: :math:`A = 0.73(LL - 20.0)`
|
104
230
|
A_LINE = __A_LINE()
|
231
|
+
"""The ``A-line`` determines if a soil is clayey or silty.
|
232
|
+
|
233
|
+
$A = 0.73(LL - 20.0)$
|
234
|
+
"""
|
105
235
|
|
106
236
|
def __init__(self, liquid_limit: float, plastic_limit: float):
|
107
237
|
"""
|
108
|
-
:param liquid_limit: Water content beyond which soils flows
|
109
|
-
own weight (%). It can also be
|
110
|
-
minimum moisture content at
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
:type plastic_limit: float
|
238
|
+
:param liquid_limit: Water content beyond which soils flows
|
239
|
+
under their own weight (%). It can also be
|
240
|
+
defined as the minimum moisture content at
|
241
|
+
which a soil flows upon application of a
|
242
|
+
very small shear force.
|
243
|
+
:param plastic_limit: Water content at which plastic deformation
|
244
|
+
can be initiated (%). It is also the
|
245
|
+
minimum water content at which soil can be
|
246
|
+
rolled into a thread 3mm thick (molded
|
247
|
+
without breaking).
|
119
248
|
"""
|
120
|
-
if liquid_limit < plastic_limit:
|
121
|
-
raise ValueError("liquid_limit cannot be less than plastic_limit")
|
122
|
-
|
123
249
|
self.liquid_limit = liquid_limit
|
124
250
|
self.plastic_limit = plastic_limit
|
125
251
|
|
126
252
|
@property
|
127
253
|
def liquid_limit(self) -> float:
|
128
|
-
"""
|
254
|
+
"""
|
255
|
+
Water content beyond which soils flows under their own weight (%).
|
256
|
+
"""
|
129
257
|
return self._liquid_limit
|
130
258
|
|
131
259
|
@liquid_limit.setter
|
132
|
-
@
|
133
|
-
def liquid_limit(self, val: float)
|
260
|
+
@validate_func_args
|
261
|
+
def liquid_limit(self, val: Annotated[float, MustBeNonNegative]):
|
134
262
|
self._liquid_limit = val
|
135
263
|
|
136
264
|
@property
|
137
265
|
def plastic_limit(self) -> float:
|
138
|
-
"""
|
266
|
+
"""
|
267
|
+
Water content at which plastic deformation can be initiated (%).
|
268
|
+
"""
|
139
269
|
return self._plastic_limit
|
140
270
|
|
141
271
|
@plastic_limit.setter
|
142
|
-
@
|
143
|
-
def plastic_limit(self, val: float)
|
272
|
+
@validate_func_args
|
273
|
+
def plastic_limit(self, val: Annotated[float, MustBeNonNegative]):
|
274
|
+
if self.liquid_limit < val:
|
275
|
+
msg = (
|
276
|
+
f"plastic_limit: {val} cannot be greater than "
|
277
|
+
f"liquid_limit: {self.liquid_limit}"
|
278
|
+
)
|
279
|
+
raise ValueError(msg)
|
280
|
+
|
144
281
|
self._plastic_limit = val
|
145
282
|
|
146
283
|
@property
|
147
284
|
@round_(2)
|
148
285
|
def plasticity_index(self) -> float:
|
149
|
-
"""Plasticity index (PI) is the range of water content over which
|
150
|
-
soil remains in the plastic state.
|
286
|
+
"""Plasticity index (PI) is the range of water content over which
|
287
|
+
the soil remains in the plastic state.
|
151
288
|
|
152
289
|
It is also the numerical difference between the liquid limit and
|
153
290
|
plastic limit of the soil.
|
154
291
|
|
155
|
-
|
156
|
-
|
157
|
-
.. math:: PI = LL - PL
|
292
|
+
$$PI = LL - PL$$
|
158
293
|
"""
|
159
294
|
return self.liquid_limit - self.plastic_limit
|
160
295
|
|
@@ -168,8 +303,8 @@ class AtterbergLimits:
|
|
168
303
|
return self.plasticity_index > self.A_LINE
|
169
304
|
|
170
305
|
def limit_plot_in_hatched_zone(self) -> bool:
|
171
|
-
"""Checks if soil sample plot in the hatched zone on the
|
172
|
-
chart.
|
306
|
+
"""Checks if soil sample plot in the hatched zone on the
|
307
|
+
atterberg chart.
|
173
308
|
"""
|
174
309
|
return 4 <= self.plasticity_index <= 7 and 10 < self.liquid_limit < 30
|
175
310
|
|
@@ -177,17 +312,16 @@ class AtterbergLimits:
|
|
177
312
|
def liquidity_index(self, nmc: float) -> float:
|
178
313
|
r"""Return the liquidity index of the soil.
|
179
314
|
|
180
|
-
|
181
|
-
content`` to its ``liquid limit``. When the soil is at the plastic
|
182
|
-
limit its liquidity index is zero. Negative values of the liquidity
|
183
|
-
index indicate that the soil is in a hard (desiccated) state. It is
|
184
|
-
also known as Water-Plasticity ratio.
|
185
|
-
|
186
|
-
:param float nmc: Moisture contents of the soil in natural condition.
|
315
|
+
$$I_l = \dfrac{w - PL}{PI} \cdot 100$$
|
187
316
|
|
188
|
-
|
317
|
+
Liquidity index of a soil indicates the nearness of its
|
318
|
+
`natural water content` to its `liquid limit`. When the soil
|
319
|
+
is at the plastic limit its liquidity index is zero. Negative
|
320
|
+
values of the liquidity index indicate that the soil is in a
|
321
|
+
hard (desiccated) state. It is also known as Water-Plasticity
|
322
|
+
ratio.
|
189
323
|
|
190
|
-
|
324
|
+
:param nmc: Moisture contents of the soil in natural condition.
|
191
325
|
"""
|
192
326
|
return ((nmc - self.plastic_limit) / self.plasticity_index) * 100.0
|
193
327
|
|
@@ -195,22 +329,21 @@ class AtterbergLimits:
|
|
195
329
|
def consistency_index(self, nmc: float) -> float:
|
196
330
|
r"""Return the consistency index of the soil.
|
197
331
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
.. math:: I_c = \dfrac{LL - w}{PI} \cdot 100
|
332
|
+
$$I_c = \dfrac{LL - w}{PI} \cdot 100$$
|
333
|
+
|
334
|
+
Consistency index indicates the consistency (firmness) of soil.
|
335
|
+
It shows the nearness of the ``natural water content`` of the
|
336
|
+
soil to its `plastic limit`. When the soil is at the liquid
|
337
|
+
limit, the consistency index is zero. The soil at consistency
|
338
|
+
index of zero will be extremely soft and has negligible shear
|
339
|
+
strength. A soil at a water content equal to the plastic limit
|
340
|
+
has consistency index of 100% indicating that the soil is
|
341
|
+
relatively firm. A consistency index of greater than 100% shows
|
342
|
+
the soil is relatively strong (semi-solid state). A negative
|
343
|
+
value indicate the soil is in the liquid state. It is also known
|
344
|
+
as Relative Consistency.
|
345
|
+
|
346
|
+
:param nmc: Moisture contents of the soil in natural condition.
|
214
347
|
"""
|
215
348
|
return ((self.liquid_limit - nmc) / self.plasticity_index) * 100.0
|
216
349
|
|
@@ -221,8 +354,7 @@ class _SizeDistribution:
|
|
221
354
|
Features obtained from the Particle Size Distribution graph.
|
222
355
|
"""
|
223
356
|
|
224
|
-
def __init__(self, d_10: float = 0.0,
|
225
|
-
d_30: float = 0.0,
|
357
|
+
def __init__(self, d_10: float = 0.0, d_30: float = 0.0,
|
226
358
|
d_60: float = 0.0):
|
227
359
|
self.d_10 = d_10
|
228
360
|
self.d_30 = d_30
|
@@ -240,12 +372,10 @@ class _SizeDistribution:
|
|
240
372
|
return self.d_60 / self.d_10
|
241
373
|
|
242
374
|
def grade(self, coarse_soil: USCSSymbol) -> USCSSymbol:
|
243
|
-
"""Grade of soil sample. Soil grade can either be well graded or
|
244
|
-
graded.
|
375
|
+
"""Grade of soil sample. Soil grade can either be well graded or
|
376
|
+
poorly graded.
|
245
377
|
|
246
|
-
:param coarse_soil: Coarse fraction of the soil sample.
|
247
|
-
are :py:enum:mem:`~USCSSymbol.GRAVEL` and
|
248
|
-
:py:enum:mem:`~USCSSymbol.SAND`.
|
378
|
+
:param coarse_soil: Coarse fraction of the soil sample.
|
249
379
|
"""
|
250
380
|
if coarse_soil is USCSSymbol.GRAVEL:
|
251
381
|
if 1 < self.coeff_of_curvature < 3 and self.coeff_of_uniformity >= 4:
|
@@ -263,27 +393,26 @@ class _SizeDistribution:
|
|
263
393
|
|
264
394
|
|
265
395
|
class PSD:
|
266
|
-
"""Quantitative proportions by mass of various sizes of particles
|
267
|
-
in a soil.
|
396
|
+
"""Quantitative proportions by mass of various sizes of particles
|
397
|
+
present in a soil.
|
268
398
|
"""
|
269
399
|
|
270
|
-
def __init__(
|
271
|
-
|
400
|
+
def __init__(
|
401
|
+
self,
|
402
|
+
fines: float,
|
403
|
+
sand: float,
|
404
|
+
d_10: float = 0,
|
405
|
+
d_30: float = 0,
|
406
|
+
d_60: float = 0,
|
407
|
+
):
|
272
408
|
"""
|
273
409
|
:param fines: Percentage of fines in soil sample (%) i.e. The
|
274
|
-
percentage of soil sample passing through No. 200
|
275
|
-
(0.075mm).
|
276
|
-
:type fines: float
|
277
|
-
|
410
|
+
percentage of soil sample passing through No. 200
|
411
|
+
sieve (0.075mm).
|
278
412
|
:param sand: Percentage of sand in soil sample (%).
|
279
|
-
:type sand: float
|
280
|
-
|
281
413
|
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
282
|
-
:type d_10: float
|
283
414
|
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
284
|
-
:type d_30: float
|
285
415
|
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
286
|
-
:type d_60: float
|
287
416
|
"""
|
288
417
|
self.fines = fines
|
289
418
|
self.sand = sand
|
@@ -306,11 +435,9 @@ class PSD:
|
|
306
435
|
def coeff_of_curvature(self) -> float:
|
307
436
|
r"""Coefficient of curvature of soil sample.
|
308
437
|
|
309
|
-
|
310
|
-
|
311
|
-
.. math:: C_c = \dfrac{D^2_{30}}{D_{60} \cdot D_{10}}
|
438
|
+
$$C_c = \dfrac{D^2_{30}}{D_{60} \cdot D_{10}}$$
|
312
439
|
|
313
|
-
For the soil to be well graded, the value of
|
440
|
+
For the soil to be well graded, the value of $C_c$ must be
|
314
441
|
between 1 and 3.
|
315
442
|
"""
|
316
443
|
return self.size_dist.coeff_of_curvature
|
@@ -320,15 +447,14 @@ class PSD:
|
|
320
447
|
def coeff_of_uniformity(self) -> float:
|
321
448
|
r"""Coefficient of uniformity of soil sample.
|
322
449
|
|
323
|
-
|
450
|
+
$$C_u = \dfrac{D_{60}}{D_{10}}$$
|
324
451
|
|
325
|
-
|
452
|
+
$C_u$ value greater than 4 to 6 classifies the soil as well
|
453
|
+
graded for gravels and sands respectively. When $C_u$ is less
|
454
|
+
than 4, it is classified as poorly graded or uniformly graded
|
455
|
+
soil.
|
326
456
|
|
327
|
-
|
328
|
-
graded for gravels and sands respectively. When :math:`C_u` is less
|
329
|
-
than 4, it is classified as poorly graded or uniformly graded soil.
|
330
|
-
|
331
|
-
Higher values of :math:`C_u` indicates that the soil mass consists of
|
457
|
+
Higher values of $C_u$ indicates that the soil mass consists of
|
332
458
|
soil particles with different size ranges.
|
333
459
|
"""
|
334
460
|
return self.size_dist.coeff_of_uniformity
|
@@ -338,70 +464,64 @@ class PSD:
|
|
338
464
|
return any(self.size_dist)
|
339
465
|
|
340
466
|
def grade(self) -> USCSSymbol:
|
341
|
-
r"""Return the grade of the soil sample, either well graded or
|
342
|
-
graded.
|
467
|
+
r"""Return the grade of the soil sample, either well graded or
|
468
|
+
poorly graded.
|
343
469
|
|
344
470
|
Conditions for a well-graded soil:
|
345
471
|
|
346
|
-
|
347
|
-
|
348
|
-
- :math:`1 \lt C_c \lt 3` and :math:`C_u \ge 4` (for gravels)
|
349
|
-
- :math:`1 \lt C_c \lt 3` and :math:`C_u \ge 6` (for sands)
|
472
|
+
- $1 \lt C_c \lt 3$ and $C_u \ge 4$ (for gravels)
|
473
|
+
- $1 \lt C_c \lt 3$ and $C_u \ge 6$ (for sands)
|
350
474
|
"""
|
351
475
|
return self.size_dist.grade(coarse_soil=self.coarse_material_type)
|
352
476
|
|
353
477
|
|
354
|
-
|
478
|
+
@dataclass
|
479
|
+
class AASHTOResult:
|
355
480
|
symbol: str
|
481
|
+
symbol_no_group_idx: str
|
356
482
|
description: str
|
483
|
+
group_index: str
|
357
484
|
|
358
485
|
|
359
486
|
class AASHTO:
|
360
|
-
r"""American Association of State Highway and Transportation
|
361
|
-
(AASHTO) classification system.
|
487
|
+
r"""American Association of State Highway and Transportation
|
488
|
+
Officials (AASHTO) classification system.
|
362
489
|
|
363
490
|
The AASHTO classification system is useful for classifying soils for
|
364
|
-
highways. It categorizes soils for highways based on particle size
|
365
|
-
and plasticity characteristics. It classifies both
|
366
|
-
fine-grained soils into eight main groups (A1-A7)
|
367
|
-
a separate category (A8) for organic
|
368
|
-
|
369
|
-
- ``A1 ~ A3`` (Granular Materials) :math:`\le` 35% pass No. 200 sieve
|
370
|
-
- ``A4 ~ A7`` (Silt-clay Materials) :math:`\ge` 36% pass No. 200 sieve
|
371
|
-
- ``A8`` (Organic Materials)
|
491
|
+
highways. It categorizes soils for highways based on particle size
|
492
|
+
analysis and plasticity characteristics. It classifies both
|
493
|
+
coarse-grained and fine-grained soils into eight main groups (A1-A7)
|
494
|
+
with subgroups, along with a separate category (A8) for organic
|
495
|
+
soils.
|
372
496
|
|
373
|
-
|
497
|
+
- `A1 ~ A3` (Granular Materials) $\le$ 35% pass No. 200 sieve
|
498
|
+
- `A4 ~ A7` (Silt-clay Materials) $\ge$ 36% pass No. 200 sieve
|
499
|
+
- `A8` (Organic Materials)
|
374
500
|
|
375
|
-
|
501
|
+
The Group Index `(GI)` is used to further evaluate soils within a
|
502
|
+
group.
|
376
503
|
|
377
|
-
|
378
|
-
soil has been classified as per AASHTO system.
|
504
|
+
!!! note
|
379
505
|
|
380
|
-
|
506
|
+
The `GI` must be mentioned even when it is zero, to indicate
|
507
|
+
that the soil has been classified as per AASHTO system.
|
381
508
|
|
382
|
-
.. math::
|
383
509
|
|
384
|
-
|
510
|
+
$$
|
511
|
+
GI = (F_{200} - 35)[0.2 + 0.005(LL - 40)] + 0.01(F_{200} - 15)(PI - 10)
|
512
|
+
$$
|
385
513
|
"""
|
386
514
|
|
387
|
-
def __init__(self, atterberg_limits: AtterbergLimits,
|
388
|
-
fines: float, add_group_idx: bool = True):
|
515
|
+
def __init__(self, atterberg_limits: AtterbergLimits, fines: float):
|
389
516
|
"""
|
390
517
|
:param atterberg_limits: Atterberg limits of soil sample.
|
391
|
-
:type atterberg_limits: AtterbergLimits
|
392
518
|
|
393
|
-
:param fines: Percentage of fines in soil sample (%) i.e. The
|
394
|
-
of soil sample passing through No. 200
|
395
|
-
|
396
|
-
|
397
|
-
:param add_group_idx: Used to indicate whether the group index should
|
398
|
-
be added to the classification or not, defaults
|
399
|
-
to True.
|
400
|
-
:type add_group_idx: bool, optional
|
519
|
+
:param fines: Percentage of fines in soil sample (%) i.e. The
|
520
|
+
percentage of soil sample passing through No. 200
|
521
|
+
sieve (0.075mm).
|
401
522
|
"""
|
402
523
|
self.atterberg_limits = atterberg_limits
|
403
524
|
self.fines = fines
|
404
|
-
self.add_group_idx = add_group_idx
|
405
525
|
|
406
526
|
@property
|
407
527
|
def fines(self) -> float:
|
@@ -409,35 +529,38 @@ class AASHTO:
|
|
409
529
|
return self._fines
|
410
530
|
|
411
531
|
@fines.setter
|
412
|
-
@
|
413
|
-
def fines(self, val: float)
|
532
|
+
@validate_func_args
|
533
|
+
def fines(self, val: Annotated[float, MustBeNonNegative]):
|
414
534
|
self._fines = val
|
415
535
|
|
416
536
|
@round_(ndigits=0)
|
417
537
|
def group_index(self) -> float:
|
418
538
|
"""Return the Group Index (GI) of the soil sample."""
|
419
|
-
|
420
539
|
liquid_lmt = self.atterberg_limits.liquid_limit
|
421
540
|
plasticity_idx = self.atterberg_limits.plasticity_index
|
422
541
|
fines = self.fines
|
423
542
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
543
|
+
x_1 = 1.0 if (x_0 := fines - 35.0) < 0.0 else min(x_0, 40.0)
|
544
|
+
x_2 = 1.0 if (x_0 := liquid_lmt - 40.0) < 0.0 else min(x_0, 20.0)
|
545
|
+
x_3 = 1.0 if (x_0 := fines - 15.0) < 0.0 else min(x_0, 40.0)
|
546
|
+
x_4 = 1.0 if (x_0 := plasticity_idx - 10.0) < 0.0 else min(x_0, 20.0)
|
428
547
|
|
429
|
-
return
|
548
|
+
return x_1 * (0.2 + 0.005 * x_2) + 0.01 * x_3 * x_4
|
430
549
|
|
431
|
-
def classify(self) ->
|
550
|
+
def classify(self) -> AASHTOResult:
|
432
551
|
"""Return the AASHTO classification of the soil."""
|
433
552
|
soil_clf = self._classify()
|
434
553
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
symbol = f"{symbol}({self.group_index():.0f})"
|
554
|
+
symbol_no_grp_idx, description = soil_clf.symbol, soil_clf.description
|
555
|
+
group_idx = f"{self.group_index():.0f}"
|
556
|
+
symbol = f"{symbol_no_grp_idx}({group_idx})"
|
439
557
|
|
440
|
-
return
|
558
|
+
return AASHTOResult(
|
559
|
+
symbol=symbol,
|
560
|
+
symbol_no_group_idx=symbol_no_grp_idx,
|
561
|
+
description=description,
|
562
|
+
group_index=group_idx,
|
563
|
+
)
|
441
564
|
|
442
565
|
def _classify(self) -> AASHTOSymbol:
|
443
566
|
# Silts A4-A7
|
@@ -498,46 +621,52 @@ class AASHTO:
|
|
498
621
|
return soil_clf
|
499
622
|
|
500
623
|
|
624
|
+
@dataclass
|
625
|
+
class USCSResult:
|
626
|
+
symbol: str
|
627
|
+
description: str
|
628
|
+
|
629
|
+
|
501
630
|
class USCS:
|
502
631
|
"""Unified Soil Classification System (USCS).
|
503
632
|
|
504
|
-
The Unified Soil Classification System, initially developed by
|
505
|
-
in 1948 and later modified in 1952, is widely utilized in
|
506
|
-
projects involving soils. It is the most popular system
|
507
|
-
classification and is similar to Casagrande's
|
508
|
-
system relies on particle size analysis
|
509
|
-
classification.
|
633
|
+
The Unified Soil Classification System, initially developed by
|
634
|
+
Casagrande in 1948 and later modified in 1952, is widely utilized in
|
635
|
+
engineering projects involving soils. It is the most popular system
|
636
|
+
for soil classification and is similar to Casagrande's
|
637
|
+
Classification System. The system relies on particle size analysis
|
638
|
+
and atterberg limits for classification.
|
510
639
|
|
511
640
|
In this system, soils are first classified into two categories:
|
512
641
|
|
513
642
|
- Coarse grained soils: If more than 50% of the soils is retained on
|
514
643
|
No. 200 (0.075 mm) sieve, it is designated as coarse-grained soil.
|
515
644
|
|
516
|
-
- Fine grained soils: If more than 50% of the soil passes through
|
517
|
-
sieve, it is designated as fine-grained soil.
|
645
|
+
- Fine grained soils: If more than 50% of the soil passes through
|
646
|
+
No. 200 sieve, it is designated as fine-grained soil.
|
518
647
|
|
519
|
-
Highly Organic soils are identified by visual inspection. These
|
520
|
-
termed as Peat
|
648
|
+
Highly Organic soils are identified by visual inspection. These
|
649
|
+
soils are termed as Peat ($P_t$).
|
521
650
|
"""
|
522
651
|
|
523
|
-
def __init__(
|
524
|
-
|
652
|
+
def __init__(
|
653
|
+
self,
|
654
|
+
atterberg_limits: AtterbergLimits,
|
655
|
+
psd: PSD,
|
656
|
+
organic=False,
|
657
|
+
):
|
525
658
|
"""
|
526
659
|
:param atterberg_limits: Atterberg limits of the soil.
|
527
|
-
:type atterberg_limits: AtterbergLimits
|
528
660
|
|
529
661
|
:param psd: Particle size distribution of the soil.
|
530
|
-
:type psd: PSD
|
531
662
|
|
532
|
-
:param organic: Indicates whether soil is organic or not
|
533
|
-
False.
|
534
|
-
:type organic: bool, optional
|
663
|
+
:param organic: Indicates whether soil is organic or not.
|
535
664
|
"""
|
536
665
|
self.atterberg_limits = atterberg_limits
|
537
666
|
self.psd = psd
|
538
667
|
self.organic = organic
|
539
668
|
|
540
|
-
def classify(self)
|
669
|
+
def classify(self):
|
541
670
|
"""Return the USCS classification of the soil."""
|
542
671
|
soil_clf = self._classify()
|
543
672
|
|
@@ -546,15 +675,17 @@ class USCS:
|
|
546
675
|
soil_clf = USCSSymbol[soil_clf]
|
547
676
|
|
548
677
|
if isinstance(soil_clf, USCSSymbol):
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
678
|
+
soil_clf = USCSResult(
|
679
|
+
symbol=soil_clf.symbol, description=soil_clf.description
|
680
|
+
)
|
681
|
+
else:
|
682
|
+
# Handling tuple or list case for dual classification
|
683
|
+
first_clf, second_clf = map(lambda clf: USCSSymbol[clf], soil_clf)
|
684
|
+
comb_symbol = f"{first_clf.symbol},{second_clf.symbol}"
|
685
|
+
comb_desc = f"{first_clf.description},{second_clf.description}"
|
686
|
+
soil_clf = USCSResult(symbol=comb_symbol, description=comb_desc)
|
556
687
|
|
557
|
-
return
|
688
|
+
return soil_clf
|
558
689
|
|
559
690
|
def _classify(self) -> USCSSymbol | str | Sequence[str]:
|
560
691
|
# Fine-grained, Run Atterberg
|
@@ -573,21 +704,17 @@ class USCS:
|
|
573
704
|
# Above A-line and PI > 7
|
574
705
|
if self.atterberg_limits.above_A_LINE() and plasticity_idx > 7.0:
|
575
706
|
soil_clf = USCSSymbol.CL
|
576
|
-
|
577
707
|
# Limit plot in hatched area on plasticity chart
|
578
708
|
elif self.atterberg_limits.limit_plot_in_hatched_zone():
|
579
709
|
soil_clf = USCSSymbol.ML_CL
|
580
|
-
|
581
710
|
# Below A-line or PI < 4
|
582
711
|
else:
|
583
712
|
soil_clf = USCSSymbol.OL if self.organic else USCSSymbol.ML
|
584
|
-
|
585
713
|
# High LL
|
586
714
|
else:
|
587
715
|
# Above A-Line
|
588
716
|
if self.atterberg_limits.above_A_LINE():
|
589
717
|
soil_clf = USCSSymbol.CH
|
590
|
-
|
591
718
|
# Below A-Line
|
592
719
|
else:
|
593
720
|
soil_clf = USCSSymbol.OH if self.organic else USCSSymbol.MH
|
@@ -623,11 +750,12 @@ class USCS:
|
|
623
750
|
soil_clf = self._dual_soil_classifier()
|
624
751
|
else:
|
625
752
|
fine_material_type = self.atterberg_limits.fine_material_type
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
753
|
+
soil_clf = (
|
754
|
+
f"{coarse_material_type}{USCSSymbol.WELL_GRADED}_"
|
755
|
+
f"{coarse_material_type}{fine_material_type}",
|
756
|
+
f"{coarse_material_type}{USCSSymbol.POORLY_GRADED}_"
|
757
|
+
f"{coarse_material_type}{fine_material_type}",
|
758
|
+
)
|
631
759
|
|
632
760
|
# Less than 5% pass No. 200 sieve
|
633
761
|
# Obtain Cc and Cu from grain size graph
|
@@ -636,8 +764,10 @@ class USCS:
|
|
636
764
|
soil_clf = f"{coarse_material_type}{self.psd.grade()}"
|
637
765
|
|
638
766
|
else:
|
639
|
-
soil_clf = (
|
640
|
-
|
767
|
+
soil_clf = (
|
768
|
+
f"{coarse_material_type}{USCSSymbol.WELL_GRADED}",
|
769
|
+
f"{coarse_material_type}{USCSSymbol.POORLY_GRADED}",
|
770
|
+
)
|
641
771
|
|
642
772
|
return soil_clf
|
643
773
|
|
@@ -645,104 +775,75 @@ class USCS:
|
|
645
775
|
fine_material_type = self.atterberg_limits.fine_material_type
|
646
776
|
coarse_material_type = self.psd.coarse_material_type
|
647
777
|
|
648
|
-
return (
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
@enum_repr
|
653
|
-
class ClfType(enum.StrEnum):
|
654
|
-
"""Enumeration of soil classification types."""
|
655
|
-
AASHTO = enum.auto()
|
656
|
-
USCS = enum.auto()
|
657
|
-
|
778
|
+
return (
|
779
|
+
f"{coarse_material_type}{self.psd.grade()}_"
|
780
|
+
f"{coarse_material_type}{fine_material_type}"
|
781
|
+
)
|
658
782
|
|
659
|
-
def create_soil_classifier(liquid_limit: float,
|
660
|
-
plastic_limit: float,
|
661
|
-
fines: float,
|
662
|
-
sand: Optional[float] = None,
|
663
|
-
d_10: float = 0, d_30: float = 0, d_60: float = 0,
|
664
|
-
add_group_idx: bool = True,
|
665
|
-
organic: bool = False,
|
666
|
-
clf_type: Optional[ClfType | str] = None
|
667
|
-
) -> AASHTO | USCS:
|
668
|
-
""" A factory function that encapsulates the creation of a soil classifier.
|
669
783
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
784
|
+
def create_aashto_classifier(
|
785
|
+
liquid_limit: float, plastic_limit: float, fines: float
|
786
|
+
) -> AASHTO:
|
787
|
+
"""A helper function that encapsulates the creation of a AASHTO
|
788
|
+
classifier.
|
675
789
|
|
676
|
-
:param
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
790
|
+
:param liquid_limit: Water content beyond which soils flows under
|
791
|
+
their own weight (%). It can also be defined as
|
792
|
+
the minimum moisture content at which a soil
|
793
|
+
flows upon application of a very small shear
|
794
|
+
force.
|
681
795
|
|
682
|
-
:param
|
683
|
-
|
684
|
-
|
796
|
+
:param plastic_limit: Water content at which plastic deformation can
|
797
|
+
be initiated (%). It is also the minimum water
|
798
|
+
content at which soil can be rolled into a
|
799
|
+
thread 3mm thick (molded without breaking).
|
685
800
|
|
686
|
-
:param
|
687
|
-
|
688
|
-
|
801
|
+
:param fines: Percentage of fines in soil sample (%) i.e. The
|
802
|
+
percentage of soil sample passing through No. 200
|
803
|
+
sieve (0.075mm).
|
804
|
+
"""
|
805
|
+
atterberg_limits = AtterbergLimits(liquid_limit, plastic_limit)
|
806
|
+
return AASHTO(atterberg_limits, fines)
|
807
|
+
|
808
|
+
|
809
|
+
def create_uscs_classifier(
|
810
|
+
liquid_limit: float,
|
811
|
+
plastic_limit: float,
|
812
|
+
fines: float,
|
813
|
+
sand: float,
|
814
|
+
d_10: float = 0,
|
815
|
+
d_30: float = 0,
|
816
|
+
d_60: float = 0,
|
817
|
+
organic: bool = False,
|
818
|
+
):
|
819
|
+
"""A helper function that encapsulates the creation of a USCS
|
820
|
+
classifier.
|
821
|
+
|
822
|
+
:param liquid_limit: Water content beyond which soils flows under
|
823
|
+
their own weight (%). It can also be defined as
|
824
|
+
the minimum moisture content at which a soil
|
825
|
+
flows upon application of a very small shear
|
826
|
+
force.
|
827
|
+
|
828
|
+
:param plastic_limit: Water content at which plastic deformation can
|
829
|
+
be initiated (%). It is also the minimum water
|
830
|
+
content at which soil can be rolled into a
|
831
|
+
thread 3mm thick. (molded without breaking)
|
832
|
+
|
833
|
+
:param fines: Percentage of fines in soil sample (%) i.e. The
|
834
|
+
percentage of soil sample passing through No. 200
|
835
|
+
sieve (0.075mm).
|
836
|
+
|
837
|
+
:param sand: Percentage of sand in soil sample (%).
|
689
838
|
|
690
839
|
:param d_10: Diameter at which 10% of the soil by weight is finer.
|
691
|
-
:type d_10: float, optional
|
692
840
|
|
693
841
|
:param d_30: Diameter at which 30% of the soil by weight is finer.
|
694
|
-
:type d_30: float, optional
|
695
842
|
|
696
843
|
:param d_60: Diameter at which 60% of the soil by weight is finer.
|
697
|
-
:type d_60: float, optional
|
698
|
-
|
699
|
-
:param add_group_idx: Used to indicate whether the group index should
|
700
|
-
be added to the classification or not, defaults to
|
701
|
-
True.
|
702
|
-
:type add_group_idx: bool, optional
|
703
|
-
|
704
|
-
:param organic: Indicates whether soil is organic or not, defaults to False.
|
705
|
-
:type organic: bool, optional
|
706
844
|
|
707
|
-
:param
|
708
|
-
used, defaults to None.
|
709
|
-
:type clf_type: ClfType | str
|
710
|
-
|
711
|
-
:raises ValueError: Raises ValueError if ``clf_type`` is not supported or
|
712
|
-
None
|
713
|
-
:raises ValueError: Raises ValueError if ``sand`` is not provided for
|
714
|
-
:class:`USCS` classification.
|
845
|
+
:param organic: Indicates whether soil is organic or not.
|
715
846
|
"""
|
716
|
-
|
717
|
-
param_value=clf_type,
|
718
|
-
symbol="in",
|
719
|
-
param_value_bound=list(ClfType))
|
720
|
-
|
721
|
-
if clf_type is None:
|
722
|
-
raise ValidationError(msg)
|
723
|
-
|
724
|
-
try:
|
725
|
-
clf_type = ClfType(str(clf_type).casefold())
|
726
|
-
except ValueError as e:
|
727
|
-
raise ValidationError(msg) from e
|
728
|
-
|
729
|
-
atterberg_lmts = AtterbergLimits(liquid_limit=liquid_limit,
|
730
|
-
plastic_limit=plastic_limit)
|
731
|
-
|
732
|
-
if clf_type == ClfType.AASHTO:
|
733
|
-
clf = AASHTO(atterberg_limits=atterberg_lmts,
|
734
|
-
fines=fines,
|
735
|
-
add_group_idx=add_group_idx)
|
736
|
-
return clf
|
737
|
-
|
738
|
-
# USCS classification
|
739
|
-
if not sand:
|
740
|
-
msg = ErrorMsg(param_name="sand",
|
741
|
-
param_value=sand,
|
742
|
-
msg="sand must be specified for USCS classification")
|
743
|
-
raise ValidationError(msg)
|
744
|
-
|
847
|
+
atterberg_lmts = AtterbergLimits(liquid_limit, plastic_limit)
|
745
848
|
psd = PSD(fines=fines, sand=sand, d_10=d_10, d_30=d_30, d_60=d_60)
|
746
|
-
|
747
|
-
|
748
|
-
return clf
|
849
|
+
return USCS(atterberg_limits=atterberg_lmts, psd=psd, organic=organic)
|