pastastore 1.7.1__py3-none-any.whl → 1.8.0__py3-none-any.whl
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.
- docs/conf.py +215 -0
- pastastore/__init__.py +6 -1
- pastastore/base.py +72 -630
- pastastore/connectors.py +876 -18
- pastastore/extensions/hpd.py +220 -37
- pastastore/store.py +238 -110
- pastastore/util.py +1 -1
- pastastore/version.py +1 -1
- {pastastore-1.7.1.dist-info → pastastore-1.8.0.dist-info}/METADATA +40 -39
- pastastore-1.8.0.dist-info/RECORD +28 -0
- {pastastore-1.7.1.dist-info → pastastore-1.8.0.dist-info}/WHEEL +1 -1
- {pastastore-1.7.1.dist-info → pastastore-1.8.0.dist-info}/top_level.txt +2 -0
- tests/conftest.py +169 -0
- tests/test_001_import.py +8 -0
- tests/test_002_connectors.py +277 -0
- tests/test_003_pastastore.py +321 -0
- tests/test_004_yaml.py +135 -0
- tests/test_005_maps_plots.py +81 -0
- tests/test_006_benchmark.py +181 -0
- tests/test_007_hpdextension.py +87 -0
- tests/test_008_stressmodels.py +128 -0
- pastastore-1.7.1.dist-info/RECORD +0 -18
- {pastastore-1.7.1.dist-info → pastastore-1.8.0.dist-info}/LICENSE +0 -0
pastastore/extensions/hpd.py
CHANGED
|
@@ -164,10 +164,10 @@ class HydroPandasExtension:
|
|
|
164
164
|
metadata.pop("name", None)
|
|
165
165
|
metadata.pop("meta", None)
|
|
166
166
|
unit = metadata.get("unit", None)
|
|
167
|
-
if unit == "m" and unit_multiplier
|
|
167
|
+
if unit == "m" and np.allclose(unit_multiplier, 1e-3):
|
|
168
168
|
metadata["unit"] = "mm"
|
|
169
169
|
elif unit_multiplier != 1.0:
|
|
170
|
-
metadata["unit"] = f"{unit_multiplier
|
|
170
|
+
metadata["unit"] = f"{unit_multiplier:.1e}*{unit}"
|
|
171
171
|
|
|
172
172
|
source = metadata.get("source", "")
|
|
173
173
|
if len(source) > 0:
|
|
@@ -199,13 +199,67 @@ class HydroPandasExtension:
|
|
|
199
199
|
else:
|
|
200
200
|
raise ValueError("libname must be 'oseries' or 'stresses'.")
|
|
201
201
|
|
|
202
|
+
def _get_tmin_tmax(self, tmin, tmax, oseries=None):
|
|
203
|
+
"""Get tmin and tmax from store if not specified.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
tmin : TimeType
|
|
208
|
+
start time
|
|
209
|
+
tmax : TimeType
|
|
210
|
+
end time
|
|
211
|
+
oseries : str, optional
|
|
212
|
+
name of the observation series to get tmin/tmax for, by default None
|
|
213
|
+
|
|
214
|
+
Returns
|
|
215
|
+
-------
|
|
216
|
+
tmin, tmax : TimeType, TimeType
|
|
217
|
+
tmin and tmax
|
|
218
|
+
"""
|
|
219
|
+
# get tmin/tmax if not specified
|
|
220
|
+
if tmin is None or tmax is None:
|
|
221
|
+
tmintmax = self._store.get_tmin_tmax(
|
|
222
|
+
"oseries", names=[oseries] if oseries else None
|
|
223
|
+
)
|
|
224
|
+
if tmin is None:
|
|
225
|
+
tmin = tmintmax.loc[:, "tmin"].min() - Timedelta(days=10 * 365)
|
|
226
|
+
if tmax is None:
|
|
227
|
+
tmax = tmintmax.loc[:, "tmax"].max()
|
|
228
|
+
return tmin, tmax
|
|
229
|
+
|
|
230
|
+
@staticmethod
|
|
231
|
+
def _normalize_datetime_index(obs):
|
|
232
|
+
"""Normalize observation datetime index (i.e. set observation time to midnight).
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
obs : pandas.Series
|
|
237
|
+
observation series to normalize
|
|
238
|
+
|
|
239
|
+
Returns
|
|
240
|
+
-------
|
|
241
|
+
hpd.Obs
|
|
242
|
+
observation series with normalized datetime index
|
|
243
|
+
"""
|
|
244
|
+
if isinstance(obs, hpd.Obs):
|
|
245
|
+
metadata = {k: getattr(obs, k) for k in obs._metadata}
|
|
246
|
+
else:
|
|
247
|
+
metadata = {}
|
|
248
|
+
return obs.__class__(
|
|
249
|
+
timestep_weighted_resample(
|
|
250
|
+
obs,
|
|
251
|
+
obs.index.normalize(),
|
|
252
|
+
).rename(obs.name),
|
|
253
|
+
**metadata,
|
|
254
|
+
)
|
|
255
|
+
|
|
202
256
|
def download_knmi_precipitation(
|
|
203
257
|
self,
|
|
204
258
|
stns: Optional[list[int]] = None,
|
|
205
259
|
meteo_var: str = "RD",
|
|
206
260
|
tmin: TimeType = None,
|
|
207
261
|
tmax: TimeType = None,
|
|
208
|
-
unit_multiplier: float =
|
|
262
|
+
unit_multiplier: float = 1e-3,
|
|
209
263
|
fill_missing_obs: bool = True,
|
|
210
264
|
normalize_datetime_index: bool = True,
|
|
211
265
|
**kwargs,
|
|
@@ -244,7 +298,7 @@ class HydroPandasExtension:
|
|
|
244
298
|
meteo_var: str = "EV24",
|
|
245
299
|
tmin: TimeType = None,
|
|
246
300
|
tmax: TimeType = None,
|
|
247
|
-
unit_multiplier: float =
|
|
301
|
+
unit_multiplier: float = 1e-3,
|
|
248
302
|
fill_missing_obs: bool = True,
|
|
249
303
|
normalize_datetime_index: bool = True,
|
|
250
304
|
**kwargs,
|
|
@@ -303,7 +357,7 @@ class HydroPandasExtension:
|
|
|
303
357
|
variable to download, by default "RH", valid options are
|
|
304
358
|
e.g. ["RD", "RH", "EV24", "T", "Q"].
|
|
305
359
|
kind : str
|
|
306
|
-
kind identifier for observations, usually "prec" or "evap".
|
|
360
|
+
kind identifier for observations in pastastore, usually "prec" or "evap".
|
|
307
361
|
stns : list of int/str, optional
|
|
308
362
|
list of station numbers to download data for, by default None
|
|
309
363
|
tmin : TimeType, optional
|
|
@@ -320,12 +374,7 @@ class HydroPandasExtension:
|
|
|
320
374
|
if True, normalize the datetime so stress value at midnight represents
|
|
321
375
|
the daily total, by default True.
|
|
322
376
|
"""
|
|
323
|
-
|
|
324
|
-
tmintmax = self._store.get_tmin_tmax("oseries")
|
|
325
|
-
if tmin is None:
|
|
326
|
-
tmin = tmintmax.loc[:, "tmin"].min() - Timedelta(days=10 * 365)
|
|
327
|
-
if tmax is None:
|
|
328
|
-
tmax = tmintmax.loc[:, "tmax"].max()
|
|
377
|
+
tmin, tmax = self._get_tmin_tmax(tmin, tmax)
|
|
329
378
|
|
|
330
379
|
if stns is None:
|
|
331
380
|
locations = self._store.oseries.loc[:, ["x", "y"]]
|
|
@@ -354,6 +403,155 @@ class HydroPandasExtension:
|
|
|
354
403
|
normalize_datetime_index=normalize_datetime_index,
|
|
355
404
|
)
|
|
356
405
|
|
|
406
|
+
def download_nearest_knmi_precipitation(
|
|
407
|
+
self,
|
|
408
|
+
oseries: str,
|
|
409
|
+
meteo_var: str = "RD",
|
|
410
|
+
tmin: Optional[TimeType] = None,
|
|
411
|
+
tmax: Optional[TimeType] = None,
|
|
412
|
+
unit_multiplier: float = 1e-3,
|
|
413
|
+
normalize_datetime_index: bool = True,
|
|
414
|
+
fill_missing_obs: bool = True,
|
|
415
|
+
**kwargs,
|
|
416
|
+
):
|
|
417
|
+
"""Download precipitation time series data from nearest KNMI station.
|
|
418
|
+
|
|
419
|
+
Parameters
|
|
420
|
+
----------
|
|
421
|
+
oseries : str
|
|
422
|
+
download nearest precipitation information for this observation well
|
|
423
|
+
meteo_var : str, optional
|
|
424
|
+
variable to download, by default "RD", valid options are ["RD", "RH"].
|
|
425
|
+
tmin : TimeType
|
|
426
|
+
start time
|
|
427
|
+
tmax : TimeType
|
|
428
|
+
end time
|
|
429
|
+
unit_multiplier : float, optional
|
|
430
|
+
multiply unit by this value before saving it in the store,
|
|
431
|
+
by default 1.0 (no conversion)
|
|
432
|
+
fill_missing_obs : bool, optional
|
|
433
|
+
if True, fill missing observations by getting observations from nearest
|
|
434
|
+
station with data.
|
|
435
|
+
fill_missing_obs : bool, optional
|
|
436
|
+
if True, fill missing observations by getting observations from nearest
|
|
437
|
+
station with data.
|
|
438
|
+
"""
|
|
439
|
+
self.download_nearest_knmi_meteo(
|
|
440
|
+
oseries=oseries,
|
|
441
|
+
meteo_var=meteo_var,
|
|
442
|
+
kind="prec",
|
|
443
|
+
tmin=tmin,
|
|
444
|
+
tmax=tmax,
|
|
445
|
+
unit_multiplier=unit_multiplier,
|
|
446
|
+
normalize_datetime_index=normalize_datetime_index,
|
|
447
|
+
fill_missing_obs=fill_missing_obs,
|
|
448
|
+
**kwargs,
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
def download_nearest_knmi_evaporation(
|
|
452
|
+
self,
|
|
453
|
+
oseries: str,
|
|
454
|
+
meteo_var: str = "EV24",
|
|
455
|
+
tmin: Optional[TimeType] = None,
|
|
456
|
+
tmax: Optional[TimeType] = None,
|
|
457
|
+
unit_multiplier: float = 1e-3,
|
|
458
|
+
normalize_datetime_index: bool = True,
|
|
459
|
+
fill_missing_obs: bool = True,
|
|
460
|
+
**kwargs,
|
|
461
|
+
):
|
|
462
|
+
"""Download evaporation time series data from nearest KNMI station.
|
|
463
|
+
|
|
464
|
+
Parameters
|
|
465
|
+
----------
|
|
466
|
+
oseries : str
|
|
467
|
+
download nearest evaporation information for this observation well
|
|
468
|
+
meteo_var : str, optional
|
|
469
|
+
variable to download, by default "EV24", valid options are:
|
|
470
|
+
["EV24", "penman", "hargreaves", "makkink"].
|
|
471
|
+
tmin : TimeType
|
|
472
|
+
start time
|
|
473
|
+
tmax : TimeType
|
|
474
|
+
end time
|
|
475
|
+
unit_multiplier : float, optional
|
|
476
|
+
multiply unit by this value before saving it in the store,
|
|
477
|
+
by default 1.0 (no conversion)
|
|
478
|
+
fill_missing_obs : bool, optional
|
|
479
|
+
if True, fill missing observations by getting observations from nearest
|
|
480
|
+
station with data.
|
|
481
|
+
fill_missing_obs : bool, optional
|
|
482
|
+
if True, fill missing observations by getting observations from nearest
|
|
483
|
+
station with data.
|
|
484
|
+
"""
|
|
485
|
+
self.download_nearest_knmi_meteo(
|
|
486
|
+
oseries=oseries,
|
|
487
|
+
meteo_var=meteo_var,
|
|
488
|
+
kind="evap",
|
|
489
|
+
tmin=tmin,
|
|
490
|
+
tmax=tmax,
|
|
491
|
+
unit_multiplier=unit_multiplier,
|
|
492
|
+
normalize_datetime_index=normalize_datetime_index,
|
|
493
|
+
fill_missing_obs=fill_missing_obs,
|
|
494
|
+
**kwargs,
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
def download_nearest_knmi_meteo(
|
|
498
|
+
self,
|
|
499
|
+
oseries: str,
|
|
500
|
+
meteo_var: str,
|
|
501
|
+
kind: str,
|
|
502
|
+
tmin: Optional[TimeType] = None,
|
|
503
|
+
tmax: Optional[TimeType] = None,
|
|
504
|
+
unit_multiplier: float = 1.0,
|
|
505
|
+
normalize_datetime_index: bool = True,
|
|
506
|
+
fill_missing_obs: bool = True,
|
|
507
|
+
**kwargs,
|
|
508
|
+
):
|
|
509
|
+
"""Download meteorological data from nearest KNMI station.
|
|
510
|
+
|
|
511
|
+
Parameters
|
|
512
|
+
----------
|
|
513
|
+
oseries : str
|
|
514
|
+
download nearest meteorological information for this observation well
|
|
515
|
+
meteo_var : str
|
|
516
|
+
meteorological variable to download, e.g. "RD", "RH", "EV24", "T", "Q"
|
|
517
|
+
kind : str
|
|
518
|
+
kind identifier for observations in pastastore, usually "prec" or "evap".
|
|
519
|
+
tmin : TimeType
|
|
520
|
+
start time
|
|
521
|
+
tmax : TimeType
|
|
522
|
+
end time
|
|
523
|
+
unit_multiplier : float, optional
|
|
524
|
+
multiply unit by this value before saving it in the store,
|
|
525
|
+
by default 1.0 (no conversion)
|
|
526
|
+
fill_missing_obs : bool, optional
|
|
527
|
+
if True, fill missing observations by getting observations from nearest
|
|
528
|
+
station with data.
|
|
529
|
+
fill_missing_obs : bool, optional
|
|
530
|
+
if True, fill missing observations by getting observations from nearest
|
|
531
|
+
station with data.
|
|
532
|
+
"""
|
|
533
|
+
xy = self._store.oseries.loc[[oseries], ["x", "y"]].to_numpy()
|
|
534
|
+
# download data
|
|
535
|
+
tmin, tmax = self._get_tmin_tmax(tmin, tmax, oseries=oseries)
|
|
536
|
+
knmi = hpd.read_knmi(
|
|
537
|
+
xy=xy,
|
|
538
|
+
meteo_vars=[meteo_var],
|
|
539
|
+
starts=tmin,
|
|
540
|
+
ends=tmax,
|
|
541
|
+
fill_missing_obs=fill_missing_obs,
|
|
542
|
+
**kwargs,
|
|
543
|
+
)
|
|
544
|
+
# add to store
|
|
545
|
+
self.add_obscollection(
|
|
546
|
+
libname="stresses",
|
|
547
|
+
oc=knmi,
|
|
548
|
+
kind=kind,
|
|
549
|
+
data_column=meteo_var,
|
|
550
|
+
unit_multiplier=unit_multiplier,
|
|
551
|
+
update=False,
|
|
552
|
+
normalize_datetime_index=normalize_datetime_index,
|
|
553
|
+
)
|
|
554
|
+
|
|
357
555
|
def update_knmi_meteo(
|
|
358
556
|
self,
|
|
359
557
|
names: Optional[List[str]] = None,
|
|
@@ -386,6 +584,17 @@ class HydroPandasExtension:
|
|
|
386
584
|
**kwargs : dict, optional
|
|
387
585
|
Additional keyword arguments to pass to `hpd.read_knmi()`
|
|
388
586
|
"""
|
|
587
|
+
if "source" not in self._store.stresses.columns:
|
|
588
|
+
msg = (
|
|
589
|
+
"Cannot update KNMI stresses! "
|
|
590
|
+
"KNMI stresses cannot be identified if 'source' column is not defined."
|
|
591
|
+
)
|
|
592
|
+
logger.error(msg)
|
|
593
|
+
if raise_on_error:
|
|
594
|
+
raise ValueError(msg)
|
|
595
|
+
else:
|
|
596
|
+
return
|
|
597
|
+
|
|
389
598
|
if names is None:
|
|
390
599
|
names = self._store.stresses.loc[
|
|
391
600
|
self._store.stresses["source"] == "KNMI"
|
|
@@ -497,32 +706,6 @@ class HydroPandasExtension:
|
|
|
497
706
|
if raise_on_error:
|
|
498
707
|
raise e
|
|
499
708
|
|
|
500
|
-
@staticmethod
|
|
501
|
-
def _normalize_datetime_index(obs):
|
|
502
|
-
"""Normalize observation datetime index (i.e. set observation time to midnight).
|
|
503
|
-
|
|
504
|
-
Parameters
|
|
505
|
-
----------
|
|
506
|
-
obs : pandas.Series
|
|
507
|
-
observation series to normalize
|
|
508
|
-
|
|
509
|
-
Returns
|
|
510
|
-
-------
|
|
511
|
-
hpd.Obs
|
|
512
|
-
observation series with normalized datetime index
|
|
513
|
-
"""
|
|
514
|
-
if isinstance(obs, hpd.Obs):
|
|
515
|
-
metadata = {k: getattr(obs, k) for k in obs._metadata}
|
|
516
|
-
else:
|
|
517
|
-
metadata = {}
|
|
518
|
-
return obs.__class__(
|
|
519
|
-
timestep_weighted_resample(
|
|
520
|
-
obs,
|
|
521
|
-
obs.index.normalize(),
|
|
522
|
-
).rename(obs.name),
|
|
523
|
-
**metadata,
|
|
524
|
-
)
|
|
525
|
-
|
|
526
709
|
def download_bro_gmw(
|
|
527
710
|
self,
|
|
528
711
|
extent: Optional[List[float]] = None,
|