weac 3.0.0__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/utils/misc.py ADDED
@@ -0,0 +1,127 @@
1
+ """
2
+ This module contains miscellaneous utility functions.
3
+ """
4
+
5
+ from typing import Literal
6
+
7
+ import numpy as np
8
+
9
+ from weac.components import Layer
10
+ from weac.constants import G_MM_S2, LSKI_MM
11
+
12
+
13
+ def decompose_to_normal_tangential(f: float, phi: float) -> tuple[float, float]:
14
+ """
15
+ Resolve a gravity-type force/line-load into its tangential (downslope) and
16
+ normal (into-slope) components with respect to an inclined surface.
17
+
18
+ Parameters
19
+ ----------
20
+ f : float
21
+ is interpreted as a vertical load magnitude
22
+ acting straight downward (global y negative).
23
+ phi : float
24
+ Surface dip angle `in degrees`, measured from horizontal.
25
+ Positive `phi` means the surface slopes upward in +x.
26
+
27
+ Returns
28
+ -------
29
+ f_norm, f_tan : float
30
+ Magnitudes of the tangential ( + downslope ) and normal
31
+ ( + into-slope ) components, respectively.
32
+ """
33
+ # Convert units
34
+ phi = np.deg2rad(phi) # Convert inclination to rad
35
+ # Split into components
36
+ f_norm = f * np.cos(phi) # Normal direction
37
+ f_tan = -f * np.sin(phi) # Tangential direction
38
+ return f_norm, f_tan
39
+
40
+
41
+ def get_skier_point_load(m: float) -> float:
42
+ """
43
+ Calculate skier point load.
44
+
45
+ Arguments
46
+ ---------
47
+ m : float
48
+ Skier weight [kg].
49
+
50
+ Returns
51
+ -------
52
+ f : float
53
+ Skier load [N/mm].
54
+ """
55
+ F = 1e-3 * m * G_MM_S2 / LSKI_MM # Total skier
56
+ return F
57
+
58
+
59
+ def load_dummy_profile(
60
+ profile_id: Literal[
61
+ "a", "b", "c", "d", "e", "f", "h", "soft", "medium", "hard", "comp"
62
+ ],
63
+ ) -> list[Layer]:
64
+ """Define standard layering types for comparison."""
65
+ soft_layer = Layer(rho=180, h=120, E=5)
66
+ medium_layer = Layer(rho=270, h=120, E=30)
67
+ hard_layer = Layer(rho=350, h=120, E=93.8)
68
+
69
+ tested_layers = [
70
+ Layer(rho=350, h=120),
71
+ Layer(rho=270, h=120),
72
+ Layer(rho=180, h=120),
73
+ ]
74
+
75
+ # Database (top to bottom)
76
+ database = {
77
+ # Layered
78
+ "a": [hard_layer, medium_layer, soft_layer],
79
+ "b": [soft_layer, medium_layer, hard_layer],
80
+ "c": [hard_layer, soft_layer, hard_layer],
81
+ "d": [soft_layer, hard_layer, soft_layer],
82
+ "e": [hard_layer, soft_layer, soft_layer],
83
+ "f": [soft_layer, soft_layer, hard_layer],
84
+ "tested": tested_layers,
85
+ # Homogeneous
86
+ "h": [medium_layer, medium_layer, medium_layer],
87
+ "soft": [soft_layer, soft_layer, soft_layer],
88
+ "medium": [medium_layer, medium_layer, medium_layer],
89
+ "hard": [hard_layer, hard_layer, hard_layer],
90
+ # Comparison
91
+ "comp": [
92
+ Layer(rho=240, h=200, E=5.23),
93
+ ],
94
+ }
95
+
96
+ # Load profile
97
+ try:
98
+ profile = database[profile_id.lower()]
99
+ except KeyError:
100
+ raise ValueError(f"Profile {profile_id} is not defined.") from None
101
+ return profile
102
+
103
+
104
+ def isnotebook() -> bool:
105
+ """
106
+ Check if code is running in a Jupyter notebook environment.
107
+
108
+ Returns
109
+ -------
110
+ bool
111
+ True if running in Jupyter notebook, False otherwise.
112
+ """
113
+ try:
114
+ # Check if we're in IPython
115
+ from IPython import get_ipython # pylint: disable=import-outside-toplevel
116
+
117
+ if get_ipython() is None:
118
+ return False
119
+
120
+ # Check if we're specifically in a notebook (not just IPython terminal)
121
+ if get_ipython().__class__.__name__ == "ZMQInteractiveShell":
122
+ return True # Jupyter notebook
123
+ if get_ipython().__class__.__name__ == "TerminalInteractiveShell":
124
+ return False # IPython terminal
125
+ return False # Other IPython environments
126
+ except ImportError:
127
+ return False # IPython not available
@@ -0,0 +1,82 @@
1
+ """
2
+ Snow grain types and hand hardness values.
3
+
4
+ These values are used in Pydantic models for validation and correspond to the
5
+ parameterizations available in `geldsetzer.py`.
6
+ """
7
+
8
+ from enum import Enum
9
+
10
+
11
+ class GrainType(str, Enum):
12
+ """SnowPilot grain type codes (see `geldsetzer.GRAIN_TYPE`)."""
13
+
14
+ DF = "DF"
15
+ DFbk = "DFbk"
16
+ DFdc = "DFdc"
17
+ DH = "DH"
18
+ DHch = "DHch"
19
+ DHcp = "DHcp"
20
+ DHla = "DHla"
21
+ DHpr = "DHpr"
22
+ DHxr = "DHxr"
23
+ FC = "FC"
24
+ FCsf = "FCsf"
25
+ FCso = "FCso"
26
+ FCxr = "FCxr"
27
+ IF = "IF"
28
+ IFbi = "IFbi"
29
+ IFic = "IFic"
30
+ IFil = "IFil"
31
+ IFrc = "IFrc"
32
+ IFsc = "IFsc"
33
+ MF = "MF"
34
+ MFcl = "MFcl"
35
+ MFcr = "MFcr"
36
+ MFpc = "MFpc"
37
+ MFsl = "MFsl"
38
+ PP = "PP"
39
+ PPco = "PPco"
40
+ PPgp = "PPgp"
41
+ PPhl = "PPhl"
42
+ PPip = "PPip"
43
+ PPir = "PPir"
44
+ PPnd = "PPnd"
45
+ PPpl = "PPpl"
46
+ PPrm = "PPrm"
47
+ PPsd = "PPsd"
48
+ RG = "RG"
49
+ RGlr = "RGlr"
50
+ RGsr = "RGsr"
51
+ RGwp = "RGwp"
52
+ RGxf = "RGxf"
53
+ SH = "SH"
54
+ SHcv = "SHcv"
55
+ SHsu = "SHsu"
56
+ SHxr = "SHxr"
57
+
58
+
59
+ class HandHardness(str, Enum):
60
+ """Field hand hardness codes (see `geldsetzer.HAND_HARDNESS`).
61
+
62
+ Enum member names avoid starting with digits and special characters.
63
+ """
64
+
65
+ Fm = "F-"
66
+ F = "F"
67
+ Fp = "F+"
68
+ _4Fm = "4F-"
69
+ _4F = "4F"
70
+ _4Fp = "4F+"
71
+ _1Fm = "1F-"
72
+ _1F = "1F"
73
+ _1Fp = "1F+"
74
+ Pm = "P-"
75
+ P = "P"
76
+ Pp = "P+"
77
+ Km = "K-"
78
+ K = "K"
79
+ Kp = "K+"
80
+ Im = "I-"
81
+ I = "I"
82
+ Ip = "I+"
@@ -0,0 +1,332 @@
1
+ """
2
+ Utilizes the snowpylot library to convert a CAAML file to a WEAC ModelInput.
3
+
4
+ The snowpylot library is used to parse the CAAML file and extract the snowpit.
5
+ The snowpit is then converted to a List of WEAC ModelInput.
6
+
7
+ Based on the different stability tests performed, several scenarios are created.
8
+ Each scenario is a WEAC ModelInput.
9
+
10
+ The scenarios are created based on the following logic:
11
+ - For each PropSawTest, a scenario is created with `the cut length` and `a standard segment.`
12
+ - For each ExtColumnTest, a scenario is created with `a standard segment.`
13
+ - For each ComprTest, a scenario is created with `a standard segment.`
14
+ - For each RBlockTest, a scenario is created with `a standard segment.`
15
+
16
+ The `a standard segment` is a segment with a length of 1000 mm and a foundation of True.
17
+
18
+ The `the cut length` is the cut length of the PropSawTest.
19
+ The `the column length` is the column length of the PropSawTest.
20
+ """
21
+
22
+ import logging
23
+ from typing import List, Tuple
24
+
25
+ import numpy as np
26
+ from snowpylot import caaml_parser
27
+ from snowpylot.layer import Layer as SnowpylotLayer
28
+ from snowpylot.snow_pit import SnowPit
29
+ from snowpylot.snow_profile import DensityObs
30
+
31
+ # Import WEAC components
32
+ from weac.components import (
33
+ Layer,
34
+ WeakLayer,
35
+ )
36
+ from weac.utils.geldsetzer import compute_density
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+ convert_to_mm = {"cm": 10, "mm": 1, "m": 1000, "dm": 100}
41
+ convert_to_deg = {"deg": 1, "rad": 180 / np.pi}
42
+
43
+
44
+ class SnowPilotParser:
45
+ """Parser for SnowPilot files using the snowpylot library."""
46
+
47
+ def __init__(self, file_path: str):
48
+ self.snowpit: SnowPit = caaml_parser(file_path)
49
+
50
+ def extract_layers(self) -> Tuple[List[Layer], List[str]]:
51
+ """Extract layers from snowpit."""
52
+ snowpit = self.snowpit
53
+ # Extract layers from snowpit: List[SnowpylotLayer]
54
+ sp_layers: List[SnowpylotLayer] = [
55
+ layer
56
+ for layer in snowpit.snow_profile.layers
57
+ if layer.depth_top is not None
58
+ ]
59
+ sp_layers = sorted(sp_layers, key=lambda x: x.depth_top[0]) # type: ignore
60
+
61
+ # Extract density layers from snowpit: List[DensityObs]
62
+ sp_density_layers: List[DensityObs] = [
63
+ layer
64
+ for layer in snowpit.snow_profile.density_profile
65
+ if layer.depth_top is not None
66
+ ]
67
+ sp_density_layers = sorted(sp_density_layers, key=lambda x: x.depth_top[0]) # type: ignore
68
+
69
+ # Populate WEAC layers: List[Layer]
70
+ layers: List[Layer] = []
71
+ density_methods: List[str] = []
72
+ for _i, layer in enumerate(sp_layers):
73
+ # Parameters
74
+ grain_type = None
75
+ grain_size = None
76
+ hand_hardness = None
77
+ density = None
78
+ thickness = None
79
+
80
+ # extract THICKNESS
81
+ if layer.thickness is not None:
82
+ thickness, unit = layer.thickness
83
+ thickness = thickness * convert_to_mm[unit] # Convert to mm
84
+ else:
85
+ raise ValueError("Thickness not found")
86
+
87
+ # extract GRAIN TYPE and SIZE
88
+ if layer.grain_form_primary:
89
+ if layer.grain_form_primary.grain_form:
90
+ grain_type = layer.grain_form_primary.grain_form
91
+ if layer.grain_form_primary.grain_size_avg:
92
+ grain_size = (
93
+ layer.grain_form_primary.grain_size_avg[0]
94
+ * convert_to_mm[layer.grain_form_primary.grain_size_avg[1]]
95
+ )
96
+ elif layer.grain_form_primary.grain_size_max:
97
+ grain_size = (
98
+ layer.grain_form_primary.grain_size_max[0]
99
+ * convert_to_mm[layer.grain_form_primary.grain_size_max[1]]
100
+ )
101
+
102
+ # extract DENSITY
103
+ # Get layer depth range in mm for density matching
104
+ layer_depth_top_mm = layer.depth_top[0] * convert_to_mm[layer.depth_top[1]]
105
+ layer_depth_bottom_mm = layer_depth_top_mm + thickness
106
+ # Try to find density measurement that overlaps with this layer
107
+ measured_density = self.get_density_for_layer_range(
108
+ layer_depth_top_mm, layer_depth_bottom_mm, sp_density_layers
109
+ )
110
+
111
+ # Handle hardness and create layers accordingly
112
+ if layer.hardness_top is not None and layer.hardness_bottom is not None:
113
+ hand_hardness_top = layer.hardness_top
114
+ hand_hardness_bottom = layer.hardness_bottom
115
+
116
+ # Two hardness values - split into two layers
117
+ half_thickness = thickness / 2
118
+ layer_mid_depth_mm = layer_depth_top_mm + half_thickness
119
+
120
+ # Create top layer (first half)
121
+ if measured_density is not None:
122
+ density_top = self.get_density_for_layer_range(
123
+ layer_depth_top_mm, layer_mid_depth_mm, sp_density_layers
124
+ )
125
+ if density_top is None:
126
+ density_methods.append("geldsetzer")
127
+ density_top = compute_density(grain_type, hand_hardness_top)
128
+ else:
129
+ density_methods.append("density_obs")
130
+ else:
131
+ density_methods.append("geldsetzer")
132
+ density_top = compute_density(grain_type, hand_hardness_top)
133
+
134
+ layers.append(
135
+ Layer(
136
+ rho=density_top,
137
+ h=half_thickness,
138
+ grain_type=grain_type,
139
+ grain_size=grain_size,
140
+ hand_hardness=hand_hardness_top,
141
+ )
142
+ )
143
+
144
+ # Create bottom layer (second half)
145
+ if measured_density is not None:
146
+ density_bottom = self.get_density_for_layer_range(
147
+ layer_mid_depth_mm, layer_depth_bottom_mm, sp_density_layers
148
+ )
149
+ if density_bottom is None:
150
+ density_methods.append("geldsetzer")
151
+ density_bottom = compute_density(
152
+ grain_type, hand_hardness_bottom
153
+ )
154
+ else:
155
+ density_methods.append("density_obs")
156
+ else:
157
+ try:
158
+ density_methods.append("geldsetzer")
159
+ density_bottom = compute_density(
160
+ grain_type, hand_hardness_bottom
161
+ )
162
+ except Exception as exc:
163
+ raise AttributeError(
164
+ "Layer is missing density information; density profile, "
165
+ "hand hardness and grain type are all missing. "
166
+ "Excluding SnowPit from calculations."
167
+ ) from exc
168
+
169
+ layers.append(
170
+ Layer(
171
+ rho=density_bottom,
172
+ h=half_thickness,
173
+ grain_type=grain_type,
174
+ grain_size=grain_size,
175
+ hand_hardness=hand_hardness_bottom,
176
+ )
177
+ )
178
+ else:
179
+ # Single hardness value - create one layer
180
+ hand_hardness = layer.hardness
181
+
182
+ if measured_density is not None:
183
+ density = measured_density
184
+ density_methods.append("density_obs")
185
+ else:
186
+ try:
187
+ density_methods.append("geldsetzer")
188
+ density = compute_density(grain_type, hand_hardness)
189
+ except Exception as exc:
190
+ raise AttributeError(
191
+ "Layer is missing density information; density profile, "
192
+ "hand hardness and grain type are all missing. "
193
+ "Excluding SnowPit from calculations."
194
+ ) from exc
195
+
196
+ layers.append(
197
+ Layer(
198
+ rho=density,
199
+ h=thickness,
200
+ grain_type=grain_type,
201
+ grain_size=grain_size,
202
+ hand_hardness=hand_hardness,
203
+ )
204
+ )
205
+
206
+ if len(layers) == 0:
207
+ raise AttributeError(
208
+ "No layers found for snowpit. Excluding SnowPit from calculations."
209
+ )
210
+ return layers, density_methods
211
+
212
+ def get_density_for_layer_range(
213
+ self,
214
+ layer_top_mm: float,
215
+ layer_bottom_mm: float,
216
+ sp_density_layers: List[DensityObs],
217
+ ) -> float | None:
218
+ """Find density measurements that overlap with the given layer depth range.
219
+
220
+ Args:
221
+ layer_top_mm: Top depth of layer in mm
222
+ layer_bottom_mm: Bottom depth of layer in mm
223
+ sp_density_layers: List of density observations
224
+
225
+ Returns:
226
+ Average density from overlapping measurements, or None if no overlap
227
+ """
228
+ if not sp_density_layers:
229
+ return None
230
+
231
+ overlapping_densities = []
232
+ overlapping_weights = []
233
+
234
+ for density_obs in sp_density_layers:
235
+ if density_obs.depth_top is None or density_obs.thickness is None:
236
+ continue
237
+
238
+ # Convert density observation depth range to mm
239
+ density_top_mm = (
240
+ density_obs.depth_top[0] * convert_to_mm[density_obs.depth_top[1]]
241
+ )
242
+ density_thickness_mm = (
243
+ density_obs.thickness[0] * convert_to_mm[density_obs.thickness[1]]
244
+ )
245
+ density_bottom_mm = density_top_mm + density_thickness_mm
246
+
247
+ # Check for overlap between layer and density measurement
248
+ overlap_top = max(layer_top_mm, density_top_mm)
249
+ overlap_bottom = min(layer_bottom_mm, density_bottom_mm)
250
+
251
+ if overlap_top < overlap_bottom: # There is overlap
252
+ overlap_thickness = overlap_bottom - overlap_top
253
+
254
+ # Extract density value
255
+ if density_obs.density is not None:
256
+ density_value = density_obs.density[0] # (value, unit)
257
+
258
+ overlapping_densities.append(density_value)
259
+ overlapping_weights.append(overlap_thickness)
260
+
261
+ if overlapping_densities:
262
+ # Calculate weighted average based on overlap thickness
263
+ total_weight = sum(overlapping_weights)
264
+ if total_weight > 0:
265
+ weighted_density = (
266
+ sum(
267
+ d * w
268
+ for d, w in zip(overlapping_densities, overlapping_weights)
269
+ )
270
+ / total_weight
271
+ )
272
+ return float(weighted_density)
273
+ return None
274
+
275
+ def extract_weak_layer_and_layers_above(
276
+ self, weak_layer_depth: float, layers: List[Layer]
277
+ ) -> Tuple[WeakLayer, List[Layer]]:
278
+ """Extract weak layer and layers above the weak layer for the given
279
+ depth_top extracted from the stability test."""
280
+ depth = 0
281
+ layers_above = []
282
+ weak_layer_rho = None
283
+ weak_layer_hand_hardness = None
284
+ weak_layer_grain_type = None
285
+ weak_layer_grain_size = None
286
+ if weak_layer_depth <= 0:
287
+ raise ValueError(
288
+ "The depth of the weak layer is not positive. "
289
+ "Excluding SnowPit from calculations."
290
+ )
291
+ if weak_layer_depth > sum(layer.h for layer in layers):
292
+ raise ValueError(
293
+ "The depth of the weak layer is below the recorded layers. "
294
+ "Excluding SnowPit from calculations."
295
+ )
296
+ layers = [layer.model_copy(deep=True) for layer in layers]
297
+ for i, layer in enumerate(layers):
298
+ if depth + layer.h < weak_layer_depth:
299
+ layers_above.append(layer)
300
+ depth += layer.h
301
+ elif depth < weak_layer_depth < depth + layer.h:
302
+ layer.h = weak_layer_depth - depth
303
+ layers_above.append(layer)
304
+ weak_layer_rho = layers[i].rho
305
+ weak_layer_hand_hardness = layers[i].hand_hardness
306
+ weak_layer_grain_type = layers[i].grain_type
307
+ weak_layer_grain_size = layers[i].grain_size
308
+ break
309
+ elif depth + layer.h == weak_layer_depth:
310
+ if i + 1 < len(layers):
311
+ layers_above.append(layer)
312
+ weak_layer_rho = layers[i + 1].rho
313
+ weak_layer_hand_hardness = layers[i + 1].hand_hardness
314
+ weak_layer_grain_type = layers[i + 1].grain_type
315
+ weak_layer_grain_size = layers[i + 1].grain_size
316
+ else:
317
+ weak_layer_rho = layers[i].rho
318
+ weak_layer_hand_hardness = layers[i].hand_hardness
319
+ weak_layer_grain_type = layers[i].grain_type
320
+ weak_layer_grain_size = layers[i].grain_size
321
+ break
322
+
323
+ weak_layer = WeakLayer(
324
+ rho=weak_layer_rho,
325
+ h=20.0,
326
+ hand_hardness=weak_layer_hand_hardness,
327
+ grain_type=weak_layer_grain_type,
328
+ grain_size=weak_layer_grain_size,
329
+ )
330
+ if len(layers_above) == 0:
331
+ raise ValueError("No layers above weak layer found")
332
+ return weak_layer, layers_above
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: weac
3
- Version: 3.0.0
3
+ Version: 3.0.1
4
4
  Summary: Weak layer anticrack nucleation model
5
5
  Author-email: 2phi GbR <mail@2phi.de>
6
- License: Proprietary
6
+ License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/2phi/weac
8
8
  Project-URL: Demo, https://github.com/2phi/weac/blob/main/demo/demo.ipynb
9
9
  Project-URL: Documentation, https://2phi.github.io/weac
@@ -11,7 +11,6 @@ Project-URL: Issues and feature requests, https://github.com/2phi/weac/issues
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
- Classifier: License :: Other/Proprietary License
15
14
  Classifier: Operating System :: OS Independent
16
15
  Classifier: Topic :: Scientific/Engineering
17
16
  Requires-Python: >=3.12
@@ -55,7 +54,8 @@ Requires-Dist: pylint>=3.2.0; extra == "dev"
55
54
  Requires-Dist: pycodestyle>=2.11.1; extra == "dev"
56
55
  Requires-Dist: black>=24.4.0; extra == "dev"
57
56
  Requires-Dist: isort>=5.13.0; extra == "dev"
58
- Requires-Dist: bump2version>=1.0.1; extra == "dev"
57
+ Requires-Dist: bump-my-version; extra == "dev"
58
+ Requires-Dist: build; extra == "dev"
59
59
  Dynamic: license-file
60
60
 
61
61
  <!-- LOGO AND TITLE-->
@@ -0,0 +1,32 @@
1
+ weac/__init__.py,sha256=YrbBczmXbMc2L2DRklNEOFxlfY0Z9FLDnpW8ZhbaIww,76
2
+ weac/constants.py,sha256=BX8ifZhFciCuzzako1p-2Wh5CWWzR3cPdvyu501UtUs,1194
3
+ weac/logging_config.py,sha256=BFphsxo5s_7E6rPOO2PbOfu0Wy8zHD4AUnnJdqvrn5I,1134
4
+ weac/analysis/__init__.py,sha256=twF9OYrZiVmBtw6Lyzf5QUhLZNtqFFM2H3OuaYCog1k,486
5
+ weac/analysis/analyzer.py,sha256=AR1yxM5trK1c-_lTEVn9e6e96IhWVWSRgHgQcaLy4Io,27089
6
+ weac/analysis/criteria_evaluator.py,sha256=oIVL7Mq3fjyiVx_ms-miULdHE4-EYE2OXoMalM9eU1Q,43458
7
+ weac/analysis/plotter.py,sha256=UdiPZKb8vzZAdB1tjVUNfV2INtZaqEiJ7EA8Y-dzxoM,66056
8
+ weac/components/__init__.py,sha256=94WIUVjPI3U-grN_7v0oi9bZB3Z8rCBcx9wJPOwJBAQ,439
9
+ weac/components/config.py,sha256=tnOnJ0M-_knZBhdr052nDyyFFAZN0f2hQ68XRuXG6d8,869
10
+ weac/components/criteria_config.py,sha256=f2agU7nXWURFAw8_68igiSk5aICUxwaB9u3Qasit-Q0,2909
11
+ weac/components/layer.py,sha256=sF47006ORRmNnHW7QMk9h-M0vQQR6TL_PKOvInjdNsk,10560
12
+ weac/components/model_input.py,sha256=dp695ZMXkSXzJaD-ih9XO0QhnFRPKn8zUJY7g-bomhE,3354
13
+ weac/components/scenario_config.py,sha256=Tam-m9DQtdjmTm-lKQ8Dcjqje04ttJS2X3v_Nn7AUHQ,2563
14
+ weac/components/segment.py,sha256=F279KcAAkRuJKWav_BZ4BanO96WZm4KXtKHinFZki7s,941
15
+ weac/core/__init__.py,sha256=pRyCKD8XD3qXVUWtFG7N3cS91P5x5d8Jpr1hMEgxQ2U,233
16
+ weac/core/eigensystem.py,sha256=I4AIGD_uDVKIGv_sv9AXbIXhJ4Eol64BLB-lZF8X3jw,13735
17
+ weac/core/field_quantities.py,sha256=ci7MvhJ4aYdbW6xxH8vHVgWtk5iypCYv6dZ6KjFNvt8,8964
18
+ weac/core/scenario.py,sha256=f5EZaeFJWMFN_JNOrzVDv5_CeRruHn6jSjGbV9fdxhY,6076
19
+ weac/core/slab.py,sha256=nidM3FvTwtj30LmM4OxOfPwqm5TpPzJrH5UvQR6w4no,5150
20
+ weac/core/slab_touchdown.py,sha256=D0mVVeRktFpjywuhEiIZHOVJflslfKX3oesx1mMQGxg,14025
21
+ weac/core/system_model.py,sha256=XMovKslSTvoNHyxeL7zTFMhAqVOTHnXD7MUPkaGSl9Q,15577
22
+ weac/core/unknown_constants_solver.py,sha256=cDXMVKIdhA8AWZQbJnNpM19pvLllvIVc6Mw6xaZGqYw,17839
23
+ weac/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ weac/utils/geldsetzer.py,sha256=DxvpqmWulBacl-mGeAmAuJcv2xqFBx92PEfNC3aeDzk,3500
25
+ weac/utils/misc.py,sha256=lGz0IDDJ_3nvYjSkivPJ5Xscl1D_AmvQLSjaL7SUbKs,3674
26
+ weac/utils/snow_types.py,sha256=eX9-5La6Oom7zh6pg5JZ4MZ6nLdWdc7RoUzm5e6b9w8,1483
27
+ weac/utils/snowpilot_parser.py,sha256=5fKC0FKcEJvfFQfZbPW5cHqb_nyzIltweq7Bdz5-a0A,13713
28
+ weac-3.0.1.dist-info/licenses/LICENSE,sha256=ojZPWKFHbFGDrlNOvuAKGH9WcKhpLHWZPcQ4SzhK91M,1082
29
+ weac-3.0.1.dist-info/METADATA,sha256=-14ZLdvT2GKGX5n8XLJbd3wxPUHvj8Fi5hg85GfdJPs,23666
30
+ weac-3.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ weac-3.0.1.dist-info/top_level.txt,sha256=8tyXUHPFU4Ba_5kPtpwvXo5l6GjJmOnODVBJFygpdeE,5
32
+ weac-3.0.1.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 2phi GbR and contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,8 +0,0 @@
1
- weac/__init__.py,sha256=dv7A3r-vIVUaQJDEt5pxC8IJq_Lej2camGA7fIhTsmc,76
2
- weac/constants.py,sha256=BX8ifZhFciCuzzako1p-2Wh5CWWzR3cPdvyu501UtUs,1194
3
- weac/logging_config.py,sha256=BFphsxo5s_7E6rPOO2PbOfu0Wy8zHD4AUnnJdqvrn5I,1134
4
- weac-3.0.0.dist-info/licenses/LICENSE,sha256=CZlY87tZ1Kq7QxKLVrMknnDXGpc1yEZ8SKoXMAk-d4k,1463
5
- weac-3.0.0.dist-info/METADATA,sha256=lDtqRgn6B42TJM7ju83uFvlzzjkFm93qFIIa99-vI-g,23679
6
- weac-3.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- weac-3.0.0.dist-info/top_level.txt,sha256=8tyXUHPFU4Ba_5kPtpwvXo5l6GjJmOnODVBJFygpdeE,5
8
- weac-3.0.0.dist-info/RECORD,,
@@ -1,24 +0,0 @@
1
- Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
2
-
3
- WEAC (c) 2024 is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/.
4
-
5
- You are free to:
6
-
7
- - Share — copy and redistribute the material in any medium or format
8
- - Adapt — remix, transform, and build upon the material.
9
-
10
- Under the following terms:
11
-
12
- - Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
13
-
14
- - NonCommercial — You may not use the material for commercial purposes.
15
-
16
- - ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
17
-
18
- No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
19
-
20
- Notices:
21
-
22
- You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation.
23
-
24
- No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material.
File without changes