Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/fema-ffrd/rashdf into featu…
Browse files Browse the repository at this point in the history
…re/stac-funcs
  • Loading branch information
Stevenray Janke committed May 1, 2024
2 parents b893185 + 909301a commit da5a6ec
Show file tree
Hide file tree
Showing 16 changed files with 210 additions and 114 deletions.
4 changes: 0 additions & 4 deletions .devcontainer/Dockerfile

This file was deleted.

10 changes: 0 additions & 10 deletions .devcontainer/README.md

This file was deleted.

47 changes: 0 additions & 47 deletions .devcontainer/devcontainer.json

This file was deleted.

11 changes: 0 additions & 11 deletions .devcontainer/env.yaml

This file was deleted.

5 changes: 5 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ jobs:
python -m pip install --upgrade pip
pip install ".[dev]"
- name: Lint (ruff)
run: |
ruff check
ruff format --check
- name: Test with pytest
run: |
pytest
9 changes: 9 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.2
hooks:
# Run the linter.
- id: ruff
# Run the formatter.
- id: ruff-format
12 changes: 3 additions & 9 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@
"python.testing.pytestArgs": [
"."
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.formatting.provider": "none",
"editor.formatOnSave": true,
"python.formatting.blackArgs": [
"--line-length=120"
],
"python.languageServer": "Pylance",
"python.linting.lintOnSave": true,
"python.testing.unittestEnabled": false,
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
}
}
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
# rashdf
Read data from HEC-RAS HDF files.
[![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)
[![Release](https://github.com/fema-ffrd/rashdf/actions/workflows/release.yml/badge.svg)](https://github.com/fema-ffrd/rashdf/actions/workflows/release.yml)
[![PyPI version](https://badge.fury.io/py/rashdf.svg)](https://badge.fury.io/py/rashdf)

## Setup
Read data from [HEC-RAS](https://www.hec.usace.army.mil/software/hec-ras/) [HDF](https://github.com/HDFGroup/hdf5) files.

*Pronunciation: `raz·aitch·dee·eff`*

## Install
A prerelease version of `rashdf` is available from PyPI:
```bash
$ pip install rashdf=0.1.0b1
```

## Developer Setup
Create a virtual environment in the project directory:
```
$ python -m venv venv-rashdf
Expand All @@ -13,6 +25,16 @@ $ source ./venv/bin/activate
(venv-rashdf) $
```

Install dev dependencies:
```
(venv-rashdf) $ pip install ".[dev]"
```

Install git hook scripts (used for automatic liniting/formatting)
```
(venv-rashdf) $ pre-commit install
```

With the virtual environment activated, run the tests:
```
(venv-rashdf) $ pytest
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ version = "0.1.0-beta.1"
dependencies = ["h5py", "geopandas"]

[project.optional-dependencies]
dev = ["pytest"]
dev = ["pre-commit", "ruff", "pytest"]

[project.urls]
repository = "https://github.com/fema-ffrd/rashdf"
Expand Down
2 changes: 2 additions & 0 deletions src/rashdf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from .base import RasHdf
from .geom import RasGeomHdf
from .plan import RasPlanHdf

__all__ = ["RasHdf", "RasGeomHdf", "RasPlanHdf"]
128 changes: 119 additions & 9 deletions src/rashdf/geom.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
from .utils import convert_ras_hdf_string, get_first_hdf_group, hdf5_attrs_to_dict

import numpy as np
import pandas as pd
from geopandas import GeoDataFrame
from pyproj import CRS
from shapely import Polygon, Point, LineString, polygonize
from shapely import (
Polygon,
Point,
LineString,
MultiLineString,
MultiPolygon,
polygonize,
)

from typing import Optional
from typing import List, Optional


class RasGeomHdf(RasHdf):
Expand All @@ -30,11 +36,11 @@ def projection(self) -> Optional[CRS]:
proj_wkt = self.attrs.get("Projection")
if proj_wkt is None:
return None
if type(proj_wkt) == bytes or type(proj_wkt) == np.bytes_:
if isinstance(proj_wkt, bytes) or isinstance(proj_wkt, np.bytes_):
proj_wkt = proj_wkt.decode("utf-8")
return CRS.from_wkt(proj_wkt)

def mesh_area_names(self) -> list:
def mesh_area_names(self) -> List[str]:
"""Return a list of the 2D mesh area names of
the RAS geometry.
Expand All @@ -60,7 +66,9 @@ def mesh_areas(self) -> GeoDataFrame:
return GeoDataFrame()
mesh_area_polygons = [Polygon(self[f"/Geometry/2D Flow Areas/{n}/Perimeter"][()]) for n in mesh_area_names]
return GeoDataFrame(
{"mesh_name": mesh_area_names, "geometry": mesh_area_polygons}, geometry="geometry", crs=self.projection()
{"mesh_name": mesh_area_names, "geometry": mesh_area_polygons},
geometry="geometry",
crs=self.projection(),
)

def mesh_cell_polygons(self) -> GeoDataFrame:
Expand Down Expand Up @@ -197,13 +205,115 @@ def get_geom_2d_flow_area_attrs(self):
return d2_flow_area_attrs

def bc_lines(self) -> GeoDataFrame:
raise NotImplementedError
"""Return the 2D mesh area boundary condition lines.
Returns
-------
GeoDataFrame
A GeoDataFrame containing the 2D mesh area boundary condition lines if they exist.
"""
if "/Geometry/Boundary Condition Lines" not in self:
return GeoDataFrame()
bc_line_data = self["/Geometry/Boundary Condition Lines"]
bc_line_ids = range(bc_line_data["Attributes"][()].shape[0])
v_conv_str = np.vectorize(convert_ras_hdf_string)
names = v_conv_str(bc_line_data["Attributes"][()]["Name"])
mesh_names = v_conv_str(bc_line_data["Attributes"][()]["SA-2D"])
types = v_conv_str(bc_line_data["Attributes"][()]["Type"])
geoms = list()
for pnt_start, pnt_cnt, part_start, part_cnt in bc_line_data["Polyline Info"][()]:
points = bc_line_data["Polyline Points"][()][pnt_start : pnt_start + pnt_cnt]
if part_cnt == 1:
geoms.append(LineString(points))
else:
parts = bc_line_data["Polyline Parts"][()][part_start : part_start + part_cnt]
geoms.append(
MultiLineString(
list(
points[part_pnt_start : part_pnt_start + part_pnt_cnt]
for part_pnt_start, part_pnt_cnt in parts
)
)
)
return GeoDataFrame(
{
"bc_line_id": bc_line_ids,
"name": names,
"mesh_name": mesh_names,
"type": types,
"geometry": geoms,
},
geometry="geometry",
crs=self.projection(),
)

def breaklines(self) -> GeoDataFrame:
raise NotImplementedError
"""Return the 2D mesh area breaklines.
Returns
-------
GeoDataFrame
A GeoDataFrame containing the 2D mesh area breaklines if they exist.
"""
if "/Geometry/2D Flow Area Break Lines" not in self:
return GeoDataFrame()
bl_line_data = self["/Geometry/2D Flow Area Break Lines"]
bl_line_ids = range(bl_line_data["Attributes"][()].shape[0])
names = np.vectorize(convert_ras_hdf_string)(bl_line_data["Attributes"][()]["Name"])
geoms = list()
for pnt_start, pnt_cnt, part_start, part_cnt in bl_line_data["Polyline Info"][()]:
points = bl_line_data["Polyline Points"][()][pnt_start : pnt_start + pnt_cnt]
if part_cnt == 1:
geoms.append(LineString(points))
else:
parts = bl_line_data["Polyline Parts"][()][part_start : part_start + part_cnt]
geoms.append(
MultiLineString(
list(
points[part_pnt_start : part_pnt_start + part_pnt_cnt]
for part_pnt_start, part_pnt_cnt in parts
)
)
)
return GeoDataFrame(
{"bl_id": bl_line_ids, "name": names, "geometry": geoms},
geometry="geometry",
crs=self.projection(),
)

def refinement_regions(self) -> GeoDataFrame:
raise NotImplementedError
"""Return the 2D mesh area refinement regions.
Returns
-------
GeoDataFrame
A GeoDataFrame containing the 2D mesh area refinement regions if they exist.
"""
if "/Geometry/2D Flow Area Refinement Regions" not in self:
return GeoDataFrame()
rr_data = self["/Geometry/2D Flow Area Refinement Regions"]
rr_ids = range(rr_data["Attributes"][()].shape[0])
names = np.vectorize(convert_ras_hdf_string)(rr_data["Attributes"][()]["Name"])
geoms = list()
for pnt_start, pnt_cnt, part_start, part_cnt in rr_data["Polygon Info"][()]:
points = rr_data["Polygon Points"][()][pnt_start : pnt_start + pnt_cnt]
if part_cnt == 1:
geoms.append(Polygon(points))
else:
parts = rr_data["Polygon Parts"][()][part_start : part_start + part_cnt]
geoms.append(
MultiPolygon(
list(
points[part_pnt_start : part_pnt_start + part_pnt_cnt]
for part_pnt_start, part_pnt_cnt in parts
)
)
)
return GeoDataFrame(
{"rr_id": rr_ids, "name": names, "geometry": geoms},
geometry="geometry",
crs=self.projection(),
)

def connections(self) -> GeoDataFrame:
raise NotImplementedError
Expand Down
1 change: 1 addition & 0 deletions tests/data/json/bc_lines.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "properties": {"bc_line_id": 0, "name": "2d_out", "mesh_name": "2D Interior Area", "type": "External"}, "geometry": {"type": "LineString", "coordinates": [[406023.42, 1801556.29], [406029.95, 1801947.71]]}}, {"id": "1", "type": "Feature", "properties": {"bc_line_id": 1, "name": "NW_out", "mesh_name": "Perimeter_NW", "type": "External"}, "geometry": {"type": "LineString", "coordinates": [[403925.27, 1802019.54], [403620.03, 1802568.0]]}}], "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::2965"}}}
1 change: 1 addition & 0 deletions tests/data/json/breaklines.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "properties": {"bl_id": 0, "name": "Road 1"}, "geometry": {"type": "LineString", "coordinates": [[409074.78, 1802876.36], [409026.14, 1802817.66], [408942.28, 1802769.02], [408870.17, 1802745.54], [408828.24, 1802740.51], [408806.44, 1802720.39], [408774.57, 1802686.84], [408719.22, 1802626.47], [408695.74, 1802596.28], [408695.74, 1802564.41], [408727.61, 1802530.87], [408781.28, 1802463.78], [408819.85, 1802436.95], [408943.96, 1802418.5], [409019.43, 1802416.82], [409051.3, 1802396.7], [409026.14, 1802322.9], [409006.02, 1802249.11], [409019.43, 1802116.61], [409007.69, 1802026.05], [409002.66, 1801870.07]]}}, {"id": "1", "type": "Feature", "properties": {"bl_id": 1, "name": "HighGround 1"}, "geometry": {"type": "LineString", "coordinates": [[410305.8, 1801586.64], [410290.71, 1801675.53], [410240.39, 1801740.93], [410134.73, 1801789.57], [410015.65, 1801878.46], [409901.61, 1801963.99], [409871.42, 1802052.88], [409849.62, 1802158.54], [409837.88, 1802265.88], [409804.33, 1802336.32], [409737.25, 1802374.89], [409650.04, 1802391.67], [409594.69, 1802405.08], [409537.67, 1802405.08], [409484.0, 1802395.02], [409430.33, 1802401.73], [409374.99, 1802423.53], [409334.74, 1802426.89], [409271.0, 1802416.82], [409232.43, 1802406.76], [409123.42, 1802410.11], [409063.04, 1802410.11]]}}, {"id": "2", "type": "Feature", "properties": {"bl_id": 2, "name": "Breakline 1"}, "geometry": {"type": "LineString", "coordinates": [[410388.19, 1802731.41], [410547.77, 1802837.8], [410735.99, 1802907.36], [410891.48, 1802911.45], [411267.92, 1802874.62]]}}, {"id": "3", "type": "Feature", "properties": {"bl_id": 3, "name": "Breakline 2"}, "geometry": {"type": "LineString", "coordinates": [[402838.91, 1804637.9], [402791.97, 1804500.22], [402879.58, 1804431.38], [402820.13, 1804362.54], [402557.28, 1804346.89], [402375.79, 1804315.6], [402350.76, 1804231.11], [402375.79, 1804059.01], [402463.41, 1804002.69], [402641.77, 1803987.04], [402782.58, 1804005.82], [402798.23, 1803918.2]]}}], "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::2965"}}}
1 change: 1 addition & 0 deletions tests/data/json/refinement_regions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "FeatureCollection", "features": [{"id": "0", "type": "Feature", "properties": {"rr_id": 0, "name": "Region 1"}, "geometry": {"type": "Polygon", "coordinates": [[[403466.64123541984, 1804195.9021819197], [403449.7976758183, 1804409.253936872], [403607.00423209905, 1804515.9298143482], [403865.27214598877, 1804549.6169335512], [403955.1044638635, 1804392.4103772705], [403932.6463843948, 1804201.5167017868], [403792.2833877156, 1804083.6117845762], [403646.3058711692, 1804061.1537051075], [403539.62999369303, 1804094.8408243107], [403466.64123541984, 1804195.9021819197]]]}}, {"id": "1", "type": "Feature", "properties": {"rr_id": 1, "name": "Region 2"}, "geometry": {"type": "Polygon", "coordinates": [[[408105.7632410168, 1803317.9615429805], [408201.9074582713, 1803374.3219461986], [408404.14184628957, 1803251.6551862531], [408397.51121061685, 1803065.9973874167], [408500.2860635441, 1802926.7540382894], [408599.74559863505, 1802837.2404567075], [408719.09704074415, 1802777.564735653], [408735.673629926, 1802731.1502859439], [408652.7906840169, 1802648.267340035], [408503.6013813805, 1802628.3754330166], [408288.10572201683, 1802717.8890145984], [408155.49300856225, 1802850.501728053], [408049.4028377986, 1802946.6459453076], [407979.7811632349, 1803029.5288912167], [407963.2045740531, 1803158.826286835], [408022.88029510767, 1803251.6551862531], [408105.7632410168, 1803317.9615429805]]]}}, {"id": "2", "type": "Feature", "properties": {"rr_id": 2, "name": "Region 3"}, "geometry": {"type": "Polygon", "coordinates": [[[410254.0891989809, 1802329.9968277444], [410366.81000541727, 1802356.5193704353], [410615.4588431446, 1802366.4653239443], [410761.3328279446, 1802313.4202385624], [410874.053634381, 1802220.5913391444], [410814.37791332643, 1802071.4020365078], [410648.6120215082, 1802005.0956797807], [410532.5758972355, 1802011.7263154534], [410356.86405190814, 1802078.0326721806], [410277.2964238354, 1802187.4381607806], [410254.0891989809, 1802329.9968277444]]]}}], "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::2965"}}}
Loading

0 comments on commit da5a6ec

Please sign in to comment.