예제 #1
0
class FrictGlobal(INIBasedModel):
    """A `[Global]` block for use inside a friction file.

    Multiple of such blocks may be present to define multiple frictionId classes.
    """
    class Comments(INIBasedModel.Comments):
        frictionid: Optional[str] = Field("Name of the roughness variable.",
                                          alias="frictionId")
        frictiontype: Optional[str] = Field(
            "The global roughness type for this variable, which is used " +
            "if no branch specific roughness definition is given.",
            alias="frictionType",
        )
        frictionvalue: Optional[str] = Field(
            "The global default value for this roughness variable.",
            alias="frictionValue",
        )

    comments: Comments = Comments()
    _header: Literal["Global"] = "Global"
    frictionid: str = Field(alias="frictionId")
    frictiontype: FrictionType = Field(alias="frictionType")
    frictionvalue: float = Field(alias="frictionValue")

    _frictiontype_validator = get_enum_validator("frictiontype",
                                                 enum=FrictionType)

    def _get_identifier(self, data: dict) -> Optional[str]:
        return data.get("frictionid")
예제 #2
0
class Bridge(Structure):
    """
    Hydraulic structure with `type=bridge`, to be included in a structure file.
    Typically inside the structure list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.structurefile[0].structure[..]`

    All lowercased attributes match with the bridge input as described in
    [UM Sec.C.12.5](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.12.5).
    """

    class Comments(Structure.Comments):
        type: Optional[str] = Field("Structure type; must read bridge", alias="type")
        allowedflowdir: Optional[str] = Field(
            FlowDirection.allowedvaluestext, alias="allowedFlowdir"
        )

        csdefid: Optional[str] = Field(
            "Id of Cross-Section Definition.", alias="csDefId"
        )
        shift: Optional[str] = Field(
            "Vertical shift of the cross section definition [m]. Defined positive upwards."
        )
        inletlosscoeff: Optional[str] = Field(
            "Inlet loss coefficient [-], ξ_i.",
            alias="inletLossCoeff",
        )
        outletlosscoeff: Optional[str] = Field(
            "Outlet loss coefficient [-], k.",
            alias="outletLossCoeff",
        )
        frictiontype: Optional[str] = Field(
            "Friction type, possible values are: Chezy, Manning, wallLawNikuradse, WhiteColebrook, StricklerNikuradse, Strickler, deBosBijkerk.",
            alias="frictionType",
        )
        friction: Optional[str] = Field(
            "Friction value, used in friction loss.",
            alias="friction",
        )
        length: Optional[str] = Field("Length [m], L.")

    comments: Comments = Comments()

    type: Literal["bridge"] = Field("bridge", alias="type")
    allowedflowdir: FlowDirection = Field(alias="allowedFlowdir")

    csdefid: str = Field(alias="csDefId")
    shift: float
    inletlosscoeff: float = Field(alias="inletLossCoeff")
    outletlosscoeff: float = Field(alias="outletLossCoeff")
    frictiontype: FrictionType = Field(alias="frictionType")
    friction: float
    length: float

    _frictiontype_validator = get_enum_validator("frictiontype", enum=FrictionType)
예제 #3
0
class Orifice(Structure):
    """
    Hydraulic structure with `type=orifice`, to be included in a structure file.
    Typically inside the structure list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.structurefile[0].structure[..]`

    All lowercased attributes match with the orifice input as described in
    [UM Sec.C.12.7](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.12.7).
    """

    type: Literal["orifice"] = Field("orifice", alias="type")
    allowedflowdir: Optional[FlowDirection] = Field(
        FlowDirection.both.value, alias="allowedFlowDir"
    )

    crestlevel: Union[float, Path] = Field(alias="crestLevel")
    crestwidth: Optional[float] = Field(None, alias="crestWidth")
    gateloweredgelevel: Union[float, Path] = Field(alias="gateLowerEdgeLevel")
    corrcoeff: float = Field(1.0, alias="corrCoeff")
    usevelocityheight: bool = Field(True, alias="useVelocityHeight")

    # TODO Use a validator here to check the optionals related to the bool field
    uselimitflowpos: Optional[bool] = Field(False, alias="useLimitFlowPos")
    limitflowpos: Optional[float] = Field(alias="limitFlowPos")

    uselimitflowneg: Optional[bool] = Field(False, alias="useLimitFlowNeg")
    limitflowneg: Optional[float] = Field(alias="limitFlowNeg")

    _flowdirection_validator = get_enum_validator("allowedflowdir", enum=FlowDirection)

    @validator("limitflowpos", always=True)
    @classmethod
    def _validate_limitflowpos(cls, v, values):
        return cls._validate_limitflow(v, values, "limitFlowPos", "useLimitFlowPos")

    @validator("limitflowneg", always=True)
    @classmethod
    def _validate_limitflowneg(cls, v, values):
        return cls._validate_limitflow(v, values, "limitFlowNeg", "useLimitFlowNeg")

    @classmethod
    def _validate_limitflow(cls, v, values, limitflow: str, uselimitflow: str):
        if v is None and values[uselimitflow.lower()] == True:
            raise ValueError(
                f"{limitflow} should be defined when {uselimitflow} is true"
            )

        return v
예제 #4
0
class UniversalWeir(Structure):
    """
    Hydraulic structure with `type=universalWeir`, to be included in a structure file.
    Typically inside the structure list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.structurefile[0].structure[..]`

    All lowercased attributes match with the universal weir input as described in
    [UM Sec.C.12.2](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.12.2).
    """

    class Comments(Structure.Comments):
        type: Optional[str] = Field(
            "Structure type; must read universalWeir", alias="type"
        )
        allowedflowdir: Optional[str] = Field(
            FlowDirection.allowedvaluestext, alias="allowedFlowdir"
        )

        numlevels: Optional[str] = Field("Number of yz-Values.", alias="numLevels")
        yvalues: Optional[str] = Field(
            "y-values of the cross section (m). (number of values = numLevels)",
            alias="yValues",
        )
        zvalues: Optional[str] = Field(
            "z-values of the cross section (m). (number of values = numLevels)",
            alias="zValues",
        )
        crestlevel: Optional[str] = Field(
            "Crest level of weir (m AD).", alias="crestLevel"
        )
        dischargecoeff: Optional[str] = Field(
            "Discharge coefficient c_e (-).", alias="dischargeCoeff"
        )

    comments: Comments = Comments()

    type: Literal["universalWeir"] = Field("universalWeir", alias="type")
    allowedflowdir: FlowDirection = Field(alias="allowedFlowDir")

    numlevels: int = Field(alias="numLevels")
    yvalues: List[float] = Field(alias="yValues")
    zvalues: List[float] = Field(alias="zValues")
    crestlevel: float = Field(alias="crestLevel")
    dischargecoeff: float = Field(alias="dischargeCoeff")

    _split_to_list = get_split_string_on_delimiter_validator("yvalues", "zvalues")
    _flowdirection_validator = get_enum_validator("allowedflowdir", enum=FlowDirection)
예제 #5
0
class RectangleCrsDef(CrossSectionDefinition):
    """
    Crosssection definition with `type=rectangle`, to be included in a crossdef file.
    Typically inside the definition list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.crossdeffile.definition[..]`

    All lowercased attributes match with the rectangle input as described in
    [UM Sec.C.16.1.2](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.16.1.2).
    """

    class Comments(CrossSectionDefinition.Comments):
        type: Optional[str] = Field("Cross section type; must read rectangle")
        width: Optional[str] = Field("Width of the rectangle [m].")
        height: Optional[str] = Field("Height of the rectangle [m].")
        closed: Optional[str] = Field("no: Open channel, yes: Closed channel.")
        frictionid: Optional[str] = Field(
            frictionid_description,
            alias="frictionId",
        )
        frictiontype: Optional[str] = Field(
            frictiontype_description,
            alias="frictionType",
        )
        frictionvalue: Optional[str] = Field(
            frictionvalue_description,
            alias="frictionValue",
        )

    comments: Comments = Comments()

    type: Literal["rectangle"] = Field("rectangle")
    width: float
    height: float
    closed: bool = Field(True)
    frictionid: Optional[str] = Field(alias="frictionId")
    frictiontype: Optional[FrictionType] = Field(alias="frictionType")
    frictionvalue: Optional[float] = Field(alias="frictionValue")

    _friction_validator = CrossSectionDefinition._get_friction_root_validator(
        "frictionid", "frictiontype", "frictionvalue"
    )
    _frictiontype_validator = get_enum_validator("frictiontype", enum=FrictionType)
예제 #6
0
class Weir(Structure):
    """
    Hydraulic structure with `type=weir`, to be included in a structure file.
    Typically inside the structure list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.structurefile[0].structure[..]`

    All lowercased attributes match with the weir input as described in
    [UM Sec.C.12.1](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.12.1).
    """

    class Comments(Structure.Comments):
        type: Optional[str] = Field("Structure type; must read weir", alias="type")
        allowedflowdir: Optional[str] = Field(
            FlowDirection.allowedvaluestext, alias="allowedFlowdir"
        )

        crestlevel: Optional[str] = Field(
            "Crest level of weir (m AD).", alias="crestLevel"
        )
        crestwidth: Optional[str] = Field("Width of the weir (m).", alias="crestWidth")
        corrcoeff: Optional[str] = Field(
            "Correction coefficient (-).", alias="corrCoeff"
        )
        usevelocityheight: Optional[str] = Field(
            "Flag indicating whether the velocity height is to be calculated or not.",
            alias="useVelocityHeight",
        )

    comments: Comments = Comments()

    type: Literal["weir"] = Field("weir", alias="type")
    allowedflowdir: Optional[FlowDirection] = Field(
        FlowDirection.both.value, alias="allowedFlowDir"
    )

    crestlevel: Union[float, Path] = Field(alias="crestLevel")
    crestwidth: Optional[float] = Field(None, alias="crestWidth")
    corrcoeff: float = Field(1.0, alias="corrCoeff")
    usevelocityheight: bool = Field(True, alias="useVelocityHeight")

    _flowdirection_validator = get_enum_validator("allowedflowdir", enum=FlowDirection)
예제 #7
0
class CircleCrsDef(CrossSectionDefinition):
    """
    Crosssection definition with `type=circle`, to be included in a crossdef file.
    Typically inside the definition list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.crossdeffile.definition[..]`

    All lowercased attributes match with the circle input as described in
    [UM Sec.C.16.1.1](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.16.1.1).
    """

    class Comments(CrossSectionDefinition.Comments):
        type: Optional[str] = Field("Cross section type; must read circle")

        diameter: Optional[str] = Field("Internal diameter of the circle [m].")
        frictionid: Optional[str] = Field(
            frictionid_description,
            alias="frictionId",
        )
        frictiontype: Optional[str] = Field(
            frictiontype_description,
            alias="frictionType",
        )
        frictionvalue: Optional[str] = Field(
            frictionvalue_description,
            alias="frictionValue",
        )

    comments: Comments = Comments()

    type: Literal["circle"] = Field("circle")
    diameter: float
    frictionid: Optional[str] = Field(alias="frictionId")
    frictiontype: Optional[FrictionType] = Field(alias="frictionType")
    frictionvalue: Optional[float] = Field(alias="frictionValue")

    _friction_validator = CrossSectionDefinition._get_friction_root_validator(
        "frictionid", "frictiontype", "frictionvalue"
    )
    _frictiontype_validator = get_enum_validator("frictiontype", enum=FrictionType)
예제 #8
0
class Pump(Structure):
    """
    Hydraulic structure with `type=pump`, to be included in a structure file.
    Typically inside the structure list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.structurefile[0].structure[..]`

    All lowercased attributes match with the pump input as described in
    [UM Sec.C.12.6](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.12.6).
    """

    type: Literal["pump"] = Field("pump", alias="type")

    orientation: Optional[Orientation] = Field(alias="orientation")
    controlside: Optional[str] = Field(alias="controlSide")  # TODO Enum
    numstages: Optional[int] = Field(alias="numStages")
    capacity: Union[float, Path] = Field(alias="capacity")

    startlevelsuctionside: Optional[List[float]] = Field(alias="startLevelSuctionSide")
    stoplevelsuctionside: Optional[List[float]] = Field(alias="stopLevelSuctionSide")
    startleveldeliveryside: Optional[List[float]] = Field(
        alias="startLevelDeliverySide"
    )
    stopleveldeliveryside: Optional[List[float]] = Field(alias="stopLevelDeliverySide")
    numreductionlevels: Optional[int] = Field(alias="numReductionLevels")
    head: Optional[List[float]] = Field(alias="head")
    reductionfactor: Optional[List[float]] = Field(alias="reductionFactor")

    _split_to_list = get_split_string_on_delimiter_validator(
        "startlevelsuctionside",
        "stoplevelsuctionside",
        "startleveldeliveryside",
        "stopleveldeliveryside",
        "head",
        "reductionfactor",
    )

    _orientation_validator = get_enum_validator("orientation", enum=Orientation)

    _control_side_check = get_required_fields_validator(
        "controlside",
        conditional_field_name="numstages",
        conditional_value=0,
        comparison_func=gt,
    )

    _check_list_length1 = get_conditional_root_validator(
        make_list_length_root_validator(
            "startlevelsuctionside",
            "stoplevelsuctionside",
            length_name="numstages",
            list_required_with_length=True,
        ),
        "controlside",
        "deliverySide",
        ne,
    )

    _check_list_length2 = get_conditional_root_validator(
        make_list_length_root_validator(
            "startleveldeliveryside",
            "stopleveldeliveryside",
            length_name="numstages",
            list_required_with_length=True,
        ),
        "controlside",
        "suctionSide",
        ne,
    )

    _check_list_length3 = make_list_length_root_validator(
        "head",
        "reductionfactor",
        length_name="numreductionlevels",
        list_required_with_length=True,
    )
예제 #9
0
class Culvert(Structure):
    """
    Hydraulic structure with `type=culvert`, to be included in a structure file.
    Typically inside the structure list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.structurefile[0].structure[..]`

    All lowercased attributes match with the culvert input as described in
    [UM Sec.C.12.3](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.12.3).
    """

    type: Literal["culvert"] = Field("culvert", alias="type")
    allowedflowdir: FlowDirection = Field(alias="allowedFlowDir")

    leftlevel: float = Field(alias="leftLevel")
    rightlevel: float = Field(alias="rightLevel")
    csdefid: str = Field(alias="csDefId")
    length: float = Field(alias="length")
    inletlosscoeff: float = Field(alias="inletLossCoeff")
    outletlosscoeff: float = Field(alias="outletLossCoeff")
    valveonoff: bool = Field(alias="valveOnOff")
    valveopeningheight: Optional[Union[float, Path]] = Field(alias="valveOpeningHeight")
    numlosscoeff: Optional[int] = Field(alias="numLossCoeff")
    relopening: Optional[List[float]] = Field(alias="relOpening")
    losscoeff: Optional[List[float]] = Field(alias="lossCoeff")
    bedfrictiontype: Optional[FrictionType] = Field(alias="bedFrictionType")
    bedfriction: Optional[float] = Field(alias="bedFriction")
    subtype: Optional[CulvertSubType] = Field(
        CulvertSubType.culvert.value, alias="subType"
    )
    bendlosscoeff: Optional[float] = Field(alias="bendLossCoeff")

    _split_to_list = get_split_string_on_delimiter_validator("relopening", "losscoeff")
    _flowdirection_validator = get_enum_validator("allowedflowdir", enum=FlowDirection)
    _subtype_validator = get_enum_validator("subtype", enum=CulvertSubType)
    _frictiontype_validator = get_enum_validator("bedfrictiontype", enum=FrictionType)

    _valveonoff_validator = get_required_fields_validator(
        "valveopeningheight",
        "numlosscoeff",
        "relopening",
        "losscoeff",
        conditional_field_name="valveonoff",
        conditional_value=True,
    )

    _check_list_length = make_list_length_root_validator(
        "relopening",
        "losscoeff",
        length_name="numlosscoeff",
        list_required_with_length=True,
    )

    _bendlosscoeff_invertedsiphon = get_required_fields_validator(
        "bendlosscoeff",
        conditional_field_name="subtype",
        conditional_value=CulvertSubType.invertedSiphon,
    )

    _bendlosscoeff_culvert = get_forbidden_fields_validator(
        "bendlosscoeff",
        conditional_field_name="subtype",
        conditional_value=CulvertSubType.culvert,
    )
예제 #10
0
class StorageNode(INIBasedModel):
    """
    A storage node that is included in the storage node file.

    All lowercased attributes match with the storage node input as described in
    [UM Sec.C.17](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#section.C.17).
    """
    class Comments(INIBasedModel.Comments):
        id: Optional[str] = Field("Unique id of the storage node.", alias="id")
        name: Optional[str] = Field("Long name in the user interface.",
                                    alias="name")
        manholeid: Optional[str] = Field(
            "(optional) Unique id of manhole that this (compartment) node is part of.",
            alias="manholeId",
        )
        nodetype: Optional[str] = Field(
            "(optional) Type of the node. Possible values are: " +
            "inspection: inspection chamber, " +
            "soakawayDrain: soakaway drain (infiltration), " +
            "compartment: manhole compartment, " +
            "unspecified: general storage node of unspecified type",
            alias="nodeType",
        )
        nodeid: Optional[str] = Field(
            "Connection node on which the storage node is located.",
            alias="nodeId")
        usetable: Optional[str] = Field(
            "Switch to select a simple (false) or tabulated (true) storage area.",
            alias="useTable",
        )
        bedlevel: Optional[str] = Field(
            "Bed level of the storage area [m AD].", alias="bedLevel")
        area: Optional[str] = Field(
            "Storage area from bedLevel up to streetLevel (and beyond if useStreetStorage = false) [m2].",
            alias="area",
        )
        streetlevel: Optional[str] = Field(
            "Street level of the storage area [m AD].", alias="streetLevel")
        streetstoragearea: Optional[str] = Field(
            "Storage area from streetLevel upwards if useStreetStorage = true [m2].",
            alias="streetStorageArea",
        )
        storagetype: Optional[str] = Field(
            "Possible values: " +
            "reservoir: Above streetLevel the storage area of this node is also taken into account. "
            +
            "closed: Above streetLevel this storage node has no storage area.",
            alias="storageType",
        )
        numlevels: Optional[str] = Field(
            "Number of levels in storage area table.", alias="numLevels")
        levels: Optional[str] = Field("Levels in storage area table [m].",
                                      alias="levels")
        storagearea: Optional[str] = Field("Areas in storage area table [m2].",
                                           alias="storageArea")
        interpolate: Optional[str] = Field(
            "Interpolation type for storage area table. Possible values: linear or block.",
            alias="interpolate",
        )

    comments: Comments = Comments()
    _header: Literal["StorageNode"] = "StorageNode"
    id: str = Field(alias="id")
    name: str = Field(alias="name")
    manholeid: Optional[str] = Field(alias="manholeId")

    nodetype: Optional[NodeType] = Field(NodeType.unspecified.value,
                                         alias="nodeType")
    nodeid: str = Field(alias="nodeId")
    usetable: bool = Field(alias="useTable")

    # useTable is True
    bedlevel: Optional[float] = Field(alias="bedLevel")
    area: Optional[float] = Field(alias="area")
    streetlevel: Optional[float] = Field(alias="streetLevel")
    streetstoragearea: Optional[float] = Field(alias="streetStorageArea")
    storagetype: Optional[StorageType] = Field(StorageType.reservoir.value,
                                               alias="storageType")

    # useTable is False
    numlevels: Optional[int] = Field(alias="numLevels")
    levels: Optional[List[float]] = Field(alias="levels")
    storagearea: Optional[List[float]] = Field(alias="storageArea")
    interpolate: Optional[Interpolation] = Field(Interpolation.linear.value,
                                                 alias="interpolate")

    _interpolation_validator = get_enum_validator("interpolate",
                                                  enum=Interpolation)
    _nodetype_validator = get_enum_validator("nodetype", enum=NodeType)
    _storagetype_validator = get_enum_validator("storagetype",
                                                enum=StorageType)
    _split_to_list = get_split_string_on_delimiter_validator(
        "levels",
        "storagearea",
    )

    _check_list_length = make_list_length_root_validator(
        "levels",
        "storagearea",
        length_name="numlevels",
        list_required_with_length=True,
    )

    _usetable_true_validator = get_required_fields_validator(
        "numlevels",
        "levels",
        "storagearea",
        conditional_field_name="usetable",
        conditional_value=True,
    )

    _usetable_false_validator = get_required_fields_validator(
        "bedlevel",
        "area",
        "streetlevel",
        conditional_field_name="usetable",
        conditional_value=False,
    )

    def _get_identifier(self, data: dict) -> Optional[str]:
        return data.get("id") or data.get("name")
예제 #11
0
class YZCrsDef(CrossSectionDefinition):
    """
    Crosssection definition with `type=yz`, to be included in a crossdef file.
    Typically inside the definition list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.crossdeffile.definition[..]`

    All lowercased attributes match with the yz input as described in
    [UM Sec.C.16.1.6](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.16.1.6).
    """

    class Comments(CrossSectionDefinition.Comments):
        type: Optional[str] = Field("Cross section type; must read yz", alias="type")
        conveyance: Optional[str] = Field(
            "lumped: Lumped, segmented: Vertically segmented. Only the default lumped "
            + "option is allowed if singleValuedZ = no. In the case of lumped conveyance, "
            + "only a single uniform roughness for the whole cross section is allowed, "
            + "i.e., sectionCount must equal 1.",
        )
        yzcount: Optional[str] = Field("Number of YZ-coordinates.", alias="yzCount")
        yCoordinates: Optional[str] = Field(
            "Space separated list of monotonic increasing y-coordinates [m].",
            alias="yCoordinates",
        )
        zCoordinates: Optional[str] = Field(
            "Space separated list of single-valued z-coordinates [m AD].",
            alias="zCoordinates",
        )
        sectioncount: Optional[str] = Field(
            "Number of roughness sections. If the lumped conveyance is selected then "
            + "sectionCount must equal 1.",
            alias="sectionCount",
        )
        frictionpositions: Optional[str] = Field(
            "Locations where the roughness sections start and end. Always one location more than "
            + "sectionCount. The first value should equal 0 and the last value should equal the "
            + "cross section length. Keyword may be skipped if sectionCount = 1.",
            alias="frictionPositions",
        )
        frictionids: Optional[str] = Field(
            "Semicolon separated list of roughness variable names associated with the roughness "
            + "sections. Either this parameter or frictionTypes should be specified. If neither "
            + 'parameter is specified, the frictionIds default to "Main", "FloodPlain1" '
            + 'and "FloodPlain2".',
            alias="frictionIds",
        )
        frictiontypes: Optional[str] = Field(
            "Semicolon separated list of roughness types associated with the roughness sections. "
            + "Either this parameter or frictionIds should be specified. Can be specified as a "
            + "single value if all roughness sections use the same type.",
            alias="frictionTypes",
        )
        frictionvalues: Optional[str] = Field(
            "Space separated list of roughness values; their meaning depends on the roughness "
            + "types selected (only used if frictionTypes specified).",
            alias="frictionValues",
        )

    comments: Comments = Comments()

    type: Literal["yz"] = Field("yz")
    singlevaluedz: Optional[bool] = Field(alias="singleValuedZ")
    yzcount: int = Field(alias="yzCount")
    ycoordinates: List[float] = Field(alias="yCoordinates")
    zcoordinates: List[float] = Field(alias="zCoordinates")
    conveyance: Optional[str] = Field("segmented")
    sectioncount: Optional[int] = Field(1, alias="sectionCount")
    frictionpositions: Optional[List[float]] = Field(alias="frictionPositions")
    frictionids: Optional[List[str]] = Field(alias="frictionIds", delimiter=";")
    frictiontypes: Optional[List[FrictionType]] = Field(
        alias="frictionTypes", delimiter=";"
    )
    frictionvalues: Optional[List[float]] = Field(alias="frictionValues")

    _split_to_list = get_split_string_on_delimiter_validator(
        "ycoordinates",
        "zcoordinates",
        "frictionpositions",
        "frictionvalues",
        "frictionids",
        "frictiontypes",
    )

    _check_yzlist_length = make_list_length_root_validator(
        "ycoordinates",
        "zcoordinates",
        length_name="yzcount",
    )

    _check_frictlist_length = make_list_length_root_validator(
        "frictionids",
        "frictiontypes",
        "frictionvalues",
        length_name="sectioncount",
    )
    _check_frictlist_length1 = make_list_length_root_validator(
        "frictionpositions",
        length_name="sectioncount",
        length_incr=1,  # 1 extra for frictionpositions
    )

    _friction_validator = CrossSectionDefinition._get_friction_root_validator(
        "frictionids", "frictiontypes", "frictionvalues"
    )
    _frictiontype_validator = get_enum_validator("frictiontypes", enum=FrictionType)
예제 #12
0
class ZWCrsDef(CrossSectionDefinition):
    """
    Crosssection definition with `type=zw`, to be included in a crossdef file.
    Typically inside the definition list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.crossdeffile.definition[..]`

    All lowercased attributes match with the zw input as described in
    [UM Sec.C.16.1.4](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.16.1.4).
    """

    class Comments(CrossSectionDefinition.Comments):
        type: Optional[str] = Field("Cross section type; must read zw", alias="type")
        # NOTE: Field "template" deliberately ignored for now.
        numlevels: Optional[str] = Field(
            "Number of levels in the table.", alias="numLevels"
        )
        levels: Optional[str] = Field(
            "Space separated list of monotonic increasing heights/levels [m AD].",
            alias="levels",
        )
        flowwidths: Optional[str] = Field(
            "Space separated list of flow widths at the selected heights [m)].",
            alias="flowWidths",
        )
        totalwidths: Optional[str] = Field(
            "Space separated list of total widths at the selected heights [m]. "
            + "Equal to flowWidths if not specified. If specified, the totalWidths"
            + "should be larger than flowWidths.",
            alias="totalWidths",
        )
        frictionid: Optional[str] = Field(
            frictionid_description,
            alias="frictionId",
        )
        frictiontype: Optional[str] = Field(
            frictiontype_description,
            alias="frictionType",
        )
        frictionvalue: Optional[str] = Field(
            frictionvalue_description,
            alias="frictionValue",
        )

    comments: Comments = Comments()

    type: Literal["zw"] = Field("zw")
    numlevels: int = Field(alias="numLevels")
    levels: List[float]
    flowwidths: List[float] = Field(alias="flowWidths")
    totalwidths: Optional[List[float]] = Field(alias="totalWidths")
    frictionid: Optional[str] = Field(alias="frictionId")
    frictiontype: Optional[FrictionType] = Field(alias="frictionType")
    frictionvalue: Optional[float] = Field(alias="frictionValue")

    _split_to_list = get_split_string_on_delimiter_validator(
        "levels",
        "flowwidths",
        "totalwidths",
    )

    _check_list_length = make_list_length_root_validator(
        "levels",
        "flowwidths",
        "totalwidths",
        length_name="numlevels",
    )

    _friction_validator = CrossSectionDefinition._get_friction_root_validator(
        "frictionid", "frictiontype", "frictionvalue"
    )
    _frictiontype_validator = get_enum_validator("frictiontype", enum=FrictionType)
예제 #13
0
class ZWRiverCrsDef(CrossSectionDefinition):
    """
    Crosssection definition with `type=zwRiver`, to be included in a crossdef file.
    Typically inside the definition list of a [FMModel][hydrolib.core.io.mdu.models.FMModel]`.geometry.crossdeffile.definition[..]`

    All lowercased attributes match with the zwRiver input as described in
    [UM Sec.C.16.1.3](https://content.oss.deltares.nl/delft3d/manuals/D-Flow_FM_User_Manual_1D2D.pdf#subsection.C.16.1.3).
    """

    class Comments(CrossSectionDefinition.Comments):
        type: Optional[str] = Field(
            "Cross section type; must read zwRiver", alias="type"
        )
        numlevels: Optional[str] = Field(
            "Number of levels in the table.", alias="numLevels"
        )
        levels: Optional[str] = Field(
            "Space separated list of monotonic increasing heights/levels [m AD].",
            alias="levels",
        )
        flowwidths: Optional[str] = Field(
            "Space separated list of flow widths at the selected heights [m)].",
            alias="flowWidths",
        )
        totalwidths: Optional[str] = Field(
            "Space separated list of total widths at the selected heights [m]. "
            + "Equal to flowWidths if not specified. If specified, the totalWidths"
            + "should be larger than flowWidths.",
            alias="totalWidths",
        )
        leveecrestLevel: Optional[str] = Field(
            "Crest level of levee [m AD].", alias="leveeCrestlevel"
        )
        leveebaselevel: Optional[str] = Field(
            "Base level of levee [m AD].", alias="leveeBaseLevel"
        )
        leveeflowarea: Optional[str] = Field(
            "Flow area behind levee [m2].", alias="leveeFlowArea"
        )
        leveetotalarea: Optional[str] = Field(
            "Total area behind levee [m2].", alias="leveeTotalArea"
        )
        mainwidth: Optional[str] = Field(
            "Width of main section [m]. Default value: max(flowWidths).",
            alias="mainWidth",
        )
        fp1width: Optional[str] = Field(
            "Width of floodplain 1 section [m]. Default value: max(flowWidths)-mainWidth",
            alias="fp1Width",
        )
        fp2width: Optional[str] = Field(
            "Width of floodplain 2 section [m]. Default value: max(flowWidths)-mainWidth-fp1Width",
            alias="fp2Width",
        )
        frictionids: Optional[str] = Field(
            "Semicolon separated list of roughness variable names associated with the roughness "
            + "sections. Either this parameter or frictionTypes should be specified. If neither "
            + 'parameter is specified, the frictionIds default to "Main", "FloodPlain1" '
            + 'and "FloodPlain2".',
            alias="frictionIds",
        )
        frictiontypes: Optional[str] = Field(
            "Semicolon separated list of roughness types associated with the roughness sections. "
            + "Either this parameter or frictionIds should be specified. Can be specified as a "
            + "single value if all roughness sections use the same type.",
            alias="frictionTypes",
        )
        frictionvalues: Optional[str] = Field(
            "Space separated list of roughness values; their meaning depends on the roughness "
            + "types selected (only used if frictionTypes specified).",
            alias="frictionValues",
        )

    comments: Comments = Comments()

    type: Literal["zwRiver"] = Field("zwRiver")
    numlevels: int = Field(alias="numLevels")
    levels: List[float]
    flowwidths: List[float] = Field(alias="flowWidths")
    totalwidths: Optional[List[float]] = Field(alias="totalWidths")
    leveecrestLevel: Optional[float] = Field(alias="leveeCrestlevel")
    leveebaselevel: Optional[float] = Field(alias="leveeBaseLevel")
    leveeflowarea: Optional[float] = Field(alias="leveeFlowArea")
    leveetotalrea: Optional[float] = Field(alias="leveeTotalArea")
    mainwidth: Optional[float] = Field(alias="mainWidth")
    fp1width: Optional[float] = Field(alias="fp1Width")
    fp2width: Optional[float] = Field(alias="fp2Width")
    frictionids: Optional[List[str]] = Field(alias="frictionIds", delimiter=";")
    frictiontypes: Optional[List[FrictionType]] = Field(
        alias="frictionTypes", delimiter=";"
    )
    frictionvalues: Optional[List[float]] = Field(alias="frictionValues")

    _split_to_list = get_split_string_on_delimiter_validator(
        "levels",
        "flowwidths",
        "totalwidths",
        "frictionvalues",
        "frictionids",
        "frictiontypes",
    )

    _friction_validator = CrossSectionDefinition._get_friction_root_validator(
        "frictionids", "frictiontypes", "frictionvalues"
    )
    _frictiontype_validator = get_enum_validator("frictiontypes", enum=FrictionType)

    _check_list_length = make_list_length_root_validator(
        "levels",
        "flowwidths",
        "totalwidths",
        length_name="numlevels",
    )
예제 #14
0
class FrictBranch(INIBasedModel):
    """A `[Branch]` block for use inside a friction file.

    Each block can define the roughness value(s) on a particular branch.
    """
    class Comments(INIBasedModel.Comments):
        branchid: Optional[str] = Field("The name of the branch.",
                                        alias="branchId")
        frictiontype: Optional[str] = Field(
            "The roughness type to be used on this branch.",
            alias="frictionType")
        functiontype: Optional[str] = Field(
            "Function type for the calculation of the value. " +
            "Possible values: constant, timeSeries, absDischarge, waterlevel.",
            alias="functionType",
        )
        timeseriesid: Optional[str] = Field(
            "Refers to a data block in the <*.bc> frictionValuesFile. " +
            "Only if functionType = timeSeries.",
            alias="timeSeriesId",
        )
        numlevels: Optional[str] = Field(
            "Number of levels in table. Only if functionType is not constant.",
            alias="numLevels",
        )
        levels: Optional[str] = Field(
            "Space separated list of discharge [m3/s] or water level [m AD] values. "
            + "Only if functionType is absDischarge or waterLevel.")
        numlocations: Optional[str] = Field(
            "Number of locations on branch. The default 0 implies branch uniform values.",
            alias="numLocations",
        )
        chainage: Optional[str] = Field(
            "Space separated list of locations on the branch [m]. Locations sorted by "
            +
            "increasing chainage. The keyword must be specified if numLocations>0."
        )
        frictionvalues: Optional[str] = Field(
            "numLevels lines containing space separated lists of roughness values: "
            +
            "numLocations values per line. If the functionType is constant, then a "
            + "single line is required. For a uniform roughness per branch " +
            "(numLocations = 0) a single entry per line is required. The meaning "
            +
            "of the values depends on the roughness type selected (see frictionType).",
            alias="frictionValues",
        )

    comments: Comments = Comments()
    _header: Literal["Branch"] = "Branch"
    branchid: str = Field(alias="branchId")
    frictiontype: FrictionType = Field(alias="frictionType")
    functiontype: Optional[str] = Field("constant", alias="functionType")
    timeseriesid: Optional[str] = Field(alias="timeSeriesId")
    numlevels: Optional[PositiveInt] = Field(alias="numLevels")
    levels: Optional[List[float]]
    numlocations: Optional[NonNegativeInt] = Field(0, alias="numLocations")
    chainage: Optional[List[float]]
    frictionvalues: Optional[List[float]] = Field(
        alias="frictionValues"
    )  # TODO: turn this into List[List[float]], see issue #143.

    _split_to_list = get_split_string_on_delimiter_validator(
        "levels",
        "chainage",
        "frictionvalues",
    )

    _frictiontype_validator = get_enum_validator("frictiontype",
                                                 enum=FrictionType)

    def _get_identifier(self, data: dict) -> Optional[str]:
        return data.get("branchid")

    @validator("levels", always=True)
    @classmethod
    def _validate_levels(cls, v, values):
        if v is not None and (values["numlevels"] is None
                              or len(v) != values["numlevels"]):
            raise ValueError(
                f"Number of values for levels should be equal to the numLevels value (branchId={values.get('branchid', '')})."
            )

        return v

    @validator("chainage", always=True)
    @classmethod
    def _validate_chainage(cls, v, values):
        if v is not None and len(v) != values["numlocations"]:
            raise ValueError(
                f"Number of values for chainage should be equal to the numLocations value (branchId={values.get('branchid', '')})."
            )

        return v

    @validator("frictionvalues", always=True)
    @classmethod
    def _validate_frictionvalues(cls, v, values):
        # number of values should be equal to numlocations*numlevels
        numlevels = (1 if
                     ("numlevels" not in values or values["numlevels"] is None
                      or values["numlevels"] == 0) else values["numlevels"])
        numvals = max(1, values["numlocations"]) * numlevels
        if v is not None and len(v) != numvals:
            raise ValueError(
                f"Number of values for frictionValues should be equal to the numLocations*numLevels value (branchId={values.get('branchid', '')})."
            )

        return v
예제 #15
0
class AbstractSpatialField(INIBasedModel, ABC):
    """
    Abstract base class for `[Initial]` and `[Parameter]` block data in
    inifield files.

    Defines all common fields. Used via subclasses InitialField and ParameterField.
    """
    class Comments(INIBasedModel.Comments):
        quantity: Optional[str] = Field(
            "Name of the quantity. See UM Table D.2.", alias="quantity")
        datafile: Optional[str] = Field(
            "Name of file containing field data values.", alias="dataFile")
        datafiletype: Optional[str] = Field("Type of dataFile.",
                                            alias="dataFileType")
        interpolationmethod: Optional[str] = Field(
            "Type of (spatial) interpolation.", alias="interpolationmethod")
        operand: Optional[str] = Field(
            "How this data is combined with previous data for the same quantity (if any).",
            alias="operand",
        )
        averagingtype: Optional[str] = Field(
            "Type of averaging, if interpolationMethod=averaging .",
            alias="averagingtype",
        )
        averagingrelsize: Optional[str] = Field(
            "Relative search cell size for averaging.",
            alias="averagingrelsize")
        averagingnummin: Optional[str] = Field(
            "Minimum number of points in averaging. Must be ≥ 1.",
            alias="averagingnummin",
        )
        averagingpercentile: Optional[str] = Field(
            "Percentile value for which data values to include in averaging. 0.0 means off.",
            alias="averagingpercentile",
        )
        extrapolationmethod: Optional[str] = Field(
            "Option for (spatial) extrapolation.", alias="extrapolationmethod")
        locationtype: Optional[str] = Field(
            "Target location of interpolation.", alias="locationtype")
        value: Optional[str] = Field(
            "Only for dataFileType=polygon. The constant value to be set inside for all model points inside the polygon."
        )

    comments: Comments = Comments()

    quantity: str = Field(alias="quantity")
    datafile: Path = Field(alias="dataFile")
    datafiletype: DataFileType = Field(alias="dataFileType")
    interpolationmethod: Optional[InterpolationMethod] = Field(
        alias="interpolationMethod")
    operand: Optional[Operand] = Field(Operand.override.value, alias="operand")
    averagingtype: Optional[AveragingType] = Field(AveragingType.mean.value,
                                                   alias="averagingType")
    averagingrelsize: Optional[NonNegativeFloat] = Field(
        1.01, alias="averagingRelSize")
    averagingnummin: Optional[PositiveInt] = Field(1, alias="averagingNumMin")
    averagingpercentile: Optional[NonNegativeFloat] = Field(
        0, alias="averagingPercentile")
    extrapolationmethod: Optional[bool] = Field(False,
                                                alias="extrapolationMethod")
    locationtype: Optional[LocationType] = Field(LocationType.all.value,
                                                 alias="locationType")
    value: Optional[float] = Field(alias="value")

    datafiletype_validator = get_enum_validator("datafiletype",
                                                enum=DataFileType)
    interpolationmethod_validator = get_enum_validator(
        "interpolationmethod", enum=InterpolationMethod)
    operand_validator = get_enum_validator("operand", enum=Operand)
    averagingtype_validator = get_enum_validator("averagingtype",
                                                 enum=AveragingType)
    locationtype_validator = get_enum_validator("locationtype",
                                                enum=LocationType)

    _value_validator = get_required_fields_validator(
        "value",
        conditional_field_name="datafiletype",
        conditional_value=DataFileType.polygon,
    )

    @validator("value", always=True)
    @classmethod
    def _validate_value_and_filetype(cls, v, values: dict):
        if v is not None and values.get(
                "datafiletype") != DataFileType.polygon:
            raise ValueError(
                f"When value={v} is given, dataFileType={DataFileType.polygon} is required."
            )

        return v