Source code for weac.components.segment
"""
This module defines the Segment class, which represents a segment of the snowpack.
"""
from typing import Annotated
import numpy as np
from pydantic import BaseModel, Field, field_validator, PlainSerializer, WithJsonSchema
from pydantic import ConfigDict
from numpy.typing import NDArray
def _serialize_ndarray(arr: np.ndarray) -> list:
"""Serialize numpy array to nested list for JSON compatibility."""
return arr.tolist()
NumpyArray = Annotated[
np.ndarray,
PlainSerializer(_serialize_ndarray, return_type=list),
WithJsonSchema(
{"type": "array", "items": {"type": "array", "items": {"type": "number"}}}
),
]
[docs]
class Segment(BaseModel):
"""
Defines a snow-slab segment: its length, foundation support, and applied loads.
Attributes
----------
length: float
Segment length in millimeters [mm].
has_foundation: bool
Whether the segment is supported (foundation present) or cracked/free-hanging
(no foundation).
is_loaded: bool
Whether additional loading is applied at the segment's top side.
m: float
Skier mass at the segment's right edge [kg].
"""
model_config = ConfigDict(arbitrary_types_allowed=True)
length: float = Field(default=5e3, ge=0, description="Segment length in [mm]")
has_foundation: bool = Field(
default=True,
description="Whether the segment is supported (foundation present) or "
"cracked/free-hanging (no foundation)",
)
is_loaded: bool = Field(
default=True,
description="Whether additional loading is applied at the segment's top side",
)
m: float = Field(
default=0, ge=0, description="Skier mass at the segment's right edge in [kg]"
)
f: NumpyArray = Field(
default_factory=lambda: np.zeros((6, 1), dtype=float),
description=(
"Load vector acting on the right side of the segment. "
"Includes the six section forces [Nx, Vy, Vz, Mx, My, Mz]."
),
)
[docs]
@field_validator("f")
@classmethod
def ensure_ndarray(cls, v: NDArray[np.float64]) -> NDArray[np.float64]:
# allows passing lists/tuples etc. and enforces float dtype
return np.asarray(v, dtype=float)