geolysis 0.3.0__py3-none-any.whl → 0.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
geolysis/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- from . import core
2
-
3
- __version__ = "0.3.0"
1
+ from . import foundation, soil_classifier, spt, utils
2
+
3
+ __version__ = "0.4.2"
geolysis/foundation.py ADDED
@@ -0,0 +1,326 @@
1
+ import enum
2
+ from abc import abstractmethod
3
+ from typing import Optional, Protocol, TypeVar
4
+
5
+ from geolysis import validators
6
+ from geolysis.utils import inf
7
+
8
+ __all__ = ["create_foundation", "FoundationSize", "Shape", "StripFooting",
9
+ "CircularFooting", "SquareFooting", "RectangularFooting"]
10
+
11
+ T = TypeVar("T")
12
+
13
+
14
+ class _Field:
15
+ """A field that references another field."""
16
+
17
+ def __init__(self, *, ref_attr: str, ref_obj: Optional[str] = None,
18
+ doc: Optional[str] = None):
19
+ self.ref_attr = ref_attr
20
+ self.ref_obj = ref_obj
21
+ self.__doc__ = doc
22
+
23
+ def __get__(self, obj, objtype=None) -> T:
24
+ if self.ref_obj is not None:
25
+ ref_obj = getattr(obj, self.ref_obj)
26
+ return getattr(ref_obj, self.ref_attr)
27
+ return getattr(obj, self.ref_attr)
28
+
29
+ def __set__(self, obj, value) -> None:
30
+ if self.ref_obj is not None:
31
+ ref_obj = getattr(obj, self.ref_obj)
32
+ setattr(ref_obj, self.ref_attr, value)
33
+ else:
34
+ setattr(obj, self.ref_attr, value)
35
+
36
+ def __set_name__(self, objtype, property_name) -> None:
37
+ self.property_name = property_name
38
+
39
+
40
+ class Shape(enum.StrEnum):
41
+ """Enumeration of foundation shapes."""
42
+ STRIP = enum.auto()
43
+ CIRCLE = enum.auto()
44
+ SQUARE = enum.auto()
45
+ RECTANGLE = enum.auto()
46
+
47
+
48
+ class FootingSize(Protocol):
49
+ @property
50
+ @abstractmethod
51
+ def width(self) -> float: ...
52
+
53
+ @property
54
+ @abstractmethod
55
+ def length(self) -> float: ...
56
+
57
+ @property
58
+ @abstractmethod
59
+ def shape(self) -> Shape: ...
60
+
61
+
62
+ class StripFooting:
63
+ """A class representation of strip footing."""
64
+
65
+ def __init__(self, width: float, length: float = inf) -> None:
66
+ """
67
+ :param width: Width of foundation footing. (m)
68
+ :type width: float
69
+
70
+ :param float length: Length of foundation footing, defaults to inf. (m)
71
+ :type length: float
72
+ """
73
+ self.width = width
74
+ self.length = length
75
+ self._shape = Shape.STRIP
76
+
77
+ @property
78
+ def width(self) -> float:
79
+ return self._width
80
+
81
+ @width.setter
82
+ @validators.gt(0.0)
83
+ def width(self, val):
84
+ self._width = val
85
+
86
+ @property
87
+ def length(self) -> float:
88
+ return self._length
89
+
90
+ @length.setter
91
+ @validators.ge(0.0)
92
+ def length(self, val):
93
+ self._length = val
94
+
95
+ @property
96
+ def shape(self) -> Shape:
97
+ return self._shape
98
+
99
+
100
+ class CircularFooting:
101
+ """A class representation of circular footing.
102
+
103
+ .. note::
104
+
105
+ The ``width`` and ``length`` properties refer to the diameter of the
106
+ circular footing. This is to make it compatible with the protocol
107
+ square and rectangular footing follow.
108
+ """
109
+
110
+ _doc = "Refers to the diameter of the circular footing."
111
+
112
+ width = _Field(ref_attr="diameter", doc=_doc)
113
+ length = _Field(ref_attr="diameter", doc=_doc)
114
+
115
+ del _doc
116
+
117
+ def __init__(self, diameter: float):
118
+ """
119
+ :param float diameter: Diameter of foundation footing. (m)
120
+ """
121
+ self.diameter = diameter
122
+ self._shape = Shape.CIRCLE
123
+
124
+ @property
125
+ def diameter(self) -> float:
126
+ return self._diameter
127
+
128
+ @diameter.setter
129
+ @validators.gt(0.0)
130
+ def diameter(self, val):
131
+ self._diameter = val
132
+
133
+ @property
134
+ def shape(self) -> Shape:
135
+ return self._shape
136
+
137
+
138
+ class SquareFooting:
139
+ """A class representation of square footing."""
140
+
141
+ length = _Field(ref_attr="width",
142
+ doc="Refers to the width of the square footing.")
143
+
144
+ def __init__(self, width: float):
145
+ """
146
+ :param float width: Width of foundation footing. (m)
147
+ """
148
+ self.width = width
149
+ self._shape = Shape.SQUARE
150
+
151
+ @property
152
+ def width(self):
153
+ return self._width
154
+
155
+ @width.setter
156
+ @validators.gt(0)
157
+ def width(self, val):
158
+ self._width = val
159
+
160
+ @property
161
+ def shape(self):
162
+ return self._shape
163
+
164
+
165
+ class RectangularFooting:
166
+ """A class representation of rectangular footing."""
167
+
168
+ def __init__(self, width: float, length: float):
169
+ """
170
+ :param width: Width of foundation footing. (m)
171
+ :type width: float
172
+
173
+ :param length: Length of foundation footing. (m)
174
+ :type length: float
175
+ """
176
+ self.width = width
177
+ self.length = length
178
+ self._shape = Shape.RECTANGLE
179
+
180
+ @property
181
+ def width(self) -> float:
182
+ return self._width
183
+
184
+ @width.setter
185
+ @validators.gt(0.0)
186
+ def width(self, val):
187
+ self._width = val
188
+
189
+ @property
190
+ def length(self) -> float:
191
+ return self._length
192
+
193
+ @length.setter
194
+ @validators.gt(0.0)
195
+ def length(self, val):
196
+ self._length = val
197
+
198
+ @property
199
+ def shape(self) -> Shape:
200
+ return self._shape
201
+
202
+
203
+ class FoundationSize:
204
+ """A simple class representing a foundation structure."""
205
+
206
+ width = _Field(ref_attr="width", ref_obj="footing_size",
207
+ doc="Refers to the width of foundation footing.")
208
+ length = _Field(ref_attr="length", ref_obj="footing_size",
209
+ doc="Refers to the length of foundation footing.")
210
+ footing_shape = _Field(ref_attr="shape", ref_obj="footing_size",
211
+ doc="Refers to the shape of foundation footing.")
212
+
213
+ def __init__(self, depth: float, footing_size: FootingSize,
214
+ eccentricity: float = 0.0,
215
+ ground_water_level: float = inf) -> None:
216
+ """
217
+ :param depth: Depth of foundation. (m)
218
+ :type depth: float
219
+
220
+ :param footing_size: Represents the size of the foundation footing.
221
+ :type footing_size: FootingSize
222
+
223
+ :param eccentricity: The deviation of the foundation load from the
224
+ center of gravity of the foundation footing,
225
+ defaults to 0.0. This means that the foundation
226
+ load aligns with the center of gravity of the
227
+ foundation footing. (m)
228
+ :type eccentricity: float, optional
229
+
230
+ :param ground_water_level: Depth of the water below ground level (m),
231
+ defaults to inf.
232
+ :type ground_water_level: float, optional
233
+ """
234
+ self.depth = depth
235
+ self.footing_size = footing_size
236
+ self.eccentricity = eccentricity
237
+ self.ground_water_level = ground_water_level
238
+
239
+ @property
240
+ def depth(self) -> float:
241
+ return self._depth
242
+
243
+ @depth.setter
244
+ @validators.gt(0.0)
245
+ def depth(self, val: float) -> None:
246
+ self._depth = val
247
+
248
+ @property
249
+ def eccentricity(self) -> float:
250
+ return self._eccentricity
251
+
252
+ @eccentricity.setter
253
+ @validators.ge(0.0)
254
+ def eccentricity(self, val: float) -> None:
255
+ self._eccentricity = val
256
+
257
+ @property
258
+ def ground_water_level(self) -> float:
259
+ return self._ground_water_level
260
+
261
+ @ground_water_level.setter
262
+ @validators.ge(0.0)
263
+ def ground_water_level(self, val: float) -> None:
264
+ self._ground_water_level = val
265
+
266
+ @property
267
+ def effective_width(self) -> float:
268
+ """Returns the effective width of the foundation footing."""
269
+ return self.width - 2.0 * self.eccentricity
270
+
271
+
272
+ def create_foundation(depth: float, width: float,
273
+ length: Optional[float] = None,
274
+ eccentricity: float = 0.0,
275
+ ground_water_level: float = inf,
276
+ shape: Shape | str = Shape.SQUARE) -> FoundationSize:
277
+ """A factory function that encapsulate the creation of a foundation.
278
+
279
+ :param depth: Depth of foundation. (m)
280
+ :type depth: float
281
+
282
+ :param width: Width of foundation footing. In the case of a circular
283
+ footing, it refers to the footing diameter. (m)
284
+ :type width: float
285
+
286
+ :param length: Length of foundation footing, defaults to None. (m)
287
+ :type length: float, optional
288
+
289
+ :param eccentricity: The deviation of the foundation load from the
290
+ center of gravity of the foundation footing,
291
+ defaults to 0.0. This means that the foundation
292
+ load aligns with the center of gravity of the
293
+ foundation footing. (m)
294
+ :type eccentricity: float, optional
295
+
296
+ :param ground_water_level: Depth of the water below ground level (m),
297
+ defaults to inf.
298
+ :type ground_water_level: float, optional
299
+
300
+ :param shape: Shape of foundation footing, defaults to :class:`Shape.SQUARE`
301
+ :type shape: Shape | str
302
+
303
+ :raises ValueError: Raised when length is not provided for a rectangular
304
+ footing.
305
+ :raises TypeError: Raised if an invalid footing shape is provided.
306
+ """
307
+
308
+ if isinstance(shape, str):
309
+ shape = Shape(shape.casefold())
310
+
311
+ if shape is Shape.STRIP:
312
+ footing_size = StripFooting(width=width)
313
+ elif shape is Shape.SQUARE:
314
+ footing_size = SquareFooting(width=width)
315
+ elif shape is Shape.CIRCLE:
316
+ footing_size = CircularFooting(diameter=width)
317
+ elif shape is Shape.RECTANGLE:
318
+ if not length:
319
+ raise ValueError("Length of footing must be provided.")
320
+ footing_size = RectangularFooting(width=width, length=length)
321
+ else:
322
+ raise TypeError(f"shape {shape} is not supported.")
323
+
324
+ return FoundationSize(depth=depth, eccentricity=eccentricity,
325
+ ground_water_level=ground_water_level,
326
+ footing_size=footing_size)