ngiab-data-preprocess 4.6.8__tar.gz → 4.7.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.
Files changed (57) hide show
  1. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/PKG-INFO +2 -1
  2. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/create_realization.py +60 -4
  3. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/file_paths.py +3 -0
  4. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/forcings.py +14 -5
  5. ngiab_data_preprocess-4.7.0/modules/data_sources/dhbv2-catchment-template.yaml +46 -0
  6. ngiab_data_preprocess-4.7.0/modules/data_sources/dhbv2-realization-template.json +56 -0
  7. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/source_validation.py +26 -2
  8. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_cli/__main__.py +11 -1
  9. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_cli/arguments.py +13 -2
  10. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_preprocess.egg-info/PKG-INFO +2 -1
  11. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_preprocess.egg-info/SOURCES.txt +2 -0
  12. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_preprocess.egg-info/requires.txt +1 -0
  13. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/pyproject.toml +2 -1
  14. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/.github/pull_request_template.md +0 -0
  15. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/.github/workflows/build_only.yml +0 -0
  16. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/.github/workflows/publish.yml +0 -0
  17. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/.gitignore +0 -0
  18. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/LICENSE +0 -0
  19. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/README.md +0 -0
  20. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/ciroh-bgsafe.png +0 -0
  21. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/dask_utils.py +0 -0
  22. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/dataset_utils.py +0 -0
  23. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/datasets.py +0 -0
  24. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/gpkg_utils.py +0 -0
  25. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/graph_utils.py +0 -0
  26. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/s3fs_utils.py +0 -0
  27. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_processing/subset.py +0 -0
  28. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/cfe-nowpm-realization-template.json +0 -0
  29. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/cfe-template.ini +0 -0
  30. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/forcing_template.nc +0 -0
  31. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/lstm-catchment-template.yml +0 -0
  32. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/lstm-realization-template.json +0 -0
  33. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/lstm-rust-realization-template.json +0 -0
  34. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/ngen-routing-template.yaml +0 -0
  35. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/noah-owp-modular-init.namelist.input +0 -0
  36. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/template.sql +0 -0
  37. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/data_sources/triggers.sql +0 -0
  38. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/__init__.py +0 -0
  39. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/__main__.py +0 -0
  40. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/css/console.css +0 -0
  41. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/css/main.css +0 -0
  42. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/css/toggle.css +0 -0
  43. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/js/console.js +0 -0
  44. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/js/data_processing.js +0 -0
  45. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/js/main.js +0 -0
  46. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/resources/loading.gif +0 -0
  47. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/static/resources/screenshot.jpg +0 -0
  48. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/templates/index.html +0 -0
  49. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/map_app/views.py +0 -0
  50. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_cli/custom_logging.py +0 -0
  51. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_cli/forcing_cli.py +0 -0
  52. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_preprocess.egg-info/dependency_links.txt +0 -0
  53. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_preprocess.egg-info/entry_points.txt +0 -0
  54. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/modules/ngiab_data_preprocess.egg-info/top_level.txt +0 -0
  55. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/setup.cfg +0 -0
  56. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/tests/test_nan_impute.py +0 -0
  57. {ngiab_data_preprocess-4.6.8 → ngiab_data_preprocess-4.7.0}/tests/test_ngiab_data_cli_regression.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngiab_data_preprocess
3
- Version: 4.6.8
3
+ Version: 4.7.0
4
4
  Summary: Graphical Tools for creating Next Gen Water model input data.
5
5
  Author-email: Josh Cunningham <jcunningham8@ua.edu>
6
6
  Project-URL: Homepage, https://github.com/CIROH-UA/NGIAB_data_preprocess
@@ -33,6 +33,7 @@ Requires-Dist: bokeh==3.8.2
33
33
  Requires-Dist: boto3
34
34
  Requires-Dist: numcodecs<0.16.0
35
35
  Requires-Dist: scipy>=1.15.3
36
+ Requires-Dist: pyarrow
36
37
  Provides-Extra: eval
37
38
  Requires-Dist: ngiab_eval; extra == "eval"
38
39
  Provides-Extra: plot
@@ -20,6 +20,7 @@ from data_processing.gpkg_utils import (
20
20
  get_cat_to_nhd_feature_id,
21
21
  get_table_crs_short,
22
22
  )
23
+ from data_sources.source_validation import download_dhbv_attributes
23
24
  from pyproj import Transformer
24
25
  from tqdm.rich import tqdm
25
26
 
@@ -112,19 +113,20 @@ def make_noahowp_config(
112
113
  )
113
114
 
114
115
 
115
- def get_model_attributes(hydrofabric: Path) -> pandas.DataFrame:
116
+ def get_model_attributes(hydrofabric: Path, layer: str = "divides") -> pandas.DataFrame:
116
117
  with sqlite3.connect(hydrofabric) as conn:
117
118
  conf_df = pandas.read_sql_query(
118
119
  """
119
120
  SELECT
120
121
  d.areasqkm,
122
+ d.lengthkm,
121
123
  da.*
122
124
  FROM divides AS d
123
125
  JOIN 'divide-attributes' AS da ON d.divide_id = da.divide_id
124
126
  """,
125
127
  conn,
126
128
  )
127
- source_crs = get_table_crs_short(hydrofabric, "divides")
129
+ source_crs = get_table_crs_short(hydrofabric, layer)
128
130
  transformer = Transformer.from_crs(source_crs, "EPSG:4326", always_xy=True)
129
131
  lon, lat = transformer.transform(conf_df["centroid_x"].values, conf_df["centroid_y"].values)
130
132
  conf_df["longitude"] = lon
@@ -172,6 +174,44 @@ def make_lstm_config(
172
174
  )
173
175
 
174
176
 
177
+ def make_dhbv2_config(
178
+ hydrofabric: Path,
179
+ output_dir: Path,
180
+ start_time: datetime,
181
+ end_time: datetime,
182
+ template_path: Path = FilePaths.template_dhbv2_config,
183
+ ):
184
+ divide_conf_df = get_model_attributes(hydrofabric)
185
+ divide_ids = divide_conf_df["divide_id"].to_list()
186
+
187
+ download_dhbv_attributes()
188
+ dhbv_atts = pandas.read_parquet(FilePaths.dhbv_attributes)
189
+ atts_df = dhbv_atts.loc[dhbv_atts["divide_id"].isin(divide_ids)]
190
+
191
+ cat_config_dir = output_dir / "cat_config" / "dhbv2"
192
+ if cat_config_dir.exists():
193
+ shutil.rmtree(cat_config_dir)
194
+ cat_config_dir.mkdir(parents=True, exist_ok=True)
195
+
196
+ with open(template_path, "r") as file:
197
+ template = file.read()
198
+
199
+ for _, row in atts_df.iterrows():
200
+ divide = row["divide_id"]
201
+ divide_conf_df_row = divide_conf_df.loc[divide_conf_df["divide_id"] == divide]
202
+
203
+ with open(cat_config_dir / f"{divide}.yml", "w") as file:
204
+ file.write(
205
+ template.format(
206
+ **row,
207
+ catchsize=divide_conf_df_row["areasqkm"].values[0],
208
+ lengthkm=divide_conf_df_row["lengthkm"].values[0],
209
+ start_time=start_time,
210
+ end_time=end_time,
211
+ )
212
+ )
213
+
214
+
175
215
  def configure_troute(
176
216
  cat_id: str, config_dir: Path, start_time: datetime, end_time: datetime
177
217
  ) -> None:
@@ -218,7 +258,10 @@ def configure_troute(
218
258
 
219
259
 
220
260
  def make_ngen_realization_json(
221
- config_dir: Path, template_path: Path, start_time: datetime, end_time: datetime
261
+ config_dir: Path,
262
+ template_path: Path,
263
+ start_time: datetime,
264
+ end_time: datetime,
222
265
  ) -> None:
223
266
  with open(template_path, "r") as file:
224
267
  realization = json.load(file)
@@ -252,7 +295,20 @@ def create_lstm_realization(
252
295
  (paths.config_dir / "python_lstm_real.json").rename(realization_path)
253
296
 
254
297
  make_lstm_config(paths.geopackage_path, paths.config_dir)
255
- # create some partitions for parallelization
298
+ paths.setup_run_folders()
299
+
300
+
301
+ def create_dhbv2_realization(cat_id: str, start_time: datetime, end_time: datetime):
302
+ paths = FilePaths(cat_id)
303
+ configure_troute(cat_id, paths.config_dir, start_time, end_time)
304
+
305
+ make_ngen_realization_json(
306
+ paths.config_dir,
307
+ FilePaths.template_dhbv2_realization_config,
308
+ start_time,
309
+ end_time,
310
+ )
311
+ make_dhbv2_config(paths.geopackage_path, paths.config_dir, start_time, end_time)
256
312
  paths.setup_run_folders()
257
313
 
258
314
 
@@ -22,6 +22,7 @@ class FilePaths:
22
22
  template_sql = data_sources / "template.sql"
23
23
  triggers_sql = data_sources / "triggers.sql"
24
24
  conus_hydrofabric = hydrofabric_dir / "conus_nextgen.gpkg"
25
+ dhbv_attributes = hydrofabric_dir / "dhbv_attrs.parquet"
25
26
  hydrofabric_graph = hydrofabric_dir / "conus_igraph_network.gpickle"
26
27
  template_nc = data_sources / "forcing_template.nc"
27
28
  dev_file = Path(__file__).parent.parent.parent / ".dev"
@@ -32,6 +33,8 @@ class FilePaths:
32
33
  template_noahowp_config = data_sources / "noah-owp-modular-init.namelist.input"
33
34
  template_cfe_config = data_sources / "cfe-template.ini"
34
35
  template_lstm_config = data_sources / "lstm-catchment-template.yml"
36
+ template_dhbv2_realization_config = data_sources / "dhbv2-realization-template.json"
37
+ template_dhbv2_config = data_sources / "dhbv2-catchment-template.yaml"
35
38
 
36
39
  def __init__(self, folder_name: Optional[str] = None, output_dir: Optional[Path] = None):
37
40
  """
@@ -117,6 +117,7 @@ def get_cell_weights(raster: xr.Dataset, gdf: gpd.GeoDataFrame, wkt: str) -> pd.
117
117
  ) # type: ignore
118
118
  return output.set_index("divide_id")
119
119
 
120
+
120
121
  def add_APCP_SURFACE_to_dataset(dataset: xr.Dataset) -> xr.Dataset:
121
122
  """Convert precipitation value to correct units."""
122
123
  # precip_rate is mm/s
@@ -311,6 +312,7 @@ def get_units(dataset: xr.Dataset) -> dict:
311
312
  units[var] = dataset[var].attrs["units"]
312
313
  return units
313
314
 
315
+
314
316
  def interpolate_nan_values(
315
317
  dataset: xr.Dataset,
316
318
  dim: str = "time",
@@ -383,9 +385,12 @@ def compute_zonal_stats(
383
385
  progress_file = FilePaths(output_dir=forcings_dir.parent).forcing_progress_file
384
386
  ex_var_name = list(gridded_data.data_vars)[0]
385
387
  example_time_chunks = get_index_chunks(gridded_data[ex_var_name])
386
- all_steps = len(example_time_chunks) * len(gridded_data.data_vars)
388
+
389
+ data_vars = gridded_data.data_vars
390
+
391
+ all_steps = len(example_time_chunks) * len(data_vars)
387
392
  logger.info(
388
- f"Total steps: {all_steps}, Number of time chunks: {len(example_time_chunks)}, Number of variables: {len(gridded_data.data_vars)}"
393
+ f"Total steps: {all_steps}, Number of time chunks: {len(example_time_chunks)}, Number of variables: {len(data_vars)}"
389
394
  )
390
395
  steps_completed = 0
391
396
  with open(progress_file, "w") as f:
@@ -405,10 +410,11 @@ def compute_zonal_stats(
405
410
 
406
411
  timer = time.perf_counter()
407
412
  variable_task = progress.add_task(
408
- "[cyan]Processing variables...", total=len(gridded_data.data_vars), elapsed=0
413
+ "[cyan]Processing variables...", total=len(data_vars), elapsed=0
409
414
  )
410
415
  progress.start()
411
- for data_var_name in list(gridded_data.data_vars):
416
+
417
+ for data_var_name in list(data_vars):
412
418
  data_var_name: str
413
419
  progress.update(variable_task, advance=1)
414
420
  progress.update(variable_task, description=f"Processing {data_var_name}")
@@ -524,6 +530,7 @@ def write_outputs(forcings_dir: Path, units: dict) -> None:
524
530
  # time is stored as unix timestamps, units have to be set
525
531
  # add the catchment ids as a 1d data var
526
532
  final_ds["ids"] = final_ds["catchment"].astype(str)
533
+
527
534
  # time needs to be a 2d array of the same time array as unix timestamps for every catchment
528
535
  with warnings.catch_warnings():
529
536
  warnings.simplefilter("ignore")
@@ -575,5 +582,7 @@ def create_forcings(dataset: xr.Dataset, output_folder_name: str) -> None:
575
582
  gdf = gpd.read_file(forcing_paths.geopackage_path, layer="divides")
576
583
  logger.debug(f"gdf bounds: {gdf.total_bounds}")
577
584
  gdf = gdf.to_crs(dataset.crs)
578
- dataset = dataset.isel(y=slice(None, None, -1)) # Flip y-axis: source data has y ordered from top-to-bottom (as in image arrays), but geospatial operations expect y to increase from bottom-to-top (increasing latitude).
585
+ dataset = dataset.isel(
586
+ y=slice(None, None, -1)
587
+ ) # Flip y-axis: source data has y ordered from top-to-bottom (as in image arrays), but geospatial operations expect y to increase from bottom-to-top (increasing latitude).
579
588
  compute_zonal_stats(gdf, dataset, forcing_paths.forcings_dir)
@@ -0,0 +1,46 @@
1
+ ### Single-catchment configuration ###
2
+ catchment_id: {divide_id}
3
+ catchment_name: {divide_id}
4
+
5
+ # Static catchment attributes
6
+ aridity: {aridity}
7
+ meanP: {meanP}
8
+ ETPOT_Hargr: {ETPOT_Hargr}
9
+ NDVI: {NDVI}
10
+ FW: {FW}
11
+ meanslope: {meanslope}
12
+ SoilGrids1km_sand: {SoilGrids1km_sand}
13
+ SoilGrids1km_clay: {SoilGrids1km_clay}
14
+ SoilGrids1km_silt: {SoilGrids1km_silt}
15
+ glaciers: {glaciers}
16
+ HWSD_clay: {HWSD_clay}
17
+ HWSD_gravel: {HWSD_gravel}
18
+ HWSD_sand: {HWSD_sand}
19
+ HWSD_silt: {HWSD_silt}
20
+ meanelevation: {meanelevation}
21
+ meanTa: {meanTa}
22
+ permafrost: {permafrost}
23
+ permeability: {permeability}
24
+ seasonality_P: {seasonality_P}
25
+ seasonality_PET: {seasonality_PET}
26
+ snow_fraction: {snow_fraction}
27
+ snowfall_fraction: {snowfall_fraction}
28
+ T_clay: {T_clay}
29
+ T_gravel: {T_gravel}
30
+ T_sand: {T_sand}
31
+ T_silt: {T_silt}
32
+ Porosity: {Porosity}
33
+ uparea: {uparea}
34
+ catchsize: {catchsize}
35
+ lengthkm: {lengthkm}
36
+
37
+ model_dir: /ngen/ngen/extern/dhbv2/ngen_resources/data/dhbv_2_mts/model/dhbv_2_mts
38
+ stepwise: True # True: stepwise inference, False: Single forward simulation on all data in one go
39
+ initial_state: zero # zero: set initial states of the model to zero
40
+ dtype: float32
41
+ verbose: 1 # 0: no output, 1: print output
42
+
43
+ # Simulation window
44
+ time_step: 1 hour
45
+ start_time: {start_time}
46
+ end_time: {end_time}
@@ -0,0 +1,56 @@
1
+ {
2
+ "global": {
3
+ "formulations": [
4
+ {
5
+ "name": "bmi_multi",
6
+ "params": {
7
+ "model_type_name": "dhbv2",
8
+ "forcing_file": "",
9
+ "init_config": "",
10
+ "allow_exceed_end_time": true,
11
+ "main_output_variable": "land_surface_water__runoff_volume_flux",
12
+ "modules": [
13
+ {
14
+ "name": "bmi_python",
15
+ "params": {
16
+ "python_type": "dhbv2.mts_bmi.MtsDeltaModelBmi",
17
+ "model_type_name": "DeltaModelBmi",
18
+ "init_config": "./config/cat_config/dhbv2/{{id}}.yml",
19
+ "allow_exceed_end_time": true,
20
+ "main_output_variable": "land_surface_water__runoff_volume_flux",
21
+ "fixed_time_step": false,
22
+ "uses_forcing_file": false,
23
+ "variables_names_map" : {
24
+ "atmosphere_water__liquid_equivalent_precipitation_rate":"precip_rate",
25
+ "land_surface_air__temperature":"TMP_2maboveground",
26
+ "atmosphere_air_water~vapor__relative_saturation":"SPFH_2maboveground",
27
+ "land_surface_radiation~incoming~longwave__energy_flux":"DLWRF_surface",
28
+ "land_surface_radiation~incoming~shortwave__energy_flux":"DSWRF_surface",
29
+ "land_surface_air__pressure":"PRES_surface",
30
+ "land_surface_wind__x_component_of_velocity":"UGRD_10maboveground",
31
+ "land_surface_wind__y_component_of_velocity":"VGRD_10maboveground",
32
+ "land_surface_water__runoff_volume_flux":"streamflow_cms"
33
+
34
+ }
35
+
36
+ }
37
+ }
38
+ ]
39
+ }
40
+ }
41
+ ],
42
+ "forcing": {
43
+ "path": "./forcings/forcings.nc",
44
+ "provider": "NetCDF"
45
+ }
46
+ },
47
+ "time": {
48
+ "start_time": "2000-01-01 00:00:00",
49
+ "end_time": "2005-12-30 23:00:00",
50
+ "output_interval": 3600
51
+ },
52
+ "routing": {
53
+ "t_route_config_file_with_path": "./config/troute.yaml"
54
+ },
55
+ "output_root": "./outputs/ngen"
56
+ }
@@ -126,16 +126,40 @@ def download_from_s3(save_path, bucket=S3_BUCKET, key=S3_KEY, region=S3_REGION):
126
126
  return False
127
127
 
128
128
 
129
- def get_headers():
129
+ def get_headers(url: str = hydrofabric_url):
130
130
  # for versioning
131
131
  # Useful Headers: { 'Last-Modified': 'Wed, 20 Nov 2024 18:45:59 GMT', 'ETag': '"cc1452838886a7ab3065a61073fa991b-207"'}
132
132
  try:
133
- response = requests.head(hydrofabric_url)
133
+ response = requests.head(url)
134
134
  except requests.exceptions.ConnectionError:
135
135
  return 500, {}
136
136
  return response.status_code, response.headers
137
137
 
138
138
 
139
+ def download_dhbv_attributes():
140
+ s3_key = "hydrofabrics/community/resources/dhbv_attrs.parquet"
141
+ attributes_url = f"https://{S3_BUCKET}.s3.{S3_REGION}.amazonaws.com/{s3_key}"
142
+
143
+ status, headers = get_headers(attributes_url)
144
+ download_log = FilePaths.dhbv_attributes.with_suffix(".log")
145
+ if download_log.exists():
146
+ with open(download_log, "r") as f:
147
+ local_headers = json.load(f)
148
+ else:
149
+ local_headers = {}
150
+
151
+ if not FilePaths.dhbv_attributes.exists() or headers.get("ETag", "") != local_headers.get(
152
+ "ETag", ""
153
+ ):
154
+ download_from_s3(
155
+ FilePaths.dhbv_attributes,
156
+ bucket=S3_BUCKET,
157
+ key=s3_key,
158
+ )
159
+ with open(FilePaths.dhbv_attributes.with_suffix(".log"), "w") as f:
160
+ json.dump(dict(headers), f)
161
+
162
+
139
163
  def download_and_update_hf():
140
164
  if FilePaths.conus_hydrofabric.is_file():
141
165
  console.print(
@@ -12,7 +12,11 @@ with rich.status.Status("loading") as status:
12
12
  from pathlib import Path
13
13
 
14
14
  import geopandas as gpd
15
- from data_processing.create_realization import create_lstm_realization, create_realization
15
+ from data_processing.create_realization import (
16
+ create_dhbv2_realization,
17
+ create_lstm_realization,
18
+ create_realization,
19
+ )
16
20
  from data_processing.dask_utils import shutdown_cluster
17
21
  from data_processing.dataset_utils import save_and_clip_dataset
18
22
  from data_processing.datasets import load_aorc_zarr, load_v3_retrospective_zarr
@@ -217,6 +221,12 @@ def main() -> None:
217
221
  end_time=args.end_date,
218
222
  use_rust=args.lstm_rust,
219
223
  )
224
+ if args.dhbv2:
225
+ create_dhbv2_realization(
226
+ output_folder,
227
+ start_time=args.start_date,
228
+ end_time=args.end_date,
229
+ )
220
230
  else:
221
231
  create_realization(
222
232
  output_folder,
@@ -92,13 +92,17 @@ def parse_arguments() -> argparse.Namespace:
92
92
  parser.add_argument(
93
93
  "--start_date",
94
94
  "--start",
95
- type=lambda s: datetime.strptime(s, DATE_FORMAT) if len(s) == 10 else datetime.strptime(s, DATE_FORMAT2),
95
+ type=lambda s: datetime.strptime(s, DATE_FORMAT)
96
+ if len(s) == 10
97
+ else datetime.strptime(s, DATE_FORMAT2),
96
98
  help=f"Start date for forcings/realization (format {DATE_FORMAT_HINT})",
97
99
  )
98
100
  parser.add_argument(
99
101
  "--end_date",
100
102
  "--end",
101
- type=lambda s: datetime.strptime(s, DATE_FORMAT) if len(s) == 10 else datetime.strptime(s, DATE_FORMAT2),
103
+ type=lambda s: datetime.strptime(s, DATE_FORMAT)
104
+ if len(s) == 10
105
+ else datetime.strptime(s, DATE_FORMAT2),
102
106
  help=f"End date for forcings/realization (format {DATE_FORMAT_HINT})",
103
107
  )
104
108
  parser.add_argument(
@@ -124,6 +128,13 @@ def parse_arguments() -> argparse.Namespace:
124
128
  action="store_true",
125
129
  help="enable experimental high speed Rust bindings of LSTM model realization and forcings",
126
130
  )
131
+
132
+ parser.add_argument(
133
+ "--dhbv2",
134
+ action="store_true",
135
+ help="enable dHBV2 model realization and forcings",
136
+ )
137
+
127
138
  parser.add_argument(
128
139
  "--nwm_gw",
129
140
  action="store_true",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ngiab_data_preprocess
3
- Version: 4.6.8
3
+ Version: 4.7.0
4
4
  Summary: Graphical Tools for creating Next Gen Water model input data.
5
5
  Author-email: Josh Cunningham <jcunningham8@ua.edu>
6
6
  Project-URL: Homepage, https://github.com/CIROH-UA/NGIAB_data_preprocess
@@ -33,6 +33,7 @@ Requires-Dist: bokeh==3.8.2
33
33
  Requires-Dist: boto3
34
34
  Requires-Dist: numcodecs<0.16.0
35
35
  Requires-Dist: scipy>=1.15.3
36
+ Requires-Dist: pyarrow
36
37
  Provides-Extra: eval
37
38
  Requires-Dist: ngiab_eval; extra == "eval"
38
39
  Provides-Extra: plot
@@ -18,6 +18,8 @@ modules/data_processing/s3fs_utils.py
18
18
  modules/data_processing/subset.py
19
19
  modules/data_sources/cfe-nowpm-realization-template.json
20
20
  modules/data_sources/cfe-template.ini
21
+ modules/data_sources/dhbv2-catchment-template.yaml
22
+ modules/data_sources/dhbv2-realization-template.json
21
23
  modules/data_sources/forcing_template.nc
22
24
  modules/data_sources/lstm-catchment-template.yml
23
25
  modules/data_sources/lstm-realization-template.json
@@ -20,6 +20,7 @@ bokeh==3.8.2
20
20
  boto3
21
21
  numcodecs<0.16.0
22
22
  scipy>=1.15.3
23
+ pyarrow
23
24
 
24
25
  [eval]
25
26
  ngiab_eval
@@ -19,7 +19,7 @@ filterwarnings = [
19
19
  ]
20
20
  [project]
21
21
  name = "ngiab_data_preprocess"
22
- version = "v4.6.8"
22
+ version = "v4.7.0"
23
23
  authors = [{ name = "Josh Cunningham", email = "jcunningham8@ua.edu" }]
24
24
  description = "Graphical Tools for creating Next Gen Water model input data."
25
25
  readme = "README.md"
@@ -52,6 +52,7 @@ dependencies = [
52
52
  "boto3",
53
53
  "numcodecs<0.16.0",
54
54
  "scipy>=1.15.3",
55
+ "pyarrow",
55
56
  ]
56
57
 
57
58
  [project.optional-dependencies]