pthelma 1.1.0__tar.gz → 2.1.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {pthelma-1.1.0 → pthelma-2.1.0}/.github/workflows/run-tests.yml +1 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/CHANGELOG.rst +14 -0
- {pthelma-1.1.0/src/pthelma.egg-info → pthelma-2.1.0}/PKG-INFO +2 -2
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/evaporation/api.rst +1 -1
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/haggregate/api.rst +8 -1
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/haggregate/usage.rst +7 -6
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/htimeseries.rst +2 -2
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/rocc.rst +1 -1
- {pthelma-1.1.0 → pthelma-2.1.0}/src/enhydris_cache/cli.py +0 -2
- {pthelma-1.1.0 → pthelma-2.1.0}/src/evaporation/cli.py +5 -7
- {pthelma-1.1.0 → pthelma-2.1.0}/src/evaporation/evaporation.py +1 -1
- {pthelma-1.1.0 → pthelma-2.1.0}/src/haggregate/haggregate.py +6 -6
- {pthelma-1.1.0 → pthelma-2.1.0}/src/haggregate/regularize.c +123 -123
- {pthelma-1.1.0 → pthelma-2.1.0}/src/hspatial/cli.py +2 -4
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma/_version.py +2 -2
- {pthelma-1.1.0 → pthelma-2.1.0/src/pthelma.egg-info}/PKG-INFO +2 -2
- {pthelma-1.1.0 → pthelma-2.1.0}/src/rocc/calculation.c +123 -123
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_cache/test_cli.py +32 -22
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/evaporation/test_cli.py +220 -197
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/evaporation/test_evaporation.py +5 -5
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/haggregate/test_haggregate.py +33 -15
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/hspatial/test_cli.py +41 -31
- {pthelma-1.1.0 → pthelma-2.1.0}/.github/workflows/build_wheels.yml +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/.gitignore +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/.readthedocs.yaml +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/GPL-3 +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/LICENSE.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/MANIFEST.in +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/README.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/Makefile +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/changelog.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/conf.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/enhydris_api_client.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/enhydris_cache/api.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/enhydris_cache/usage.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/evaporation/usage.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/hspatial/api.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/hspatial/testutils.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/hspatial/usage.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/index.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/install.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/license.rst +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/docs/requirements.txt +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/pyproject.toml +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/setup.cfg +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/setup.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/enhydris_api_client/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/enhydris_cache/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/enhydris_cache/enhydris_cache.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/evaporation/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/haggregate/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/haggregate/cli.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/haggregate/regularize.pyx +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/hspatial/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/hspatial/hspatial.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/hspatial/test.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/htimeseries/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/htimeseries/htimeseries.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/htimeseries/timezone_utils.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma.egg-info/SOURCES.txt +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma.egg-info/dependency_links.txt +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma.egg-info/entry_points.txt +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma.egg-info/requires.txt +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/pthelma.egg-info/top_level.txt +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/rocc/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/src/rocc/calculation.pyx +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/test_e2e.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/test_misc.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/test_station.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/test_timeseries.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/test_timeseriesgroup.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_api_client/test_tsdata.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_cache/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/enhydris_cache/test_enhydris_cache.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/evaporation/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/haggregate/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/haggregate/test_cli.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/haggregate/test_regularize.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/hspatial/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/hspatial/test_hspatial.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/htimeseries/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/htimeseries/test_htimeseries.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/htimeseries/test_timezone_utils.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/rocc/__init__.py +0 -0
- {pthelma-1.1.0 → pthelma-2.1.0}/tests/rocc/test_rocc.py +0 -0
@@ -2,6 +2,20 @@
|
|
2
2
|
Changelog
|
3
3
|
=========
|
4
4
|
|
5
|
+
|
6
|
+
2.1.0 (2025-01-10)
|
7
|
+
==================
|
8
|
+
|
9
|
+
* haggregate: The ``missing_flag`` parameter to ``aggregate()`` can now
|
10
|
+
include the substring "{}", which will be replaced with the number of
|
11
|
+
missing values.
|
12
|
+
|
13
|
+
2.0.0 (2024-12-04)
|
14
|
+
==================
|
15
|
+
|
16
|
+
We now use "h" instead of "H", and generally we use modern pandas time
|
17
|
+
step ("frequency") designations.
|
18
|
+
|
5
19
|
1.1.0 (2024-12-01)
|
6
20
|
==================
|
7
21
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: pthelma
|
3
|
-
Version:
|
3
|
+
Version: 2.1.0
|
4
4
|
Summary: Utilities for hydrological and meteorological time series processing
|
5
5
|
Author-email: Antonis Christofides <antonis@antonischristofides.com>
|
6
6
|
Maintainer-email: Antonis Christofides <antonis@antonischristofides.com>
|
@@ -44,7 +44,7 @@ evaporation API
|
|
44
44
|
(negative for west or south). Only *latitude* needs to be specified
|
45
45
|
for calculating daily evaporation.
|
46
46
|
|
47
|
-
*time_step* is a string: "D" for daily, "
|
47
|
+
*time_step* is a string: "D" for daily, "h" for hourly.
|
48
48
|
|
49
49
|
In order to estimate the outgoing radiation, the ratio of incoming
|
50
50
|
solar radiation to clear sky solar radiation is used as a
|
@@ -34,7 +34,14 @@ haggregate API
|
|
34
34
|
than *min_count* source records corresponding, the resulting
|
35
35
|
destination record is null; otherwise, the destination record is
|
36
36
|
derived even though some records are missing. In that case, the flag
|
37
|
-
specified by *missing_flag* is raised in the destination record.
|
37
|
+
specified by *missing_flag* is raised in the destination record. If
|
38
|
+
missing flag contains the string ``{}``, it is replaced with the
|
39
|
+
number of missing records. The recommended setting for *missing_flag*
|
40
|
+
is ``MISSING{}``, which, for example, will result in ``MISSING3``
|
41
|
+
when three records are missing. The default for *missing_flag* is
|
42
|
+
``MISS`` for backwards compatibility (it was ``MISS`` for some years,
|
43
|
+
however this was undocumented), but this is deprecated; use
|
44
|
+
``MISSING{}``.
|
38
45
|
|
39
46
|
If an error occurs, such as *ts* not having a strictly regular step,
|
40
47
|
:exc:`AggregateError` (or a subclass) is raised.
|
@@ -53,9 +53,9 @@ explanatory comments that follow it:
|
|
53
53
|
loglevel = INFO
|
54
54
|
logfile = /var/log/haggregate/haggregate.log
|
55
55
|
base_dir = /var/cache/timeseries/
|
56
|
-
target_step =
|
56
|
+
target_step = 1h
|
57
57
|
min_count = 2
|
58
|
-
missing_flag =
|
58
|
+
missing_flag = MISSING{}
|
59
59
|
|
60
60
|
[temperature]
|
61
61
|
source_file = temperature-10min.hts
|
@@ -69,7 +69,7 @@ explanatory comments that follow it:
|
|
69
69
|
|
70
70
|
With the above configuration file, ``haggregate`` will log information
|
71
71
|
in the file specified by ``logfile``. It will aggregate the
|
72
|
-
specified time series into hourly (``
|
72
|
+
specified time series into hourly (``1h``). The filenames specified with
|
73
73
|
:option:`source_file` and :option:`target_file` are relative to
|
74
74
|
``base_dir``. For the temperature, source records will be
|
75
75
|
averaged, whereas for rainfall they will be summed.
|
@@ -108,8 +108,8 @@ General parameters
|
|
108
108
|
.. option:: target_step
|
109
109
|
|
110
110
|
A string specifying the target time step, as a pandas "frequency".
|
111
|
-
Examples of steps are "1D" for day, "
|
112
|
-
minute. You can also use larger multipliers, like "
|
111
|
+
Examples of steps are "1D" for day, "1h" for hour, "1min" for
|
112
|
+
minute. You can also use larger multipliers, like "30min" for 30 minutes.
|
113
113
|
The program hasn't been tested for monthly or larger time steps.
|
114
114
|
|
115
115
|
.. option:: target_timestamp_offset
|
@@ -133,7 +133,8 @@ General parameters
|
|
133
133
|
to a destination record, the resulting destination record is null;
|
134
134
|
otherwise, the destination record is derived even though some records
|
135
135
|
are missing. In that case, the flag specified by
|
136
|
-
:option:`missing_flag` is raised in the destination record.
|
136
|
+
:option:`missing_flag` is raised in the destination record. See
|
137
|
+
:meth:`~haggregate.aggregate` for details on :option:`missing_flag`.
|
137
138
|
|
138
139
|
Time series sections
|
139
140
|
--------------------
|
@@ -250,8 +250,8 @@ The parameters available are:
|
|
250
250
|
|
251
251
|
**Time_step**
|
252
252
|
In version 5, a pandas "frequency" string such as ``10min`` (10
|
253
|
-
minutes), ``
|
254
|
-
the time series is without time step.
|
253
|
+
minutes), ``1h`` (one hour), or ``2M`` (two months). If missing or
|
254
|
+
empty, the time series is without time step.
|
255
255
|
|
256
256
|
Up to version 4, a comma-separated pair of integers; the number of
|
257
257
|
minutes and months in the time step (one of the two must be zero).
|
@@ -2,7 +2,6 @@ import configparser
|
|
2
2
|
import datetime as dt
|
3
3
|
import logging
|
4
4
|
import os
|
5
|
-
import sys
|
6
5
|
import traceback
|
7
6
|
|
8
7
|
import click
|
@@ -81,7 +80,6 @@ class AppConfig:
|
|
81
80
|
try:
|
82
81
|
self._parse_config()
|
83
82
|
except (OSError, configparser.Error) as e:
|
84
|
-
sys.stderr.write(str(e))
|
85
83
|
raise click.ClickException(str(e))
|
86
84
|
|
87
85
|
def _parse_config(self):
|
@@ -2,7 +2,6 @@ import configparser
|
|
2
2
|
import datetime as dt
|
3
3
|
import logging
|
4
4
|
import os
|
5
|
-
import sys
|
6
5
|
import traceback
|
7
6
|
from glob import glob
|
8
7
|
from io import StringIO
|
@@ -100,7 +99,6 @@ class AppConfig:
|
|
100
99
|
try:
|
101
100
|
self._parse_config()
|
102
101
|
except (OSError, configparser.Error) as e:
|
103
|
-
sys.stderr.write(str(e))
|
104
102
|
raise click.ClickException(str(e))
|
105
103
|
|
106
104
|
def _parse_config(self):
|
@@ -155,10 +153,10 @@ class AppConfig:
|
|
155
153
|
self.time_step = s
|
156
154
|
|
157
155
|
def _check_time_step(self, s):
|
158
|
-
if s not in ("D", "
|
156
|
+
if s not in ("D", "h"):
|
159
157
|
raise WrongValueError(
|
160
158
|
'"{}" is not an appropriate time step; in this version of '
|
161
|
-
"vaporize, the step must be either D or
|
159
|
+
"vaporize, the step must be either D or h.".format(s)
|
162
160
|
)
|
163
161
|
|
164
162
|
def _parse_unit_converters(self):
|
@@ -412,11 +410,11 @@ class ProcessAtPoint:
|
|
412
410
|
self.pet.unit = "mm"
|
413
411
|
self.pet.timezone = self.timezone
|
414
412
|
self.pet.variable = "Potential Evapotranspiration"
|
415
|
-
self.pet.precision = 2 if self.config.time_step == "
|
413
|
+
self.pet.precision = 2 if self.config.time_step == "h" else 1
|
416
414
|
self.pet.location = self.location
|
417
415
|
|
418
416
|
def _determine_variables_to_use_in_calculation(self):
|
419
|
-
if self.config.time_step == "
|
417
|
+
if self.config.time_step == "h":
|
420
418
|
vars = ["temperature", "humidity", "wind_speed", "solar_radiation"]
|
421
419
|
if "pressure" in self.input_timeseries:
|
422
420
|
vars.append("pressure")
|
@@ -571,7 +569,7 @@ class ProcessSpatial:
|
|
571
569
|
self._read_input_geofile(var, timestamp)
|
572
570
|
|
573
571
|
def _get_variables(self):
|
574
|
-
if self.config.time_step == "
|
572
|
+
if self.config.time_step == "h":
|
575
573
|
return {
|
576
574
|
"temperature",
|
577
575
|
"humidity",
|
@@ -45,7 +45,7 @@ class PenmanMonteith(object):
|
|
45
45
|
self.unit_converters = unit_converters
|
46
46
|
|
47
47
|
def calculate(self, **kwargs):
|
48
|
-
if self.time_step == "
|
48
|
+
if self.time_step == "h":
|
49
49
|
return self.calculate_hourly(**kwargs)
|
50
50
|
elif self.time_step == "D":
|
51
51
|
return self.calculate_daily(**kwargs)
|
@@ -75,8 +75,8 @@ class Aggregation:
|
|
75
75
|
def get_result_flags(self):
|
76
76
|
max_count = int(pd.Timedelta(self.result.time_step) / self.source.freq)
|
77
77
|
values_count = self.resampler.count()
|
78
|
-
self.result.data["flags"] = (
|
79
|
-
lambda x: self.missing_flag if x else ""
|
78
|
+
self.result.data["flags"] = (max_count - values_count).apply(
|
79
|
+
lambda x: self.missing_flag.format(x) if x else ""
|
80
80
|
)
|
81
81
|
|
82
82
|
|
@@ -106,7 +106,7 @@ class SourceTimeseries(HTimeseries):
|
|
106
106
|
)
|
107
107
|
except ValueError:
|
108
108
|
raise CannotInferFrequency()
|
109
|
-
first_timestamp = (current_range[0] - pd.Timedelta("
|
109
|
+
first_timestamp = (current_range[0] - pd.Timedelta("1s")).floor(target_step)
|
110
110
|
end_timestamp = current_range[-1].ceil(target_step)
|
111
111
|
new_range = pd.date_range(first_timestamp, end_timestamp, freq=self.freq)
|
112
112
|
self.data = self.data.reindex(new_range)
|
@@ -116,8 +116,8 @@ class AggregatedTimeseries(HTimeseries):
|
|
116
116
|
def set_metadata(self, source_timeseries):
|
117
117
|
for attr in attrs:
|
118
118
|
setattr(self, attr, getattr(source_timeseries, attr, None))
|
119
|
-
if self.time_step not in ("
|
120
|
-
raise AggregateError("The target step can currently only be
|
119
|
+
if self.time_step not in ("1h", "1D"):
|
120
|
+
raise AggregateError("The target step can currently only be 1h or 1D")
|
121
121
|
if hasattr(source_timeseries, "title"):
|
122
122
|
self.title = "Aggregated " + source_timeseries.title
|
123
123
|
if hasattr(source_timeseries, "comment"):
|
@@ -140,7 +140,7 @@ class AggregatedTimeseries(HTimeseries):
|
|
140
140
|
|
141
141
|
|
142
142
|
def _get_offset_in_minutes(timestamp_offset):
|
143
|
-
m = re.match(r"(-?)(\d*)
|
143
|
+
m = re.match(r"(-?)(\d*)min$", timestamp_offset)
|
144
144
|
if not m:
|
145
145
|
raise AggregateError(
|
146
146
|
"The target timestamp offset can currently only be a number of minutes "
|