weac.core package

Submodules

Module contents

Core modules for the WEAC model.

class weac.core.Eigensystem(weak_layer, slab)[source]

Bases: object

Calculates system properties and solves the eigenvalue problem for a layered beam on an elastic foundation (Winkler model).

Parameters:
weak_layer
Type:

WeakLayer

slab
Type:

Slab

System properties
-----------------
A11
Type:

float # extensional stiffness

B11
Type:

float # coupling stiffness

D11
Type:

float # bending stiffness

kA55
Type:

float # shear stiffness

K0
Type:

float # foundation stiffness

Eigenvalues and Eigenvectors
----------------------------
ewC
Type:

NDArray[np.complex128] # shape (k): Complex Eigenvalues

ewR
Type:

NDArray[np.float64] # shape (k): Real Eigenvalues

evC
Type:

NDArray[np.complex128] # shape (6, k): Complex Eigenvectors

evR
Type:

NDArray[np.float64] # shape (6, k): Real Eigenvectors

sR

# (for numerical robustness)

Type:

NDArray[np.float64] # shape (k): Real positive eigenvalue shifts

sC

# (for numerical robustness)

Type:

NDArray[np.float64] # shape (k): Complex positive eigenvalue shifts

__init__(weak_layer, slab)[source]
Parameters:
assemble_system_matrix(kn, kt)[source]

Assemble first-order ODE system matrix K.

Using the solution vector z = [u, u’, w, w’, psi, psi’] the ODE system is written in the form Az’ + Bz = d and rearranged to z’ = -(A^-1)Bz + (A^-1)d = Kz + q

Returns:

System matrix K (6x6).

Return type:

NDArray[np.float64]

Parameters:
  • kn (float | None)

  • kt (float | None)

calc_eigensystem()[source]

Calculate the fundamental system of the problem.

calc_eigenvalues_and_eigenvectors(system_matrix)[source]

Calculate eigenvalues and eigenvectors of the system matrix.

Parameters:

system_matrix: NDArray # system_matrix size (6x6) of the eigenvalue problem

Return:

ewC: NDArray[np.complex128] # shape (k): Complex Eigenvalues ewR: NDArray[np.float64] # shape (g): Real Eigenvalues evC: NDArray[np.complex128] # shape (6, k): Complex Eigenvectors evR: NDArray[np.float64] # shape (6, g): Real Eigenvectors sR: NDArray[np.float64] # shape (k): Real positive eigenvalue shifts

# (for numerical robustness)

sC: NDArray[np.float64] # shape (g): Complex positive eigenvalue shifts

# (for numerical robustness)

Parameters:

system_matrix (ndarray[tuple[Any, ...], dtype[float64]])

Return type:

tuple[ndarray[tuple[Any, …], dtype[complex128]], ndarray[tuple[Any, …], dtype[float64]], ndarray[tuple[Any, …], dtype[complex128]], ndarray[tuple[Any, …], dtype[float64]], ndarray[tuple[Any, …], dtype[float64]], ndarray[tuple[Any, …], dtype[float64]]]

get_load_vector(phi, qs=0)[source]

Compute system load vector q.

Using the solution vector z = [u, u’, w, w’, psi, psi’] the ODE system is written in the form Az’ + Bz = d and rearranged to z’ = -(A ^ -1)Bz + (A ^ -1)d = Kz + q

Parameters:
  • phi (float) – Inclination [deg]. Counterclockwise positive.

  • qs (float) – Surface Load [N/mm]

Returns:

System load vector q (6x1).

Return type:

ndarray

zh(x, length=0, has_foundation=True)[source]

Compute bedded or free complementary solution at position x.

Parameters:
  • x (float) – Horizontal coordinate (mm).

  • length (float, optional) – Segment length (mm). Default is 0.

  • has_foundation (bool) – Indicates whether segment has foundation or not. Default is True.

Returns:

zh – Complementary solution matrix (6x6) at position x.

Return type:

ndarray

zp(x, phi=0, has_foundation=True, qs=0)[source]

Compute bedded or free particular integrals at position x.

Parameters:
  • x (float) – Horizontal coordinate (mm).

  • phi (float) – Inclination (degrees).

  • has_foundation (bool) – Indicates whether segment has foundation (True) or not (False). Default is True.

  • qs (float) – additional surface load weight

Returns:

zp – Particular integral vector (6x1) at position x.

Return type:

ndarray

weak_layer: WeakLayer
slab: Slab
A11: float
B11: float
D11: float
kA55: float
K0: float
K: ndarray[tuple[Any, ...], dtype[_ScalarT]]
ewC: ndarray[tuple[Any, ...], dtype[complex128]]
ewR: ndarray[tuple[Any, ...], dtype[float64]]
evC: ndarray[tuple[Any, ...], dtype[complex128]]
evR: ndarray[tuple[Any, ...], dtype[float64]]
sR: ndarray[tuple[Any, ...], dtype[float64]]
sC: ndarray[tuple[Any, ...], dtype[float64]]
class weac.core.Scenario(scenario_config, segments, weak_layer, slab)[source]

Bases: object

Sets up the scenario on which the eigensystem is solved.

Parameters:
li

length of segment i [mm]

Type:

List[float]

ki

booleans indicating foundation support for segment i

Type:

List[bool]

mi

skier masses (kg) on boundary of segment i and i+1 [kg]

Type:

List[float]

system_type
Type:

SystemType

phi

Angle of slab in positive in counter-clockwise direction [deg]

Type:

float

L

Length of the model [mm]

Type:

float

crack_h

Height of the crack [mm]

Type:

float

__init__(scenario_config, segments, weak_layer, slab)[source]
Parameters:
get_segment_idx(x)[source]

Get the segment index for a given x-coordinate or coordinates.

Parameters:

x (Union[float, Sequence[float], np.ndarray]) – A single x-coordinate or a sequence of x-coordinates.

Returns:

The segment index or an array of indices.

Return type:

Union[int, np.ndarray]

refresh_from_config()[source]

Pull changed values out of scenario_config and recompute derived attributes.

scenario_config: ScenarioConfig
segments: List[Segment]
weak_layer: WeakLayer
slab: Slab
li: ndarray
ki: ndarray
mi: ndarray
cum_sum_li: ndarray
system_type: Literal['skier', 'skiers', 'pst-', '-pst', 'rot', 'trans', 'vpst-', '-vpst']
phi: float
surface_load: float
qw: float
qn: float
qt: float
L: float
crack_h: float
cut_length: float
class weac.core.Slab(layers)[source]

Bases: object

Parameters of all layers assembled into a slab, provided as np.ndarray for easier access.

Coordinate frame: - z-axis points downward (first index: top layer, last index: bottom layer) - z = 0 is set at the mid-point of the slab’s thickness

Parameters:

layers (List[Layer])

zi_mid

z-coordinate of the layer i mid-point

Type:

np.ndarray

zi_bottom

z-coordinate of the layer i (boundary towards bottom)

Type:

np.ndarray

rhoi

densities of the layer i [t/mm^3]

Type:

np.ndarray

hi

thickness of the layer i [mm]

Type:

np.ndarray

Ei

Young’s modulus of the layer i [MPa]

Type:

np.ndarray

Gi

Shear Modulus of the layer i [MPa]

Type:

np.ndarray

nui

Poisson Ratio of the layer i [-]

Type:

np.ndarray

H

Total slab thickness (i.e. assembled layers) [mm]

Type:

float

z_cog

z-coordinate of Center of Gravity [mm]

Type:

float

qw

Weight Load of the slab [N/mm]

Type:

float

__init__(layers)[source]
Parameters:

layers (List[Layer])

Return type:

None

calc_vertical_center_of_gravity(phi)[source]

Vertical PSTs use triangular slabs (with horizontal cuts on the slab ends) Calculate center of gravity of triangular slab segments for vertical PSTs.

Parameters:

phi (float) – Slope angle [deg]

Returns:

  • x_cog (float) – Horizontal coordinate of center of gravity [mm]

  • z_cog (float) – Vertical coordinate of center of gravity [mm]

  • w (float) – Weight of the slab segment that is cut off or added [t]

layers: List[Layer]
rhoi: ndarray
hi: ndarray
Ei: ndarray
Gi: ndarray
nui: ndarray
z0: float
zi_mid: ndarray
zi_bottom: ndarray
H: float
z_cog: float
qw: float
class weac.core.SystemModel(model_input, config=None)[source]

Bases: object

The heart of the WEAC simulation system for avalanche release modeling.

This class orchestrates all components of the WEAC simulation, including slab mechanics, weak layer properties, touchdown calculations, and the solution of unknown constants for beam-on-elastic-foundation problems.

The SystemModel follows a lazy evaluation pattern using cached properties, meaning expensive calculations (eigensystem, touchdown, unknown constants) are only computed when first accessed and then cached for subsequent use.

Extracting Unknown Constants:

The primary output of the SystemModel is the unknown_constants matrix, which contains the solution constants for the beam segments:

```python # Basic usage system = SystemModel(model_input=model_input, config=config) constants = system.unknown_constants # Shape: (6, N) where N = number of segments

# Each column represents the 6 constants for one segment: # constants[:, i] = [C1, C2, C3, C4, C5, C6] for segment i # These constants define the beam deflection solution within that segment ```

Calculation Flow:

  1. Eigensystem: Computes eigenvalues/eigenvectors for the beam-foundation system

  2. Slab Touchdown (if enabled): Calculates touchdown behavior and updates segment lengths

  3. Unknown Constants: Solves the linear system for beam deflection constants

Touchdown Behavior:

When config.touchdown=True, the system automatically: - Calculates touchdown mode (A: free-hanging, B: point contact, C: in contact) - Determines touchdown length based on slab-foundation interaction - Redefines scenario segments to use touchdown length instead of crack length - This matches the behavior of the original WEAC implementation

Performance Notes:

  • First access to unknown_constants triggers all necessary calculations

  • Subsequent accesses return cached results instantly

  • Use update_* methods to modify parameters and invalidate caches as needed

Example Usage:

```python from weac.components import ModelInput, Layer, Segment, Config from weac.core.system_model import SystemModel

# Define system components layers = [Layer(rho=200, h=150), Layer(rho=300, h=100)] segments = [Segment(length=10000, has_foundation=True, m=0),

Segment(length=4000, has_foundation=False, m=0)]

# Create system system = SystemModel(model_input=model_input, config=Config(touchdown=True))

# Solve system and extract results constants = system.unknown_constants # Solution constants (6 x N_segments) touchdown_info = system.slab_touchdown # Touchdown analysis (if enabled) eigensystem = system.eigensystem # Eigenvalue problem solution ```

Parameters:
config

Configuration settings including touchdown enable/disable

Type:

weac.components.config.Config

slab

Slab properties (thickness, material properties per layer)

Type:

weac.core.slab.Slab

weak_layer

Weak layer properties (stiffness, thickness, etc.)

Type:

weac.components.layer.WeakLayer

scenario

Scenario definition (segments, loads, boundary conditions)

Type:

weac.core.scenario.Scenario

eigensystem

Eigenvalue problem solution (computed lazily)

Type:

weac.core.eigensystem.Eigensystem

slab_touchdown

Touchdown analysis results (computed lazily if enabled)

Type:

weac.core.slab_touchdown.SlabTouchdown | None

unknown_constants

Solution constants matrix (computed lazily)

Type:

numpy.ndarray

__init__(model_input, config=None)[source]
Parameters:
property eigensystem: Eigensystem

Solve for the eigensystem.

property fq: FieldQuantities

Compute the field quantities.

property slab_touchdown: SlabTouchdown | None

Solve for the slab touchdown. Modifies the scenario object in place by replacing the undercut segment with a new segment of length equal to the touchdown distance if the system is a PST or VPST.

toggle_touchdown(touchdown)[source]

Toggle the touchdown.

Parameters:

touchdown (bool)

property uncracked_unknown_constants: ndarray

Solve for the uncracked unknown constants. This is the solution for the case where the slab is cracked nowhere.

property unknown_constants: ndarray

Solve for the unknown constants matrix defining beam deflection in each segment.

This is the core solution of the WEAC beam-on-elastic-foundation problem. The unknown constants define the deflection, slope, moment, and shear force distributions within each beam segment.

Returns:

np.ndarray: Solution constants matrix of shape (6, N_segments)

Each column contains the 6 constants for one segment: [C1, C2, C3, C4, C5, C6]

These constants are used in the general solution: u(x) = Σ Ci * φi(x) + up(x)

Where φi(x) are the homogeneous solutions and up(x) is the particular solution.

Notes

  • For touchdown systems, segment lengths are automatically adjusted based on touchdown calculations before solving

  • The solution accounts for boundary conditions, load transmission between segments, and foundation support

  • Results are cached after first computation for performance

Example

```python system = SystemModel(model_input, config) C = system.unknown_constants # Shape: (6, 2) for 2-segment system

# Constants for first segment segment_0_constants = C[:, 0]

# Use with eigensystem to compute field quantities x = 1000 # Position in mm segment_length = system.scenario.li[0] ```

update_layers(new_layers)[source]

Update the layers.

Parameters:

new_layers (List[Layer])

update_scenario(segments=None, scenario_config=None)[source]

Update fields on scenario_config (if present) or on the Scenario object itself, then refresh and invalidate constants.

Parameters:
update_weak_layer(weak_layer)[source]

Update the weak layer.

Parameters:

weak_layer (WeakLayer)

z(x, C, length, phi, has_foundation=True, qs=0)[source]

Assemble solution vector at positions x.

Parameters:
  • x (float or sequence) – Horizontal coordinate (mm). Can be sequence of length N.

  • C (ndarray) – Vector of constants (6xN) at positions x.

  • length (float) – Segment length (mm).

  • phi (float) – Inclination (degrees).

  • has_foundation (bool) – Indicates whether segment has foundation (True) or not (False). Default is True.

  • qs (float) – Surface Load [N/mm]

Returns:

z – Solution vector (6xN) at position x.

Return type:

ndarray

config: Config
slab: Slab
weak_layer: WeakLayer
scenario: Scenario