Source code for snowprofile.stability_tests

# -*- coding: utf-8 -*-

import typing

import pydantic

from snowprofile._base_classes import AdditionalData, datetime_with_tz, datetime_tuple_with_tz
from snowprofile._constants import GRAIN_SHAPES

__all__ = ['CTStabilityTest', 'CTStabilityTestResult',
           'ECTStabilityTest', 'ECTStabilityTestResult',
           'PSTStabilityTest',
           'RBStabilityTest', 'RBStabilityTestResult',
           'ShearFrameStabilityTest', 'ShearFrameStabilityTestResult']


class _StabilityTest(pydantic.BaseModel):
    """
    Base class for Stability test representation.
    """
    model_config = pydantic.ConfigDict(
        validate_assignment=True,
        extra='forbid')

    id: typing.Optional[str] = None
    name: typing.Optional[str] = pydantic.Field(
        None,
        description="Name/short description of the test")
    related_profiles: typing.List[str] = pydantic.Field(
        [],
        description="id of related profiles")
    comment: typing.Optional[str] = None
    test_nr: typing.Optional[int] = pydantic.Field(
        None, ge=0,
        description="Test number (the lower is the higher priority)")
    name: typing.Optional[str] = pydantic.Field(
        None,
        description="Name/short description of the profile")
    comment: typing.Optional[str] = pydantic.Field(
        None,
        description="A comment associated to the profile")
    additional_data: typing.Optional[AdditionalData] = pydantic.Field(
        None,
        description="Field to store additional data for CAAML compatibility (customData), do not use.")


class _StabilityTestResult(pydantic.BaseModel):
    """
    Base class for stability tests result representation.

    """
    model_config = pydantic.ConfigDict(
        validate_assignment=True,
        extra='forbid')

    height: typing.Optional[float] = pydantic.Field(
        None,
        description="Height of the failed layer (with zero at bottom of the snowpack (m)")
    layer_thickness: typing.Optional[float] = pydantic.Field(
        None,
        description="Thickness of the failed layer (m)")
    grain_1: typing.Optional[typing.Literal[tuple(GRAIN_SHAPES)]] = pydantic.Field(
        None,
        description="Primary grain shape of the failed layer")
    grain_2: typing.Optional[typing.Literal[tuple(GRAIN_SHAPES)]] = pydantic.Field(
        None,
        description="Secondary grain shape of the failed layer")
    grain_size: typing.Optional[float] = pydantic.Field(
        None,
        description="Snow grain size of the failed layer (m)")
    grain_size_max: typing.Optional[float] = pydantic.Field(
        None,
        description="Maximum snow grain size of the failed layer (m)")
    layer_formation_time: typing.Optional[datetime_with_tz] = pydantic.Field(
        None,
        description="The formation time of the failed layer.")
    layer_formation_period: typing.Optional[datetime_tuple_with_tz] = pydantic.Field(
        (None, None),
        description="The formation period (begin, end) of the failed layer.")
    layer_comment: typing.Optional[str] = pydantic.Field(
        None,
        description="Comment associated to layer description (for CAAML compatibility only, do not fill).")
    layer_additional_data: typing.Optional[AdditionalData] = pydantic.Field(
        None,
        description="Field to store additional data for CAAML compatibility (customData), do not use.")


[docs] class RBStabilityTestResult(_StabilityTestResult): """ Class for RB (Rutschblock) stability test results. """ model_config = pydantic.ConfigDict( validate_assignment=True, extra='forbid') test_score: int = pydantic.Field( description="RB result [1-7], 7 meaning no fracture", ge=1, le=7) release_type: typing.Optional[typing.Literal[ 'WB', 'MB', 'EB']] = pydantic.Field( None, description="Release type among:\n\n" "- WB: Whole block\n" "- MB: Most of the block\n" "- EB: Edge of the block") fracture_character: typing.Optional[typing.Literal[ 'SDN', 'SP', 'SC', 'RES', 'RP', 'PC', 'BRK', 'Clean', 'Rough', 'Irregular', 'Q1', 'Q2', 'Q3']] = pydantic.Field( None, description="Fracture characteristic among: \n\n" "- SP: Sudden planar\n" "- SC: Sudden collapse\n" "- SDN: Sudden (both)\n" "- RP: Resistant planar\n" "- PC: Progressive compression\n" "- RES: Resistant (both)\n" "- BRK or B: Break\n" "- Clean\n" "- Rough\n" "- Irregular\n" "- Q1\n" "- Q2\n" "- Q3")
[docs] class RBStabilityTest(_StabilityTest): """ Class for RB (Rutschblock) stability test. """ results: typing.List[RBStabilityTestResult] = pydantic.Field( [], description="Successive results of a single RB test. No results mean RB7.") type: typing.Literal['Rutschblock'] = 'Rutschblock'
[docs] class CTStabilityTestResult(_StabilityTestResult): """ Class for CT (Comprerssion test) stability test results. """ model_config = pydantic.ConfigDict( validate_assignment=True, extra='forbid') test_score: int = pydantic.Field( description="CT result [0-30]", ge=0, le=30) fracture_character: typing.Optional[typing.Literal[ 'SDN', 'SP', 'SC', 'RES', 'RP', 'PC', 'BRK', 'Clean', 'Rough', 'Irregular', 'Q1', 'Q2', 'Q3']] = pydantic.Field( None, description="Fracture characteristic among: \n\n" "- SP: Sudden planar\n" "- SC: Sudden collapse\n" "- SDN: Sudden (both)\n" "- RP: Resistant planar\n" "- PC: Progressive compression\n" "- RES: Resistant (both)\n" "- BRK or B: Break\n" "- Clean\n" "- Rough\n" "- Irregular\n" "- Q1\n" "- Q2\n" "- Q3")
[docs] class CTStabilityTest(_StabilityTest): """ Class for CT (Compression test) stability test. """ results: typing.List[CTStabilityTestResult] = pydantic.Field( [], description="Successive results of a single CT test. No results mean CT31.") type: typing.Literal['CT'] = 'CT'
[docs] class ECTStabilityTestResult(_StabilityTestResult): """ Class for ECT (extended column test) stability test result. Set score=0 for ECTPV. """ test_score: int = pydantic.Field( description="CT result [0-30]", ge=0, le=30) propagation: bool = False
[docs] class ECTStabilityTest(_StabilityTest): """ Class for ECT (Extended column test) stability test. """ results: typing.List[ECTStabilityTestResult] = pydantic.Field( [], description="Successive results of a single ECT test. No results mean ECTN.") type: typing.Literal['ECT'] = 'ECT'
[docs] class PSTStabilityTest(_StabilityTest, _StabilityTestResult): """ Class for PST (Propagation Saw test) stability test. """ column_length: typing.Optional[float] = pydantic.Field( None, description="Length of the column used for stability test (m).") cut_length: float = pydantic.Field( description="The cut length necessary to start the propagation.") propagation: typing.Literal['End', 'SF', 'Arr'] = pydantic.Field( description="Propagation type: \n\n" "- End means the fracture propagate through the end of the column,\n" "- SF means slab fracture,\n" "- Arr means arrest of the propagation before the end of the column.") type: typing.Literal['PST'] = 'PST'
[docs] class ShearFrameStabilityTestResult(_StabilityTestResult): """ Class for shear frame stability test results. """ model_config = pydantic.ConfigDict( validate_assignment=True, extra='forbid') force: float = pydantic.Field( description="Failure force (N).", ge=0) fracture_character: typing.Optional[typing.Literal[ 'SDN', 'SP', 'SC', 'RES', 'RP', 'PC', 'BRK', 'Clean', 'Rough', 'Irregular', 'Q1', 'Q2', 'Q3']] = pydantic.Field( None, description="Fracture characteristic among: \n\n" "- SP: Sudden planar\n" "- SC: Sudden collapse\n" "- SDN: Sudden (both)\n" "- RP: Resistant planar\n" "- PC: Progressive compression\n" "- RES: Resistant (both)\n" "- BRK or B: Break\n" "- Clean\n" "- Rough\n" "- Irregular\n" "- Q1\n" "- Q2\n" "- Q3")
[docs] class ShearFrameStabilityTest(_StabilityTest): """ Class for Shear frame stability test. """ results: typing.List[ShearFrameStabilityTestResult] = pydantic.Field( [], description="Successive results of a single SF test. No results mean no failure.") type: typing.Literal['Shear Frame'] = 'Shear Frame'