Skip to content

Commit ea1fab4

Browse files
committed
feat: add create_repeating command to the repeating CLI group
1 parent cfb1de6 commit ea1fab4

2 files changed

Lines changed: 346 additions & 21 deletions

File tree

README.md

Lines changed: 345 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -51,38 +51,362 @@ pip install "pydsm[dev]" # test + docs tools
5151

5252
## Commands
5353

54-
The `pydsm` command-line tool provides the following subcommands:
55-
5654
```
5755
pydsm --help
5856
```
5957

6058
### DSS file utilities
6159

62-
| Command | Description |
63-
|---------|-------------|
64-
| [`pydsm extract-dss`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#extract-dss) `<dssfile>` | Extract time series from a DSS file; optionally filter by C-part, apply Godin filter, and resample to daily/monthly values. Output can be pickle (`.gz`/`.zip`/`.bz2`), HDF5 (`.h5`), or DSS. |
65-
| [`pydsm compare-dss`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#compare-dss) `<dssfile1> <dssfile2>` | Compare two DSS files on matching B/C-part pathnames and write goodness-of-fit metrics (RMSE, Nash-Sutcliffe, percent bias, etc.) to a CSV. |
66-
| [`pydsm copy-all-dss`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#copy-all-dss) `<from_file> <to_file>` | Copy all paths from one DSS file to another. |
67-
| [`pydsm csv-to-dss`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#csv-to-dss) `<csv_file> <dss_file>` | Convert a CSV time series file to a DSS file with configurable path parts, units, period type, resampling, and a numeric multiplier. |
68-
| [`pydsm extend-dss-ts`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#extend-dss-ts) `<dss_filename> <dss_ext_filename>` | Extend time series in a DSS file by a number of days (default 366) by appending a shifted copy at the end. |
69-
| [`pydsm repeating`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#repeating) `create <datafile>` | Create a repeating annual time series from a CSV template year and write it to a DSS file. |
70-
| [`pydsm repeating`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#repeating) `extend <datafile>` | Extend an existing repeating time series in a DSS file forward to a given end year. |
60+
#### `extract-dss`
61+
62+
Extract time series from a DSS file, with optional C-part filtering, Godin tidal filter, and resampling.
63+
64+
```
65+
pydsm extract-dss DSSFILE [OPTIONS]
66+
```
67+
68+
| Argument / Option | Default | Description |
69+
|---|---|---|
70+
| `DSSFILE` | *(required)* | Input DSS file |
71+
| `-o / --outfile` | `out.gz` | Output file path. Extension determines format: `.gz`/`.zip`/`.bz2` → pickle, `.h5` → HDF5, `.dss` → DSS |
72+
| `--cpart` || Filter to paths matching this C-part string (e.g. `EC`) |
73+
| `-godin / --godin-filter` | off | Apply Godin tidal filter before writing |
74+
| `-davg / --daily-average` | off | Average to daily values |
75+
| `-dmax / --daily-max` | off | Daily maximum |
76+
| `-dmin / --daily-min` | off | Daily minimum |
77+
| `-mavg / --monthly-average` | off | Monthly average |
78+
79+
```bash
80+
pydsm extract-dss model_output.dss -o ec_daily.gz --cpart EC -davg
81+
```
82+
83+
---
84+
85+
#### `compare-dss`
86+
87+
Compare two DSS files on matching B/C-part pathnames and write goodness-of-fit metrics to a CSV.
88+
89+
```
90+
pydsm compare-dss DSSFILE1 DSSFILE2 [OPTIONS]
91+
```
92+
93+
| Argument / Option | Default | Description |
94+
|---|---|---|
95+
| `DSSFILE1`, `DSSFILE2` | *(required)* | Two DSS files to compare |
96+
| `--cpart` || Filter to paths matching this C-part string |
97+
| `--threshold` | `0.001` | Metric value above which a path is flagged as different |
98+
| `--threshold-metric` | `rmse` | Metric used for threshold check. Choices: `mean_error`, `nmean_error`, `mse`, `nmse`, `rmse`, `nrmse`, `nash_sutcliffe`, `percent_bias` |
99+
| `--metricsfile` | `compare_dss_metrics_diff.csv` | Output metrics CSV filename |
100+
| `--time-window` || Comparison window, e.g. `"01JAN1990 - 01OCT1991"` |
101+
| `--threshold-plots` | `False` | Write HTML plots for paths that exceed the threshold |
102+
103+
```bash
104+
pydsm compare-dss base.dss variant.dss --cpart EC --time-window "01JAN2020 - 01JAN2022"
105+
```
106+
107+
---
108+
109+
#### `copy-all-dss`
110+
111+
Copy all pathnames from one DSS file to another.
112+
113+
```
114+
pydsm copy-all-dss FROM_FILE TO_FILE
115+
```
116+
117+
```bash
118+
pydsm copy-all-dss source.dss destination.dss
119+
```
120+
121+
---
122+
123+
#### `csv-to-dss`
124+
125+
Convert a CSV time series file to a DSS file.
126+
127+
```
128+
pydsm csv-to-dss CSV_FILE DSS_FILE [OPTIONS]
129+
```
130+
131+
| Argument / Option | Default | Description |
132+
|---|---|---|
133+
| `CSV_FILE`, `DSS_FILE` | *(required)* | Input CSV and output DSS paths |
134+
| `--index_col` | `0` | Column index to use as the datetime index |
135+
| `--apart` | `A` | DSS A-part |
136+
| `--bpart` | `F` | DSS B-part (location) |
137+
| `--fpart` | `F` | DSS F-part (version/study label) |
138+
| `--unit` | `UNK` | Physical unit string |
139+
| `--period_type` | `INST-VAL` | Period type (e.g. `INST-VAL`, `PER-AVER`) |
140+
| `--multiplier` | `1.0` | Scale factor applied to all values |
141+
| `--resample_to` | `15T` | Pandas resample frequency (e.g. `15T`, `1H`, `1D`) |
142+
143+
```bash
144+
pydsm csv-to-dss observed_ec.csv observed_ec.dss --bpart RSAC075 --unit uS/cm --resample_to 15T
145+
```
146+
147+
---
148+
149+
#### `extend-dss-ts`
150+
151+
Extend time series in a DSS file by appending a shifted copy.
152+
153+
```
154+
pydsm extend-dss-ts DSS_FILENAME DSS_EXT_FILENAME [OPTIONS]
155+
```
156+
157+
| Argument / Option | Default | Description |
158+
|---|---|---|
159+
| `DSS_FILENAME` | *(required)* | Source DSS file |
160+
| `DSS_EXT_FILENAME` | *(required)* | Output DSS file with extended data |
161+
| `--days` | `366` | Number of days to shift the appended copy |
162+
| `--pathfilter` | `///////` | HECDSS path filter (HEC wildcard syntax) |
163+
164+
```bash
165+
pydsm extend-dss-ts boundary.dss boundary_extended.dss --days 366
166+
```
167+
168+
---
169+
170+
#### `repeating create`
171+
172+
Create a repeating annual time series from a CSV template year and write it to a DSS file.
173+
174+
```
175+
pydsm repeating create DATAFILE --input-file FILE --path PATH --units UNITS [OPTIONS]
176+
```
177+
178+
| Argument / Option | Default | Description |
179+
|---|---|---|
180+
| `DATAFILE` | *(required)* | Output DSS file to write repeating series into |
181+
| `--input-file` | *(required)* | CSV file containing the template year data |
182+
| `--path` | *(required)* | Full HECDSS path to write (e.g. `/A/STATION/FLOW//1DAY/F/`) |
183+
| `--units` | *(required)* | Physical unit string |
184+
| `--period-type` | `PER-AVER` | DSS period type |
185+
186+
```bash
187+
pydsm repeating create output.dss --input-file template_year.csv --path "/TEMPLATE/STATION/FLOW//1DAY/REP/" --units CFS
188+
```
189+
190+
---
191+
192+
#### `repeating extend`
193+
194+
Extend an existing repeating time series in a DSS file forward to a given end year.
195+
196+
```
197+
pydsm repeating extend DATAFILE --cpart CPART --end-year YEAR
198+
```
199+
200+
| Argument / Option | Default | Description |
201+
|---|---|---|
202+
| `DATAFILE` | *(required)* | DSS file containing the repeating series |
203+
| `--cpart` | *(required)* | C-part filter to identify the datasets to extend |
204+
| `--end-year` | *(required)* | Target end year (integer) |
205+
206+
```bash
207+
pydsm repeating extend output.dss --cpart FLOW --end-year 2030
208+
```
209+
210+
---
211+
212+
#### `calc-netcd`
213+
214+
Calculate aggregated Net Channel Depletion (NetCD = DIV-FLOW − DRAIN-FLOW + SEEP-FLOW) from a DSS file.
215+
216+
```
217+
pydsm calc-netcd DSSFILE [OPTIONS]
218+
```
219+
220+
| Argument / Option | Default | Description |
221+
|---|---|---|
222+
| `DSSFILE` | *(required)* | Input DSS file containing diversion, drain, and seepage paths |
223+
| `--bpart` || B-part to include (repeatable, e.g. `--bpart BBID --bpart 12345`). Defaults to all numeric node IDs. |
224+
| `--bpart-file` || Text file with one B-part per line |
225+
| `--no-seepage` | off | Exclude seepage: NetCD = DIV − DRAIN only |
226+
| `--epart` | `1DAY` | Time interval E-part (e.g. `1DAY`, `1MON`) |
227+
| `-o / --output` | `netcd.csv` | Output CSV file path |
228+
229+
```bash
230+
pydsm calc-netcd dcd_nodes.dss --bpart BBID --epart 1MON -o netcd_monthly.csv
231+
```
232+
233+
---
71234

72235
### DSM2 input / echo files
73236

74-
| Command | Description |
75-
|---------|-------------|
76-
| [`pydsm pretty-print-input`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#pretty-print-input) `<input_file> [output_file]` | Reformat (pretty-print) a DSM2 `.inp` echo file. Defaults to `<basename>.pretty.inp`. |
77-
| [`pydsm create-dsm2-input-for-cd`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#create-dsm2-input-for-cd) `<dss_filename> <dsm2_input_filename> <file_field_string>` | Generate a DSM2 `.inp` boundary file for consumptive demand from a DSS file. |
78-
| [`pydsm chan-orient`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#chan-orient) `<channel_line_geojson_file> <hydro_echo_file>` | Generate a channel orientation file (angles) from a GeoJSON channel geometry and a Hydro echo file. |
237+
#### `pretty-print-input`
238+
239+
Reformat (pretty-print) a DSM2 `.inp` echo file, normalising whitespace and column alignment.
240+
241+
```
242+
pydsm pretty-print-input INPUT_FILE [OUTPUT_FILE]
243+
```
244+
245+
| Argument | Default | Description |
246+
|---|---|---|
247+
| `INPUT_FILE` | *(required)* | DSM2 `.inp` echo file to reformat |
248+
| `OUTPUT_FILE` | `<basename>.pretty.inp` | Output file path |
249+
250+
```bash
251+
pydsm pretty-print-input hydro_echo.inp
252+
```
253+
254+
---
255+
256+
#### `create-dsm2-input-for-cd`
257+
258+
Generate a DSM2 `.inp` boundary-condition file for consumptive demand from a DSS file.
259+
260+
```
261+
pydsm create-dsm2-input-for-cd DSS_FILENAME DSM2_INPUT_FILENAME FILE_FIELD_STRING
262+
```
263+
264+
| Argument | Description |
265+
|---|---|
266+
| `DSS_FILENAME` | DSS file containing the consumptive demand time series |
267+
| `DSM2_INPUT_FILENAME` | Output `.inp` file to write |
268+
| `FILE_FIELD_STRING` | String used as the `FILE` field value in the generated input table |
269+
270+
```bash
271+
pydsm create-dsm2-input-for-cd dcd_2020.dss dcd_boundary.inp "\${BNDRYINPUT}"
272+
```
273+
274+
---
275+
276+
#### `chan-orient`
277+
278+
Generate a channel orientation (angle) `.inp` file from a GeoJSON channel geometry and a Hydro echo file.
279+
280+
```
281+
pydsm chan-orient CHANNEL_LINE_GEOJSON_FILE HYDRO_ECHO_FILE [OPTIONS]
282+
```
283+
284+
| Argument / Option | Default | Description |
285+
|---|---|---|
286+
| `CHANNEL_LINE_GEOJSON_FILE` | *(required)* | GeoJSON file of channel centrelines |
287+
| `HYDRO_ECHO_FILE` | *(required)* | DSM2 Hydro echo `.inp` file |
288+
| `--channel_orient_file` | `channel_orient.inp` | Output orientation `.inp` file path |
289+
290+
```bash
291+
pydsm chan-orient dsm2_channels.geojson hydro_echo.inp --channel_orient_file channel_orient.inp
292+
```
293+
294+
---
295+
296+
#### `diff`
297+
298+
Compare two DSM2 studies by their Hydro echo files. Reports structural differences in all input tables and computes RMSE/bias for DSS-backed time-series inputs.
299+
300+
```
301+
pydsm diff ECHO_A ECHO_B [OPTIONS]
302+
```
303+
304+
| Argument / Option | Default | Description |
305+
|---|---|---|
306+
| `ECHO_A`, `ECHO_B` | *(required)* | Paths to the two Hydro echo `.inp` files |
307+
| `-t / --tables` | `BOUNDARY_FLOW BOUNDARY_STAGE OPRULE_TIME_SERIES` | DSS-backed tables to compare for time-series data (repeatable) |
308+
| `--all-tables` | off | Compare DSS data in all known TS-backed tables |
309+
| `--timewindow` | run-period intersection | Comparison window, e.g. `"01JAN2020 0000 - 01JAN2022 0000"` |
310+
| `--threshold` | `0.01` | RMSE below this is not reported as a difference |
311+
| `--max-ts` | `25` | Skip DSS loading for tables with more rows than this |
312+
| `--force` | off | Load DSS data even when a table exceeds `--max-ts` rows |
313+
| `--outdir` | `.` | Directory for CSV output files |
314+
| `--no-csv` | off | Print report to terminal only; suppress CSV output |
315+
316+
```bash
317+
pydsm diff base/hydro_echo.inp variant/hydro_echo.inp --timewindow "01JAN2020 0000 - 01JAN2022 0000" --outdir diff_output/
318+
```
319+
320+
---
79321

80322
### HDF5 tidefile utilities
81323

82-
| Command | Description |
83-
|---------|-------------|
84-
| [`pydsm slice-hydro`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#slice-hydro) `<infile> <outfile> <stime> <etime>` | Slice a Hydro HDF5 tidefile to a time window (e.g. `1990-01-10` to `1990-03-31`) and write a new tidefile. |
85-
| [`pydsm update-hydro-tidefile-with-inp`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#update-hydro-tidefile-with-inp) `<hydro_tidefile> <input_file>` | Patch an HDF5 Hydro tidefile's input table from a `.inp` file. |
86-
| [`pydsm create-gtm-restart`](https://cadwrdeltamodeling.github.io/pydsm/pydsm.cli.html#create-gtm-restart) `<tidefile> <target_time> <outfile>` | Write a GTM/Qual restart file from an HDF5 tidefile at the nearest stored time step to `target_time` (e.g. `05FEB2020 0300`). |
324+
#### `slice-hydro`
325+
326+
Slice a Hydro HDF5 tidefile to a time window and write a new tidefile.
327+
328+
```
329+
pydsm slice-hydro INFILE OUTFILE STIME ETIME
330+
```
331+
332+
| Argument | Description |
333+
|---|---|
334+
| `INFILE` | Input Hydro HDF5 tidefile |
335+
| `OUTFILE` | Output (sliced) Hydro HDF5 tidefile |
336+
| `STIME` | Start datetime string, e.g. `1990-01-10` |
337+
| `ETIME` | End datetime string, e.g. `1990-03-31` |
338+
339+
```bash
340+
pydsm slice-hydro historical.h5 sliced.h5 1990-01-10 1990-03-31
341+
```
342+
343+
---
344+
345+
#### `update-hydro-tidefile-with-inp`
346+
347+
Patch an input table inside a Hydro HDF5 tidefile from a DSM2 `.inp` file.
348+
349+
```
350+
pydsm update-hydro-tidefile-with-inp HYDRO_TIDEFILE INPUT_FILE [TIDEFILE_PATH] [TABLE_NAME]
351+
```
352+
353+
| Argument | Default | Description |
354+
|---|---|---|
355+
| `HYDRO_TIDEFILE` | *(required)* | HDF5 tidefile to update (modified in place) |
356+
| `INPUT_FILE` | *(required)* | DSM2 `.inp` file containing the updated table |
357+
| `TIDEFILE_PATH` | `/hydro/input/channel` | HDF5 dataset path to overwrite |
358+
| `TABLE_NAME` | `CHANNEL` | Table name to read from the `.inp` file |
359+
360+
```bash
361+
pydsm update-hydro-tidefile-with-inp historical.h5 modified_channels.inp
362+
```
363+
364+
---
365+
366+
#### `create-gtm-restart`
367+
368+
Write a GTM/Qual restart file from an HDF5 tidefile at the nearest stored time step to a target time.
369+
370+
```
371+
pydsm create-gtm-restart TIDEFILE TARGET_TIME OUTFILE [OPTIONS]
372+
```
373+
374+
| Argument / Option | Default | Description |
375+
|---|---|---|
376+
| `TIDEFILE` | *(required)* | GTM/Qual HDF5 tidefile |
377+
| `TARGET_TIME` | *(required)* | Desired time, e.g. `"05FEB2020 0300"`. Nearest model output time is used. |
378+
| `OUTFILE` | *(required)* | Destination restart file path |
379+
| `-c / --constituent` | `ec` | Constituent to export |
380+
381+
```bash
382+
pydsm create-gtm-restart qual_output.h5 "01OCT2015 0000" restart_oct2015.inp
383+
```
384+
385+
---
386+
387+
#### `calc-volumes`
388+
389+
Calculate DSM2 channel and/or reservoir volumes from a Hydro HDF5 tidefile.
390+
391+
```
392+
pydsm calc-volumes HYDROFILE [OPTIONS]
393+
```
394+
395+
| Argument / Option | Default | Description |
396+
|---|---|---|
397+
| `HYDROFILE` | *(required)* | Hydro HDF5 tidefile |
398+
| `--timewindow` | full run period | Time window, e.g. `"01JAN2014 - 01JAN2015"` |
399+
| `--channel` | all | Channel number to include (repeatable) |
400+
| `--channel-file` || Text file with one channel number per line |
401+
| `--reservoir` | all | Reservoir name to include (repeatable) |
402+
| `--reservoir-file` || Text file with one reservoir name per line |
403+
| `--unit` | `acre-feet` | Volume unit. Choices: `cubic-feet`, `acre-feet`, `maf` |
404+
| `--no-channels` | off | Skip channel volume calculation |
405+
| `--no-reservoirs` | off | Skip reservoir volume calculation |
406+
| `-o / --output` | `volumes.csv` | Output CSV file path |
407+
408+
```bash
409+
pydsm calc-volumes historical.h5 --timewindow "01JAN2014 - 01JAN2015" -o volumes_2014.csv
410+
```
87411

88412
---

pydsm/cli.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ def create_gtm_restart_cmd(tidefile, target_time, outfile, constituent):
351351

352352

353353
# Add the commands to the group repeating
354+
repeating.add_command(create_repeating)
354355
repeating.add_command(extend_repeating)
355356
# adding sub commands to main
356357
main.add_command(repeating)

0 commit comments

Comments
 (0)