weac 2.6.3__py3-none-any.whl → 3.0.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.
- weac/__init__.py +2 -14
- weac/constants.py +37 -0
- weac/logging_config.py +39 -0
- {weac-2.6.3.dist-info → weac-3.0.0.dist-info}/METADATA +194 -62
- weac-3.0.0.dist-info/RECORD +8 -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.3.dist-info/RECORD +0 -12
- {weac-2.6.3.dist-info → weac-3.0.0.dist-info}/WHEEL +0 -0
- {weac-2.6.3.dist-info → weac-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {weac-2.6.3.dist-info → weac-3.0.0.dist-info}/top_level.txt +0 -0
weac/eigensystem.py
DELETED
|
@@ -1,658 +0,0 @@
|
|
|
1
|
-
"""Base class for the elastic analysis of layered snow slabs."""
|
|
2
|
-
# pylint: disable=invalid-name,too-many-instance-attributes
|
|
3
|
-
# pylint: disable=too-many-arguments,too-many-locals
|
|
4
|
-
|
|
5
|
-
# Third party imports
|
|
6
|
-
import numpy as np
|
|
7
|
-
|
|
8
|
-
# Project imports
|
|
9
|
-
from weac.tools import bergfeld, calc_center_of_gravity, load_dummy_profile
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Eigensystem:
|
|
13
|
-
"""
|
|
14
|
-
Base class for a layered beam on an elastic foundation.
|
|
15
|
-
|
|
16
|
-
Provides geometry, material and loading attributes, and methods
|
|
17
|
-
for the assembly of a fundamental system.
|
|
18
|
-
|
|
19
|
-
Attributes
|
|
20
|
-
----------
|
|
21
|
-
g : float
|
|
22
|
-
Gravitational constant (mm/s^2). Default is 9180.
|
|
23
|
-
lski : float
|
|
24
|
-
Effective out-of-plance length of skis (mm). Default is 1000.
|
|
25
|
-
tol : float
|
|
26
|
-
Relative Romberg integration toleranc. Default is 1e-3.
|
|
27
|
-
system : str
|
|
28
|
-
Type of boundary value problem. Default is 'pst-'.
|
|
29
|
-
weak : dict
|
|
30
|
-
Dictionary that holds the weak layer properties Young's
|
|
31
|
-
modulus (MPa) and Poisson's ratio. Defaults are 0.25
|
|
32
|
-
and 0.25, respectively.
|
|
33
|
-
t : float
|
|
34
|
-
Weak-layer thickness (mm). Default is 30.
|
|
35
|
-
kn : float
|
|
36
|
-
Compressive foundation (weak-layer) stiffness (N/mm^3).
|
|
37
|
-
kt : float
|
|
38
|
-
Shear foundation (weak-layer) stiffness (N/mm^3).
|
|
39
|
-
tc : float
|
|
40
|
-
Weak-layer thickness after collapse (mm).
|
|
41
|
-
slab : ndarray
|
|
42
|
-
Matrix that holds the elastic properties of all slab layers.
|
|
43
|
-
Columns are density (kg/m^3), layer heigth (mm), Young's
|
|
44
|
-
modulus (MPa), shear modulus (MPa), and Poisson's ratio.
|
|
45
|
-
k : float
|
|
46
|
-
Shear correction factor of the slab. Default is 5/6.
|
|
47
|
-
h : float
|
|
48
|
-
Slab thickness (mm). Default is 300.
|
|
49
|
-
zs : float
|
|
50
|
-
Z-coordinate of the center of gravity of the slab (mm).
|
|
51
|
-
A11 : float
|
|
52
|
-
Extensional stiffness of the slab (N/mm).
|
|
53
|
-
B11 : float
|
|
54
|
-
Bending-extension coupling stiffness of the slab (N).
|
|
55
|
-
D11 : float
|
|
56
|
-
Bending stiffness of the slab (Nmm).
|
|
57
|
-
kA55 : float
|
|
58
|
-
Shear stiffness of the slab (N/mm).
|
|
59
|
-
K0 : float
|
|
60
|
-
Characteristic stiffness value (N).
|
|
61
|
-
ewC : ndarray
|
|
62
|
-
List of complex eigenvalues.
|
|
63
|
-
ewR : ndarray
|
|
64
|
-
List of real eigenvalues.
|
|
65
|
-
evC : ndarray
|
|
66
|
-
Matrix with eigenvectors corresponding to complex
|
|
67
|
-
eigenvalues as columns.
|
|
68
|
-
evR : ndarray
|
|
69
|
-
Matrix with eigenvectors corresponding to real
|
|
70
|
-
eigenvalues as columns.
|
|
71
|
-
sC : float
|
|
72
|
-
X-coordinate shift (mm) of complex parts of the solution.
|
|
73
|
-
Used for numerical stability.
|
|
74
|
-
sR : float
|
|
75
|
-
X-coordinate shift (mm) of real parts of the solution.
|
|
76
|
-
Used for numerical stability.
|
|
77
|
-
sysmat : ndarray
|
|
78
|
-
System matrix.
|
|
79
|
-
lC : float
|
|
80
|
-
Cracklength whose maximum deflection equals the
|
|
81
|
-
weak-layer thickness (mm).
|
|
82
|
-
lS : float
|
|
83
|
-
Cracklength when touchdown exerts maximum support
|
|
84
|
-
on the slab (mm). Corresponds to the longest possible
|
|
85
|
-
unbedded length.
|
|
86
|
-
ratio : float
|
|
87
|
-
Increment factor for the weak-layer stiffness from intact
|
|
88
|
-
to collapsed state.
|
|
89
|
-
beta : float
|
|
90
|
-
Describes the stiffnesses of weak-layer and slab.
|
|
91
|
-
"""
|
|
92
|
-
|
|
93
|
-
def __init__(self, system="pst-", touchdown=False):
|
|
94
|
-
"""
|
|
95
|
-
Initialize eigensystem with user input.
|
|
96
|
-
|
|
97
|
-
Arguments
|
|
98
|
-
---------
|
|
99
|
-
system : {'pst-', '-pst', 'vpst-', '-vpst', 'skier', 'skiers'}, optional
|
|
100
|
-
Type of system to analyse: PST cut from the right (pst-),
|
|
101
|
-
PST cut form the left (-pst), PST with vertical faces cut
|
|
102
|
-
from the right (vpst-), PST with vertical faces cut from the
|
|
103
|
-
left (-vpst), one skier on infinite slab (skier) or multiple
|
|
104
|
-
skiers on infinite slab (skiers). Default is 'pst-'.
|
|
105
|
-
layers : list, optional
|
|
106
|
-
2D list of layer densities and thicknesses. Columns are
|
|
107
|
-
density (kg/m^3) and thickness (mm). One row corresponds
|
|
108
|
-
to one layer. Default is [[240, 200], ].
|
|
109
|
-
"""
|
|
110
|
-
# Assign global attributes
|
|
111
|
-
self.g = 9810 # Gravitaiton (mm/s^2)
|
|
112
|
-
self.lski = 1000 # Effective out-of-plane length of skis (mm)
|
|
113
|
-
self.tol = 1e-3 # Relative Romberg integration tolerance
|
|
114
|
-
self.system = system # 'pst-', '-pst', 'vpst-', '-vpst', 'skier', 'skiers'
|
|
115
|
-
|
|
116
|
-
# Initialize weak-layer attributes that will be filled later
|
|
117
|
-
self.weak = False # Weak-layer properties dictionary
|
|
118
|
-
self.t = False # Weak-layer thickness (mm)
|
|
119
|
-
self.kn = False # Weak-layer compressive stiffness
|
|
120
|
-
self.kt = False # Weak-layer shear stiffness
|
|
121
|
-
|
|
122
|
-
# Initialize slab attributes
|
|
123
|
-
self.p = 0 # Surface line load (N/mm)
|
|
124
|
-
self.slab = False # Slab properties dictionary
|
|
125
|
-
self.k = False # Slab shear correction factor
|
|
126
|
-
self.h = False # Total slab height (mm)
|
|
127
|
-
self.zs = False # Z-coordinate of slab center of gravity (mm)
|
|
128
|
-
self.phi = False # Slab inclination (°)
|
|
129
|
-
self.A11 = False # Slab extensional stiffness
|
|
130
|
-
self.B11 = False # Slab bending-extension coupling stiffness
|
|
131
|
-
self.D11 = False # Slab bending stiffness
|
|
132
|
-
self.kA55 = False # Slab shear stiffness
|
|
133
|
-
self.K0 = False # Stiffness determinant
|
|
134
|
-
|
|
135
|
-
# Inizialize eigensystem attributes
|
|
136
|
-
self.ewC = False # Complex eigenvalues
|
|
137
|
-
self.ewR = False # Real eigenvalues
|
|
138
|
-
self.evC = False # Complex eigenvectors
|
|
139
|
-
self.evR = False # Real eigenvectors
|
|
140
|
-
self.sC = False # Stability shift of complex eigenvalues
|
|
141
|
-
self.sR = False # Stability shift of real eigenvalues
|
|
142
|
-
|
|
143
|
-
# Initialize touchdown attributes
|
|
144
|
-
self.touchdown = touchdown # Flag whether touchdown is possible
|
|
145
|
-
self.a = False # Cracklength
|
|
146
|
-
self.tc = False # Weak-layer collapse height (mm)
|
|
147
|
-
self.ratio = False # Stiffness ratio of collapsed to uncollapsed weak-layer
|
|
148
|
-
self.betaU = False # Ratio of slab to bedding stiffness (uncollapsed)
|
|
149
|
-
self.betaC = False # Ratio of slab to bedding stiffness (collapsed)
|
|
150
|
-
self.mode = False # Touchdown-mode can be either A, B, C or D
|
|
151
|
-
self.td = False # Touchdown length
|
|
152
|
-
|
|
153
|
-
def set_foundation_properties(
|
|
154
|
-
self, t: float = 30.0, E: float = 0.25, nu: float = 0.25, update: bool = False
|
|
155
|
-
):
|
|
156
|
-
"""
|
|
157
|
-
Set material properties and geometry of foundation (weak layer).
|
|
158
|
-
|
|
159
|
-
Arguments
|
|
160
|
-
---------
|
|
161
|
-
t : float, optional
|
|
162
|
-
Weak-layer thickness (mm). Default is 30.
|
|
163
|
-
cf : float
|
|
164
|
-
Fraction by which the weak-layer thickness is reduced
|
|
165
|
-
due to collapse. Default is 0.5.
|
|
166
|
-
E : float, optional
|
|
167
|
-
Weak-layer Young modulus (MPa). Default is 0.25.
|
|
168
|
-
nu : float, optional
|
|
169
|
-
Weak-layer Poisson ratio. Default is 0.25.
|
|
170
|
-
update : bool, optional
|
|
171
|
-
If true, recalculate the fundamental system after
|
|
172
|
-
foundation properties have changed.
|
|
173
|
-
"""
|
|
174
|
-
# Geometry
|
|
175
|
-
self.t = t # Weak-layer thickness (mm)
|
|
176
|
-
|
|
177
|
-
# Material properties
|
|
178
|
-
self.weak = {
|
|
179
|
-
"nu": nu, # Poisson's ratio (-)
|
|
180
|
-
"E": E, # Young's modulus (MPa)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
# Recalculate the fundamental system after properties have changed
|
|
184
|
-
if update:
|
|
185
|
-
self.calc_fundamental_system()
|
|
186
|
-
|
|
187
|
-
def set_beam_properties(self, layers, C0=6.5, C1=4.4, nu=0.25, update=False):
|
|
188
|
-
"""
|
|
189
|
-
Set material and properties geometry of beam (slab).
|
|
190
|
-
|
|
191
|
-
Arguments
|
|
192
|
-
---------
|
|
193
|
-
layers : list or str
|
|
194
|
-
2D list of top-to-bottom layer densities and thicknesses.
|
|
195
|
-
Columns are density (kg/m^3) and thickness (mm). One row
|
|
196
|
-
corresponds to one layer. If entered as str, last split
|
|
197
|
-
must be available in database.
|
|
198
|
-
C0 : float, optional
|
|
199
|
-
Multiplicative constant of Young modulus parametrization
|
|
200
|
-
according to Bergfeld et al. (2023). Default is 6.5.
|
|
201
|
-
C1 : float, optional
|
|
202
|
-
Exponent of Young modulus parameterization according to
|
|
203
|
-
Bergfeld et al. (2023). Default is 4.6.
|
|
204
|
-
nu : float, optional
|
|
205
|
-
Possion's ratio. Default is 0.25
|
|
206
|
-
update : bool, optional
|
|
207
|
-
If true, recalculate the fundamental system after
|
|
208
|
-
foundation properties have changed.
|
|
209
|
-
"""
|
|
210
|
-
if isinstance(layers, str):
|
|
211
|
-
# Read layering and Young's modulus from database
|
|
212
|
-
layers, E = load_dummy_profile(layers.split()[-1])
|
|
213
|
-
else:
|
|
214
|
-
# Compute Young's modulus from density parametrization
|
|
215
|
-
layers = np.array(layers)
|
|
216
|
-
E = bergfeld(layers[:, 0], C0=C0, C1=C1) # Young's modulus
|
|
217
|
-
|
|
218
|
-
# Derive other elastic properties
|
|
219
|
-
nu = nu * np.ones(layers.shape[0]) # Global poisson's ratio
|
|
220
|
-
G = E / (2 * (1 + nu)) # Shear modulus
|
|
221
|
-
self.k = 5 / 6 # Shear correction factor
|
|
222
|
-
|
|
223
|
-
# Compute total slab thickness and center of gravity
|
|
224
|
-
self.h, self.zs = calc_center_of_gravity(layers)
|
|
225
|
-
|
|
226
|
-
# Assemble layering into matrix (top to bottom)
|
|
227
|
-
# Columns are density (kg/m^3), layer thickness (mm)
|
|
228
|
-
# Young's modulus (MPa), shear modulus (MPa), and
|
|
229
|
-
# Poisson's ratio
|
|
230
|
-
self.slab = np.vstack([layers.T, E, G, nu]).T
|
|
231
|
-
|
|
232
|
-
# Recalculate the fundamental system after properties have changed
|
|
233
|
-
if update:
|
|
234
|
-
self.calc_fundamental_system()
|
|
235
|
-
|
|
236
|
-
def set_surface_load(self, p):
|
|
237
|
-
"""
|
|
238
|
-
Set surface line load.
|
|
239
|
-
|
|
240
|
-
Define a distributed surface load (N/mm) that acts
|
|
241
|
-
in vertical (gravity) direction on the top surface
|
|
242
|
-
of the slab.
|
|
243
|
-
|
|
244
|
-
Arguments
|
|
245
|
-
---------
|
|
246
|
-
p : float
|
|
247
|
-
Surface line load (N/mm) that acts in vertical
|
|
248
|
-
(gravity) direction onm the top surface of the
|
|
249
|
-
slab.
|
|
250
|
-
"""
|
|
251
|
-
self.p = p
|
|
252
|
-
|
|
253
|
-
def calc_foundation_stiffness(self):
|
|
254
|
-
"""Compute foundation normal and shear stiffness."""
|
|
255
|
-
# Elastic moduli (MPa) under plane-strain conditions
|
|
256
|
-
G = self.weak["E"] / (2 * (1 + self.weak["nu"])) # Shear modulus
|
|
257
|
-
E = self.weak["E"] / (1 - self.weak["nu"] ** 2) # Young's modulus
|
|
258
|
-
|
|
259
|
-
# Foundation (weak layer) stiffnesses (N/mm^3)
|
|
260
|
-
self.kn = E / self.t # Normal stiffness
|
|
261
|
-
self.kt = G / self.t # Shear stiffness
|
|
262
|
-
|
|
263
|
-
def get_ply_coordinates(self):
|
|
264
|
-
"""
|
|
265
|
-
Calculate ply (layer) z-coordinates.
|
|
266
|
-
|
|
267
|
-
Returns
|
|
268
|
-
-------
|
|
269
|
-
ndarray
|
|
270
|
-
Ply (layer) z-coordinates (top to bottom) in coordinate system with
|
|
271
|
-
downward pointing z-axis (z-list will be negative to positive).
|
|
272
|
-
|
|
273
|
-
"""
|
|
274
|
-
# Get list of ply (layer) thicknesses and prepend 0
|
|
275
|
-
t = np.concatenate(([0], self.slab[:, 1]))
|
|
276
|
-
# Calculate and return ply z-coordiantes
|
|
277
|
-
return np.cumsum(t) - self.h / 2
|
|
278
|
-
|
|
279
|
-
def calc_laminate_stiffness_matrix(self):
|
|
280
|
-
"""
|
|
281
|
-
Provide ABD matrix.
|
|
282
|
-
|
|
283
|
-
Return plane-strain laminate stiffness matrix (ABD matrix).
|
|
284
|
-
"""
|
|
285
|
-
# Get ply coordinates (z-list is top to bottom, negative to positive)
|
|
286
|
-
z = self.get_ply_coordinates()
|
|
287
|
-
# Initialize stiffness components
|
|
288
|
-
A11, B11, D11, kA55 = 0, 0, 0, 0
|
|
289
|
-
# Add layerwise contributions
|
|
290
|
-
for i in range(len(z) - 1):
|
|
291
|
-
E, G, nu = self.slab[i, 2:5]
|
|
292
|
-
A11 = A11 + E / (1 - nu**2) * (z[i + 1] - z[i])
|
|
293
|
-
B11 = B11 + 1 / 2 * E / (1 - nu**2) * (z[i + 1] ** 2 - z[i] ** 2)
|
|
294
|
-
D11 = D11 + 1 / 3 * E / (1 - nu**2) * (z[i + 1] ** 3 - z[i] ** 3)
|
|
295
|
-
kA55 = kA55 + self.k * G * (z[i + 1] - z[i])
|
|
296
|
-
|
|
297
|
-
self.A11 = A11
|
|
298
|
-
self.B11 = B11
|
|
299
|
-
self.D11 = D11
|
|
300
|
-
self.kA55 = kA55
|
|
301
|
-
self.K0 = B11**2 - A11 * D11
|
|
302
|
-
|
|
303
|
-
def calc_system_matrix(self):
|
|
304
|
-
"""
|
|
305
|
-
Assemble first-order ODE system matrix K.
|
|
306
|
-
|
|
307
|
-
Using the solution vector z = [u, u', w, w', psi, psi']
|
|
308
|
-
the ODE system is written in the form Az' + Bz = d
|
|
309
|
-
and rearranged to z' = -(A ^ -1)Bz + (A ^ -1)d = Kz + q
|
|
310
|
-
|
|
311
|
-
Returns
|
|
312
|
-
-------
|
|
313
|
-
ndarray
|
|
314
|
-
System matrix K (6x6).
|
|
315
|
-
"""
|
|
316
|
-
kn = self.kn
|
|
317
|
-
kt = self.kt
|
|
318
|
-
|
|
319
|
-
# Abbreviations (MIT t/2 im GGW, MIT w' in Kinematik)
|
|
320
|
-
K21 = kt * (-2 * self.D11 + self.B11 * (self.h + self.t)) / (2 * self.K0)
|
|
321
|
-
K24 = (
|
|
322
|
-
2 * self.D11 * kt * self.t
|
|
323
|
-
- self.B11 * kt * self.t * (self.h + self.t)
|
|
324
|
-
+ 4 * self.B11 * self.kA55
|
|
325
|
-
) / (4 * self.K0)
|
|
326
|
-
K25 = (
|
|
327
|
-
-2 * self.D11 * self.h * kt
|
|
328
|
-
+ self.B11 * self.h * kt * (self.h + self.t)
|
|
329
|
-
+ 4 * self.B11 * self.kA55
|
|
330
|
-
) / (4 * self.K0)
|
|
331
|
-
K43 = kn / self.kA55
|
|
332
|
-
K61 = kt * (2 * self.B11 - self.A11 * (self.h + self.t)) / (2 * self.K0)
|
|
333
|
-
K64 = (
|
|
334
|
-
-2 * self.B11 * kt * self.t
|
|
335
|
-
+ self.A11 * kt * self.t * (self.h + self.t)
|
|
336
|
-
- 4 * self.A11 * self.kA55
|
|
337
|
-
) / (4 * self.K0)
|
|
338
|
-
K65 = (
|
|
339
|
-
2 * self.B11 * self.h * kt
|
|
340
|
-
- self.A11 * self.h * kt * (self.h + self.t)
|
|
341
|
-
- 4 * self.A11 * self.kA55
|
|
342
|
-
) / (4 * self.K0)
|
|
343
|
-
|
|
344
|
-
# System matrix
|
|
345
|
-
K = [
|
|
346
|
-
[0, 1, 0, 0, 0, 0],
|
|
347
|
-
[K21, 0, 0, K24, K25, 0],
|
|
348
|
-
[0, 0, 0, 1, 0, 0],
|
|
349
|
-
[0, 0, K43, 0, 0, -1],
|
|
350
|
-
[0, 0, 0, 0, 0, 1],
|
|
351
|
-
[K61, 0, 0, K64, K65, 0],
|
|
352
|
-
]
|
|
353
|
-
|
|
354
|
-
return np.array(K)
|
|
355
|
-
|
|
356
|
-
def get_load_vector(self, phi):
|
|
357
|
-
"""
|
|
358
|
-
Compute sytem load vector q.
|
|
359
|
-
|
|
360
|
-
Using the solution vector z = [u, u', w, w', psi, psi']
|
|
361
|
-
the ODE system is written in the form Az' + Bz = d
|
|
362
|
-
and rearranged to z' = -(A ^ -1)Bz + (A ^ -1)d = Kz + q
|
|
363
|
-
|
|
364
|
-
Arguments
|
|
365
|
-
---------
|
|
366
|
-
phi : float
|
|
367
|
-
Inclination (degrees). Counterclockwise positive.
|
|
368
|
-
|
|
369
|
-
Returns
|
|
370
|
-
-------
|
|
371
|
-
ndarray
|
|
372
|
-
System load vector q (6x1).
|
|
373
|
-
"""
|
|
374
|
-
qn, qt = self.get_weight_load(phi)
|
|
375
|
-
pn, pt = self.get_surface_load(phi)
|
|
376
|
-
return np.array(
|
|
377
|
-
[
|
|
378
|
-
[0],
|
|
379
|
-
[
|
|
380
|
-
(
|
|
381
|
-
self.B11 * (self.h * pt - 2 * qt * self.zs)
|
|
382
|
-
+ 2 * self.D11 * (qt + pt)
|
|
383
|
-
)
|
|
384
|
-
/ (2 * self.K0)
|
|
385
|
-
],
|
|
386
|
-
[0],
|
|
387
|
-
[-(qn + pn) / self.kA55],
|
|
388
|
-
[0],
|
|
389
|
-
[
|
|
390
|
-
-(
|
|
391
|
-
self.A11 * (self.h * pt - 2 * qt * self.zs)
|
|
392
|
-
+ 2 * self.B11 * (qt + pt)
|
|
393
|
-
)
|
|
394
|
-
/ (2 * self.K0)
|
|
395
|
-
],
|
|
396
|
-
]
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
def calc_eigensystem(self):
|
|
400
|
-
"""Calculate eigenvalues and eigenvectors of the system matrix."""
|
|
401
|
-
# Calculate eigenvalues (ew) and eigenvectors (ev)
|
|
402
|
-
ew, ev = np.linalg.eig(self.calc_system_matrix())
|
|
403
|
-
# Classify real and complex eigenvalues
|
|
404
|
-
real = (ew.imag == 0) & (ew.real != 0) # real eigenvalues
|
|
405
|
-
cmplx = ew.imag > 0 # positive complex conjugates
|
|
406
|
-
# Eigenvalues
|
|
407
|
-
self.ewC = ew[cmplx]
|
|
408
|
-
self.ewR = ew[real].real
|
|
409
|
-
# Eigenvectors
|
|
410
|
-
self.evC = ev[:, cmplx]
|
|
411
|
-
self.evR = ev[:, real].real
|
|
412
|
-
# Prepare positive eigenvalue shifts for numerical robustness
|
|
413
|
-
self.sR, self.sC = np.zeros(self.ewR.shape), np.zeros(self.ewC.shape)
|
|
414
|
-
self.sR[self.ewR > 0], self.sC[self.ewC > 0] = -1, -1
|
|
415
|
-
|
|
416
|
-
def calc_fundamental_system(self):
|
|
417
|
-
"""Calculate the fundamental system of the problem."""
|
|
418
|
-
self.calc_foundation_stiffness()
|
|
419
|
-
self.calc_laminate_stiffness_matrix()
|
|
420
|
-
self.calc_eigensystem()
|
|
421
|
-
|
|
422
|
-
def get_weight_load(self, phi):
|
|
423
|
-
"""
|
|
424
|
-
Calculate line loads from slab mass.
|
|
425
|
-
|
|
426
|
-
Arguments
|
|
427
|
-
---------
|
|
428
|
-
phi : float
|
|
429
|
-
Inclination (degrees). Counterclockwise positive.
|
|
430
|
-
|
|
431
|
-
Returns
|
|
432
|
-
-------
|
|
433
|
-
qn : float
|
|
434
|
-
Line load (N/mm) at center of gravity in normal direction.
|
|
435
|
-
qt : float
|
|
436
|
-
Line load (N/mm) at center of gravity in tangential direction.
|
|
437
|
-
"""
|
|
438
|
-
# Convert units
|
|
439
|
-
phi = np.deg2rad(phi) # Convert inclination to rad
|
|
440
|
-
rho = self.slab[:, 0] * 1e-12 # Convert density to t/mm^3
|
|
441
|
-
# Sum up layer weight loads
|
|
442
|
-
q = sum(rho * self.g * self.slab[:, 1]) # Line load (N/mm)
|
|
443
|
-
# Split into components
|
|
444
|
-
qn = q * np.cos(phi) # Normal direction
|
|
445
|
-
qt = -q * np.sin(phi) # Tangential direction
|
|
446
|
-
|
|
447
|
-
return qn, qt
|
|
448
|
-
|
|
449
|
-
def get_surface_load(self, phi):
|
|
450
|
-
"""
|
|
451
|
-
Calculate surface line loads.
|
|
452
|
-
|
|
453
|
-
Arguments
|
|
454
|
-
---------
|
|
455
|
-
phi : float
|
|
456
|
-
Inclination (degrees). Counterclockwise positive.
|
|
457
|
-
|
|
458
|
-
Returns
|
|
459
|
-
-------
|
|
460
|
-
pn : float
|
|
461
|
-
Surface line load (N/mm) in normal direction.
|
|
462
|
-
pt : float
|
|
463
|
-
Surface line load (N/mm) in tangential direction.
|
|
464
|
-
"""
|
|
465
|
-
# Convert units
|
|
466
|
-
phi = np.deg2rad(phi) # Convert inclination to rad
|
|
467
|
-
# Split into components
|
|
468
|
-
pn = self.p * np.cos(phi) # Normal direction
|
|
469
|
-
pt = -self.p * np.sin(phi) # Tangential direction
|
|
470
|
-
|
|
471
|
-
return pn, pt
|
|
472
|
-
|
|
473
|
-
def get_skier_load(self, m, phi):
|
|
474
|
-
"""
|
|
475
|
-
Calculate skier point load.
|
|
476
|
-
|
|
477
|
-
Arguments
|
|
478
|
-
---------
|
|
479
|
-
m : float
|
|
480
|
-
Skier weight (kg).
|
|
481
|
-
phi : float
|
|
482
|
-
Inclination (degrees). Counterclockwise positive.
|
|
483
|
-
|
|
484
|
-
Returns
|
|
485
|
-
-------
|
|
486
|
-
Fn : float
|
|
487
|
-
Skier load (N) in normal direction.
|
|
488
|
-
Ft : float
|
|
489
|
-
Skier load (N) in tangential direction.
|
|
490
|
-
"""
|
|
491
|
-
phi = np.deg2rad(phi) # Convert inclination to rad
|
|
492
|
-
F = 1e-3 * np.array(m) * self.g / self.lski # Total skier load (N)
|
|
493
|
-
Fn = F * np.cos(phi) # Normal skier load (N)
|
|
494
|
-
Ft = -F * np.sin(phi) # Tangential skier load (N)
|
|
495
|
-
|
|
496
|
-
return Fn, Ft
|
|
497
|
-
|
|
498
|
-
def zh(self, x, l=0, bed=True):
|
|
499
|
-
"""
|
|
500
|
-
Compute bedded or free complementary solution at position x.
|
|
501
|
-
|
|
502
|
-
Arguments
|
|
503
|
-
---------
|
|
504
|
-
x : float
|
|
505
|
-
Horizontal coordinate (mm).
|
|
506
|
-
l : float, optional
|
|
507
|
-
Segment length (mm). Default is 0.
|
|
508
|
-
bed : bool
|
|
509
|
-
Indicates whether segment has foundation or not. Default
|
|
510
|
-
is True.
|
|
511
|
-
|
|
512
|
-
Returns
|
|
513
|
-
-------
|
|
514
|
-
zh : ndarray
|
|
515
|
-
Complementary solution matrix (6x6) at position x.
|
|
516
|
-
"""
|
|
517
|
-
if bed:
|
|
518
|
-
zh = np.concatenate(
|
|
519
|
-
[
|
|
520
|
-
# Real
|
|
521
|
-
self.evR * np.exp(self.ewR * (x + l * self.sR)),
|
|
522
|
-
# Complex
|
|
523
|
-
np.exp(self.ewC.real * (x + l * self.sC))
|
|
524
|
-
* (
|
|
525
|
-
self.evC.real * np.cos(self.ewC.imag * x)
|
|
526
|
-
- self.evC.imag * np.sin(self.ewC.imag * x)
|
|
527
|
-
),
|
|
528
|
-
# Complex
|
|
529
|
-
np.exp(self.ewC.real * (x + l * self.sC))
|
|
530
|
-
* (
|
|
531
|
-
self.evC.imag * np.cos(self.ewC.imag * x)
|
|
532
|
-
+ self.evC.real * np.sin(self.ewC.imag * x)
|
|
533
|
-
),
|
|
534
|
-
],
|
|
535
|
-
axis=1,
|
|
536
|
-
)
|
|
537
|
-
else:
|
|
538
|
-
# Abbreviations
|
|
539
|
-
H14 = 3 * self.B11 / self.A11 * x**2
|
|
540
|
-
H24 = 6 * self.B11 / self.A11 * x
|
|
541
|
-
H54 = -3 * x**2 + 6 * self.K0 / (self.A11 * self.kA55)
|
|
542
|
-
# Complementary solution matrix of free segments
|
|
543
|
-
zh = np.array(
|
|
544
|
-
[
|
|
545
|
-
[0, 0, 0, H14, 1, x],
|
|
546
|
-
[0, 0, 0, H24, 0, 1],
|
|
547
|
-
[1, x, x**2, x**3, 0, 0],
|
|
548
|
-
[0, 1, 2 * x, 3 * x**2, 0, 0],
|
|
549
|
-
[0, -1, -2 * x, H54, 0, 0],
|
|
550
|
-
[0, 0, -2, -6 * x, 0, 0],
|
|
551
|
-
]
|
|
552
|
-
)
|
|
553
|
-
|
|
554
|
-
return zh
|
|
555
|
-
|
|
556
|
-
def zp(self, x, phi, bed=True):
|
|
557
|
-
"""
|
|
558
|
-
Compute bedded or free particular integrals at position x.
|
|
559
|
-
|
|
560
|
-
Arguments
|
|
561
|
-
---------
|
|
562
|
-
x : float
|
|
563
|
-
Horizontal coordinate (mm).
|
|
564
|
-
phi : float
|
|
565
|
-
Inclination (degrees).
|
|
566
|
-
bed : bool
|
|
567
|
-
Indicates whether segment has foundation (True) or not
|
|
568
|
-
(False). Default is True.
|
|
569
|
-
|
|
570
|
-
Returns
|
|
571
|
-
-------
|
|
572
|
-
zp : ndarray
|
|
573
|
-
Particular integral vector (6x1) at position x.
|
|
574
|
-
"""
|
|
575
|
-
# Get weight and surface loads
|
|
576
|
-
qn, qt = self.get_weight_load(phi)
|
|
577
|
-
pn, pt = self.get_surface_load(phi)
|
|
578
|
-
|
|
579
|
-
# Set foundation stiffnesses
|
|
580
|
-
kn = self.kn
|
|
581
|
-
kt = self.kt
|
|
582
|
-
|
|
583
|
-
# Unpack laminate stiffnesses
|
|
584
|
-
A11 = self.A11
|
|
585
|
-
B11 = self.B11
|
|
586
|
-
kA55 = self.kA55
|
|
587
|
-
K0 = self.K0
|
|
588
|
-
|
|
589
|
-
# Unpack geometric properties
|
|
590
|
-
h = self.h
|
|
591
|
-
t = self.t
|
|
592
|
-
zs = self.zs
|
|
593
|
-
|
|
594
|
-
# Assemble particular integral vectors
|
|
595
|
-
if bed:
|
|
596
|
-
zp = np.array(
|
|
597
|
-
[
|
|
598
|
-
[
|
|
599
|
-
(qt + pt) / kt
|
|
600
|
-
+ h * qt * (h + t - 2 * zs) / (4 * kA55)
|
|
601
|
-
+ h * pt * (2 * h + t) / (4 * kA55)
|
|
602
|
-
],
|
|
603
|
-
[0],
|
|
604
|
-
[(qn + pn) / kn],
|
|
605
|
-
[0],
|
|
606
|
-
[-(qt * (h + t - 2 * zs) + pt * (2 * h + t)) / (2 * kA55)],
|
|
607
|
-
[0],
|
|
608
|
-
]
|
|
609
|
-
)
|
|
610
|
-
else:
|
|
611
|
-
zp = np.array(
|
|
612
|
-
[
|
|
613
|
-
[(-3 * (qt + pt) / A11 - B11 * (qn + pn) * x / K0) / 6 * x**2],
|
|
614
|
-
[(-2 * (qt + pt) / A11 - B11 * (qn + pn) * x / K0) / 2 * x],
|
|
615
|
-
[-A11 * (qn + pn) * x**4 / (24 * K0)],
|
|
616
|
-
[-A11 * (qn + pn) * x**3 / (6 * K0)],
|
|
617
|
-
[
|
|
618
|
-
A11 * (qn + pn) * x**3 / (6 * K0)
|
|
619
|
-
+ ((zs - B11 / A11) * qt - h * pt / 2 - (qn + pn) * x) / kA55
|
|
620
|
-
],
|
|
621
|
-
[(qn + pn) * (A11 * x**2 / (2 * K0) - 1 / kA55)],
|
|
622
|
-
]
|
|
623
|
-
)
|
|
624
|
-
|
|
625
|
-
return zp
|
|
626
|
-
|
|
627
|
-
def z(self, x, C, l, phi, bed=True):
|
|
628
|
-
"""
|
|
629
|
-
Assemble solution vector at positions x.
|
|
630
|
-
|
|
631
|
-
Arguments
|
|
632
|
-
---------
|
|
633
|
-
x : float or squence
|
|
634
|
-
Horizontal coordinate (mm). Can be sequence of length N.
|
|
635
|
-
C : ndarray
|
|
636
|
-
Vector of constants (6xN) at positions x.
|
|
637
|
-
l : float
|
|
638
|
-
Segment length (mm).
|
|
639
|
-
phi : float
|
|
640
|
-
Inclination (degrees).
|
|
641
|
-
bed : bool
|
|
642
|
-
Indicates whether segment has foundation (True) or not
|
|
643
|
-
(False). Default is True.
|
|
644
|
-
|
|
645
|
-
Returns
|
|
646
|
-
-------
|
|
647
|
-
z : ndarray
|
|
648
|
-
Solution vector (6xN) at position x.
|
|
649
|
-
"""
|
|
650
|
-
if isinstance(x, (list, tuple, np.ndarray)):
|
|
651
|
-
z = np.concatenate(
|
|
652
|
-
[np.dot(self.zh(xi, l, bed), C) + self.zp(xi, phi, bed) for xi in x],
|
|
653
|
-
axis=1,
|
|
654
|
-
)
|
|
655
|
-
else:
|
|
656
|
-
z = np.dot(self.zh(x, l, bed), C) + self.zp(x, phi, bed)
|
|
657
|
-
|
|
658
|
-
return z
|
weac/inverse.py
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
"""Class for the elastic analysis of layered snow slabs."""
|
|
2
|
-
# pylint: disable=invalid-name
|
|
3
|
-
|
|
4
|
-
# Project imports
|
|
5
|
-
from weac.eigensystem import Eigensystem
|
|
6
|
-
from weac.mixins import AnalysisMixin, FieldQuantitiesMixin, OutputMixin, SolutionMixin
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Inverse(
|
|
10
|
-
FieldQuantitiesMixin, SolutionMixin, AnalysisMixin, OutputMixin, Eigensystem
|
|
11
|
-
):
|
|
12
|
-
"""
|
|
13
|
-
Fit the elastic properties of the layers of a snowpack.
|
|
14
|
-
|
|
15
|
-
Allows for the inverse identification of the elastic properties
|
|
16
|
-
of the layers of a snowpack from full-field displacement
|
|
17
|
-
measurements.
|
|
18
|
-
|
|
19
|
-
Inherits methods for the eigensystem calculation from the base
|
|
20
|
-
class Eigensystem(), methods for the calculation of field
|
|
21
|
-
quantities from FieldQuantitiesMixin(), methods for the solution
|
|
22
|
-
of the system from SolutionMixin() and methods for the output
|
|
23
|
-
analysis from AnalysisMixin().
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
def __init__(self, system="pst-", layers=None, parameters=(6.0, 4.6, 0.25)):
|
|
27
|
-
"""
|
|
28
|
-
Initialize model with user input.
|
|
29
|
-
|
|
30
|
-
Arguments
|
|
31
|
-
---------
|
|
32
|
-
system : str, optional
|
|
33
|
-
Type of system to analyse. Default is 'pst-'.
|
|
34
|
-
layers : list, optional
|
|
35
|
-
List of layer densities and thicknesses. Default is None.
|
|
36
|
-
parameters : tuple, optional
|
|
37
|
-
Fitting parameters C0, C1, and Eweak. Multiplicative constant
|
|
38
|
-
of Young modulus parametrization, exponent constant of Young
|
|
39
|
-
modulus parametrization, and weak-layer Young modulus,
|
|
40
|
-
respectively. Default is (6.0, 4.6, 0.25).
|
|
41
|
-
"""
|
|
42
|
-
# Call parent __init__
|
|
43
|
-
super().__init__(system=system)
|
|
44
|
-
|
|
45
|
-
# Unpack fitting parameters
|
|
46
|
-
C0, C1, Eweak = parameters
|
|
47
|
-
|
|
48
|
-
# Set material properties and set up model
|
|
49
|
-
self.set_beam_properties(layers=layers, C0=C0, C1=C1)
|
|
50
|
-
self.set_foundation_properties(E=Eweak)
|
|
51
|
-
self.calc_fundamental_system()
|