rashdf 0.2.1__tar.gz → 0.2.2__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.
- {rashdf-0.2.1 → rashdf-0.2.2}/PKG-INFO +11 -4
- {rashdf-0.2.1 → rashdf-0.2.2}/README.md +5 -3
- {rashdf-0.2.1 → rashdf-0.2.2}/pyproject.toml +11 -8
- {rashdf-0.2.1 → rashdf-0.2.2}/src/cli.py +5 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf/__init__.py +2 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf/base.py +3 -1
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf/geom.py +58 -36
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf/plan.py +26 -13
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf/utils.py +15 -11
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf.egg-info/PKG-INFO +11 -4
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf.egg-info/requires.txt +6 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/tests/test_geom.py +19 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/LICENSE +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/setup.cfg +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf.egg-info/SOURCES.txt +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf.egg-info/dependency_links.txt +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf.egg-info/entry_points.txt +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/src/rashdf.egg-info/top_level.txt +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/tests/test_cli.py +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/tests/test_plan.py +0 -0
- {rashdf-0.2.1 → rashdf-0.2.2}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rashdf
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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
|
|
@@ -20,16 +20,26 @@ Provides-Extra: dev
|
|
|
20
20
|
Requires-Dist: pre-commit; extra == "dev"
|
|
21
21
|
Requires-Dist: ruff; extra == "dev"
|
|
22
22
|
Requires-Dist: pytest; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
+
Provides-Extra: docs
|
|
25
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
26
|
+
Requires-Dist: numpydoc; extra == "docs"
|
|
27
|
+
Requires-Dist: sphinx_rtd_theme; extra == "docs"
|
|
23
28
|
|
|
24
29
|
# rashdf
|
|
25
30
|
[](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml)
|
|
26
31
|
[](https://github.com/fema-ffrd/rashdf/actions/workflows/release.yml)
|
|
27
32
|
[](https://badge.fury.io/py/rashdf)
|
|
33
|
+
[](https://codecov.io/gh/fema-ffrd/rashdf)
|
|
34
|
+
[](https://rashdf.readthedocs.io/en/latest/?badge=latest)
|
|
28
35
|
|
|
29
36
|
Read data from [HEC-RAS](https://www.hec.usace.army.mil/software/hec-ras/) [HDF](https://github.com/HDFGroup/hdf5) files.
|
|
30
37
|
|
|
31
38
|
*Pronunciation: `raz·aitch·dee·eff`*
|
|
32
39
|
|
|
40
|
+
## Documentation
|
|
41
|
+
[rashdf on ReadTheDocs](http://rashdf.readthedocs.io/)
|
|
42
|
+
|
|
33
43
|
## Install
|
|
34
44
|
```bash
|
|
35
45
|
$ pip install rashdf
|
|
@@ -120,9 +130,6 @@ Example: write structures GeoJSON to `stdout`:
|
|
|
120
130
|
$ rashdf structures Potomac.p01.hdf
|
|
121
131
|
```
|
|
122
132
|
|
|
123
|
-
## Documentation
|
|
124
|
-
Coming soon.
|
|
125
|
-
|
|
126
133
|
## Developer Setup
|
|
127
134
|
Create a virtual environment in the project directory:
|
|
128
135
|
```
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
[](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml)
|
|
3
3
|
[](https://github.com/fema-ffrd/rashdf/actions/workflows/release.yml)
|
|
4
4
|
[](https://badge.fury.io/py/rashdf)
|
|
5
|
+
[](https://codecov.io/gh/fema-ffrd/rashdf)
|
|
6
|
+
[](https://rashdf.readthedocs.io/en/latest/?badge=latest)
|
|
5
7
|
|
|
6
8
|
Read data from [HEC-RAS](https://www.hec.usace.army.mil/software/hec-ras/) [HDF](https://github.com/HDFGroup/hdf5) files.
|
|
7
9
|
|
|
8
10
|
*Pronunciation: `raz·aitch·dee·eff`*
|
|
9
11
|
|
|
12
|
+
## Documentation
|
|
13
|
+
[rashdf on ReadTheDocs](http://rashdf.readthedocs.io/)
|
|
14
|
+
|
|
10
15
|
## Install
|
|
11
16
|
```bash
|
|
12
17
|
$ pip install rashdf
|
|
@@ -97,9 +102,6 @@ Example: write structures GeoJSON to `stdout`:
|
|
|
97
102
|
$ rashdf structures Potomac.p01.hdf
|
|
98
103
|
```
|
|
99
104
|
|
|
100
|
-
## Documentation
|
|
101
|
-
Coming soon.
|
|
102
|
-
|
|
103
105
|
## Developer Setup
|
|
104
106
|
Create a virtual environment in the project directory:
|
|
105
107
|
```
|
|
@@ -12,11 +12,12 @@ classifiers = [
|
|
|
12
12
|
"Programming Language :: Python :: 3.11",
|
|
13
13
|
"Programming Language :: Python :: 3.12",
|
|
14
14
|
]
|
|
15
|
-
version = "0.2.
|
|
15
|
+
version = "0.2.2"
|
|
16
16
|
dependencies = ["h5py", "geopandas", "pyarrow"]
|
|
17
17
|
|
|
18
18
|
[project.optional-dependencies]
|
|
19
|
-
dev = ["pre-commit", "ruff", "pytest"]
|
|
19
|
+
dev = ["pre-commit", "ruff", "pytest", "pytest-cov"]
|
|
20
|
+
docs = ["sphinx", "numpydoc", "sphinx_rtd_theme"]
|
|
20
21
|
|
|
21
22
|
[project.urls]
|
|
22
23
|
repository = "https://github.com/fema-ffrd/rashdf"
|
|
@@ -28,10 +29,12 @@ rashdf = "cli:main"
|
|
|
28
29
|
pythonpath = "src"
|
|
29
30
|
testpaths = "tests"
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# [tool.ruff.lint]
|
|
34
|
-
# select = ["D"]
|
|
32
|
+
[tool.ruff.lint]
|
|
33
|
+
select = ["D"]
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
[tool.ruff.lint.pydocstyle]
|
|
36
|
+
convention = "numpy"
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint.per-file-ignores]
|
|
39
|
+
"tests/**" = ["D"]
|
|
40
|
+
"docs/**" = ["D"]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""rashdf CLI."""
|
|
2
|
+
|
|
1
3
|
from rashdf import RasGeomHdf
|
|
2
4
|
from rashdf.utils import df_datetimes_to_str
|
|
3
5
|
|
|
@@ -60,6 +62,7 @@ def fiona_supported_drivers() -> List[str]:
|
|
|
60
62
|
|
|
61
63
|
|
|
62
64
|
def parse_args(args: str) -> argparse.Namespace:
|
|
65
|
+
"""Parse command-line arguments."""
|
|
63
66
|
parser = argparse.ArgumentParser(description="Extract data from HEC-RAS HDF files.")
|
|
64
67
|
parser.add_argument(
|
|
65
68
|
"--fiona-drivers",
|
|
@@ -100,6 +103,7 @@ def parse_args(args: str) -> argparse.Namespace:
|
|
|
100
103
|
|
|
101
104
|
|
|
102
105
|
def export(args: argparse.Namespace) -> Optional[str]:
|
|
106
|
+
"""Act on parsed arguments to extract data from HEC-RAS HDF files."""
|
|
103
107
|
if args.fiona_drivers:
|
|
104
108
|
for driver in fiona_supported_drivers():
|
|
105
109
|
print(driver)
|
|
@@ -147,6 +151,7 @@ def export(args: argparse.Namespace) -> Optional[str]:
|
|
|
147
151
|
|
|
148
152
|
|
|
149
153
|
def main():
|
|
154
|
+
"""Entry point for the rashdf CLI."""
|
|
150
155
|
args = parse_args(sys.argv[1:])
|
|
151
156
|
export(args)
|
|
152
157
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Base class for reading HEC-RAS HDF files."""
|
|
2
|
+
|
|
1
3
|
import h5py
|
|
2
4
|
from .utils import hdf5_attrs_to_dict
|
|
3
5
|
from typing import Dict
|
|
@@ -68,7 +70,7 @@ class RasHdf(h5py.File):
|
|
|
68
70
|
return {}
|
|
69
71
|
|
|
70
72
|
def get_root_attrs(self):
|
|
71
|
-
"""
|
|
73
|
+
"""Return attributes at root level of HEC-RAS HDF file.
|
|
72
74
|
|
|
73
75
|
Returns
|
|
74
76
|
-------
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""HEC-RAS Geometry HDF class."""
|
|
2
|
+
|
|
1
3
|
from .base import RasHdf
|
|
2
4
|
from .utils import (
|
|
3
5
|
convert_ras_hdf_string,
|
|
@@ -16,27 +18,37 @@ from shapely import (
|
|
|
16
18
|
LineString,
|
|
17
19
|
MultiLineString,
|
|
18
20
|
MultiPolygon,
|
|
19
|
-
|
|
21
|
+
polygonize_full,
|
|
20
22
|
)
|
|
21
23
|
|
|
22
|
-
from typing import List, Optional
|
|
24
|
+
from typing import Dict, List, Optional
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
class RasGeomHdf(RasHdf):
|
|
28
|
+
"""HEC-RAS Geometry HDF class."""
|
|
29
|
+
|
|
26
30
|
GEOM_PATH = "Geometry"
|
|
27
31
|
GEOM_STRUCTURES_PATH = f"{GEOM_PATH}/Structures"
|
|
28
32
|
FLOW_AREA_2D_PATH = f"{GEOM_PATH}/2D Flow Areas"
|
|
29
33
|
|
|
30
34
|
def __init__(self, name: str, **kwargs):
|
|
35
|
+
"""Open a HEC-RAS Geometry HDF file.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
name : str
|
|
40
|
+
The path to the RAS Geometry HDF file.
|
|
41
|
+
kwargs : dict
|
|
42
|
+
Additional keyword arguments to pass to h5py.File
|
|
43
|
+
"""
|
|
31
44
|
super().__init__(name, **kwargs)
|
|
32
45
|
|
|
33
46
|
def projection(self) -> Optional[CRS]:
|
|
34
|
-
"""Return the projection of the RAS geometry as a
|
|
35
|
-
pyproj.CRS object.
|
|
47
|
+
"""Return the projection of the RAS geometry as a pyproj.CRS object.
|
|
36
48
|
|
|
37
49
|
Returns
|
|
38
50
|
-------
|
|
39
|
-
CRS
|
|
51
|
+
pyproj.CRS or None
|
|
40
52
|
The projection of the RAS geometry.
|
|
41
53
|
"""
|
|
42
54
|
proj_wkt = self.attrs.get("Projection")
|
|
@@ -47,12 +59,11 @@ class RasGeomHdf(RasHdf):
|
|
|
47
59
|
return CRS.from_wkt(proj_wkt)
|
|
48
60
|
|
|
49
61
|
def mesh_area_names(self) -> List[str]:
|
|
50
|
-
"""Return a list of the 2D mesh area names of
|
|
51
|
-
the RAS geometry.
|
|
62
|
+
"""Return a list of the 2D mesh area names of the RAS geometry.
|
|
52
63
|
|
|
53
64
|
Returns
|
|
54
65
|
-------
|
|
55
|
-
|
|
66
|
+
List[str]
|
|
56
67
|
A list of the 2D mesh area names (str) within the RAS geometry if 2D areas exist.
|
|
57
68
|
"""
|
|
58
69
|
if "/Geometry/2D Flow Areas" not in self:
|
|
@@ -128,13 +139,19 @@ class RasGeomHdf(RasHdf):
|
|
|
128
139
|
cell_dict["cell_id"] += cell_ids
|
|
129
140
|
cell_dict["geometry"] += list(
|
|
130
141
|
np.vectorize(
|
|
131
|
-
lambda face_id_list:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
lambda face_id_list: (
|
|
143
|
+
lambda geom_col: Polygon((geom_col[0] or geom_col[3]).geoms[0])
|
|
144
|
+
)(
|
|
145
|
+
polygonize_full(
|
|
146
|
+
np.ravel(
|
|
147
|
+
mesh_faces[
|
|
148
|
+
np.array(face_id_list.strip("[]").split()).astype(
|
|
149
|
+
int
|
|
150
|
+
)
|
|
151
|
+
]
|
|
152
|
+
)
|
|
136
153
|
)
|
|
137
|
-
)
|
|
154
|
+
)
|
|
138
155
|
)(face_id_lists)
|
|
139
156
|
)
|
|
140
157
|
return GeoDataFrame(cell_dict, geometry="geometry", crs=self.projection())
|
|
@@ -206,8 +223,8 @@ class RasGeomHdf(RasHdf):
|
|
|
206
223
|
face_dict["geometry"].append(LineString(coordinates))
|
|
207
224
|
return GeoDataFrame(face_dict, geometry="geometry", crs=self.projection())
|
|
208
225
|
|
|
209
|
-
def get_geom_attrs(self):
|
|
210
|
-
"""
|
|
226
|
+
def get_geom_attrs(self) -> Dict:
|
|
227
|
+
"""Return base geometry attributes from a HEC-RAS HDF file.
|
|
211
228
|
|
|
212
229
|
Returns
|
|
213
230
|
-------
|
|
@@ -216,8 +233,8 @@ class RasGeomHdf(RasHdf):
|
|
|
216
233
|
"""
|
|
217
234
|
return self.get_attrs(self.GEOM_PATH)
|
|
218
235
|
|
|
219
|
-
def get_geom_structures_attrs(self):
|
|
220
|
-
"""
|
|
236
|
+
def get_geom_structures_attrs(self) -> Dict:
|
|
237
|
+
"""Return geometry structures attributes from a HEC-RAS HDF file.
|
|
221
238
|
|
|
222
239
|
Returns
|
|
223
240
|
-------
|
|
@@ -226,8 +243,8 @@ class RasGeomHdf(RasHdf):
|
|
|
226
243
|
"""
|
|
227
244
|
return self.get_attrs(self.GEOM_STRUCTURES_PATH)
|
|
228
245
|
|
|
229
|
-
def get_geom_2d_flow_area_attrs(self):
|
|
230
|
-
"""
|
|
246
|
+
def get_geom_2d_flow_area_attrs(self) -> Dict:
|
|
247
|
+
"""Return geometry 2d flow area attributes from a HEC-RAS HDF file.
|
|
231
248
|
|
|
232
249
|
Returns
|
|
233
250
|
-------
|
|
@@ -373,6 +390,11 @@ class RasGeomHdf(RasHdf):
|
|
|
373
390
|
def structures(self, datetime_to_str: bool = False) -> GeoDataFrame:
|
|
374
391
|
"""Return the model structures.
|
|
375
392
|
|
|
393
|
+
Parameters
|
|
394
|
+
----------
|
|
395
|
+
datetime_to_str : bool, optional
|
|
396
|
+
If True, convert datetime values to string format (default: False).
|
|
397
|
+
|
|
376
398
|
Returns
|
|
377
399
|
-------
|
|
378
400
|
GeoDataFrame
|
|
@@ -419,50 +441,50 @@ class RasGeomHdf(RasHdf):
|
|
|
419
441
|
)
|
|
420
442
|
return struct_gdf
|
|
421
443
|
|
|
422
|
-
def connections(self) -> GeoDataFrame:
|
|
444
|
+
def connections(self) -> GeoDataFrame: # noqa D102
|
|
423
445
|
raise NotImplementedError
|
|
424
446
|
|
|
425
|
-
def ic_points(self) -> GeoDataFrame:
|
|
447
|
+
def ic_points(self) -> GeoDataFrame: # noqa D102
|
|
426
448
|
raise NotImplementedError
|
|
427
449
|
|
|
428
|
-
def reference_lines(self) -> GeoDataFrame:
|
|
450
|
+
def reference_lines(self) -> GeoDataFrame: # noqa D102
|
|
429
451
|
raise NotImplementedError
|
|
430
452
|
|
|
431
|
-
def reference_points(self) -> GeoDataFrame:
|
|
453
|
+
def reference_points(self) -> GeoDataFrame: # noqa D102
|
|
432
454
|
raise NotImplementedError
|
|
433
455
|
|
|
434
|
-
def pump_stations(self) -> GeoDataFrame:
|
|
456
|
+
def pump_stations(self) -> GeoDataFrame: # noqa D102
|
|
435
457
|
raise NotImplementedError
|
|
436
458
|
|
|
437
|
-
def mannings_calibration_regions(self) -> GeoDataFrame:
|
|
459
|
+
def mannings_calibration_regions(self) -> GeoDataFrame: # noqa D102
|
|
438
460
|
raise NotImplementedError
|
|
439
461
|
|
|
440
|
-
def classification_polygons(self) -> GeoDataFrame:
|
|
462
|
+
def classification_polygons(self) -> GeoDataFrame: # noqa D102
|
|
441
463
|
raise NotImplementedError
|
|
442
464
|
|
|
443
|
-
def terrain_modifications(self) -> GeoDataFrame:
|
|
465
|
+
def terrain_modifications(self) -> GeoDataFrame: # noqa D102
|
|
444
466
|
raise NotImplementedError
|
|
445
467
|
|
|
446
|
-
def cross_sections(self) -> GeoDataFrame:
|
|
468
|
+
def cross_sections(self) -> GeoDataFrame: # noqa D102
|
|
447
469
|
raise NotImplementedError
|
|
448
470
|
|
|
449
|
-
def river_reaches(self) -> GeoDataFrame:
|
|
471
|
+
def river_reaches(self) -> GeoDataFrame: # noqa D102
|
|
450
472
|
raise NotImplementedError
|
|
451
473
|
|
|
452
|
-
def flowpaths(self) -> GeoDataFrame:
|
|
474
|
+
def flowpaths(self) -> GeoDataFrame: # noqa D102
|
|
453
475
|
raise NotImplementedError
|
|
454
476
|
|
|
455
|
-
def bank_points(self) -> GeoDataFrame:
|
|
477
|
+
def bank_points(self) -> GeoDataFrame: # noqa D102
|
|
456
478
|
raise NotImplementedError
|
|
457
479
|
|
|
458
|
-
def bank_lines(self) -> GeoDataFrame:
|
|
480
|
+
def bank_lines(self) -> GeoDataFrame: # noqa D102
|
|
459
481
|
raise NotImplementedError
|
|
460
482
|
|
|
461
|
-
def ineffective_areas(self) -> GeoDataFrame:
|
|
483
|
+
def ineffective_areas(self) -> GeoDataFrame: # noqa D102
|
|
462
484
|
raise NotImplementedError
|
|
463
485
|
|
|
464
|
-
def ineffective_points(self) -> GeoDataFrame:
|
|
486
|
+
def ineffective_points(self) -> GeoDataFrame: # noqa D102
|
|
465
487
|
raise NotImplementedError
|
|
466
488
|
|
|
467
|
-
def blocked_obstructions(self) -> GeoDataFrame:
|
|
489
|
+
def blocked_obstructions(self) -> GeoDataFrame: # noqa D102
|
|
468
490
|
raise NotImplementedError
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
"""HEC-RAS Plan HDF class."""
|
|
2
|
+
|
|
1
3
|
from .geom import RasGeomHdf
|
|
2
4
|
from typing import Dict
|
|
3
5
|
from geopandas import GeoDataFrame
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class RasPlanHdf(RasGeomHdf):
|
|
9
|
+
"""HEC-RAS Plan HDF class."""
|
|
10
|
+
|
|
7
11
|
PLAN_INFO_PATH = "Plan Data/Plan Information"
|
|
8
12
|
PLAN_PARAMS_PATH = "Plan Data/Plan Parameters"
|
|
9
13
|
PRECIP_PATH = "Event Conditions/Meteorology/Precipitation"
|
|
@@ -12,67 +16,76 @@ class RasPlanHdf(RasGeomHdf):
|
|
|
12
16
|
VOLUME_ACCOUNTING_PATH = f"{RESULTS_UNSTEADY_PATH}/Volume Accounting"
|
|
13
17
|
|
|
14
18
|
def __init__(self, name: str, **kwargs):
|
|
19
|
+
"""Open a HEC-RAS Plan HDF file.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
name : str
|
|
24
|
+
The path to the RAS Plan HDF file.
|
|
25
|
+
kwargs : dict
|
|
26
|
+
Additional keyword arguments to pass to h5py.File
|
|
27
|
+
"""
|
|
15
28
|
super().__init__(name, **kwargs)
|
|
16
29
|
|
|
17
30
|
def get_plan_info_attrs(self) -> Dict:
|
|
18
|
-
"""
|
|
31
|
+
"""Return plan information attributes from a HEC-RAS HDF plan file.
|
|
19
32
|
|
|
20
33
|
Returns
|
|
21
34
|
-------
|
|
22
35
|
dict
|
|
23
|
-
Dictionary
|
|
36
|
+
Dictionary of plan information attributes.
|
|
24
37
|
"""
|
|
25
38
|
return self.get_attrs(self.PLAN_INFO_PATH)
|
|
26
39
|
|
|
27
40
|
def get_plan_param_attrs(self) -> Dict:
|
|
28
|
-
"""
|
|
41
|
+
"""Return plan parameter attributes from a HEC-RAS HDF plan file.
|
|
29
42
|
|
|
30
43
|
Returns
|
|
31
44
|
-------
|
|
32
45
|
dict
|
|
33
|
-
Dictionary
|
|
46
|
+
Dictionary of plan parameter attributes.
|
|
34
47
|
"""
|
|
35
48
|
return self.get_attrs(self.PLAN_PARAMS_PATH)
|
|
36
49
|
|
|
37
50
|
def get_meteorology_precip_attrs(self) -> Dict:
|
|
38
|
-
"""
|
|
51
|
+
"""Return precipitation attributes from a HEC-RAS HDF plan file.
|
|
39
52
|
|
|
40
53
|
Returns
|
|
41
54
|
-------
|
|
42
55
|
dict
|
|
43
|
-
Dictionary
|
|
56
|
+
Dictionary of precipitation attributes.
|
|
44
57
|
"""
|
|
45
58
|
return self.get_attrs(self.PRECIP_PATH)
|
|
46
59
|
|
|
47
60
|
def get_results_unsteady_attrs(self) -> Dict:
|
|
48
|
-
"""
|
|
61
|
+
"""Return unsteady attributes from a HEC-RAS HDF plan file.
|
|
49
62
|
|
|
50
63
|
Returns
|
|
51
64
|
-------
|
|
52
65
|
dict
|
|
53
|
-
Dictionary
|
|
66
|
+
Dictionary of unsteady attributes.
|
|
54
67
|
"""
|
|
55
68
|
return self.get_attrs(self.RESULTS_UNSTEADY_PATH)
|
|
56
69
|
|
|
57
70
|
def get_results_unsteady_summary_attrs(self) -> Dict:
|
|
58
|
-
"""
|
|
71
|
+
"""Return results unsteady summary attributes from a HEC-RAS HDF plan file.
|
|
59
72
|
|
|
60
73
|
Returns
|
|
61
74
|
-------
|
|
62
75
|
dict
|
|
63
|
-
Dictionary
|
|
76
|
+
Dictionary of results summary attributes.
|
|
64
77
|
"""
|
|
65
78
|
return self.get_attrs(self.RESULTS_UNSTEADY_SUMMARY_PATH)
|
|
66
79
|
|
|
67
80
|
def get_results_volume_accounting_attrs(self) -> Dict:
|
|
68
|
-
"""
|
|
81
|
+
"""Return volume accounting attributes from a HEC-RAS HDF plan file.
|
|
69
82
|
|
|
70
83
|
Returns
|
|
71
84
|
-------
|
|
72
85
|
dict
|
|
73
|
-
Dictionary
|
|
86
|
+
Dictionary of volume accounting attributes.
|
|
74
87
|
"""
|
|
75
88
|
return self.get_attrs(self.VOLUME_ACCOUNTING_PATH)
|
|
76
89
|
|
|
77
|
-
def enroachment_points(self) -> GeoDataFrame:
|
|
90
|
+
def enroachment_points(self) -> GeoDataFrame: # noqa: D102
|
|
78
91
|
raise NotImplementedError
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Utility functions for reading HEC-RAS HDF data."""
|
|
2
|
+
|
|
1
3
|
import h5py
|
|
2
4
|
import numpy as np
|
|
3
5
|
import pandas as pd
|
|
@@ -5,12 +7,13 @@ import pandas as pd
|
|
|
5
7
|
from datetime import datetime, timedelta
|
|
6
8
|
import re
|
|
7
9
|
from typing import Any, List, Tuple, Union, Optional
|
|
10
|
+
from shapely import LineString, Polygon, polygonize_full
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
def parse_ras_datetime(datetime_str: str) -> datetime:
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
a time of 2400, then it is converted to midnight of the next day.
|
|
14
|
+
"""Parse a datetime string from a RAS file into a datetime object.
|
|
15
|
+
|
|
16
|
+
If the datetime has a time of 2400, then it is converted to midnight of the next day.
|
|
14
17
|
|
|
15
18
|
Parameters
|
|
16
19
|
----------
|
|
@@ -34,8 +37,9 @@ def parse_ras_datetime(datetime_str: str) -> datetime:
|
|
|
34
37
|
|
|
35
38
|
def parse_ras_simulation_window_datetime(datetime_str) -> datetime:
|
|
36
39
|
"""
|
|
37
|
-
Parse a datetime string from a RAS simulation window into a datetime object.
|
|
38
|
-
|
|
40
|
+
Parse a datetime string from a RAS simulation window into a datetime object.
|
|
41
|
+
|
|
42
|
+
If the datetime has a time of 2400, then it is converted to midnight of the next day.
|
|
39
43
|
|
|
40
44
|
Parameters
|
|
41
45
|
----------
|
|
@@ -202,13 +206,13 @@ def hdf5_attrs_to_dict(attrs: dict, prefix: str = None) -> dict:
|
|
|
202
206
|
"""
|
|
203
207
|
Convert a dictionary of attributes from an HDF5 file into a Python dictionary.
|
|
204
208
|
|
|
205
|
-
Parameters
|
|
209
|
+
Parameters
|
|
206
210
|
----------
|
|
207
211
|
attrs (dict): The attributes to be converted.
|
|
208
212
|
prefix (str, optional): An optional prefix to prepend to the keys.
|
|
209
213
|
|
|
210
|
-
Returns
|
|
211
|
-
|
|
214
|
+
Returns
|
|
215
|
+
-------
|
|
212
216
|
dict: A dictionary with the converted attributes.
|
|
213
217
|
"""
|
|
214
218
|
results = {}
|
|
@@ -229,12 +233,12 @@ def get_first_hdf_group(parent_group: h5py.Group) -> Optional[h5py.Group]:
|
|
|
229
233
|
This function iterates over the items in the parent group and returns the first item that is an instance of
|
|
230
234
|
h5py.Group. If no such item is found, it returns None.
|
|
231
235
|
|
|
232
|
-
Parameters
|
|
236
|
+
Parameters
|
|
233
237
|
----------
|
|
234
238
|
parent_group (h5py.Group): The parent group to search in.
|
|
235
239
|
|
|
236
|
-
Returns
|
|
237
|
-
|
|
240
|
+
Returns
|
|
241
|
+
-------
|
|
238
242
|
Optional[h5py.Group]: The first HDF5 group in the parent group, or None if no group is found.
|
|
239
243
|
"""
|
|
240
244
|
for _, item in parent_group.items():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rashdf
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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
|
|
@@ -20,16 +20,26 @@ Provides-Extra: dev
|
|
|
20
20
|
Requires-Dist: pre-commit; extra == "dev"
|
|
21
21
|
Requires-Dist: ruff; extra == "dev"
|
|
22
22
|
Requires-Dist: pytest; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
24
|
+
Provides-Extra: docs
|
|
25
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
26
|
+
Requires-Dist: numpydoc; extra == "docs"
|
|
27
|
+
Requires-Dist: sphinx_rtd_theme; extra == "docs"
|
|
23
28
|
|
|
24
29
|
# rashdf
|
|
25
30
|
[](https://github.com/fema-ffrd/rashdf/actions/workflows/continuous-integration.yml)
|
|
26
31
|
[](https://github.com/fema-ffrd/rashdf/actions/workflows/release.yml)
|
|
27
32
|
[](https://badge.fury.io/py/rashdf)
|
|
33
|
+
[](https://codecov.io/gh/fema-ffrd/rashdf)
|
|
34
|
+
[](https://rashdf.readthedocs.io/en/latest/?badge=latest)
|
|
28
35
|
|
|
29
36
|
Read data from [HEC-RAS](https://www.hec.usace.army.mil/software/hec-ras/) [HDF](https://github.com/HDFGroup/hdf5) files.
|
|
30
37
|
|
|
31
38
|
*Pronunciation: `raz·aitch·dee·eff`*
|
|
32
39
|
|
|
40
|
+
## Documentation
|
|
41
|
+
[rashdf on ReadTheDocs](http://rashdf.readthedocs.io/)
|
|
42
|
+
|
|
33
43
|
## Install
|
|
34
44
|
```bash
|
|
35
45
|
$ pip install rashdf
|
|
@@ -120,9 +130,6 @@ Example: write structures GeoJSON to `stdout`:
|
|
|
120
130
|
$ rashdf structures Potomac.p01.hdf
|
|
121
131
|
```
|
|
122
132
|
|
|
123
|
-
## Documentation
|
|
124
|
-
Coming soon.
|
|
125
|
-
|
|
126
133
|
## Developer Setup
|
|
127
134
|
Create a virtual environment in the project directory:
|
|
128
135
|
```
|
|
@@ -9,6 +9,7 @@ from . import _create_hdf_with_group_attrs
|
|
|
9
9
|
|
|
10
10
|
TEST_DATA = Path("./tests/data")
|
|
11
11
|
MUNCIE_G05 = TEST_DATA / "ras/Muncie.g05.hdf"
|
|
12
|
+
COAL_G01 = TEST_DATA / "ras/Coal.g01.hdf"
|
|
12
13
|
TEST_JSON = TEST_DATA / "json"
|
|
13
14
|
|
|
14
15
|
TEST_ATTRS = {"test_attribute1": "test_str1", "test_attribute2": 500}
|
|
@@ -59,6 +60,24 @@ def test_mesh_cell_polygons():
|
|
|
59
60
|
assert _gdf_matches_json(ghdf.mesh_cell_polygons(), mesh_cell_polygons_json)
|
|
60
61
|
|
|
61
62
|
|
|
63
|
+
def test_mesh_cell_polygons_coal():
|
|
64
|
+
"""Test with the mesh from the Coal River model.
|
|
65
|
+
|
|
66
|
+
The Jan 2024 Coal River model from the Kanawha FFRD pilot project
|
|
67
|
+
contains some topologically incorrect polygons in the 2D mesh;
|
|
68
|
+
some of the mesh cell faces overlap.
|
|
69
|
+
|
|
70
|
+
See: https://github.com/fema-ffrd/rashdf/issues/31
|
|
71
|
+
"""
|
|
72
|
+
coal_bad_polygons_json = TEST_JSON / "coal-bad-mesh-cell-polygons.json"
|
|
73
|
+
with RasGeomHdf(COAL_G01) as geom_hdf:
|
|
74
|
+
gdf = geom_hdf.mesh_cell_polygons()
|
|
75
|
+
gdf_bad_polygons = gdf[gdf["cell_id"].isin([8561, 11791, 17529])].to_crs(
|
|
76
|
+
"EPSG:4326"
|
|
77
|
+
) # reproject because the Kanawha FFRD pilot project uses a custom CRS
|
|
78
|
+
assert _gdf_matches_json(gdf_bad_polygons, coal_bad_polygons_json)
|
|
79
|
+
|
|
80
|
+
|
|
62
81
|
def test_bc_lines():
|
|
63
82
|
bc_lines_json = TEST_JSON / "bc_lines.json"
|
|
64
83
|
with RasGeomHdf(MUNCIE_G05) as ghdf:
|
|
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
|