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.
@@ -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 == 1e3:
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:e}*{unit}"
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 = 1e3,
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 = 1e3,
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
- # get tmin/tmax if not specified
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,