weac 2.6.4__py3-none-any.whl → 3.0.1__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.
- weac/__init__.py +2 -14
- weac/analysis/__init__.py +23 -0
- weac/analysis/analyzer.py +790 -0
- weac/analysis/criteria_evaluator.py +1169 -0
- weac/analysis/plotter.py +1922 -0
- weac/components/__init__.py +21 -0
- weac/components/config.py +33 -0
- weac/components/criteria_config.py +86 -0
- weac/components/layer.py +284 -0
- weac/components/model_input.py +103 -0
- weac/components/scenario_config.py +72 -0
- weac/components/segment.py +31 -0
- weac/constants.py +37 -0
- weac/core/__init__.py +10 -0
- weac/core/eigensystem.py +405 -0
- weac/core/field_quantities.py +273 -0
- weac/core/scenario.py +200 -0
- weac/core/slab.py +149 -0
- weac/core/slab_touchdown.py +363 -0
- weac/core/system_model.py +413 -0
- weac/core/unknown_constants_solver.py +444 -0
- weac/logging_config.py +39 -0
- weac/utils/__init__.py +0 -0
- weac/utils/geldsetzer.py +166 -0
- weac/utils/misc.py +127 -0
- weac/utils/snow_types.py +82 -0
- weac/utils/snowpilot_parser.py +332 -0
- {weac-2.6.4.dist-info → weac-3.0.1.dist-info}/METADATA +196 -64
- weac-3.0.1.dist-info/RECORD +32 -0
- weac-3.0.1.dist-info/licenses/LICENSE +21 -0
- weac/eigensystem.py +0 -658
- weac/inverse.py +0 -51
- weac/layered.py +0 -64
- weac/mixins.py +0 -2083
- weac/plot.py +0 -675
- weac/tools.py +0 -334
- weac-2.6.4.dist-info/RECORD +0 -12
- weac-2.6.4.dist-info/licenses/LICENSE +0 -24
- {weac-2.6.4.dist-info → weac-3.0.1.dist-info}/WHEEL +0 -0
- {weac-2.6.4.dist-info → weac-3.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module handles the calculation of slab touchdown events.
|
|
3
|
+
Handling the touchdown situation in a PST.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Literal, Optional
|
|
8
|
+
|
|
9
|
+
from scipy.optimize import brentq
|
|
10
|
+
|
|
11
|
+
from weac.components.layer import WeakLayer
|
|
12
|
+
from weac.components.scenario_config import ScenarioConfig
|
|
13
|
+
from weac.components.segment import Segment
|
|
14
|
+
from weac.constants import STIFFNESS_COLLAPSE_FACTOR
|
|
15
|
+
from weac.core.eigensystem import Eigensystem
|
|
16
|
+
from weac.core.field_quantities import FieldQuantities
|
|
17
|
+
from weac.core.scenario import Scenario
|
|
18
|
+
from weac.core.unknown_constants_solver import UnknownConstantsSolver
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SlabTouchdown: # pylint: disable=too-many-instance-attributes,too-few-public-methods
|
|
24
|
+
"""
|
|
25
|
+
Handling the touchdown situation in a PST.
|
|
26
|
+
Calculations follow paper Rosendahl et al. (2024)
|
|
27
|
+
`The effect of slab touchdown on anticrack arrest in propagation saw tests`
|
|
28
|
+
|
|
29
|
+
Types of Touchdown:
|
|
30
|
+
`A_free_hanging` : Slab is free hanging (not in contact with the collapsed weak layer)
|
|
31
|
+
touchdown_distance `=` cut_length -> the unsupported segment (touchdown_distance)
|
|
32
|
+
equals the cut length
|
|
33
|
+
`B_point_contact` : End of slab is in contact with the collapsed weak layer
|
|
34
|
+
touchdown_distance `=` cut_length -> the unsupported segment (touchdown_distance)
|
|
35
|
+
equals the cut length
|
|
36
|
+
`C_in_contact` : more of the slab is in contact with the collapsed weak layer
|
|
37
|
+
touchdown_distance `<` cut_length -> the unsupported segment (touchdown_distance)
|
|
38
|
+
is strictly smaller than the cut length
|
|
39
|
+
|
|
40
|
+
The Module does:
|
|
41
|
+
1. Calculation of Zones of modes `[A_free_hanging, B_point_contact, C_in_contact]`::
|
|
42
|
+
|
|
43
|
+
|+++++++++++++++++++|-------A-------|-------B-------|--------C-------- [...]
|
|
44
|
+
| supported segment | free-hanging | point contact | in contact
|
|
45
|
+
0 `l_AB` `l_BC`
|
|
46
|
+
through calculation of boundary touchdown_distance `l_AB` and `l_BC`
|
|
47
|
+
|
|
48
|
+
Parameters:
|
|
49
|
+
-----------
|
|
50
|
+
scenario: `Scenario`
|
|
51
|
+
eigensystem: `Eigensystem`
|
|
52
|
+
|
|
53
|
+
Attributes:
|
|
54
|
+
-----------
|
|
55
|
+
l_AB : float
|
|
56
|
+
Length of the crack for transition of stage A to stage B [mm]
|
|
57
|
+
l_BC : float
|
|
58
|
+
Length of the crack for transition of stage B to stage C [mm]
|
|
59
|
+
touchdown_mode : Literal["A_free_hanging", "B_point_contact", "C_in_contact"]
|
|
60
|
+
Type of touchdown mode
|
|
61
|
+
touchdown_distance : float
|
|
62
|
+
Length of the touchdown segment [mm]
|
|
63
|
+
collapsed_weak_layer_kR : Optional[float]
|
|
64
|
+
Rotational spring stiffness of the collapsed weak layer segment
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
# Inputs
|
|
68
|
+
scenario: Scenario
|
|
69
|
+
eigensystem: Eigensystem
|
|
70
|
+
|
|
71
|
+
# Attributes
|
|
72
|
+
collapsed_weak_layer: WeakLayer # WeakLayer with modified stiffness
|
|
73
|
+
collapsed_eigensystem: Eigensystem
|
|
74
|
+
straight_scenario: Scenario
|
|
75
|
+
l_AB: float
|
|
76
|
+
l_BC: float
|
|
77
|
+
touchdown_mode: Literal[
|
|
78
|
+
"A_free_hanging", "B_point_contact", "C_in_contact"
|
|
79
|
+
] # Three types of contact with collapsed weak layer
|
|
80
|
+
touchdown_distance: float
|
|
81
|
+
collapsed_weak_layer_kR: Optional[float] = None
|
|
82
|
+
|
|
83
|
+
def __init__(self, scenario: Scenario, eigensystem: Eigensystem):
|
|
84
|
+
self.scenario = scenario
|
|
85
|
+
self.eigensystem = eigensystem
|
|
86
|
+
|
|
87
|
+
# Create a new scenario config with phi=0 (flat slab) while preserving other settings
|
|
88
|
+
self.flat_config = ScenarioConfig(
|
|
89
|
+
phi=0.0, # Flat slab for collapsed scenario
|
|
90
|
+
system_type=self.scenario.scenario_config.system_type,
|
|
91
|
+
cut_length=self.scenario.scenario_config.cut_length,
|
|
92
|
+
stiffness_ratio=self.scenario.scenario_config.stiffness_ratio,
|
|
93
|
+
surface_load=self.scenario.scenario_config.surface_load,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
self.collapsed_eigensystem = self._create_collapsed_eigensystem()
|
|
97
|
+
|
|
98
|
+
self._setup_touchdown_system()
|
|
99
|
+
|
|
100
|
+
def _setup_touchdown_system(self):
|
|
101
|
+
"""Calculate touchdown"""
|
|
102
|
+
self._calc_touchdown_mode()
|
|
103
|
+
self._calc_touchdown_distance()
|
|
104
|
+
|
|
105
|
+
def _calc_touchdown_mode(self):
|
|
106
|
+
"""Calculate touchdown-mode from thresholds"""
|
|
107
|
+
# Calculate stage transitions
|
|
108
|
+
try:
|
|
109
|
+
self.l_AB = self._calc_l_AB()
|
|
110
|
+
except ValueError:
|
|
111
|
+
self.l_AB = self.scenario.L
|
|
112
|
+
try:
|
|
113
|
+
self.l_BC = self._calc_l_BC()
|
|
114
|
+
except ValueError:
|
|
115
|
+
self.l_BC = self.scenario.L
|
|
116
|
+
# Assign stage
|
|
117
|
+
touchdown_mode = "A_free_hanging"
|
|
118
|
+
if self.scenario.cut_length <= self.l_AB:
|
|
119
|
+
touchdown_mode = "A_free_hanging"
|
|
120
|
+
elif self.l_AB < self.scenario.cut_length <= self.l_BC:
|
|
121
|
+
touchdown_mode = "B_point_contact"
|
|
122
|
+
elif self.l_BC < self.scenario.cut_length:
|
|
123
|
+
touchdown_mode = "C_in_contact"
|
|
124
|
+
self.touchdown_mode = touchdown_mode
|
|
125
|
+
|
|
126
|
+
def _calc_touchdown_distance(self):
|
|
127
|
+
"""Calculate touchdown distance"""
|
|
128
|
+
if self.touchdown_mode in ["A_free_hanging"]:
|
|
129
|
+
self.touchdown_distance = self.scenario.cut_length
|
|
130
|
+
elif self.touchdown_mode in ["B_point_contact"]:
|
|
131
|
+
self.touchdown_distance = self.scenario.cut_length
|
|
132
|
+
elif self.touchdown_mode in ["C_in_contact"]:
|
|
133
|
+
self.touchdown_distance = self._calc_touchdown_distance_in_mode_C()
|
|
134
|
+
self.collapsed_weak_layer_kR = self._calc_collapsed_weak_layer_kR()
|
|
135
|
+
|
|
136
|
+
def _calc_l_AB(self):
|
|
137
|
+
"""
|
|
138
|
+
Calc transition lengths l_AB
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
l_AB : float
|
|
143
|
+
Length of the crack for transition of stage A to stage B [mm]
|
|
144
|
+
"""
|
|
145
|
+
# Unpack variables
|
|
146
|
+
bs = -(self.eigensystem.B11**2 / self.eigensystem.A11 - self.eigensystem.D11)
|
|
147
|
+
ss = self.eigensystem.kA55
|
|
148
|
+
L = self.scenario.L
|
|
149
|
+
crack_h = self.scenario.crack_h
|
|
150
|
+
qn = self.scenario.qn
|
|
151
|
+
|
|
152
|
+
# Create polynomial expression
|
|
153
|
+
def polynomial(x: float) -> float:
|
|
154
|
+
# Spring stiffness of uncollapsed eigensystem of length L - x
|
|
155
|
+
straight_scenario = self._generate_straight_scenario(L - x)
|
|
156
|
+
kRl = self._substitute_stiffness(
|
|
157
|
+
straight_scenario, self.eigensystem, "rot"
|
|
158
|
+
) # rotational stiffness
|
|
159
|
+
kNl = self._substitute_stiffness(
|
|
160
|
+
straight_scenario, self.eigensystem, "trans"
|
|
161
|
+
) # pulling stiffness
|
|
162
|
+
c1 = 1 / (8 * bs)
|
|
163
|
+
c2 = 1 / (2 * kRl)
|
|
164
|
+
c3 = 1 / (2 * ss)
|
|
165
|
+
c4 = 1 / kNl
|
|
166
|
+
c5 = -crack_h / qn
|
|
167
|
+
return c1 * x**4 + c2 * x**3 + c3 * x**2 + c4 * x + c5
|
|
168
|
+
|
|
169
|
+
# Find root
|
|
170
|
+
l_AB = brentq(polynomial, L / 1000, 999 / 1000 * L)
|
|
171
|
+
|
|
172
|
+
return l_AB
|
|
173
|
+
|
|
174
|
+
def _calc_l_BC(self) -> float:
|
|
175
|
+
"""
|
|
176
|
+
Calc transition lengths l_BC
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
l_BC : float
|
|
181
|
+
Length of the crack for transition of stage B to stage C [mm]
|
|
182
|
+
"""
|
|
183
|
+
# Unpack variables
|
|
184
|
+
bs = -(self.eigensystem.B11**2 / self.eigensystem.A11 - self.eigensystem.D11)
|
|
185
|
+
ss = self.eigensystem.kA55
|
|
186
|
+
L = self.scenario.L
|
|
187
|
+
crack_h = self.scenario.crack_h
|
|
188
|
+
qn = self.scenario.qn
|
|
189
|
+
|
|
190
|
+
# Create polynomial function
|
|
191
|
+
def polynomial(x: float) -> float:
|
|
192
|
+
# Spring stiffness of uncollapsed eigensystem of length L - x
|
|
193
|
+
straight_scenario = self._generate_straight_scenario(L - x)
|
|
194
|
+
kRl = self._substitute_stiffness(straight_scenario, self.eigensystem, "rot")
|
|
195
|
+
kNl = self._substitute_stiffness(
|
|
196
|
+
straight_scenario, self.eigensystem, "trans"
|
|
197
|
+
)
|
|
198
|
+
c1 = ss**2 * kRl * kNl * qn
|
|
199
|
+
c2 = 6 * ss**2 * bs * kNl * qn
|
|
200
|
+
c3 = 30 * bs * ss * kRl * kNl * qn
|
|
201
|
+
c4 = 24 * bs * qn * (2 * ss**2 * kRl + 3 * bs * ss * kNl)
|
|
202
|
+
c5 = 72 * bs * (bs * qn * (ss**2 + kRl * kNl) - ss**2 * kRl * kNl * crack_h)
|
|
203
|
+
c6 = 144 * bs * ss * (bs * kRl * qn - bs * ss * kNl * crack_h)
|
|
204
|
+
c7 = -144 * bs**2 * ss * kRl * kNl * crack_h
|
|
205
|
+
return (
|
|
206
|
+
c1 * x**6 + c2 * x**5 + c3 * x**4 + c4 * x**3 + c5 * x**2 + c6 * x + c7
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# Find root
|
|
210
|
+
l_BC = brentq(polynomial, L / 1000, 999 / 1000 * L)
|
|
211
|
+
|
|
212
|
+
return l_BC
|
|
213
|
+
|
|
214
|
+
def _create_collapsed_eigensystem(self) -> Eigensystem:
|
|
215
|
+
"""
|
|
216
|
+
Create the collapsed weak layer and eigensystem with modified stiffness values.
|
|
217
|
+
This centralizes all collapsed-related logic within the SlabTouchdown class.
|
|
218
|
+
"""
|
|
219
|
+
# Create collapsed weak layer with increased stiffness
|
|
220
|
+
self.collapsed_weak_layer = self.scenario.weak_layer.model_copy(
|
|
221
|
+
update={
|
|
222
|
+
"kn": self.scenario.weak_layer.kn * STIFFNESS_COLLAPSE_FACTOR,
|
|
223
|
+
"kt": self.scenario.weak_layer.kt * STIFFNESS_COLLAPSE_FACTOR,
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Create eigensystem for the collapsed weak layer
|
|
228
|
+
return Eigensystem(
|
|
229
|
+
weak_layer=self.collapsed_weak_layer, slab=self.scenario.slab
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def _calc_touchdown_distance_in_mode_C(self) -> float:
|
|
233
|
+
"""
|
|
234
|
+
Calculate the length of the touchdown element in mode C
|
|
235
|
+
when the slab is in contact.
|
|
236
|
+
"""
|
|
237
|
+
# Unpack variables
|
|
238
|
+
bs = -(self.eigensystem.B11**2 / self.eigensystem.A11 - self.eigensystem.D11)
|
|
239
|
+
ss = self.eigensystem.kA55
|
|
240
|
+
L = self.scenario.L
|
|
241
|
+
cut_length = self.scenario.cut_length
|
|
242
|
+
crack_h = self.scenario.crack_h
|
|
243
|
+
qn = self.scenario.qn
|
|
244
|
+
|
|
245
|
+
# Spring stiffness of uncollapsed eigensystem of length L - cut_length
|
|
246
|
+
straight_scenario = self._generate_straight_scenario(L - cut_length)
|
|
247
|
+
kRl = self._substitute_stiffness(straight_scenario, self.eigensystem, "rot")
|
|
248
|
+
kNl = self._substitute_stiffness(straight_scenario, self.eigensystem, "trans")
|
|
249
|
+
|
|
250
|
+
def polynomial(x: float) -> float:
|
|
251
|
+
logger.debug("Eval. Slab Geometry with Touchdown Distance x=%.2f mm", x)
|
|
252
|
+
# Spring stiffness of collapsed eigensystem of length cut_length - x
|
|
253
|
+
straight_scenario = self._generate_straight_scenario(cut_length - x)
|
|
254
|
+
kRr = self._substitute_stiffness(
|
|
255
|
+
straight_scenario, self.collapsed_eigensystem, "rot"
|
|
256
|
+
)
|
|
257
|
+
# define constants
|
|
258
|
+
c1 = ss**2 * kRl * kNl * qn
|
|
259
|
+
c2 = 6 * ss * kNl * qn * (bs * ss + kRl * kRr)
|
|
260
|
+
c3 = 30 * bs * ss * kNl * qn * (kRl + kRr)
|
|
261
|
+
c4 = (
|
|
262
|
+
24
|
|
263
|
+
* bs
|
|
264
|
+
* qn
|
|
265
|
+
* (2 * ss**2 * kRl + 3 * bs * ss * kNl + 3 * kRl * kRr * kNl)
|
|
266
|
+
)
|
|
267
|
+
c5 = (
|
|
268
|
+
72
|
|
269
|
+
* bs
|
|
270
|
+
* (
|
|
271
|
+
bs * qn * (ss**2 + kNl * (kRl + kRr))
|
|
272
|
+
+ ss * kRl * (2 * kRr * qn - ss * kNl * crack_h)
|
|
273
|
+
)
|
|
274
|
+
)
|
|
275
|
+
c6 = (
|
|
276
|
+
144
|
|
277
|
+
* bs
|
|
278
|
+
* ss
|
|
279
|
+
* (bs * qn * (kRl + kRr) - kNl * crack_h * (bs * ss + kRl * kRr))
|
|
280
|
+
)
|
|
281
|
+
c7 = -144 * bs**2 * ss * kNl * crack_h * (kRl + kRr)
|
|
282
|
+
return (
|
|
283
|
+
c1 * x**6 + c2 * x**5 + c3 * x**4 + c4 * x**3 + c5 * x**2 + c6 * x + c7
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Find root
|
|
287
|
+
touchdown_distance = brentq(
|
|
288
|
+
polynomial, cut_length / 1000, 999 / 1000 * cut_length
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
return touchdown_distance
|
|
292
|
+
|
|
293
|
+
def _calc_collapsed_weak_layer_kR(self) -> float:
|
|
294
|
+
"""
|
|
295
|
+
Calculate the rotational stiffness of the collapsed weak layer
|
|
296
|
+
"""
|
|
297
|
+
straight_scenario = self._generate_straight_scenario(
|
|
298
|
+
self.scenario.cut_length - self.touchdown_distance
|
|
299
|
+
)
|
|
300
|
+
kR = self._substitute_stiffness(
|
|
301
|
+
straight_scenario, self.collapsed_eigensystem, "rot"
|
|
302
|
+
)
|
|
303
|
+
return kR
|
|
304
|
+
|
|
305
|
+
def _generate_straight_scenario(self, L: float) -> Scenario:
|
|
306
|
+
"""
|
|
307
|
+
Generate a straight scenario with a given length.
|
|
308
|
+
"""
|
|
309
|
+
segments = [Segment(length=L, has_foundation=True, m=0)]
|
|
310
|
+
straight_scenario = Scenario(
|
|
311
|
+
scenario_config=self.flat_config,
|
|
312
|
+
segments=segments,
|
|
313
|
+
weak_layer=self.scenario.weak_layer,
|
|
314
|
+
slab=self.scenario.slab,
|
|
315
|
+
)
|
|
316
|
+
return straight_scenario
|
|
317
|
+
|
|
318
|
+
def _substitute_stiffness(
|
|
319
|
+
self,
|
|
320
|
+
scenario: Scenario,
|
|
321
|
+
eigensystem: Eigensystem,
|
|
322
|
+
dof: Literal["rot", "trans"] = "rot",
|
|
323
|
+
) -> float:
|
|
324
|
+
"""
|
|
325
|
+
Calc substitute stiffness for beam on elastic foundation.
|
|
326
|
+
|
|
327
|
+
Arguments
|
|
328
|
+
---------
|
|
329
|
+
dof : string
|
|
330
|
+
Type of substitute spring, either 'rot' or 'trans'. Defaults to 'rot'.
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
has_foundation : stiffness of substitute spring.
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
unknown_constants = UnknownConstantsSolver.solve_for_unknown_constants(
|
|
338
|
+
scenario=scenario, eigensystem=eigensystem, system_type=dof
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
# Calculate field quantities at x=0 (left end)
|
|
342
|
+
Zh0 = eigensystem.zh(x=0, length=scenario.L, has_foundation=True)
|
|
343
|
+
zp0 = eigensystem.zp(x=0, phi=0, has_foundation=True, qs=0)
|
|
344
|
+
C_at_x0 = unknown_constants[:, 0].reshape(-1, 1) # Ensure column vector
|
|
345
|
+
z_at_x0 = Zh0 @ C_at_x0 + zp0
|
|
346
|
+
|
|
347
|
+
# Calculate stiffness based on field quantities
|
|
348
|
+
fq = FieldQuantities(eigensystem=eigensystem)
|
|
349
|
+
|
|
350
|
+
stiffness = None
|
|
351
|
+
if dof in ["rot"]:
|
|
352
|
+
# For rotational stiffness: has_foundation = M / psi
|
|
353
|
+
# Uses M = 1.0 for the moment of inertia.
|
|
354
|
+
psi_val = fq.psi(z_at_x0)[0] # Extract scalar value from the result
|
|
355
|
+
stiffness = abs(1 / psi_val) if abs(psi_val) > 1e-12 else 1e12
|
|
356
|
+
elif dof in ["trans"]:
|
|
357
|
+
# For translational stiffness: has_foundation = V / w
|
|
358
|
+
# Uses w = 1.0 for the weight of the slab.
|
|
359
|
+
w_val = fq.w(z_at_x0)[0] # Extract scalar value from the result
|
|
360
|
+
stiffness = abs(1 / w_val) if abs(w_val) > 1e-12 else 1e12
|
|
361
|
+
if stiffness is None:
|
|
362
|
+
raise ValueError(f"Stiffness for {dof} is None")
|
|
363
|
+
return stiffness
|