pthelma 1.0.0__tar.gz → 2.0.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {pthelma-1.0.0 → pthelma-2.0.0}/.github/workflows/build_wheels.yml +1 -6
- {pthelma-1.0.0 → pthelma-2.0.0}/.github/workflows/run-tests.yml +1 -1
- {pthelma-1.0.0 → pthelma-2.0.0}/.gitignore +1 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/CHANGELOG.rst +11 -0
- {pthelma-1.0.0/src/pthelma.egg-info → pthelma-2.0.0}/PKG-INFO +3 -7
- {pthelma-1.0.0 → pthelma-2.0.0}/README.rst +2 -6
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/evaporation/api.rst +1 -1
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/haggregate/usage.rst +4 -4
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/htimeseries.rst +2 -2
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/index.rst +1 -0
- pthelma-2.0.0/docs/rocc.rst +77 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/pyproject.toml +1 -1
- pthelma-2.0.0/setup.py +20 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/enhydris_cache/cli.py +0 -2
- {pthelma-1.0.0 → pthelma-2.0.0}/src/evaporation/cli.py +5 -7
- {pthelma-1.0.0 → pthelma-2.0.0}/src/evaporation/evaporation.py +1 -1
- pthelma-2.0.0/src/haggregate/__init__.py +2 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/haggregate/haggregate.py +4 -4
- {pthelma-1.0.0 → pthelma-2.0.0}/src/haggregate/regularize.c +123 -123
- {pthelma-1.0.0 → pthelma-2.0.0}/src/hspatial/cli.py +2 -4
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma/_version.py +2 -2
- {pthelma-1.0.0 → pthelma-2.0.0/src/pthelma.egg-info}/PKG-INFO +3 -7
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma.egg-info/SOURCES.txt +7 -1
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma.egg-info/top_level.txt +1 -0
- pthelma-2.0.0/src/rocc/__init__.py +9 -0
- pthelma-2.0.0/src/rocc/calculation.c +17231 -0
- pthelma-2.0.0/src/rocc/calculation.pyx +182 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_cache/test_cli.py +32 -22
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/evaporation/test_cli.py +220 -197
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/evaporation/test_evaporation.py +5 -5
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/haggregate/test_haggregate.py +14 -14
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/hspatial/test_cli.py +41 -31
- pthelma-2.0.0/tests/rocc/__init__.py +0 -0
- pthelma-2.0.0/tests/rocc/test_rocc.py +190 -0
- pthelma-1.0.0/setup.py +0 -13
- pthelma-1.0.0/src/haggregate/__init__.py +0 -5
- {pthelma-1.0.0 → pthelma-2.0.0}/.readthedocs.yaml +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/GPL-3 +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/LICENSE.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/MANIFEST.in +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/Makefile +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/changelog.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/conf.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/enhydris_api_client.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/enhydris_cache/api.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/enhydris_cache/usage.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/evaporation/usage.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/haggregate/api.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/hspatial/api.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/hspatial/testutils.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/hspatial/usage.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/install.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/license.rst +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/docs/requirements.txt +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/setup.cfg +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/enhydris_api_client/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/enhydris_cache/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/enhydris_cache/enhydris_cache.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/evaporation/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/haggregate/cli.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/haggregate/regularize.pyx +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/hspatial/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/hspatial/hspatial.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/hspatial/test.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/htimeseries/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/htimeseries/htimeseries.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/htimeseries/timezone_utils.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma.egg-info/dependency_links.txt +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma.egg-info/entry_points.txt +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/src/pthelma.egg-info/requires.txt +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/test_e2e.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/test_misc.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/test_station.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/test_timeseries.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/test_timeseriesgroup.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_api_client/test_tsdata.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_cache/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/enhydris_cache/test_enhydris_cache.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/evaporation/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/haggregate/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/haggregate/test_cli.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/haggregate/test_regularize.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/hspatial/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/hspatial/test_hspatial.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/htimeseries/__init__.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/htimeseries/test_htimeseries.py +0 -0
- {pthelma-1.0.0 → pthelma-2.0.0}/tests/htimeseries/test_timezone_utils.py +0 -0
@@ -2,6 +2,17 @@
|
|
2
2
|
Changelog
|
3
3
|
=========
|
4
4
|
|
5
|
+
2.0.0 (2024-12-04)
|
6
|
+
==================
|
7
|
+
|
8
|
+
We now use "h" instead of "H", and generally we use modern pandas time
|
9
|
+
step ("frequency") designations.
|
10
|
+
|
11
|
+
1.1.0 (2024-12-01)
|
12
|
+
==================
|
13
|
+
|
14
|
+
Added package rocc (equivalent to rocc 3.0).
|
15
|
+
|
5
16
|
1.0.0 (2024-11-29)
|
6
17
|
==================
|
7
18
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pthelma
|
3
|
-
Version:
|
3
|
+
Version: 2.0.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>
|
@@ -34,9 +34,9 @@ Requires-Dist: gdal<4,>=1.10; extra == "all"
|
|
34
34
|
pthelma
|
35
35
|
=======
|
36
36
|
|
37
|
-
.. image:: https://github.com/openmeteo/pthelma/actions/workflows/run-tests
|
37
|
+
.. image:: https://github.com/openmeteo/pthelma/actions/workflows/run-tests.yml/badge.svg
|
38
38
|
:alt: Build button
|
39
|
-
:target: https://github.com/openmeteo/pthelma/actions/workflows/run-tests
|
39
|
+
:target: https://github.com/openmeteo/pthelma/actions/workflows/run-tests.yml
|
40
40
|
|
41
41
|
.. image:: https://codecov.io/github/openmeteo/pthelma/coverage.svg?branch=master
|
42
42
|
:alt: Coverage
|
@@ -45,10 +45,6 @@ pthelma
|
|
45
45
|
.. image:: https://img.shields.io/pypi/v/pthelma.svg
|
46
46
|
:target: https://pypi.python.org/pypi/pthelma
|
47
47
|
|
48
|
-
.. image:: https://pyup.io/repos/github/openmeteo/pthelma/shield.svg
|
49
|
-
:target: https://pyup.io/repos/github/openmeteo/pthelma/
|
50
|
-
:alt: Updates
|
51
|
-
|
52
48
|
A Python library with utilities for hydrological and meteorological time
|
53
49
|
series processing.
|
54
50
|
|
@@ -1,9 +1,9 @@
|
|
1
1
|
pthelma
|
2
2
|
=======
|
3
3
|
|
4
|
-
.. image:: https://github.com/openmeteo/pthelma/actions/workflows/run-tests
|
4
|
+
.. image:: https://github.com/openmeteo/pthelma/actions/workflows/run-tests.yml/badge.svg
|
5
5
|
:alt: Build button
|
6
|
-
:target: https://github.com/openmeteo/pthelma/actions/workflows/run-tests
|
6
|
+
:target: https://github.com/openmeteo/pthelma/actions/workflows/run-tests.yml
|
7
7
|
|
8
8
|
.. image:: https://codecov.io/github/openmeteo/pthelma/coverage.svg?branch=master
|
9
9
|
:alt: Coverage
|
@@ -12,10 +12,6 @@ pthelma
|
|
12
12
|
.. image:: https://img.shields.io/pypi/v/pthelma.svg
|
13
13
|
:target: https://pypi.python.org/pypi/pthelma
|
14
14
|
|
15
|
-
.. image:: https://pyup.io/repos/github/openmeteo/pthelma/shield.svg
|
16
|
-
:target: https://pyup.io/repos/github/openmeteo/pthelma/
|
17
|
-
:alt: Updates
|
18
|
-
|
19
15
|
A Python library with utilities for hydrological and meteorological time
|
20
16
|
series processing.
|
21
17
|
|
@@ -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
|
@@ -53,7 +53,7 @@ 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
58
|
missing_flag = DATEINSERT
|
59
59
|
|
@@ -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
|
@@ -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).
|
@@ -0,0 +1,77 @@
|
|
1
|
+
===========================================
|
2
|
+
rocc - Rate-of-change check for time series
|
3
|
+
===========================================
|
4
|
+
|
5
|
+
.. class:: Threshold
|
6
|
+
|
7
|
+
A named tuple whose items are :attr:`delta_t` (a pandas interval
|
8
|
+
specification) and :attr:`allowed_diff` (a floating point number).
|
9
|
+
|
10
|
+
.. function:: rocc.rocc(ahtimeseries, thresholds, symmetric=False, flag="TEMPORAL")
|
11
|
+
|
12
|
+
Example ::
|
13
|
+
|
14
|
+
from rocc import Threshold, rocc
|
15
|
+
|
16
|
+
result = rocc(
|
17
|
+
timeseries=a_htimeseries_object,
|
18
|
+
thresholds=(
|
19
|
+
Threshold("10min", 10),
|
20
|
+
Threshold("20min", 15),
|
21
|
+
Threshold("h", 40),
|
22
|
+
),
|
23
|
+
symmetric=True,
|
24
|
+
flag="MYFLAG",
|
25
|
+
)
|
26
|
+
|
27
|
+
``timeseries`` is a :class:`HTimeseries` object. ``thresholds`` is
|
28
|
+
a list of :class:`Threshold` objects.
|
29
|
+
|
30
|
+
The function checks whether there exist intervals during which the
|
31
|
+
value of the time series changes by more than the specified
|
32
|
+
threshold. The offending records are flagged with the specified
|
33
|
+
``flag``.
|
34
|
+
|
35
|
+
It returns a list of strings describing where the thresholds have been
|
36
|
+
exceeded.
|
37
|
+
|
38
|
+
If ``flag`` is ``None`` or the empty string, then the offending records
|
39
|
+
are not flagged, and the only result is the returned value.
|
40
|
+
|
41
|
+
Here is an example time series::
|
42
|
+
|
43
|
+
2020-10-06 14:30 24.0
|
44
|
+
2020-10-06 14:40 25.0
|
45
|
+
2020-10-06 14:50 36.0 *
|
46
|
+
2020-10-06 15:01 51.0
|
47
|
+
2020-10-06 15:21 55.0
|
48
|
+
2020-10-06 15:31 65.0
|
49
|
+
2020-10-06 15:41 75.0 *
|
50
|
+
2020-10-06 15:51 70.0
|
51
|
+
|
52
|
+
After running ``rocc()`` with the ``thresholds`` specified in the
|
53
|
+
example above, the records marked with a star will be flagged. The
|
54
|
+
record ``14:50`` will be flagged because in the preceding 10-minute
|
55
|
+
interval the value increases by 11, which is more than 10. The record
|
56
|
+
``15:41`` will be flagged because in the preceding 20-minute interval
|
57
|
+
the value increases by 20, which is more than 15. The record ``15:01``
|
58
|
+
will be unflagged; although there's a large difference since ``14:40``,
|
59
|
+
this is 21 minutes, not 20, so the 20-minute threshold of 15 does not
|
60
|
+
apply; likewise, there's a difference of 15 from ``14:50``, which does
|
61
|
+
not exceed the 20-minute threshold of 15, and while it does exceed the
|
62
|
+
10-minute threshold of 10, it's 11 minutes, not 10. There's also not any
|
63
|
+
difference larger than 40 within an hour anywhere.
|
64
|
+
|
65
|
+
The return value in this example will be a list of two strings::
|
66
|
+
|
67
|
+
"2020-10-06T14:50 +11.0 in 10min (> 10.0)"
|
68
|
+
"2020-10-06T15:41 +20.0 in 20min (> 15.0)"
|
69
|
+
|
70
|
+
The return value should only be used for consumption by humans; it is
|
71
|
+
subject to change.
|
72
|
+
|
73
|
+
If ``symmetric`` is ``True``, it is the absolute value of the change
|
74
|
+
that matters, not its direction. In this case, ``allowed_diff`` must be
|
75
|
+
positive. If ``symmetric`` is ``False`` (the default), only rates larger
|
76
|
+
than positive ``allow_diff`` or rates smaller than negative
|
77
|
+
``allow_diff`` are flagged.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[build-system]
|
2
2
|
# numpy<2 is not just a dependency, it's a build dependency, because it's
|
3
|
-
# needed to build
|
3
|
+
# needed to build some .pyx files (and the _gdal_array thing, which gdal won't
|
4
4
|
# build if numpy is not available at build time). It's at "<2" because of gdal;
|
5
5
|
# pthelma can also use ">=2".
|
6
6
|
requires = ["setuptools>=61.0", "setuptools-scm>=7.1", "cython", "numpy<2"]
|
pthelma-2.0.0/setup.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
import numpy
|
2
|
+
from Cython.Build import cythonize
|
3
|
+
from setuptools import Extension, setup
|
4
|
+
|
5
|
+
setup(
|
6
|
+
ext_modules=cythonize(
|
7
|
+
[
|
8
|
+
Extension(
|
9
|
+
"haggregate.regularize",
|
10
|
+
sources=["src/haggregate/regularize.pyx"],
|
11
|
+
include_dirs=[numpy.get_include()],
|
12
|
+
),
|
13
|
+
Extension(
|
14
|
+
"rocc.calculation",
|
15
|
+
sources=["src/rocc/calculation.pyx"],
|
16
|
+
include_dirs=[numpy.get_include()],
|
17
|
+
),
|
18
|
+
]
|
19
|
+
),
|
20
|
+
)
|
@@ -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)
|
@@ -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 "
|