# generated by datamodel-codegen:
#   filename:  openapi.json
#   timestamp: 2025-08-19T11:03:47+00:00

from __future__ import annotations

from enum import Enum
from typing import Any, Dict, List, Optional, Union

from pydantic import BaseModel, RootModel, conint


class AnalysisOption(BaseModel):
    dimensionality: str
    id: conint(ge=0)
    max_iterations: Optional[conint(ge=0)] = None
    order: str
    solve_loadcases: bool
    solver: str
    tolerance: float


class DistributionShape(Enum):
    Uniform = "Uniform"
    Triangular = "Triangular"
    InverseTriangular = "InverseTriangular"


class GeneralInfo(BaseModel):
    author: str
    project_name: str
    version: str


class GoverningKey(BaseModel):
    load_case_id: Optional[conint(ge=0)] = None
    load_combination_id: Optional[conint(ge=0)] = None
    member_id: Optional[conint(ge=0)] = None


class LimitState(Enum):
    SLS = "SLS"
    ULS = "ULS"
    FLS = "FLS"
    ALS = "ALS"


class LoadCombination(BaseModel):
    check: str
    limit_state: LimitState
    load_cases_factors: Dict[str, float]
    load_combination_id: conint(ge=0)
    name: str
    situation: Optional[str] = None


class Material(BaseModel):
    density: float
    e_mod: float
    g_mod: float
    id: conint(ge=0)
    name: str
    yield_stress: float


class MemberHinge(BaseModel):
    hinge_type: str
    id: conint(ge=0)
    max_moment_mx: Optional[float] = None
    max_moment_my: Optional[float] = None
    max_moment_mz: Optional[float] = None
    max_tension_vx: Optional[float] = None
    max_tension_vy: Optional[float] = None
    max_tension_vz: Optional[float] = None
    rotational_release_mx: Optional[float] = None
    rotational_release_my: Optional[float] = None
    rotational_release_mz: Optional[float] = None
    translational_release_vx: Optional[float] = None
    translational_release_vy: Optional[float] = None
    translational_release_vz: Optional[float] = None


class MemberType(Enum):
    Normal = "Normal"
    Truss = "Truss"
    Tension = "Tension"
    Compression = "Compression"
    Rigid = "Rigid"


class NodalLoad(BaseModel):
    direction: List
    id: conint(ge=0)
    load_case: conint(ge=0)
    load_type: str
    magnitude: float
    node: conint(ge=0)


class NodalMoment(BaseModel):
    direction: List
    id: conint(ge=0)
    load_case: conint(ge=0)
    load_type: str
    magnitude: float
    node: conint(ge=0)


class NodalSupport(BaseModel):
    classification: Optional[str] = None
    displacement_conditions: Dict[str, str]
    id: conint(ge=0)
    rotation_conditions: Dict[str, str]


class Node(BaseModel):
    X: float
    Y: float
    Z: float
    id: conint(ge=0)
    nodal_support: Optional[conint(ge=0)] = None


class NodeDisplacement(BaseModel):
    dx: float
    dy: float
    dz: float
    rx: float
    ry: float
    rz: float


class NodeForces(BaseModel):
    fx: float
    fy: float
    fz: float
    mx: float
    my: float
    mz: float


class NodeLocation(BaseModel):
    X: float
    Y: float
    Z: float


class ReactionNodeResult(BaseModel):
    location: NodeLocation
    nodal_forces: NodeForces
    support_id: conint(ge=0)


class ResultType1(BaseModel):
    Loadcase: conint(ge=0)


class ResultType2(BaseModel):
    Loadcombination: conint(ge=0)


class ResultType(RootModel[Union[ResultType1, ResultType2]]):
    root: Union[ResultType1, ResultType2]


class ResultsSummary(BaseModel):
    total_displacements: conint(ge=0)
    total_member_forces: conint(ge=0)
    total_reaction_forces: conint(ge=0)


class Section(BaseModel):
    area: float
    b: Optional[float] = None
    h: Optional[float] = None
    i_y: float
    i_z: float
    id: conint(ge=0)
    j: float
    material: conint(ge=0)
    name: str
    shape_path: Optional[conint(ge=0)] = None


class Settings(BaseModel):
    analysis_option: AnalysisOption
    general_info: GeneralInfo
    id: conint(ge=0)


class ShapeCommand(BaseModel):
    command: str
    r: Optional[float] = None
    y: Optional[float] = None
    z: Optional[float] = None


class ShapePath(BaseModel):
    id: conint(ge=0)
    name: str
    shape_commands: List[ShapeCommand]


class UnityCheck(BaseModel):
    check_id: str
    details: Any
    governing: Optional[GoverningKey] = None
    limit: Optional[float] = None
    message: Optional[str] = None
    ok: bool
    value: Optional[float] = None


class UnityCheckOverview(BaseModel):
    aggregated_ok: bool
    aggregated_value: Optional[float] = None
    check_id: str
    children: List[UnityCheck]
    governing: Optional[GoverningKey] = None


class DistributedLoad(BaseModel):
    direction: List
    distribution_shape: DistributionShape
    end_frac: float
    end_magnitude: float
    load_case: conint(ge=0)
    magnitude: float
    member: conint(ge=0)
    start_frac: float


class Member(BaseModel):
    chi: Optional[float] = None
    classification: str
    end_hinge: Optional[conint(ge=0)] = None
    end_node: Node
    id: conint(ge=0)
    member_type: MemberType
    reference_member: Optional[conint(ge=0)] = None
    reference_node: Optional[conint(ge=0)] = None
    rotation_angle: float
    section: conint(ge=0)
    start_hinge: Optional[conint(ge=0)] = None
    start_node: Node
    weight: float


class MemberResult(BaseModel):
    end_node_forces: NodeForces
    maximums: NodeForces
    minimums: NodeForces
    start_node_forces: NodeForces


class MemberSet(BaseModel):
    classification: Optional[str] = None
    id: conint(ge=0)
    l_y: Optional[float] = None
    l_z: Optional[float] = None
    members: List[Member]


class Results(BaseModel):
    displacement_nodes: Dict[str, NodeDisplacement]
    member_results: Dict[str, MemberResult]
    name: str
    reaction_nodes: Dict[str, ReactionNodeResult]
    result_type: ResultType
    summary: ResultsSummary
    unity_checks: Optional[Dict[str, Any]] = None


class ResultsBundle(BaseModel):
    loadcases: Dict[str, Results]
    loadcombinations: Dict[str, Results]
    unity_checks_overview: Optional[Dict[str, Any]] = None


class RotationImperfection(BaseModel):
    axis: List
    axis_only: bool
    magnitude: float
    memberset: List[MemberSet]
    point: List


class TranslationImperfection(BaseModel):
    axis: List
    magnitude: float
    memberset: List[MemberSet]


class ImperfectionCase(BaseModel):
    imperfection_case_id: conint(ge=0)
    load_combinations: List[LoadCombination]
    rotation_imperfections: List[RotationImperfection]
    translation_imperfections: List[TranslationImperfection]


class LoadCase(BaseModel):
    distributed_loads: List[DistributedLoad]
    id: conint(ge=0)
    name: str
    nodal_loads: List[NodalLoad]
    nodal_moments: List[NodalMoment]
    rotation_imperfections: List[RotationImperfection]
    translation_imperfections: List[TranslationImperfection]


class FERS(BaseModel):
    imperfection_cases: List[ImperfectionCase]
    load_cases: List[LoadCase]
    load_combinations: List[LoadCombination]
    materials: List[Material]
    member_sets: List[MemberSet]
    memberhinges: Optional[List[MemberHinge]] = None
    nodal_supports: List[NodalSupport]
    results: Optional[ResultsBundle] = None
    sections: List[Section]
    settings: Settings
    shape_paths: Optional[List[ShapePath]] = None
