Skip to content

Sample files

Sample .xyz files contain spatial input point data for a D-Flow FM model, and are used in various other input files.

A sample data file is described by the classes below.

Model

XYZModel

Bases: ParsableFileModel

Sample or forcing file.

Attributes:

Name Type Description
points List[XYZPoint]

List of XYZPoint

Source code in hydrolib/core/dflowfm/xyz/models.py
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
class XYZModel(ParsableFileModel):
    """Sample or forcing file.

    Attributes:
        points: List of [`XYZPoint`][hydrolib.core.dflowfm.xyz.models.XYZPoint]
    """

    points: List[XYZPoint] = []

    def dict(self, *args, **kwargs):
        # speed up serializing by not converting these lowest models to dict
        return dict(points=self.points)

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

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

    @classmethod
    def _get_serializer(
        cls,
    ) -> Callable[[Path, Dict, SerializerConfig, ModelSaveSettings], None]:
        return XYZSerializer.serialize

    @classmethod
    def _get_parser(cls) -> Callable[[Path], Dict]:
        return XYZParser.parse

XYZPoint

Bases: BaseModel

Single sample or forcing point.

Attributes:

Name Type Description
x float

x or λ coordinate

y float

y or φ coordinate

z float

sample value or group number (forcing)

comment Optional[str]

keyword for grouping (forcing)

Source code in hydrolib/core/dflowfm/xyz/models.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class XYZPoint(BaseModel):
    """Single sample or forcing point.

    Attributes:
        x: x or λ coordinate
        y: y or φ coordinate
        z: sample value or group number (forcing)
        comment: keyword for grouping (forcing)
    """

    x: float
    y: float
    z: float
    comment: Optional[str] = Field(
        None, alias="group", description="comment or group name"
    )

    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}"

Parser

XYZParser

A parser for .xyz files which are like this:

number number number number number number # comment

Note that the whitespace can vary and the comment left out.

Source code in hydrolib/core/dflowfm/xyz/parser.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
class XYZParser:
    """
    A parser for .xyz files which are like this:

    number number    number
    number number number # comment

    Note that the whitespace can vary and the comment
    left out.
    """

    @staticmethod
    def parse(filepath: Path) -> Dict:
        """Parse an .xyz file into a Dict with the list of points read.

        Args:
            filepath (Path): .xyz file to be read.

        Returns:
            Dict: dictionary with "points" value set to a list of points
                each of which is a dict itself, with keys 'x', 'y', 'z'
                and 'c' for an optional comment.

        Raises:
            ValueError: if a line in the file contains no values that
                could be parsed.
        """

        data: Dict = dict(points=[])

        with filepath.open(encoding="utf8") as f:
            for linenr, line in enumerate(f.readlines()):

                line = line.strip()
                if line.startswith("*") or len(line) == 0:
                    continue

                try:
                    x, y, z, *c = re.split(xyzpattern, line, maxsplit=3)
                except ValueError:
                    raise ValueError(
                        f"Error parsing XYZ file '{filepath}', line {linenr+1}."
                    )

                c = c[0] if len(c) > 0 else ""
                c = c.strip("#").strip()
                if len(c) == 0:
                    c = None

                data["points"].append(dict(x=x, y=y, z=z, comment=c))

        return data

parse(filepath) staticmethod

Parse an .xyz file into a Dict with the list of points read.

Parameters:

Name Type Description Default
filepath Path

.xyz file to be read.

required

Returns:

Name Type Description
Dict Dict

dictionary with "points" value set to a list of points each of which is a dict itself, with keys 'x', 'y', 'z' and 'c' for an optional comment.

Raises:

Type Description
ValueError

if a line in the file contains no values that could be parsed.

Source code in hydrolib/core/dflowfm/xyz/parser.py
19
20
21
22
23
24
25
26
27
28
29
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
@staticmethod
def parse(filepath: Path) -> Dict:
    """Parse an .xyz file into a Dict with the list of points read.

    Args:
        filepath (Path): .xyz file to be read.

    Returns:
        Dict: dictionary with "points" value set to a list of points
            each of which is a dict itself, with keys 'x', 'y', 'z'
            and 'c' for an optional comment.

    Raises:
        ValueError: if a line in the file contains no values that
            could be parsed.
    """

    data: Dict = dict(points=[])

    with filepath.open(encoding="utf8") as f:
        for linenr, line in enumerate(f.readlines()):

            line = line.strip()
            if line.startswith("*") or len(line) == 0:
                continue

            try:
                x, y, z, *c = re.split(xyzpattern, line, maxsplit=3)
            except ValueError:
                raise ValueError(
                    f"Error parsing XYZ file '{filepath}', line {linenr+1}."
                )

            c = c[0] if len(c) > 0 else ""
            c = c.strip("#").strip()
            if len(c) == 0:
                c = None

            data["points"].append(dict(x=x, y=y, z=z, comment=c))

    return data

Serializer

XYZSerializer

Source code in hydrolib/core/dflowfm/xyz/serializer.py
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class XYZSerializer:
    @staticmethod
    def serialize(
        path: Path,
        data: Dict,
        config: SerializerConfig,
        save_settings: ModelSaveSettings,
    ) -> None:
        """
        Serializes the XYZ data to the file at the specified path.

        Attributes:
            path (Path): The path to the destination file.
            data (Dict): The data to be serialized.
            config (SerializerConfig): The serialization configuration.
            save_settings (ModelSaveSettings): The model save settings.
        """
        path.parent.mkdir(parents=True, exist_ok=True)

        space = 1 * " "
        format_float = lambda x: f"{x:{config.float_format}}"

        with path.open("w", encoding="utf8") as f:
            for point in data["points"]:
                geometry: str = space.join(
                    [format_float(p) for p in XYZSerializer._get_point_values(point)]
                )
                if point.comment:
                    f.write(f"{geometry} # {point.comment}\n")
                else:
                    f.write(f"{geometry}\n")

    @staticmethod
    def _get_point_values(point) -> Generator[float, None, None]:
        yield point.x
        yield point.y
        yield point.z

serialize(path, data, config, save_settings) staticmethod

Serializes the XYZ data to the file at the specified path.

Attributes:

Name Type Description
path Path

The path to the destination file.

data Dict

The data to be serialized.

config SerializerConfig

The serialization configuration.

save_settings ModelSaveSettings

The model save settings.

Source code in hydrolib/core/dflowfm/xyz/serializer.py
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@staticmethod
def serialize(
    path: Path,
    data: Dict,
    config: SerializerConfig,
    save_settings: ModelSaveSettings,
) -> None:
    """
    Serializes the XYZ data to the file at the specified path.

    Attributes:
        path (Path): The path to the destination file.
        data (Dict): The data to be serialized.
        config (SerializerConfig): The serialization configuration.
        save_settings (ModelSaveSettings): The model save settings.
    """
    path.parent.mkdir(parents=True, exist_ok=True)

    space = 1 * " "
    format_float = lambda x: f"{x:{config.float_format}}"

    with path.open("w", encoding="utf8") as f:
        for point in data["points"]:
            geometry: str = space.join(
                [format_float(p) for p in XYZSerializer._get_point_values(point)]
            )
            if point.comment:
                f.write(f"{geometry} # {point.comment}\n")
            else:
                f.write(f"{geometry}\n")