herbiedss 0.1.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.
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.3
2
+ Name: herbiedss
3
+ Version: 0.1.0
4
+ Summary: Fetch NOAA weather model output (HRRR, GFS, GEFS) with Herbie, reproject to USACE SHG or NWS HRAP hydrologic grids, clip to a watershed boundary, and write the result to HEC-DSS for use in HEC-HMS/HEC-RAS.
5
+ Keywords: herbie,hec-dss,hydrology,grib,shg,hrap,hrrr,gfs,noaa
6
+ Author: Jeff Gregory
7
+ Author-email: Jeff Gregory <jeffrey.s.gregory@usace.army.mil>
8
+ Requires-Dist: geopandas>=1.1.4
9
+ Requires-Dist: hecdss>=0.1.32
10
+ Requires-Dist: herbie-data>=2026.3.0
11
+ Requires-Dist: pyproj>=3.7.2
12
+ Requires-Dist: rasterio>=1.5.1
13
+ Requires-Dist: rich>=15.0.0
14
+ Requires-Dist: rioxarray>=0.23.0
15
+ Requires-Dist: typer>=0.27.1
16
+ Requires-Python: >=3.13
17
+ Description-Content-Type: text/markdown
18
+
19
+ # herbiedss
20
+
21
+ A command-line tool that fetches NOAA weather model output (HRRR, GFS, GEFS, and other models supported by [Herbie](https://github.com/blaylockbk/Herbie)), optionally reprojects it onto the USACE **Standard Hydrologic Grid (SHG)** or the NWS **Hydrologic Rainfall Analysis Project (HRAP)** grid, clips it to a watershed boundary, and writes the result into a **HEC-DSS** file for use in HEC-HMS, HEC-RAS, or other USACE modeling tools.
22
+
23
+ ## Features
24
+
25
+ - Downloads GRIB2 model output via Herbie for any date, forecast hour, model, and product combination.
26
+ - Filters GRIB messages with regex search strings against Herbie's inventory, so you can target specific fields like hourly (not cumulative) accumulated precipitation.
27
+ - Reprojects the native model grid (e.g. HRRR's Lambert Conformal, GFS/GEFS's regular lat-lon) onto SHG (Albers Equal-Area, 2000 m native cell size) or HRAP (polar stereographic, 4762.5 m native cell size).
28
+ - Handles both rectilinear (1D lat/lon) and curvilinear (2D lat/lon) source grids automatically.
29
+ - Clips the reprojected grid to a user-supplied watershed boundary file (shapefile, GeoJSON, GeoPackage, or anything GeoPandas can read), regardless of that file's own CRS.
30
+ - Writes each grid to HEC-DSS with a pathname whose D/E parts are derived from the grid's own start/end time, so instantaneous and accumulated fields are timestamped correctly.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install herbiedss
36
+ ```
37
+
38
+ Requires Python 3.10+. Core dependencies include `herbie-data`, `hecdss`, `rioxarray`, `pyproj`, `geopandas`, `typer`, and `rich`.
39
+
40
+ ## Usage
41
+
42
+ ### Basic export (native model projection)
43
+
44
+ ```bash
45
+ herbiedss dssexport \\
46
+ --date 2026-08-18 \\
47
+ --model hrrr \\
48
+ --fxx 6 \\
49
+ --search ":TMP:2 m above ground:" \\
50
+ --dssfile output.dss \\
51
+ --apart HRRR --bpart CONUS --cpart TMP2M
52
+ ```
53
+
54
+ ### Reproject to SHG and clip to a watershed
55
+
56
+ ```bash
57
+ herbiedss dssexport \\
58
+ --date 2026-08-18 \\
59
+ --model hrrr \\
60
+ --fxx 6 \\
61
+ --search ":APCP:.*:(?:0-1|[1-9]\\d*-\\d+) hour" \\
62
+ --grid-system shg \\
63
+ --boundary-file watershed.shp \\
64
+ --dssfile output.dss \\
65
+ --apart SHG --bpart TRINITY --cpart PRECIP
66
+ ```
67
+
68
+ ### Reproject to HRAP without clipping
69
+
70
+ ```bash
71
+ herbiedss dssexport \\
72
+ --date 2026-08-18 \\
73
+ --model gfs \\
74
+ --fxx 12 \\
75
+ --grid-system hrap \\
76
+ --dssfile output.dss \\
77
+ --apart HRAP --bpart CONUS --cpart PRECIP
78
+ ```
79
+
80
+ ## CLI Options
81
+
82
+ | Option | Description |
83
+ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
84
+ | `--date` | Forecast initialization date(s). Accepts a separator-delimited list via `--sep`. |
85
+ | `--model` | Herbie model name (`hrrr`, `gfs`, `gefs`, etc.). Default: `hrrr`. |
86
+ | `--product` | Model product/subset (e.g. `sfc`). Default: `sfc`. |
87
+ | `--fxx` | Forecast lead hour(s). Accepts a separator-delimited list. |
88
+ | `--search` | Regex pattern to filter Herbie's GRIB inventory (passed to `.xarray(search=...)`). |
89
+ | `--variable` | Explicit xarray variable name, if `--search` matches more than one. |
90
+ | `--grid-system` | Reproject onto `shg` or `hrap` before writing to DSS. Omit to keep the model's native projection. |
91
+ | `--boundary-file` | Path to a watershed boundary vector file. Requires `--grid-system`. |
92
+ | `--dssfile` | Output HEC-DSS file path. Default: `herbiedss.dss`. |
93
+ | `--apart`, `--bpart`, `--cpart`, `--fpart` | DSS pathname A/B/C/F parts. D and E parts are derived automatically from the grid's own timing metadata. |
94
+ | `--save-dir` | Local directory for downloaded GRIB2 files. |
95
+ | `--remove-grib` | Delete the local GRIB2 file after loading it into xarray. |
96
+ | `--overwrite` | Re-download and overwrite existing local GRIB2 files. |
97
+ | `--verbose` | Enable verbose Herbie logging. |
98
+
99
+ ## How Reprojection Works
100
+
101
+ Herbie's `.xarray()` accessor exposes each model's native coordinate reference system via `da.herbie.crs` (a Cartopy CRS). The `herbiedss.utils.reproject` module converts that to a `pyproj` CRS, attaches it to the DataArray with `rioxarray`, and calls `.rio.reproject()` onto one of two hardcoded target CRS definitions, since neither has a standard EPSG code:
102
+
103
+ - **SHG**: `+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=23 +lon_0=-96 +datum=NAD83 +units=m`
104
+ - **HRAP**: `+proj=stere +lat_0=90 +lat_ts=60 +lon_0=-105 +R=6371200 +units=m`
105
+
106
+ Model grids come in two shapes, handled automatically:
107
+
108
+ - **Rectilinear** grids (GFS, GEFS): latitude/longitude are already 1D dimension coordinates, so renaming to `x`/`y` is direct.
109
+ - **Curvilinear** grids (HRRR's native Lambert Conformal): latitude/longitude are 2D auxiliary coordinates. The module looks for an existing 1D projected coordinate under alternate names, or reconstructs one by round-tripping a row/column of the 2D lat/lon through the source CRS.
110
+
111
+ Clipping to a watershed boundary happens *after* reprojection, using `.rio.clip()` with the boundary file's geometry reprojected to match the target grid's CRS — this is a separate step from reprojection and works with any vector format GeoPandas supports, not just rasters.
112
+
113
+ ## Known Limitations
114
+
115
+ - `hecdss.GriddedData` attribute names for grid reference system, cell size, and lower-left origin vary by installed `hecdss` version. The export step attaches these defensively via `hasattr()` checks — verify with `dir(GriddedData())` on your installed version if georeferencing isn't showing up correctly in the output DSS file.
116
+ - Accumulated fields (e.g. `APCP`) can have multiple GRIB messages with overlapping-looking inventory strings (`0-2 hour` vs. `1-2 hour`). Always test your `--search` regex with `H.inventory(search)` before running a full export, since an imprecise pattern can silently match the wrong accumulation window.
117
+ - HRAP and SHG are both undefined outside the conterminous United States; reprojecting global or non-CONUS domains onto either grid will produce questionable results.
118
+
119
+ ## License
120
+
121
+ MIT
@@ -0,0 +1,103 @@
1
+ # herbiedss
2
+
3
+ A command-line tool that fetches NOAA weather model output (HRRR, GFS, GEFS, and other models supported by [Herbie](https://github.com/blaylockbk/Herbie)), optionally reprojects it onto the USACE **Standard Hydrologic Grid (SHG)** or the NWS **Hydrologic Rainfall Analysis Project (HRAP)** grid, clips it to a watershed boundary, and writes the result into a **HEC-DSS** file for use in HEC-HMS, HEC-RAS, or other USACE modeling tools.
4
+
5
+ ## Features
6
+
7
+ - Downloads GRIB2 model output via Herbie for any date, forecast hour, model, and product combination.
8
+ - Filters GRIB messages with regex search strings against Herbie's inventory, so you can target specific fields like hourly (not cumulative) accumulated precipitation.
9
+ - Reprojects the native model grid (e.g. HRRR's Lambert Conformal, GFS/GEFS's regular lat-lon) onto SHG (Albers Equal-Area, 2000 m native cell size) or HRAP (polar stereographic, 4762.5 m native cell size).
10
+ - Handles both rectilinear (1D lat/lon) and curvilinear (2D lat/lon) source grids automatically.
11
+ - Clips the reprojected grid to a user-supplied watershed boundary file (shapefile, GeoJSON, GeoPackage, or anything GeoPandas can read), regardless of that file's own CRS.
12
+ - Writes each grid to HEC-DSS with a pathname whose D/E parts are derived from the grid's own start/end time, so instantaneous and accumulated fields are timestamped correctly.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install herbiedss
18
+ ```
19
+
20
+ Requires Python 3.10+. Core dependencies include `herbie-data`, `hecdss`, `rioxarray`, `pyproj`, `geopandas`, `typer`, and `rich`.
21
+
22
+ ## Usage
23
+
24
+ ### Basic export (native model projection)
25
+
26
+ ```bash
27
+ herbiedss dssexport \\
28
+ --date 2026-08-18 \\
29
+ --model hrrr \\
30
+ --fxx 6 \\
31
+ --search ":TMP:2 m above ground:" \\
32
+ --dssfile output.dss \\
33
+ --apart HRRR --bpart CONUS --cpart TMP2M
34
+ ```
35
+
36
+ ### Reproject to SHG and clip to a watershed
37
+
38
+ ```bash
39
+ herbiedss dssexport \\
40
+ --date 2026-08-18 \\
41
+ --model hrrr \\
42
+ --fxx 6 \\
43
+ --search ":APCP:.*:(?:0-1|[1-9]\\d*-\\d+) hour" \\
44
+ --grid-system shg \\
45
+ --boundary-file watershed.shp \\
46
+ --dssfile output.dss \\
47
+ --apart SHG --bpart TRINITY --cpart PRECIP
48
+ ```
49
+
50
+ ### Reproject to HRAP without clipping
51
+
52
+ ```bash
53
+ herbiedss dssexport \\
54
+ --date 2026-08-18 \\
55
+ --model gfs \\
56
+ --fxx 12 \\
57
+ --grid-system hrap \\
58
+ --dssfile output.dss \\
59
+ --apart HRAP --bpart CONUS --cpart PRECIP
60
+ ```
61
+
62
+ ## CLI Options
63
+
64
+ | Option | Description |
65
+ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
66
+ | `--date` | Forecast initialization date(s). Accepts a separator-delimited list via `--sep`. |
67
+ | `--model` | Herbie model name (`hrrr`, `gfs`, `gefs`, etc.). Default: `hrrr`. |
68
+ | `--product` | Model product/subset (e.g. `sfc`). Default: `sfc`. |
69
+ | `--fxx` | Forecast lead hour(s). Accepts a separator-delimited list. |
70
+ | `--search` | Regex pattern to filter Herbie's GRIB inventory (passed to `.xarray(search=...)`). |
71
+ | `--variable` | Explicit xarray variable name, if `--search` matches more than one. |
72
+ | `--grid-system` | Reproject onto `shg` or `hrap` before writing to DSS. Omit to keep the model's native projection. |
73
+ | `--boundary-file` | Path to a watershed boundary vector file. Requires `--grid-system`. |
74
+ | `--dssfile` | Output HEC-DSS file path. Default: `herbiedss.dss`. |
75
+ | `--apart`, `--bpart`, `--cpart`, `--fpart` | DSS pathname A/B/C/F parts. D and E parts are derived automatically from the grid's own timing metadata. |
76
+ | `--save-dir` | Local directory for downloaded GRIB2 files. |
77
+ | `--remove-grib` | Delete the local GRIB2 file after loading it into xarray. |
78
+ | `--overwrite` | Re-download and overwrite existing local GRIB2 files. |
79
+ | `--verbose` | Enable verbose Herbie logging. |
80
+
81
+ ## How Reprojection Works
82
+
83
+ Herbie's `.xarray()` accessor exposes each model's native coordinate reference system via `da.herbie.crs` (a Cartopy CRS). The `herbiedss.utils.reproject` module converts that to a `pyproj` CRS, attaches it to the DataArray with `rioxarray`, and calls `.rio.reproject()` onto one of two hardcoded target CRS definitions, since neither has a standard EPSG code:
84
+
85
+ - **SHG**: `+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=23 +lon_0=-96 +datum=NAD83 +units=m`
86
+ - **HRAP**: `+proj=stere +lat_0=90 +lat_ts=60 +lon_0=-105 +R=6371200 +units=m`
87
+
88
+ Model grids come in two shapes, handled automatically:
89
+
90
+ - **Rectilinear** grids (GFS, GEFS): latitude/longitude are already 1D dimension coordinates, so renaming to `x`/`y` is direct.
91
+ - **Curvilinear** grids (HRRR's native Lambert Conformal): latitude/longitude are 2D auxiliary coordinates. The module looks for an existing 1D projected coordinate under alternate names, or reconstructs one by round-tripping a row/column of the 2D lat/lon through the source CRS.
92
+
93
+ Clipping to a watershed boundary happens *after* reprojection, using `.rio.clip()` with the boundary file's geometry reprojected to match the target grid's CRS — this is a separate step from reprojection and works with any vector format GeoPandas supports, not just rasters.
94
+
95
+ ## Known Limitations
96
+
97
+ - `hecdss.GriddedData` attribute names for grid reference system, cell size, and lower-left origin vary by installed `hecdss` version. The export step attaches these defensively via `hasattr()` checks — verify with `dir(GriddedData())` on your installed version if georeferencing isn't showing up correctly in the output DSS file.
98
+ - Accumulated fields (e.g. `APCP`) can have multiple GRIB messages with overlapping-looking inventory strings (`0-2 hour` vs. `1-2 hour`). Always test your `--search` regex with `H.inventory(search)` before running a full export, since an imprecise pattern can silently match the wrong accumulation window.
99
+ - HRAP and SHG are both undefined outside the conterminous United States; reprojecting global or non-CONUS domains onto either grid will produce questionable results.
100
+
101
+ ## License
102
+
103
+ MIT
@@ -0,0 +1,38 @@
1
+ [project]
2
+ name = "herbiedss"
3
+ readme = "README.md"
4
+ version = "0.1.0"
5
+ description = "Fetch NOAA weather model output (HRRR, GFS, GEFS) with Herbie, reproject to USACE SHG or NWS HRAP hydrologic grids, clip to a watershed boundary, and write the result to HEC-DSS for use in HEC-HMS/HEC-RAS."
6
+ keywords = [
7
+ "herbie",
8
+ "hec-dss",
9
+ "hydrology",
10
+ "grib",
11
+ "shg",
12
+ "hrap",
13
+ "hrrr",
14
+ "gfs",
15
+ "noaa",
16
+ ]
17
+ requires-python = ">=3.13"
18
+ dependencies = [
19
+ "geopandas>=1.1.4",
20
+ "hecdss>=0.1.32",
21
+ "herbie-data>=2026.3.0",
22
+ "pyproj>=3.7.2",
23
+ "rasterio>=1.5.1",
24
+ "rich>=15.0.0",
25
+ "rioxarray>=0.23.0",
26
+ "typer>=0.27.1",
27
+ ]
28
+
29
+ [[project.authors]]
30
+ name = "Jeff Gregory"
31
+ email = "jeffrey.s.gregory@usace.army.mil"
32
+
33
+ [project.scripts]
34
+ herbiedss = "herbiedss.main:app"
35
+
36
+ [build-system]
37
+ requires = ["uv_build>=0.11.32,<0.12.0"]
38
+ build-backend = "uv_build"
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "herbiedss"
3
+ readme = "README.md"
4
+ version = "0.1.0"
5
+ description = "Fetch NOAA weather model output (HRRR, GFS, GEFS) with Herbie, reproject to USACE SHG or NWS HRAP hydrologic grids, clip to a watershed boundary, and write the result to HEC-DSS for use in HEC-HMS/HEC-RAS."
6
+ keywords = [
7
+ "herbie",
8
+ "hec-dss",
9
+ "hydrology",
10
+ "grib",
11
+ "shg",
12
+ "hrap",
13
+ "hrrr",
14
+ "gfs",
15
+ "noaa",
16
+ ]
17
+ authors = [{ name = "Jeff Gregory", email = "jeffrey.s.gregory@usace.army.mil" }]
18
+ requires-python = ">=3.13"
19
+ dependencies = [
20
+ "geopandas>=1.1.4",
21
+ "hecdss>=0.1.32",
22
+ "herbie-data>=2026.3.0",
23
+ "pyproj>=3.7.2",
24
+ "rasterio>=1.5.1",
25
+ "rich>=15.0.0",
26
+ "rioxarray>=0.23.0",
27
+ "typer>=0.27.1",
28
+ ]
29
+
30
+ [project.scripts]
31
+ herbiedss = "herbiedss.main:app"
32
+
33
+ [build-system]
34
+ requires = ["uv_build>=0.11.32,<0.12.0"]
35
+ build-backend = "uv_build"
File without changes
@@ -0,0 +1,3 @@
1
+ from .main import app
2
+
3
+ app()
File without changes
@@ -0,0 +1,142 @@
1
+ """
2
+ download.py
3
+
4
+ Typer command that downloads GRIB2 model output (optionally subset to
5
+ specific fields) using the `Herbie` package, iterating over every
6
+ date/forecast-hour combination requested on the command line.
7
+
8
+ Raises
9
+ ------
10
+ typer.Exit
11
+ Raised with exit code 1 if `Herbie.download` fails for any requested
12
+ date/forecast-hour combination (e.g. the file is not found at any
13
+ known archive source, or a network/IO error occurs).
14
+ """
15
+
16
+ import typer
17
+ from herbie.core import Herbie
18
+ from rich.console import Console
19
+
20
+ from herbiedss.utils.validate import parse_date_values, parse_option_values
21
+
22
+ from ..options import (
23
+ DateOption,
24
+ FxxOption,
25
+ ModelOption,
26
+ OverwriteOption,
27
+ ProductOption,
28
+ SaveDirOption,
29
+ SepOption,
30
+ SubsetOption,
31
+ VerboseOption,
32
+ )
33
+
34
+ console = Console()
35
+ error_console = Console(stderr=True, style="bold red")
36
+
37
+
38
+ # @app.command()
39
+ def download(
40
+ # ctx: typer.Context,
41
+ date: DateOption,
42
+ model: ModelOption = "hrrr",
43
+ product: ProductOption = "sfc",
44
+ fxx: FxxOption = "0",
45
+ sep: SepOption = ",",
46
+ save_dir: SaveDirOption = None,
47
+ subset: SubsetOption = None,
48
+ verbose: VerboseOption = False,
49
+ overwrite: OverwriteOption = False,
50
+ ) -> None:
51
+ """Download the GRIB2 file (optionally subset) for the given date/model/fxx.
52
+
53
+ For every combination of model run date and forecast lead time (fxx),
54
+ this command builds a `Herbie` object and downloads the corresponding
55
+ GRIB2 file from whichever archive source (NOMADS, AWS, Google Cloud,
56
+ Azure, ECMWF, Pando, etc.) has it available. If a `subset` search
57
+ string is supplied, only the matching GRIB messages (fields) are
58
+ downloaded instead of the full file, which saves bandwidth and disk
59
+ space.
60
+
61
+ Parameters
62
+ ----------
63
+ date : DateOption
64
+ One or more model initialization dates/times to download, as a
65
+ separator-delimited string (see `sep`). Parsed via
66
+ `parse_date_values` into a list of date strings that `Herbie`
67
+ can interpret (e.g. "2024-01-01 12:00").
68
+ model : ModelOption, optional
69
+ Name of the NWP model to download, as defined in Herbie's model
70
+ template folder (e.g. "hrrr", "hrrrak", "rap", "gfs", "ecmwf").
71
+ Case-insensitive. Defaults to "hrrr".
72
+ product : ProductOption, optional
73
+ Output variable product/file type for the model (e.g. "sfc" for
74
+ surface, "prs" for pressure levels, "nat", "subh"). Case-sensitive
75
+ and model-dependent. Defaults to "sfc".
76
+ fxx : FxxOption, optional
77
+ One or more forecast lead times in hours, as a separator-delimited
78
+ string (see `sep`). Parsed via `parse_option_values` into a list
79
+ of integers. Available lead times depend on the model and model
80
+ version. Defaults to "0" (the analysis/initialization hour).
81
+ sep : SepOption, optional
82
+ Delimiter used to split multiple values passed to `date` and
83
+ `fxx` into lists. Defaults to ",".
84
+ save_dir : SaveDirOption, optional
85
+ Local directory in which to save downloaded files. If `None`,
86
+ Herbie's default data directory (from its configuration) is
87
+ used instead.
88
+ subset : SubsetOption, optional
89
+ Regular-expression search string used to filter GRIB messages by
90
+ variable/level (e.g. ":TMP:2 m" or ":500 mb"), matched against the
91
+ file's index (.idx) entries. If provided, only the matching
92
+ messages are downloaded via `Herbie.download(search=subset)`;
93
+ if `None`, the full GRIB2 file is downloaded.
94
+ verbose : VerboseOption, optional
95
+ If `True`, print additional diagnostic output while locating and
96
+ downloading each file. Defaults to `False`.
97
+ overwrite : OverwriteOption, optional
98
+ If `True`, re-download and overwrite the file even if it already
99
+ exists locally. If `False`, an existing local copy is reused.
100
+ Defaults to `False`.
101
+
102
+ Returns
103
+ -------
104
+ None
105
+ This command does not return a value. For each successfully
106
+ downloaded file, the resolved local path is printed to stdout
107
+ via `console.print`.
108
+
109
+ Raises
110
+ ------
111
+ typer.Exit
112
+ Raised with exit code 1 if `Herbie.download` raises any exception
113
+ for a given date/fxx combination. The triggering exception's
114
+ message is printed to stderr before exiting.
115
+ """
116
+
117
+ resolved_date: list[str] = parse_date_values(date, sep)
118
+ resolved_fxx: list[int] = parse_option_values(fxx, sep)
119
+
120
+ for dt in resolved_date:
121
+ for hr in resolved_fxx:
122
+ kwargs = {
123
+ "date": dt,
124
+ "model": model,
125
+ "product": product,
126
+ "fxx": hr,
127
+ "verbose": verbose,
128
+ "overwrite": overwrite,
129
+ }
130
+
131
+ if save_dir is not None:
132
+ kwargs["save_dir"] = str(save_dir)
133
+
134
+ H = Herbie(**kwargs)
135
+
136
+ try:
137
+ path = H.download(search=subset) if subset else H.download()
138
+ except Exception as exc: # noqa: BLE001
139
+ error_console.print(f"Download failed: {exc}")
140
+ raise typer.Exit(code=1)
141
+
142
+ console.print(f"[green]Saved:[/green] {path}")