rashdf 0.7.1__tar.gz → 0.8.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: rashdf
3
- Version: 0.7.1
3
+ Version: 0.8.0
4
4
  Summary: Read data from HEC-RAS HDF files.
5
5
  Project-URL: repository, https://github.com/fema-ffrd/rashdf
6
6
  Classifier: Development Status :: 4 - Beta
@@ -23,15 +23,17 @@ Requires-Dist: ruff; extra == "dev"
23
23
  Requires-Dist: pytest; extra == "dev"
24
24
  Requires-Dist: pytest-cov; extra == "dev"
25
25
  Requires-Dist: kerchunk; extra == "dev"
26
- Requires-Dist: zarr; extra == "dev"
26
+ Requires-Dist: zarr==2.18.2; extra == "dev"
27
27
  Requires-Dist: dask; extra == "dev"
28
28
  Requires-Dist: fsspec; extra == "dev"
29
29
  Requires-Dist: s3fs; extra == "dev"
30
30
  Requires-Dist: fiona==1.9.6; extra == "dev"
31
+ Requires-Dist: numcodecs<0.16; extra == "dev"
31
32
  Provides-Extra: docs
32
33
  Requires-Dist: sphinx; extra == "docs"
33
34
  Requires-Dist: numpydoc; extra == "docs"
34
35
  Requires-Dist: sphinx_rtd_theme; extra == "docs"
36
+ Dynamic: license-file
35
37
 
36
38
  # rashdf
37
39
  [![CI](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml/badge.svg?branch=main)](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml)
@@ -12,11 +12,23 @@ classifiers = [
12
12
  "Programming Language :: Python :: 3.11",
13
13
  "Programming Language :: Python :: 3.12",
14
14
  ]
15
- version = "0.7.1"
15
+ version = "0.8.0"
16
16
  dependencies = ["h5py", "geopandas>=1.0,<2.0", "pyarrow", "xarray"]
17
17
 
18
18
  [project.optional-dependencies]
19
- dev = ["pre-commit", "ruff", "pytest", "pytest-cov", "kerchunk", "zarr", "dask", "fsspec", "s3fs", "fiona==1.9.6"]
19
+ dev = [
20
+ "pre-commit",
21
+ "ruff",
22
+ "pytest",
23
+ "pytest-cov",
24
+ "kerchunk",
25
+ "zarr==2.18.2",
26
+ "dask",
27
+ "fsspec",
28
+ "s3fs",
29
+ "fiona==1.9.6",
30
+ "numcodecs<0.16"
31
+ ]
20
32
  docs = ["sphinx", "numpydoc", "sphinx_rtd_theme"]
21
33
 
22
34
  [project.urls]
@@ -21,6 +21,7 @@ COMMANDS = [
21
21
  "mesh_cell_faces",
22
22
  "refinement_regions",
23
23
  "bc_lines",
24
+ "ic_points",
24
25
  "breaklines",
25
26
  "reference_lines",
26
27
  "reference_points",
@@ -41,6 +41,7 @@ class RasGeomHdf(RasHdf):
41
41
  GEOM_STRUCTURES_PATH = f"{GEOM_PATH}/Structures"
42
42
  FLOW_AREA_2D_PATH = f"{GEOM_PATH}/2D Flow Areas"
43
43
  BC_LINES_PATH = f"{GEOM_PATH}/Boundary Condition Lines"
44
+ IC_POINTS_PATH = f"{GEOM_PATH}/IC Points"
44
45
  BREAKLINES_PATH = f"{GEOM_PATH}/2D Flow Area Break Lines"
45
46
  REFERENCE_LINES_PATH = f"{GEOM_PATH}/Reference Lines"
46
47
  REFERENCE_POINTS_PATH = f"{GEOM_PATH}/Reference Points"
@@ -408,7 +409,10 @@ class RasGeomHdf(RasHdf):
408
409
  GeoDataFrame
409
410
  A GeoDataFrame containing the model structures if they exist.
410
411
  """
411
- if self.GEOM_STRUCTURES_PATH not in self:
412
+ if (
413
+ self.GEOM_STRUCTURES_PATH not in self
414
+ or f"{self.GEOM_STRUCTURES_PATH}/Attributes" not in self
415
+ ):
412
416
  return GeoDataFrame()
413
417
  struct_data = self[self.GEOM_STRUCTURES_PATH]
414
418
  v_conv_val = np.vectorize(convert_ras_hdf_value)
@@ -438,7 +442,32 @@ class RasGeomHdf(RasHdf):
438
442
  raise NotImplementedError
439
443
 
440
444
  def ic_points(self) -> GeoDataFrame: # noqa D102
441
- raise NotImplementedError
445
+ """Return initial conditions points.
446
+
447
+ Returns
448
+ -------
449
+ GeoDataFrame
450
+ A GeoDataFrame containing the initial condition points if they exist.
451
+ """
452
+ if self.IC_POINTS_PATH not in self:
453
+ return GeoDataFrame()
454
+ ic_data = self[self.IC_POINTS_PATH]
455
+ v_conv_str = np.vectorize(convert_ras_hdf_string)
456
+ names = v_conv_str(ic_data["Attributes"][()]["Name"])
457
+ mesh_names = v_conv_str(ic_data["Attributes"][()]["SA/2D"])
458
+ cell_ids = ic_data["Attributes"][()]["Cell Index"]
459
+ points = ic_data["Points"][()]
460
+ return GeoDataFrame(
461
+ {
462
+ "icpt_id": range(len(names)),
463
+ "icpt_name": names,
464
+ "mesh_name": mesh_names,
465
+ "cell_id": cell_ids,
466
+ "geometry": list(map(Point, points)),
467
+ },
468
+ geometry="geometry",
469
+ crs=self.projection(),
470
+ )
442
471
 
443
472
  def _reference_lines_points_names(
444
473
  self, reftype: str = "lines", mesh_name: Optional[str] = None
@@ -160,7 +160,7 @@ class RasPlanHdf(RasGeomHdf):
160
160
  OBS_DATA_PATH = "Event Conditions/Observed Data"
161
161
  RESULTS_UNSTEADY_PATH = "Results/Unsteady"
162
162
  RESULTS_UNSTEADY_SUMMARY_PATH = f"{RESULTS_UNSTEADY_PATH}/Summary"
163
- VOLUME_ACCOUNTING_PATH = f"{RESULTS_UNSTEADY_PATH}/Volume Accounting"
163
+ VOLUME_ACCOUNTING_PATH = f"{RESULTS_UNSTEADY_SUMMARY_PATH}/Volume Accounting"
164
164
  BASE_OUTPUT_PATH = f"{RESULTS_UNSTEADY_PATH}/Output/Output Blocks/Base Output"
165
165
  SUMMARY_OUTPUT_2D_FLOW_AREAS_PATH = (
166
166
  f"{BASE_OUTPUT_PATH}/Summary Output/2D Flow Areas"
@@ -168,6 +168,7 @@ class RasPlanHdf(RasGeomHdf):
168
168
  UNSTEADY_TIME_SERIES_PATH = f"{BASE_OUTPUT_PATH}/Unsteady Time Series"
169
169
  REFERENCE_LINES_OUTPUT_PATH = f"{UNSTEADY_TIME_SERIES_PATH}/Reference Lines"
170
170
  REFERENCE_POINTS_OUTPUT_PATH = f"{UNSTEADY_TIME_SERIES_PATH}/Reference Points"
171
+ BOUNDARY_CONDITIONS_OUTPUT_PATH = f"{UNSTEADY_TIME_SERIES_PATH}/Boundary Conditions"
171
172
  OBS_FLOW_OUTPUT_PATH = f"{OBS_DATA_PATH}/Flow"
172
173
  OBS_STAGE_OUTPUT_PATH = f"{OBS_DATA_PATH}/Stage"
173
174
 
@@ -1121,6 +1122,81 @@ class RasPlanHdf(RasGeomHdf):
1121
1122
  """
1122
1123
  return self.reference_timeseries_output(reftype="lines")
1123
1124
 
1125
+ def bc_line_timeseries_output(self, bc_line_name: str) -> xr.Dataset:
1126
+ """Return timeseries output data for a specific boundary condition line from a HEC-RAS HDF plan file.
1127
+
1128
+ Parameters
1129
+ ----------
1130
+ bc_line_name : str
1131
+ The name of the boundary condition line.
1132
+
1133
+ Returns
1134
+ -------
1135
+ xr.Dataset
1136
+ An xarray Dataset with timeseries output data for the specified boundary condition line.
1137
+ """
1138
+ path = f"{self.BOUNDARY_CONDITIONS_OUTPUT_PATH}/{bc_line_name}"
1139
+ dataset = self.get(path)
1140
+ if dataset is None:
1141
+ raise RasPlanHdfError(
1142
+ f"Could not find HDF group at path '{path}'."
1143
+ f" Does the Plan HDF file contain boundary condition output data for '{bc_line_name}'?"
1144
+ )
1145
+ columns = [c.decode("utf-8") for c in dataset.attrs["Columns"]]
1146
+ ds = xr.Dataset()
1147
+ try:
1148
+ import dask.array as da
1149
+
1150
+ # TODO: user-specified chunks?
1151
+ values = da.from_array(dataset, chunks=dataset.chunks)
1152
+ except ImportError:
1153
+ values = dataset[:]
1154
+ for i, col in enumerate(columns):
1155
+ units = dataset.attrs.get(col, None)
1156
+ if units is not None:
1157
+ units = units.decode("utf-8")
1158
+ da = xr.DataArray(
1159
+ values[:, i],
1160
+ name=col,
1161
+ dims=["time"],
1162
+ coords={
1163
+ "time": self.unsteady_datetimes(),
1164
+ },
1165
+ attrs={
1166
+ "units": units,
1167
+ "hdf_path": f"{path}",
1168
+ },
1169
+ )
1170
+ ds[col] = da
1171
+ return ds
1172
+
1173
+ def bc_lines_timeseries_output(self) -> xr.Dataset:
1174
+ """Return timeseries output data for boundary conditions lines from a HEC-RAS HDF plan file.
1175
+
1176
+ Returns
1177
+ -------
1178
+ xr.Dataset
1179
+ An xarray Dataset with timeseries output data for boundary conditions lines.
1180
+ """
1181
+ df_bc_lines = self.bc_lines()
1182
+ bc_lines_names = df_bc_lines["name"]
1183
+ datasets = []
1184
+ for bc_line_name in bc_lines_names:
1185
+ ds_bc_line = self.bc_line_timeseries_output(bc_line_name)
1186
+ datasets.append(ds_bc_line)
1187
+ bc_line_ids = df_bc_lines["bc_line_id"].values
1188
+ ds: xr.Dataset = xr.concat(
1189
+ datasets, dim=pd.Index(bc_line_ids, name="bc_line_id")
1190
+ )
1191
+ ds = ds.assign_coords(
1192
+ {
1193
+ "bc_line_name": ("bc_line_id", bc_lines_names),
1194
+ "bc_line_type": ("bc_line_id", df_bc_lines["type"]),
1195
+ "mesh_name": ("bc_line_id", df_bc_lines["mesh_name"]),
1196
+ }
1197
+ )
1198
+ return ds
1199
+
1124
1200
  def observed_timeseries_input(self, vartype: str = "Flow") -> xr.DataArray:
1125
1201
  """Return observed timeseries input data for reference lines and points from a HEC-RAS HDF plan file.
1126
1202
 
@@ -1381,10 +1457,49 @@ class RasPlanHdf(RasGeomHdf):
1381
1457
  """
1382
1458
  return self.get_attrs(self.VOLUME_ACCOUNTING_PATH)
1383
1459
 
1384
- def enroachment_points(self) -> GeoDataFrame: # noqa: D102
1385
- raise NotImplementedError
1460
+ def encroachment_points(self, profile_name: str) -> GeoDataFrame:
1461
+ """Return encroachment points from a HEC-RAS plan HDF file based on a user-specified flow profile.
1462
+
1463
+ Returns
1464
+ -------
1465
+ GeoDataframe
1466
+ A GeoDataFrame with cross-section encroachments represented as Point geometry features along with pertinent attributes.
1467
+ """
1468
+ cross_sections = self.cross_sections()
1469
+ cross_sections["Enc_Profile"] = profile_name
1470
+
1471
+ leftmost_sta = self.cross_sections_elevations()["elevation info"].apply(
1472
+ lambda x: x[0][0]
1473
+ )
1474
+ left_enc_sta = self.cross_sections_additional_enc_station_left()[profile_name]
1475
+ left_enc_points = GeoDataFrame(
1476
+ pd.concat(
1477
+ [
1478
+ cross_sections[["River", "Reach", "RS", "Enc_Profile"]],
1479
+ left_enc_sta.rename("Enc_Sta", inplace=False),
1480
+ ],
1481
+ axis=1,
1482
+ ),
1483
+ geometry=cross_sections.geometry.interpolate(left_enc_sta - leftmost_sta),
1484
+ )
1485
+ left_enc_points["Side"] = "Left"
1486
+
1487
+ right_enc_sta = self.cross_sections_additional_enc_station_right()[profile_name]
1488
+ right_enc_points = GeoDataFrame(
1489
+ pd.concat(
1490
+ [
1491
+ cross_sections[["River", "Reach", "RS", "Enc_Profile"]],
1492
+ right_enc_sta.rename("Enc_Sta", inplace=False),
1493
+ ],
1494
+ axis=1,
1495
+ ),
1496
+ geometry=cross_sections.geometry.interpolate(right_enc_sta - leftmost_sta),
1497
+ )
1498
+ right_enc_points["Side"] = "Right"
1499
+
1500
+ return GeoDataFrame(pd.concat([left_enc_points, right_enc_points]))
1386
1501
 
1387
- def steady_flow_names(self) -> list:
1502
+ def steady_flow_names(self) -> List[str]:
1388
1503
  """Return the profile information for each steady flow event.
1389
1504
 
1390
1505
  Returns
@@ -1393,7 +1508,7 @@ class RasPlanHdf(RasGeomHdf):
1393
1508
  A Dataframe containing the profile names for each event
1394
1509
  """
1395
1510
  if self.STEADY_PROFILES_PATH not in self:
1396
- return pd.DataFrame()
1511
+ return []
1397
1512
 
1398
1513
  profile_data = self[self.STEADY_PROFILES_PATH]
1399
1514
  profile_attrs = profile_data["Profile Names"][()]
@@ -1511,7 +1626,7 @@ class RasPlanHdf(RasGeomHdf):
1511
1626
  def _zmeta(self, ds: xr.Dataset) -> Dict:
1512
1627
  """Given a xarray Dataset, return kerchunk-style zarr reference metadata."""
1513
1628
  from kerchunk.hdf import SingleHdf5ToZarr
1514
- import zarr
1629
+ from zarr.storage import MemoryStore
1515
1630
  import base64
1516
1631
 
1517
1632
  encoding = {}
@@ -1546,7 +1661,7 @@ class RasPlanHdf(RasGeomHdf):
1546
1661
  chunk_meta[chunk_key] = [str(self._loc), value["offset"], value["size"]]
1547
1662
  # "Write" the Dataset to a temporary in-memory zarr store (which
1548
1663
  # is the same a Python dictionary)
1549
- zarr_tmp = zarr.MemoryStore()
1664
+ zarr_tmp = MemoryStore()
1550
1665
  # Use compute=False here because we don't _actually_ want to write
1551
1666
  # the data to the zarr store, we just want to generate the metadata.
1552
1667
  ds.to_zarr(zarr_tmp, mode="w", compute=False, encoding=encoding)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: rashdf
3
- Version: 0.7.1
3
+ Version: 0.8.0
4
4
  Summary: Read data from HEC-RAS HDF files.
5
5
  Project-URL: repository, https://github.com/fema-ffrd/rashdf
6
6
  Classifier: Development Status :: 4 - Beta
@@ -23,15 +23,17 @@ Requires-Dist: ruff; extra == "dev"
23
23
  Requires-Dist: pytest; extra == "dev"
24
24
  Requires-Dist: pytest-cov; extra == "dev"
25
25
  Requires-Dist: kerchunk; extra == "dev"
26
- Requires-Dist: zarr; extra == "dev"
26
+ Requires-Dist: zarr==2.18.2; extra == "dev"
27
27
  Requires-Dist: dask; extra == "dev"
28
28
  Requires-Dist: fsspec; extra == "dev"
29
29
  Requires-Dist: s3fs; extra == "dev"
30
30
  Requires-Dist: fiona==1.9.6; extra == "dev"
31
+ Requires-Dist: numcodecs<0.16; extra == "dev"
31
32
  Provides-Extra: docs
32
33
  Requires-Dist: sphinx; extra == "docs"
33
34
  Requires-Dist: numpydoc; extra == "docs"
34
35
  Requires-Dist: sphinx_rtd_theme; extra == "docs"
36
+ Dynamic: license-file
35
37
 
36
38
  # rashdf
37
39
  [![CI](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml/badge.svg?branch=main)](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml)
@@ -9,11 +9,12 @@ ruff
9
9
  pytest
10
10
  pytest-cov
11
11
  kerchunk
12
- zarr
12
+ zarr==2.18.2
13
13
  dask
14
14
  fsspec
15
15
  s3fs
16
16
  fiona==1.9.6
17
+ numcodecs<0.16
17
18
 
18
19
  [docs]
19
20
  sphinx
@@ -1,7 +1,9 @@
1
+ import geopandas as gpd
1
2
  from pathlib import Path
2
3
  import h5py
3
4
  from pyproj import CRS
4
5
  from src.rashdf import RasGeomHdf
6
+ from pandas.testing import assert_frame_equal
5
7
 
6
8
  from . import _create_hdf_with_group_attrs, _gdf_matches_json, _gdf_matches_json_alt
7
9
 
@@ -11,6 +13,8 @@ COAL_G01 = TEST_DATA / "ras/Coal.g01.hdf"
11
13
  BAXTER_P01 = TEST_DATA / "ras_1d/Baxter.p01.hdf"
12
14
  TEST_JSON = TEST_DATA / "json"
13
15
  BALD_EAGLE_P18_REF = TEST_DATA / "ras/BaldEagleDamBrk.reflines-refpts.p18.hdf"
16
+ LOWER_KANAWHA_P01_IC_POINTS = TEST_DATA / "ras/LowerKanawha.p01.icpoints.hdf"
17
+ LOWER_KANAWHA_P01_IC_POINTS_JSON = TEST_JSON / "LowerKanawha.p01.icpoints.geojson"
14
18
 
15
19
  TEST_ATTRS = {"test_attribute1": "test_str1", "test_attribute2": 500}
16
20
 
@@ -151,7 +155,7 @@ def test_reference_points_names():
151
155
 
152
156
  def test_structs_not_found():
153
157
  with RasGeomHdf(COAL_G01) as ghdf:
154
- assert (ghdf.structures(), None)
158
+ assert ghdf.structures().empty
155
159
 
156
160
 
157
161
  def test_cross_sections():
@@ -164,7 +168,7 @@ def test_cross_sections():
164
168
 
165
169
  def test_cross_sections_not_found():
166
170
  with RasGeomHdf(COAL_G01) as ghdf:
167
- assert (ghdf.cross_sections(), None)
171
+ assert ghdf.cross_sections().empty
168
172
 
169
173
 
170
174
  def test_river_reaches():
@@ -175,7 +179,7 @@ def test_river_reaches():
175
179
 
176
180
  def test_river_reaches_not_found():
177
181
  with RasGeomHdf(COAL_G01) as ghdf:
178
- assert (ghdf.river_reaches(), None)
182
+ assert ghdf.river_reaches().empty
179
183
 
180
184
 
181
185
  def test_cross_sections_elevations():
@@ -186,4 +190,18 @@ def test_cross_sections_elevations():
186
190
 
187
191
  def test_cross_sections_elevations_not_found():
188
192
  with RasGeomHdf(COAL_G01) as ghdf:
189
- assert (ghdf.cross_sections_elevations(), None)
193
+ assert ghdf.cross_sections_elevations().empty
194
+
195
+
196
+ def test_ic_points():
197
+ with RasGeomHdf(LOWER_KANAWHA_P01_IC_POINTS) as ghdf:
198
+ gdf_ic_points = ghdf.ic_points()
199
+ valid_gdf = gpd.read_file(
200
+ LOWER_KANAWHA_P01_IC_POINTS_JSON,
201
+ crs=ghdf.projection(),
202
+ )
203
+ assert_frame_equal(
204
+ gdf_ic_points,
205
+ valid_gdf,
206
+ check_dtype=False,
207
+ )
@@ -5,9 +5,11 @@ from src.rashdf.plan import (
5
5
  TimeSeriesOutputVar,
6
6
  )
7
7
 
8
+ import builtins
8
9
  import filecmp
9
10
  import json
10
11
  from pathlib import Path
12
+ from unittest import mock
11
13
 
12
14
  import numpy as np
13
15
  import pandas as pd
@@ -32,6 +34,7 @@ BALD_EAGLE_P18_REF = TEST_DATA / "ras/BaldEagleDamBrk.reflines-refpts.p18.hdf"
32
34
  DENTON = TEST_DATA / "ras/Denton.hdf"
33
35
  MUNCIE_G05 = TEST_DATA / "ras/Muncie.g05.hdf"
34
36
  COAL_G01 = TEST_DATA / "ras/Coal.g01.hdf"
37
+ LOWER_KANAWHA_P01_BC_LINES = TEST_DATA / "ras/LowerKanawha.p01.bclines.hdf"
35
38
  BAXTER_P01 = TEST_DATA / "ras_1d/Baxter.p01.hdf"
36
39
  FLODENCR_P01 = TEST_DATA / "ras_1d/FLODENCR.p01.hdf"
37
40
 
@@ -322,6 +325,59 @@ def test_reference_lines_timeseries(tmp_path: Path):
322
325
  assert_frame_equal(df, valid_df)
323
326
 
324
327
 
328
+ def test_bc_lines_timeseries(tmp_path: Path):
329
+ plan_hdf = RasPlanHdf(LOWER_KANAWHA_P01_BC_LINES)
330
+ ds = plan_hdf.bc_lines_timeseries_output()
331
+ assert "time" in ds.coords
332
+ assert "bc_line_id" in ds.coords
333
+ assert "bc_line_name" in ds.coords
334
+ assert "mesh_name" in ds.coords
335
+ assert "Flow" in ds.variables
336
+ assert "Stage" in ds.variables
337
+
338
+ q = ds["Flow"]
339
+ assert q.chunks is not None # Ensure Dask chunks are set
340
+ assert q.shape == (10, 577)
341
+ assert q.attrs["units"] == "cfs"
342
+
343
+ stage = ds["Stage"]
344
+ assert stage.chunks is not None # Ensure Dask chunks are set
345
+ assert stage.shape == (10, 577)
346
+ assert stage.attrs["units"] == "ft"
347
+
348
+ df = ds.sel(bc_line_id=7).to_dataframe()
349
+ valid_df = pd.read_csv(
350
+ TEST_CSV / "LowerKanawha.p01.bclines.7.csv",
351
+ index_col="time",
352
+ parse_dates=True,
353
+ dtype={"Flow": np.float32, "Stage": np.float32},
354
+ )
355
+ assert_frame_equal(df, valid_df)
356
+
357
+
358
+ def test_bc_lines_timeseries_no_dask(monkeypatch):
359
+ """Test that the bc_lines_timeseries_output method works without Dask."""
360
+ original_import = builtins.__import__
361
+
362
+ def mocked_import(name, *args, **kwargs):
363
+ if name == "dask.array":
364
+ raise ImportError("Dask is not available")
365
+ return original_import(name, *args, **kwargs)
366
+
367
+ monkeypatch.setattr(builtins, "__import__", mocked_import)
368
+
369
+ plan_hdf = RasPlanHdf(LOWER_KANAWHA_P01_BC_LINES)
370
+ ds = plan_hdf.bc_lines_timeseries_output()
371
+ assert ds["Flow"].chunks is None # Ensure no Dask chunks are set
372
+ assert ds["Stage"].chunks is None
373
+
374
+
375
+ def test_bc_line_timeseries_error():
376
+ plan_hdf = RasPlanHdf(LOWER_KANAWHA_P01_BC_LINES)
377
+ with pytest.raises(RasPlanHdfError):
378
+ plan_hdf.bc_line_timeseries_output("asdf")
379
+
380
+
325
381
  def test_reference_points(tmp_path: Path):
326
382
  plan_hdf = RasPlanHdf(BALD_EAGLE_P18_REF)
327
383
  gdf = plan_hdf.reference_points(datetime_to_str=True)
@@ -371,7 +427,7 @@ def test_cross_sections_additional_velocity_total():
371
427
 
372
428
  def test_cross_sections_additional_velocity_total_not_found():
373
429
  with RasPlanHdf(COAL_G01) as phdf:
374
- assert (phdf.cross_sections_additional_velocity_total(), None)
430
+ assert phdf.cross_sections_additional_velocity_total().empty
375
431
 
376
432
 
377
433
  def test_cross_sections_additional_area_total():
@@ -384,7 +440,7 @@ def test_cross_sections_additional_area_total():
384
440
 
385
441
  def test_cross_sections_additional_area_total_not_found():
386
442
  with RasPlanHdf(COAL_G01) as phdf:
387
- assert (phdf.cross_sections_additional_area_total(), None)
443
+ assert phdf.cross_sections_additional_area_total().empty
388
444
 
389
445
 
390
446
  def test_steady_flow_names():
@@ -394,7 +450,7 @@ def test_steady_flow_names():
394
450
 
395
451
  def test_steady_flow_names_not_found():
396
452
  with RasPlanHdf(COAL_G01) as phdf:
397
- assert (phdf.steady_flow_names(), None)
453
+ assert phdf.steady_flow_names() == []
398
454
 
399
455
 
400
456
  def test_cross_sections_wsel():
@@ -405,7 +461,7 @@ def test_cross_sections_wsel():
405
461
 
406
462
  def test_cross_sections_wsel_not_found():
407
463
  with RasPlanHdf(COAL_G01) as phdf:
408
- assert (phdf.cross_sections_wsel(), None)
464
+ assert phdf.cross_sections_wsel().empty
409
465
 
410
466
 
411
467
  def test_cross_sections_additional_enc_station_right():
@@ -419,7 +475,7 @@ def test_cross_sections_additional_enc_station_right():
419
475
 
420
476
  def test_cross_sections_additional_enc_station_right_not_found():
421
477
  with RasPlanHdf(COAL_G01) as phdf:
422
- assert (phdf.cross_sections_additional_enc_station_right(), None)
478
+ assert phdf.cross_sections_additional_enc_station_right().empty
423
479
 
424
480
 
425
481
  def test_cross_sections_additional_enc_station_left():
@@ -432,7 +488,7 @@ def test_cross_sections_additional_enc_station_left():
432
488
 
433
489
  def test_cross_sections_additional_enc_station_left_not_found():
434
490
  with RasPlanHdf(COAL_G01) as phdf:
435
- assert (phdf.cross_sections_additional_enc_station_left(), None)
491
+ assert phdf.cross_sections_additional_enc_station_left().empty
436
492
 
437
493
 
438
494
  def test_cross_sections_flow():
@@ -650,3 +706,12 @@ def test_observed_timeseries_input_rasplanhdf_error():
650
706
  with RasPlanHdf(BALD_EAGLE_P18) as phdf:
651
707
  with pytest.raises(RasPlanHdfError):
652
708
  phdf.observed_timeseries_input(vartype="Flow")
709
+
710
+
711
+ def test_encroachment_points():
712
+ enc_pnts_json = TEST_JSON / "encroachment_points.json"
713
+ with RasPlanHdf(FLODENCR_P01) as phdf:
714
+ assert _gdf_matches_json_alt(
715
+ phdf.encroachment_points(profile_name="PF#2"),
716
+ enc_pnts_json,
717
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes