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