rashdf 0.3.0__tar.gz → 0.4.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
1
  Metadata-Version: 2.1
2
2
  Name: rashdf
3
- Version: 0.3.0
3
+ Version: 0.4.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
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: h5py
17
- Requires-Dist: geopandas
17
+ Requires-Dist: geopandas<0.15,>=0.14
18
18
  Requires-Dist: pyarrow
19
19
  Requires-Dist: xarray
20
20
  Provides-Extra: dev
@@ -12,8 +12,8 @@ classifiers = [
12
12
  "Programming Language :: Python :: 3.11",
13
13
  "Programming Language :: Python :: 3.12",
14
14
  ]
15
- version = "0.3.0"
16
- dependencies = ["h5py", "geopandas", "pyarrow", "xarray"]
15
+ version = "0.4.0"
16
+ dependencies = ["h5py", "geopandas>=0.14,<0.15", "pyarrow", "xarray"]
17
17
 
18
18
  [project.optional-dependencies]
19
19
  dev = ["pre-commit", "ruff", "pytest", "pytest-cov"]
@@ -1,27 +1,27 @@
1
1
  """HEC-RAS Geometry HDF class."""
2
2
 
3
- from .base import RasHdf
4
- from .utils import (
5
- convert_ras_hdf_string,
6
- get_first_hdf_group,
7
- hdf5_attrs_to_dict,
8
- convert_ras_hdf_value,
9
- )
3
+ from typing import Dict, List, Optional
10
4
 
11
5
  import numpy as np
12
6
  import pandas as pd
13
7
  from geopandas import GeoDataFrame
14
8
  from pyproj import CRS
15
9
  from shapely import (
16
- Polygon,
17
- Point,
18
10
  LineString,
19
11
  MultiLineString,
20
12
  MultiPolygon,
13
+ Point,
14
+ Polygon,
21
15
  polygonize_full,
22
16
  )
23
17
 
24
- from typing import Dict, List, Optional
18
+ from .base import RasHdf
19
+ from .utils import (
20
+ convert_ras_hdf_string,
21
+ convert_ras_hdf_value,
22
+ get_first_hdf_group,
23
+ hdf5_attrs_to_dict,
24
+ )
25
25
 
26
26
 
27
27
  class RasGeomHdf(RasHdf):
@@ -465,11 +465,97 @@ class RasGeomHdf(RasHdf):
465
465
  def terrain_modifications(self) -> GeoDataFrame: # noqa D102
466
466
  raise NotImplementedError
467
467
 
468
- def cross_sections(self) -> GeoDataFrame: # noqa D102
469
- raise NotImplementedError
468
+ def cross_sections(self, datetime_to_str: bool = False) -> GeoDataFrame:
469
+ """Return the model 1D cross sections.
470
470
 
471
- def river_reaches(self) -> GeoDataFrame: # noqa D102
472
- raise NotImplementedError
471
+ Returns
472
+ -------
473
+ GeoDataFrame
474
+ A GeoDataFrame containing the model 1D cross sections if they exist.
475
+ """
476
+ if "/Geometry/Cross Sections" not in self:
477
+ return GeoDataFrame()
478
+
479
+ xs_data = self["/Geometry/Cross Sections"]
480
+ v_conv_val = np.vectorize(convert_ras_hdf_value)
481
+ xs_attrs = xs_data["Attributes"][()]
482
+ xs_dict = {"xs_id": range(xs_attrs.shape[0])}
483
+ xs_dict.update(
484
+ {name: v_conv_val(xs_attrs[name]) for name in xs_attrs.dtype.names}
485
+ )
486
+ geoms = list()
487
+ for pnt_start, pnt_cnt, part_start, part_cnt in xs_data["Polyline Info"][()]:
488
+ points = xs_data["Polyline Points"][()][pnt_start : pnt_start + pnt_cnt]
489
+ if part_cnt == 1:
490
+ geoms.append(LineString(points))
491
+ else:
492
+ parts = xs_data["Polyline Parts"][()][
493
+ part_start : part_start + part_cnt
494
+ ]
495
+ geoms.append(
496
+ MultiLineString(
497
+ list(
498
+ points[part_pnt_start : part_pnt_start + part_pnt_cnt]
499
+ for part_pnt_start, part_pnt_cnt in parts
500
+ )
501
+ )
502
+ )
503
+ xs_gdf = GeoDataFrame(
504
+ xs_dict,
505
+ geometry=geoms,
506
+ crs=self.projection(),
507
+ )
508
+ if datetime_to_str:
509
+ xs_gdf["Last Edited"] = xs_gdf["Last Edited"].apply(
510
+ lambda x: pd.Timestamp.isoformat(x)
511
+ )
512
+ return xs_gdf
513
+
514
+ def river_reaches(self, datetime_to_str: bool = False) -> GeoDataFrame:
515
+ """Return the model 1D river reach lines.
516
+
517
+ Returns
518
+ -------
519
+ GeoDataFrame
520
+ A GeoDataFrame containing the model 1D river reach lines if they exist.
521
+ """
522
+ if "/Geometry/River Centerlines" not in self:
523
+ return GeoDataFrame()
524
+
525
+ river_data = self["/Geometry/River Centerlines"]
526
+ v_conv_val = np.vectorize(convert_ras_hdf_value)
527
+ river_attrs = river_data["Attributes"][()]
528
+ river_dict = {"river_id": range(river_attrs.shape[0])}
529
+ river_dict.update(
530
+ {name: v_conv_val(river_attrs[name]) for name in river_attrs.dtype.names}
531
+ )
532
+ geoms = list()
533
+ for pnt_start, pnt_cnt, part_start, part_cnt in river_data["Polyline Info"][()]:
534
+ points = river_data["Polyline Points"][()][pnt_start : pnt_start + pnt_cnt]
535
+ if part_cnt == 1:
536
+ geoms.append(LineString(points))
537
+ else:
538
+ parts = river_data["Polyline Parts"][()][
539
+ part_start : part_start + part_cnt
540
+ ]
541
+ geoms.append(
542
+ MultiLineString(
543
+ list(
544
+ points[part_pnt_start : part_pnt_start + part_pnt_cnt]
545
+ for part_pnt_start, part_pnt_cnt in parts
546
+ )
547
+ )
548
+ )
549
+ river_gdf = GeoDataFrame(
550
+ river_dict,
551
+ geometry=geoms,
552
+ crs=self.projection(),
553
+ )
554
+ if datetime_to_str:
555
+ river_gdf["Last Edited"] = river_gdf["Last Edited"].apply(
556
+ lambda x: pd.Timestamp.isoformat(x)
557
+ )
558
+ return river_gdf
473
559
 
474
560
  def flowpaths(self) -> GeoDataFrame: # noqa D102
475
561
  raise NotImplementedError
@@ -488,3 +574,33 @@ class RasGeomHdf(RasHdf):
488
574
 
489
575
  def blocked_obstructions(self) -> GeoDataFrame: # noqa D102
490
576
  raise NotImplementedError
577
+
578
+ def cross_sections_elevations(self, round_to: int = 2) -> pd.DataFrame:
579
+ """Return the model cross section elevation information.
580
+
581
+ Returns
582
+ -------
583
+ DataFrame
584
+ A DataFrame containing the model cross section elevation information if they exist.
585
+ """
586
+ path = "/Geometry/Cross Sections"
587
+ if path not in self:
588
+ return pd.DataFrame()
589
+
590
+ xselev_data = self[path]
591
+ xs_df = self.cross_sections()
592
+ elevations = list()
593
+ for part_start, part_cnt in xselev_data["Station Elevation Info"][()]:
594
+ xzdata = xselev_data["Station Elevation Values"][()][
595
+ part_start : part_start + part_cnt
596
+ ]
597
+ elevations.append(xzdata)
598
+
599
+ xs_elev_df = xs_df[
600
+ ["xs_id", "River", "Reach", "RS", "Left Bank", "Right Bank"]
601
+ ].copy()
602
+ xs_elev_df["Left Bank"] = xs_elev_df["Left Bank"].round(round_to).astype(str)
603
+ xs_elev_df["Right Bank"] = xs_elev_df["Right Bank"].round(round_to).astype(str)
604
+ xs_elev_df["elevation info"] = elevations
605
+
606
+ return xs_elev_df
@@ -25,6 +25,26 @@ class RasPlanHdfError(Exception):
25
25
  pass
26
26
 
27
27
 
28
+ class XsSteadyOutputVar(Enum):
29
+ """Summary of steady cross section output variables."""
30
+
31
+ ENERGY_GRADE = "Energy Grade"
32
+ FLOW = "Flow"
33
+ WATER_SURFACE = "Water Surface"
34
+ ENCROACHMENT_STATION_LEFT = "Encroachment Station Left"
35
+ ENCROACHMENT_STATION_RIGHT = "Encroachment Station Right"
36
+ AREA_INEFFECTIVE_TOTAL = "Area including Ineffective Total"
37
+ VELOCITY_TOTAL = "Velocity Total"
38
+
39
+
40
+ XS_STEADY_OUTPUT_ADDITIONAL = [
41
+ XsSteadyOutputVar.ENCROACHMENT_STATION_LEFT,
42
+ XsSteadyOutputVar.ENCROACHMENT_STATION_RIGHT,
43
+ XsSteadyOutputVar.AREA_INEFFECTIVE_TOTAL,
44
+ XsSteadyOutputVar.VELOCITY_TOTAL,
45
+ ]
46
+
47
+
28
48
  class SummaryOutputVar(Enum):
29
49
  """Summary output variables."""
30
50
 
@@ -144,6 +164,12 @@ class RasPlanHdf(RasGeomHdf):
144
164
  )
145
165
  UNSTEADY_TIME_SERIES_PATH = f"{BASE_OUTPUT_PATH}/Unsteady Time Series"
146
166
 
167
+ RESULTS_STEADY_PATH = "Results/Steady"
168
+ BASE_STEADY_PATH = f"{RESULTS_STEADY_PATH}/Output/Output Blocks/Base Output"
169
+ STEADY_PROFILES_PATH = f"{BASE_STEADY_PATH}/Steady Profiles"
170
+ STEADY_XS_PATH = f"{STEADY_PROFILES_PATH}/Cross Sections"
171
+ STEADY_XS_ADDITIONAL_PATH = f"{STEADY_XS_PATH}/Additional Variables"
172
+
147
173
  def __init__(self, name: str, **kwargs):
148
174
  """Open a HEC-RAS Plan HDF file.
149
175
 
@@ -957,3 +983,127 @@ class RasPlanHdf(RasGeomHdf):
957
983
 
958
984
  def enroachment_points(self) -> GeoDataFrame: # noqa: D102
959
985
  raise NotImplementedError
986
+
987
+ def steady_flow_names(self) -> list:
988
+ """Return the profile information for each steady flow event.
989
+
990
+ Returns
991
+ -------
992
+ DataFrame
993
+ A Dataframe containing the profile names for each event
994
+ """
995
+ if self.STEADY_PROFILES_PATH not in self:
996
+ return pd.DataFrame()
997
+
998
+ profile_data = self[self.STEADY_PROFILES_PATH]
999
+ profile_attrs = profile_data["Profile Names"][()]
1000
+
1001
+ return [x.decode("utf-8") for x in profile_attrs]
1002
+
1003
+ def steady_profile_xs_output(
1004
+ self, var: XsSteadyOutputVar, round_to: int = 2
1005
+ ) -> DataFrame:
1006
+ """Create a Dataframe from steady cross section results based on path.
1007
+
1008
+ Parameters
1009
+ ----------
1010
+ var : XsSteadyOutputVar
1011
+ The name of the table in the steady results that information is to be retireved from.
1012
+
1013
+ round_to : int, optional
1014
+ Number of decimal places to round output data to.
1015
+
1016
+ Returns
1017
+ -------
1018
+ Dataframe with desired hdf data.
1019
+ """
1020
+ if var in XS_STEADY_OUTPUT_ADDITIONAL:
1021
+ path = f"{self.STEADY_XS_ADDITIONAL_PATH}/{var.value}"
1022
+ else:
1023
+ path = f"{self.STEADY_XS_PATH}/{var.value}"
1024
+ if path not in self:
1025
+ return DataFrame()
1026
+
1027
+ profiles = self.steady_flow_names()
1028
+
1029
+ steady_data = self[path]
1030
+ df = DataFrame(steady_data, index=profiles)
1031
+ df_t = df.T.copy()
1032
+ for p in profiles:
1033
+ df_t[p] = df_t[p].apply(lambda x: round(x, round_to))
1034
+
1035
+ return df_t
1036
+
1037
+ def cross_sections_wsel(self) -> DataFrame:
1038
+ """Return the water surface elevation information for each 1D Cross Section.
1039
+
1040
+ Returns
1041
+ -------
1042
+ DataFrame
1043
+ A Dataframe containing the water surface elevations for each cross section and event
1044
+ """
1045
+ return self.steady_profile_xs_output(XsSteadyOutputVar.WATER_SURFACE)
1046
+
1047
+ def cross_sections_flow(self) -> DataFrame:
1048
+ """Return the Flow information for each 1D Cross Section.
1049
+
1050
+ Returns
1051
+ -------
1052
+ DataFrame
1053
+ A Dataframe containing the flow for each cross section and event
1054
+ """
1055
+ return self.steady_profile_xs_output(XsSteadyOutputVar.FLOW)
1056
+
1057
+ def cross_sections_energy_grade(self) -> DataFrame:
1058
+ """Return the energy grade information for each 1D Cross Section.
1059
+
1060
+ Returns
1061
+ -------
1062
+ DataFrame
1063
+ A Dataframe containing the water surface elevations for each cross section and event
1064
+ """
1065
+ return self.steady_profile_xs_output(XsSteadyOutputVar.ENERGY_GRADE)
1066
+
1067
+ def cross_sections_additional_enc_station_left(self) -> DataFrame:
1068
+ """Return the left side encroachment information for a floodway plan hdf.
1069
+
1070
+ Returns
1071
+ -------
1072
+ DataFrame
1073
+ A DataFrame containing the cross sections left side encroachment stations
1074
+ """
1075
+ return self.steady_profile_xs_output(
1076
+ XsSteadyOutputVar.ENCROACHMENT_STATION_LEFT
1077
+ )
1078
+
1079
+ def cross_sections_additional_enc_station_right(self) -> DataFrame:
1080
+ """Return the right side encroachment information for a floodway plan hdf.
1081
+
1082
+ Returns
1083
+ -------
1084
+ DataFrame
1085
+ A DataFrame containing the cross sections right side encroachment stations
1086
+ """
1087
+ return self.steady_profile_xs_output(
1088
+ XsSteadyOutputVar.ENCROACHMENT_STATION_RIGHT
1089
+ )
1090
+
1091
+ def cross_sections_additional_area_total(self) -> DataFrame:
1092
+ """Return the 1D cross section area for each profile.
1093
+
1094
+ Returns
1095
+ -------
1096
+ DataFrame
1097
+ A DataFrame containing the wet area inside the cross sections
1098
+ """
1099
+ return self.steady_profile_xs_output(XsSteadyOutputVar.AREA_INEFFECTIVE_TOTAL)
1100
+
1101
+ def cross_sections_additional_velocity_total(self) -> DataFrame:
1102
+ """Return the 1D cross section velocity for each profile.
1103
+
1104
+ Returns
1105
+ -------
1106
+ DataFrame
1107
+ A DataFrame containing the velocity inside the cross sections
1108
+ """
1109
+ return self.steady_profile_xs_output(XsSteadyOutputVar.VELOCITY_TOTAL)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rashdf
3
- Version: 0.3.0
3
+ Version: 0.4.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
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.12
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: h5py
17
- Requires-Dist: geopandas
17
+ Requires-Dist: geopandas<0.15,>=0.14
18
18
  Requires-Dist: pyarrow
19
19
  Requires-Dist: xarray
20
20
  Provides-Extra: dev
@@ -1,5 +1,5 @@
1
1
  h5py
2
- geopandas
2
+ geopandas<0.15,>=0.14
3
3
  pyarrow
4
4
  xarray
5
5
 
@@ -1,15 +1,14 @@
1
- from src.rashdf import RasGeomHdf
2
-
1
+ from pathlib import Path
3
2
  import h5py
4
- from geopandas import GeoDataFrame
5
3
  from pyproj import CRS
6
- from pathlib import Path
4
+ from src.rashdf import RasGeomHdf
7
5
 
8
- from . import _create_hdf_with_group_attrs, _gdf_matches_json
6
+ from . import _create_hdf_with_group_attrs, _gdf_matches_json, _gdf_matches_json_alt
9
7
 
10
8
  TEST_DATA = Path("./tests/data")
11
9
  MUNCIE_G05 = TEST_DATA / "ras/Muncie.g05.hdf"
12
10
  COAL_G01 = TEST_DATA / "ras/Coal.g01.hdf"
11
+ BAXTER_P01 = TEST_DATA / "ras_1d/Baxter.p01.hdf"
13
12
  TEST_JSON = TEST_DATA / "json"
14
13
 
15
14
  TEST_ATTRS = {"test_attribute1": "test_str1", "test_attribute2": 500}
@@ -118,3 +117,43 @@ def test_structs():
118
117
  structs_json = TEST_JSON / "structures.json"
119
118
  with RasGeomHdf(MUNCIE_G05) as ghdf:
120
119
  assert _gdf_matches_json(ghdf.structures(datetime_to_str=True), structs_json)
120
+
121
+
122
+ def test_structs_not_found():
123
+ with RasGeomHdf(COAL_G01) as ghdf:
124
+ assert (ghdf.structures(), None)
125
+
126
+
127
+ def test_cross_sections():
128
+ cross_section_json = TEST_JSON / "cross_sections.json"
129
+ with RasGeomHdf(BAXTER_P01) as ghdf:
130
+ assert _gdf_matches_json_alt(
131
+ ghdf.cross_sections(datetime_to_str=True), cross_section_json
132
+ )
133
+
134
+
135
+ def test_cross_sections_not_found():
136
+ with RasGeomHdf(COAL_G01) as ghdf:
137
+ assert (ghdf.cross_sections(), None)
138
+
139
+
140
+ def test_river_reaches():
141
+ river_reaches_json = TEST_JSON / "river_reaches.json"
142
+ with RasGeomHdf(BAXTER_P01) as ghdf:
143
+ assert _gdf_matches_json_alt(ghdf.river_reaches(), river_reaches_json)
144
+
145
+
146
+ def test_river_reaches_not_found():
147
+ with RasGeomHdf(COAL_G01) as ghdf:
148
+ assert (ghdf.river_reaches(), None)
149
+
150
+
151
+ def test_cross_sections_elevations():
152
+ xs_elevs_json = TEST_JSON / "xs_elevations.json"
153
+ with RasGeomHdf(BAXTER_P01) as ghdf:
154
+ assert _gdf_matches_json_alt(ghdf.cross_sections_elevations(), xs_elevs_json)
155
+
156
+
157
+ def test_cross_sections_elevations_not_found():
158
+ with RasGeomHdf(COAL_G01) as ghdf:
159
+ assert (ghdf.cross_sections_elevations(), None)
@@ -12,7 +12,12 @@ import pandas as pd
12
12
  from pandas.testing import assert_frame_equal
13
13
  import pytest
14
14
 
15
- from . import _create_hdf_with_group_attrs, _gdf_matches_json, get_sha1_hash
15
+ from . import (
16
+ _create_hdf_with_group_attrs,
17
+ _gdf_matches_json,
18
+ get_sha1_hash,
19
+ _gdf_matches_json_alt,
20
+ )
16
21
 
17
22
  TEST_DATA = Path("./tests/data")
18
23
  TEST_JSON = TEST_DATA / "json"
@@ -21,6 +26,9 @@ TEST_ATTRS = {"test_attribute1": "test_str1", "test_attribute2": 500}
21
26
  BALD_EAGLE_P18 = TEST_DATA / "ras/BaldEagleDamBrk.p18.hdf"
22
27
  BALD_EAGLE_P18_TIMESERIES = TEST_DATA / "ras/BaldEagleDamBrk.p18.timeseries.hdf"
23
28
  MUNCIE_G05 = TEST_DATA / "ras/Muncie.g05.hdf"
29
+ COAL_G01 = TEST_DATA / "ras/Coal.g01.hdf"
30
+ BAXTER_P01 = TEST_DATA / "ras_1d/Baxter.p01.hdf"
31
+ FLODENCR_P01 = TEST_DATA / "ras_1d/FLODENCR.p01.hdf"
24
32
 
25
33
 
26
34
  def test_get_plan_info_attrs(tmp_path):
@@ -256,3 +264,91 @@ def test_mesh_timeseries_output_faces():
256
264
  dtype={"Face Velocity": np.float32},
257
265
  )
258
266
  assert_frame_equal(df, valid_df)
267
+
268
+
269
+ def test_cross_sections_additional_velocity_total():
270
+ xs_velocity_json = TEST_JSON / "xs_velocity.json"
271
+ with RasPlanHdf(BAXTER_P01) as phdf:
272
+ assert _gdf_matches_json_alt(
273
+ phdf.cross_sections_additional_velocity_total(), xs_velocity_json
274
+ )
275
+
276
+
277
+ def test_cross_sections_additional_velocity_total_not_found():
278
+ with RasPlanHdf(COAL_G01) as phdf:
279
+ assert (phdf.cross_sections_additional_velocity_total(), None)
280
+
281
+
282
+ def test_cross_sections_additional_area_total():
283
+ xs_area_json = TEST_JSON / "xs_area.json"
284
+ with RasPlanHdf(BAXTER_P01) as phdf:
285
+ assert _gdf_matches_json_alt(
286
+ phdf.cross_sections_additional_area_total(), xs_area_json
287
+ )
288
+
289
+
290
+ def test_cross_sections_additional_area_total_not_found():
291
+ with RasPlanHdf(COAL_G01) as phdf:
292
+ assert (phdf.cross_sections_additional_area_total(), None)
293
+
294
+
295
+ def test_steady_flow_names():
296
+ with RasPlanHdf(BAXTER_P01) as phdf:
297
+ assert phdf.steady_flow_names() == ["Big"]
298
+
299
+
300
+ def test_steady_flow_names_not_found():
301
+ with RasPlanHdf(COAL_G01) as phdf:
302
+ assert (phdf.steady_flow_names(), None)
303
+
304
+
305
+ def test_cross_sections_wsel():
306
+ xs_wsel_json = TEST_JSON / "xs_wsel.json"
307
+ with RasPlanHdf(BAXTER_P01) as phdf:
308
+ assert _gdf_matches_json_alt(phdf.cross_sections_wsel(), xs_wsel_json)
309
+
310
+
311
+ def test_cross_sections_wsel_not_found():
312
+ with RasPlanHdf(COAL_G01) as phdf:
313
+ assert (phdf.cross_sections_wsel(), None)
314
+
315
+
316
+ def test_cross_sections_additional_enc_station_right():
317
+ xs_enc_station_right_json = TEST_JSON / "xs_enc_station_right.json"
318
+ with RasPlanHdf(FLODENCR_P01) as phdf:
319
+ assert _gdf_matches_json_alt(
320
+ phdf.cross_sections_additional_enc_station_right(),
321
+ xs_enc_station_right_json,
322
+ )
323
+
324
+
325
+ def test_cross_sections_additional_enc_station_right_not_found():
326
+ with RasPlanHdf(COAL_G01) as phdf:
327
+ assert (phdf.cross_sections_additional_enc_station_right(), None)
328
+
329
+
330
+ def test_cross_sections_additional_enc_station_left():
331
+ xs_enc_station_left_json = TEST_JSON / "xs_enc_station_left.json"
332
+ with RasPlanHdf(FLODENCR_P01) as phdf:
333
+ assert _gdf_matches_json_alt(
334
+ phdf.cross_sections_additional_enc_station_left(), xs_enc_station_left_json
335
+ )
336
+
337
+
338
+ def test_cross_sections_additional_enc_station_left_not_found():
339
+ with RasPlanHdf(COAL_G01) as phdf:
340
+ assert (phdf.cross_sections_additional_enc_station_left(), None)
341
+
342
+
343
+ def test_cross_sections_flow():
344
+ xs_flow_json = TEST_JSON / "xs_flow.json"
345
+ with RasPlanHdf(BAXTER_P01) as phdf:
346
+ assert _gdf_matches_json_alt(phdf.cross_sections_flow(), xs_flow_json)
347
+
348
+
349
+ def test_cross_sections_energy_grade():
350
+ xs_energy_grade_json = TEST_JSON / "xs_energy_grade.json"
351
+ with RasPlanHdf(BAXTER_P01) as phdf:
352
+ assert _gdf_matches_json_alt(
353
+ phdf.cross_sections_energy_grade(), xs_energy_grade_json
354
+ )
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