Metadata-Version: 2.4
Name: hms2cng
Version: 0.1.0
Summary: HMS to Cloud Native GIS — CLI for exporting HEC-HMS results to GeoParquet, PMTiles, DuckDB, and PostGIS
Author-email: "William M. Katzenmeyer, P.E., C.F.M." <bill@clbengineering.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/gpt-cmdr/hms2cng
Project-URL: Repository, https://github.com/gpt-cmdr/hms2cng
Keywords: HEC-HMS,GeoParquet,PMTiles,hydrology,GIS,cloud-native,DuckDB
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Scientific/Engineering :: Hydrology
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: hms-commander>=0.2.0
Requires-Dist: typer>=0.9.0
Requires-Dist: rich>=13.0.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: geopandas>=0.14.0
Requires-Dist: pyarrow>=14.0.0
Provides-Extra: duckdb
Requires-Dist: duckdb>=1.4.0; extra == "duckdb"
Provides-Extra: postgis
Requires-Dist: sqlalchemy>=2.0.0; extra == "postgis"
Requires-Dist: geoalchemy2>=0.14.0; extra == "postgis"
Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgis"
Provides-Extra: pmtiles
Requires-Dist: rasterio>=1.3.0; extra == "pmtiles"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: marimo>=0.9.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Requires-Dist: build>=1.0.0; extra == "dev"
Provides-Extra: docs
Requires-Dist: mkdocs>=1.5.0; extra == "docs"
Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
Requires-Dist: mkdocs-git-revision-date-localized-plugin>=1.2.0; extra == "docs"
Provides-Extra: all
Requires-Dist: duckdb>=1.4.0; extra == "all"
Requires-Dist: sqlalchemy>=2.0.0; extra == "all"
Requires-Dist: geoalchemy2>=0.14.0; extra == "all"
Requires-Dist: psycopg[binary]>=3.2.0; extra == "all"
Requires-Dist: rasterio>=1.3.0; extra == "all"
Dynamic: license-file

# hms2cng — HMS to Cloud Native GIS

CLI tool for exporting HEC-HMS results to **GeoParquet**, querying with **DuckDB**, and generating **PMTiles** for web visualization.

Built on top of [`hms-commander`](https://github.com/gpt-cmdr/hms-commander).

## Installation

```bash
# Base installation (GeoParquet export only)
pip install hms2cng

# With DuckDB support
pip install "hms2cng[duckdb]"

# With PostGIS sync
pip install "hms2cng[postgis]"

# All features
pip install "hms2cng[all]"
```

### PMTiles Generation

PMTiles generation requires external CLI tools:
- **tippecanoe** — Install via conda-forge: `conda install -c conda-forge tippecanoe`
- **pmtiles** — Install from protomaps: `go install github.com/protomaps/go-pmtiles/pmtiles@latest`

On Windows, these are easiest to install via WSL or conda-forge.

## Quick Start

### Export Geometry

```bash
# From basin model file (exports subbasins by default)
hms2cng geometry model.basin subbasins.parquet

# Specific layer (subbasins, reaches, junctions, watershed)
hms2cng geometry model.basin reaches.parquet --layer reaches

# With explicit CRS (recommended for reprojection to WGS84)
hms2cng geometry model.basin subbasins.parquet --crs EPSG:2278 --out-crs EPSG:4326
```

### Export Results

```bash
# Export peak outflow statistics from HMS results folder
hms2cng results ./results/ subbasin_flow.parquet \
    --type subbasin \
    --var "Flow Out"

# All element types
hms2cng results ./results/ all_results.parquet --type all

# Stage instead of flow
hms2cng results ./results/ stage.parquet --type reach --var Stage
```

### Query with DuckDB

```bash
# Filter by peak flow threshold
hms2cng query subbasin_flow.parquet \
    "SELECT * FROM _ WHERE max_value > 1000 ORDER BY max_value DESC"

# Time of peak analysis
hms2cng query subbasin_flow.parquet \
    "SELECT name, max_value, time_of_max, units FROM _ WHERE max_value > 500"

# Save results to file
hms2cng query subbasin_flow.parquet \
    "SELECT * FROM _ WHERE max_value > 1000" \
    --output high_flow_subbasins.parquet
```

### Generate PMTiles

```bash
# From GeoParquet (requires tippecanoe + pmtiles CLI)
hms2cng pmtiles subbasins.parquet subbasins.pmtiles \
    --layer subbasins \
    --min-zoom 8 \
    --max-zoom 14
```

### Sync to PostGIS

```bash
# Upload to PostGIS
hms2cng sync subbasins.parquet \
    "postgresql://user:pass@192.168.3.30:5432/gis_data" \
    hms_subbasins \
    --schema uberclaw
```

## Python API

```python
from hms2cng import (
    export_basin_geometry,
    export_hms_results,
    DuckSession,
    generate_pmtiles_from_input,
    sync_to_postgres
)

# Export geometry
export_basin_geometry("model.basin", "subbasins.parquet", layer="subbasins")

# Export results (parses RUN_*.results XML for summary statistics)
export_hms_results(
    "./results/",
    "subbasin_flow.parquet",
    element_type="subbasin",
    variable="Outflow"
)

# Query with DuckDB
session = DuckSession()
session.register_parquet("subbasin_flow.parquet")
df = session.query("SELECT * FROM _ WHERE max_value > 1000")
session.close()

# Generate PMTiles (requires tippecanoe + pmtiles CLI)
generate_pmtiles_from_input("subbasins.parquet", "subbasins.pmtiles")

# Sync to PostGIS
sync_to_postgres(
    "subbasins.parquet",
    "postgresql://user:pass@host:5432/db",
    "hms_subbasins",
    schema="uberclaw"
)
```

## Tifton Example

The [Tifton HMS example project](https://github.com/gpt-cmdr/hms-commander/tree/main/hms_example_projects/tifton) demonstrates the complete workflow:

```bash
# Set paths
set TIFTON=C:\GH\hms-commander\hms_example_projects\tifton

# Export subbasin geometry
hms2cng geometry %TIFTON%\Tifton.basin tifton_subbasins.parquet --layer subbasins

# Export peak outflow results
hms2cng results %TIFTON%\results tifton_outflow.parquet --type subbasin --var Outflow

# Query for high flows
hms2cng query tifton_outflow.parquet "SELECT name, max_value, time_of_max FROM _ WHERE max_value > 500"

# Sync to PostGIS
hms2cng sync tifton_subbasins.parquet "postgresql://uberclaw:pass@192.168.3.30:5432/gis_data" tifton_subbasins --schema uberclaw
```

## Architecture

```
HEC-HMS Model (.basin, results/RUN_*.results)
         ↓
   hms-commander (geometry + XML parsing)
         ↓
   GeoParquet (.parquet)
         ↓
   ┌───────┴────────┐
   ↓                ↓
DuckDB          PostGIS
(query)        (multi-user)
   ↓                ↓
   └───────┬────────┘
           ↓
      PMTiles (.pmtiles)
           ↓
      MapLibre GL
```

## Notes

### CRS Handling

- If your HMS project has a `.prj` file or CRS is detected automatically, geometry will be reprojected to WGS84 (EPSG:4326) by default.
- Use `--crs EPSG:XXXX` to specify the input CRS manually if auto-detection fails.
- Use `--out-crs EPSG:XXXX` to control output CRS.

### Results Export

- Results are extracted from the `RUN_*.results` XML files generated by HEC-HMS.
- This provides summary statistics (peak, min, mean, time of peak) without requiring DSS file access.
- For full time-series export, `pyjnius` + HEC-DSS libraries are required (currently not bundled).

### PMTiles on Windows

- Install tippecanoe and pmtiles via conda-forge or WSL.
- The CLI will produce a clear error if the tools are not found.

## Development

```bash
# Clone and install in dev mode
git clone https://github.com/gpt-cmdr/hms2cng
cd hms2cng
uv pip install -e ".[all]"

# Run tests
uv run pytest tests/

# Build package
uv run python -m build
```

## License

MIT - See LICENSE file

## Author

William M. Katzenmeyer, P.E., C.F.M.
CLB Engineering Corporation
