Skip to content

Observation cross section files

Observation cross section files come in two flavours:

Observation cross section .ini files

The obscrosssection module provides the specific logic for accessing observation cross section .ini files. for a D-Flow FM model.

Generic parsing and serializing functionality comes from the generic hydrolib.core.dflowfm.ini modules.

An observation cross section .ini file is described by the classes below.

Model

ObservationCrossSection

Bases: INIBasedModel

The observation cross section that is included in the observation cross section file.

All lowercased attributes match with the observation cross section output as described in [UM Sec.F2.4.1] (https://content.oss.deltares.nl/delft3dfm1d2d/D-Flow_FM_User_Manual_1D2D.pdf#subsubsection.F.2.4.1)

Source code in hydrolib/core/dflowfm/obscrosssection/models.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class ObservationCrossSection(INIBasedModel):
    """
    The observation cross section that is included in the
    observation cross section file.

    All lowercased attributes match with the observation cross
    section output as described in [UM Sec.F2.4.1]
    (https://content.oss.deltares.nl/delft3dfm1d2d/D-Flow_FM_User_Manual_1D2D.pdf#subsubsection.F.2.4.1)
    """

    class Comments(INIBasedModel.Comments):
        name: Optional[str] = "Name of the cross section (max. 255 characters)."
        branchid: Optional[str] = Field(
            "(optional) Branch on which the cross section is located.", alias="branchId"
        )
        chainage: Optional[str] = "(optional) Location on the branch (m)."
        numcoordinates: Optional[str] = Field(
            "(optional) Number of values in xCoordinates and yCoordinates. "
            "This value should be greater than or equal to 2.",
            alias="numCoordinates",
        )
        xcoordinates: Optional[str] = Field(
            "(optional) x-coordinates of the cross section line. "
            "(number of values = numCoordinates)",
            alias="xCoordinates",
        )
        ycoordinates: Optional[str] = Field(
            "(optional) y-coordinates of the cross section line. "
            "(number of values = numCoordinates)",
            alias="yCoordinates",
        )

    comments: Comments = Comments()
    _header: Literal["ObservationCrossSection"] = "ObservationCrossSection"
    name: str = Field(max_length=255, alias="name")
    branchid: Optional[str] = Field(alias="branchId")
    chainage: Optional[float] = Field(alias="chainage")
    numcoordinates: Optional[int] = Field(alias="numCoordinates")
    xcoordinates: Optional[List[float]] = Field(alias="xCoordinates")
    ycoordinates: Optional[List[float]] = Field(alias="yCoordinates")

    _split_to_list = get_split_string_on_delimiter_validator(
        "xcoordinates", "ycoordinates"
    )

    @root_validator(allow_reuse=True)
    def validate_that_location_specification_is_correct(cls, values: Dict) -> Dict:
        """Validates that the correct location specification is given."""
        return validate_location_specification(
            values,
            config=LocationValidationConfiguration(
                validate_node=False,
                minimum_num_coordinates=2,
                validate_location_type=False,
            ),
        )

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

validate_that_location_specification_is_correct(values)

Validates that the correct location specification is given.

Source code in hydrolib/core/dflowfm/obscrosssection/models.py
75
76
77
78
79
80
81
82
83
84
85
@root_validator(allow_reuse=True)
def validate_that_location_specification_is_correct(cls, values: Dict) -> Dict:
    """Validates that the correct location specification is given."""
    return validate_location_specification(
        values,
        config=LocationValidationConfiguration(
            validate_node=False,
            minimum_num_coordinates=2,
            validate_location_type=False,
        ),
    )

ObservationCrossSectionGeneral

Bases: INIGeneral

The observation cross section file's [General] section with file meta data.

Source code in hydrolib/core/dflowfm/obscrosssection/models.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class ObservationCrossSectionGeneral(INIGeneral):
    """The observation cross section file's `[General]` section with file meta data."""

    class Comments(INIBasedModel.Comments):
        fileversion: Optional[str] = Field(
            "File version. Do not edit this.", alias="fileVersion"
        )
        filetype: Optional[str] = Field(
            "File type. Should be 'obsCross'. Do not edit this.", alias="fileType"
        )

    comments: Comments = Comments()
    fileversion: str = Field("2.00", alias="fileVersion")
    filetype: Literal["obsCross"] = Field("obsCross", alias="fileType")

ObservationCrossSectionModel

Bases: INIModel

The overall observation cross section model that contains the contents of one observation cross section file.

Source code in hydrolib/core/dflowfm/obscrosssection/models.py
91
92
93
94
95
96
97
98
class ObservationCrossSectionModel(INIModel):
    """
    The overall observation cross section model that contains the contents
    of one observation cross section file.
    """

    general: ObservationCrossSectionGeneral = ObservationCrossSectionGeneral()
    observationcrosssection: List[ObservationCrossSection] = []

Legacy observation cross section .pli files

Legacy .pli files for observation points are supported via the generic polyfile module.

A polyfile (hence also an observation cross section .pli file) is described by the classes below.

Model

models.py defines all classes and functions related to representing pol/pli(z) files.

Description

Bases: BaseModel

Description of a single PolyObject.

The Description will be prepended to a block. Each line will start with a '*'.

Attributes:

Name Type Description
content str

The content of this Description.

Source code in hydrolib/core/dflowfm/polyfile/models.py
 9
10
11
12
13
14
15
16
17
18
19
class Description(BaseModel):
    """Description of a single PolyObject.

    The Description will be prepended to a block. Each line will
    start with a '*'.

    Attributes:
        content (str): The content of this Description.
    """

    content: str

Metadata

Bases: BaseModel

Metadata of a single PolyObject.

Attributes:

Name Type Description
name str

The name of the PolyObject

n_rows int

The number of rows (i.e. Point instances) of the PolyObject

n_columns int

The total number of values in a Point, including x, y, and z.

Source code in hydrolib/core/dflowfm/polyfile/models.py
22
23
24
25
26
27
28
29
30
31
32
33
class Metadata(BaseModel):
    """Metadata of a single PolyObject.

    Attributes:
        name (str): The name of the PolyObject
        n_rows (int): The number of rows (i.e. Point instances) of the PolyObject
        n_columns (int): The total number of values in a Point, including x, y, and z.
    """

    name: str
    n_rows: int
    n_columns: int

Point

Bases: BaseModel

Point consisting of a x and y coordinate, an optional z coordinate and data.

Attributes:

Name Type Description
x float

The x-coordinate of this Point

y float

The y-coordinate of this Point

z Optional[float]

An optional z-coordinate of this Point.

data Sequence[float]

The additional data variables of this Point.

Source code in hydrolib/core/dflowfm/polyfile/models.py
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Point(BaseModel):
    """Point consisting of a x and y coordinate, an optional z coordinate and data.

    Attributes:
        x (float): The x-coordinate of this Point
        y (float): The y-coordinate of this Point
        z (Optional[float]): An optional z-coordinate of this Point.
        data (Sequence[float]): The additional data variables of this Point.
    """

    x: float
    y: float
    z: Optional[float]
    data: Sequence[float]

    def _get_identifier(self, data: dict) -> Optional[str]:
        x = data.get("x")
        y = data.get("y")
        z = data.get("z")
        return f"x:{x} y:{y} z:{z}"

PolyFile

Bases: ParsableFileModel

Poly-file (.pol/.pli/.pliz) representation.

Source code in hydrolib/core/dflowfm/polyfile/models.py
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
class PolyFile(ParsableFileModel):
    """Poly-file (.pol/.pli/.pliz) representation."""

    has_z_values: bool = False
    objects: Sequence[PolyObject] = []

    def _serialize(self, _: dict, save_settings: ModelSaveSettings) -> None:
        from .serializer import write_polyfile

        # We skip the passed dict for a better one.
        write_polyfile(self._resolved_filepath, self.objects, self.serializer_config)

    @classmethod
    def _ext(cls) -> str:
        return ".pli"

    @classmethod
    def _filename(cls) -> str:
        return "objects"

    @classmethod
    def _get_serializer(cls) -> Callable:
        # Unused, but requires abstract implementation
        pass

    @classmethod
    def _get_parser(cls) -> Callable:
        # TODO Prevent circular dependency in Parser
        from .parser import read_polyfile

        return read_polyfile

PolyObject

Bases: BaseModel

PolyObject describing a single block in a poly file.

The metadata should be consistent with the points: - The number of points should be equal to number of rows defined in the metadata - The data of each point should be equal to the number of columns defined in the metadata.

Attributes:

Name Type Description
description Optional[Description]

An optional description of this PolyObject

metadata Metadata

The Metadata of this PolObject, describing the structure

points List[Point]

The points describing this PolyObject, structured according to the Metadata

Source code in hydrolib/core/dflowfm/polyfile/models.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
class PolyObject(BaseModel):
    """PolyObject describing a single block in a poly file.

    The metadata should be consistent with the points:
    - The number of points should be equal to number of rows defined in the metadata
    - The data of each point should be equal to the number of columns defined in the
      metadata.

    Attributes:
        description (Optional[Description]):
            An optional description of this PolyObject
        metadata (Metadata):
            The Metadata of this PolObject, describing the structure
        points (List[Point]):
            The points describing this PolyObject, structured according to the Metadata
    """

    description: Optional[Description]
    metadata: Metadata
    points: List[Point]