domainiac 8.0.10__tar.gz → 9.0.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.
- {domainiac-8.0.10 → domainiac-9.0.0}/PKG-INFO +1 -1
- domainiac-9.0.0/domainiac/functions/__init__.py +3 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/nwp_manager.py +40 -78
- {domainiac-8.0.10 → domainiac-9.0.0}/pyproject.toml +1 -1
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/__init__.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/functions/conversions.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/functions/interpolation.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/functions/solar.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/functions/temperature.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/functions/typing.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/functions/wind.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/__init__.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/masterdata_manager.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/metering_manager.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/outage_manager.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/plant_manager.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/resource_manager.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/managers/unit_manager.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/modeling/__init__.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/modeling/nwp.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/modeling/plant.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/wrappers/__init__.py +0 -0
- {domainiac-8.0.10 → domainiac-9.0.0}/domainiac/wrappers/cache_wrapper.py +0 -0
|
@@ -3,6 +3,8 @@ import numpy as np
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
from sklearn.neighbors import KDTree
|
|
5
5
|
|
|
6
|
+
from domainiac import functions
|
|
7
|
+
|
|
6
8
|
from ..modeling.nwp import Coordinate, Neighborhood, NWPParameter, NWPProvider
|
|
7
9
|
|
|
8
10
|
|
|
@@ -15,32 +17,6 @@ class NWPManager:
|
|
|
15
17
|
- Finding closest NWP coordinates
|
|
16
18
|
"""
|
|
17
19
|
|
|
18
|
-
NWP_INTERPOLATION_METHODS = {
|
|
19
|
-
# Wind and temperature are estimates
|
|
20
|
-
# of the instantaneous value at time t.
|
|
21
|
-
# We use linear interpolation.
|
|
22
|
-
NWPParameter.WIND: ("linear", "instantanous"),
|
|
23
|
-
NWPParameter.TEMPERATURE: ("linear", "instantanous"),
|
|
24
|
-
# solar is an estimate of the average value
|
|
25
|
-
# in the interval [t-1, t].
|
|
26
|
-
# We use PCHIP interpolation to ensure
|
|
27
|
-
# a smooth shape and non-negative values
|
|
28
|
-
# (https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.PchipInterpolator.html)
|
|
29
|
-
NWPParameter.SOLAR: ("pchip", "interval_average"),
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
NWP_RESOLUTIONS = {
|
|
33
|
-
(NWPProvider.ECMWF, NWPParameter.WIND): pd.Timedelta("PT3H"),
|
|
34
|
-
(NWPProvider.ECMWF, NWPParameter.TEMPERATURE): pd.Timedelta("PT3H"),
|
|
35
|
-
(NWPProvider.ECMWF, NWPParameter.SOLAR): pd.Timedelta("PT1H"),
|
|
36
|
-
(NWPProvider.DMI, NWPParameter.WIND): pd.Timedelta("PT1H"),
|
|
37
|
-
(NWPProvider.DMI, NWPParameter.TEMPERATURE): pd.Timedelta("PT1H"),
|
|
38
|
-
(NWPProvider.DMI, NWPParameter.SOLAR): pd.Timedelta("PT1H"),
|
|
39
|
-
(NWPProvider.CONWX, NWPParameter.WIND): pd.Timedelta("PT1H"),
|
|
40
|
-
(NWPProvider.CONWX, NWPParameter.TEMPERATURE): pd.Timedelta("PT1H"),
|
|
41
|
-
(NWPProvider.CONWX, NWPParameter.SOLAR): pd.Timedelta("PT1H"),
|
|
42
|
-
}
|
|
43
|
-
|
|
44
20
|
def __init__(
|
|
45
21
|
self,
|
|
46
22
|
db: pdz.Database,
|
|
@@ -54,22 +30,6 @@ class NWPManager:
|
|
|
54
30
|
self._nwp_coordinates_kd_tree = dict()
|
|
55
31
|
self._nwp_table_name_prefix = "forecastNwp"
|
|
56
32
|
|
|
57
|
-
@classmethod
|
|
58
|
-
def get_nwp_resolution(
|
|
59
|
-
cls, provider: NWPProvider, parameter: NWPParameter
|
|
60
|
-
) -> pd.Timedelta:
|
|
61
|
-
"""
|
|
62
|
-
Get the resolution of the NWP parameter.
|
|
63
|
-
"""
|
|
64
|
-
return cls.NWP_RESOLUTIONS[(provider, parameter)]
|
|
65
|
-
|
|
66
|
-
@classmethod
|
|
67
|
-
def get_nwp_interpolation_method(cls, parameter: NWPParameter) -> tuple[str, str]:
|
|
68
|
-
"""
|
|
69
|
-
Get the interpolation method and temporal aggregation for the NWP parameter.
|
|
70
|
-
"""
|
|
71
|
-
return cls.NWP_INTERPOLATION_METHODS[parameter]
|
|
72
|
-
|
|
73
33
|
@staticmethod
|
|
74
34
|
def calculate_wind_speed_from_vectors(u: pd.Series, v: pd.Series) -> pd.Series:
|
|
75
35
|
return np.sqrt(u**2 + v**2)
|
|
@@ -167,14 +127,14 @@ class NWPManager:
|
|
|
167
127
|
"altitude_m": coordinate.altitude,
|
|
168
128
|
}
|
|
169
129
|
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
130
|
+
# Since we need to interpolate along the time dimension, we need to pad
|
|
131
|
+
# the desired time interval when querying data, so we ensure we have data
|
|
132
|
+
# points to interpolate between. Padding with 6 hours should be enough
|
|
133
|
+
# for all our current NWP providers
|
|
134
|
+
query_margin = pd.Timedelta("P6H")
|
|
175
135
|
padded_time_interval = pdz.TimeInterval(
|
|
176
|
-
self.time_interval.left -
|
|
177
|
-
self.time_interval.right +
|
|
136
|
+
self.time_interval.left - query_margin,
|
|
137
|
+
self.time_interval.right + query_margin,
|
|
178
138
|
)
|
|
179
139
|
|
|
180
140
|
df = self.db.query(table, padded_time_interval, filters=filters)
|
|
@@ -205,41 +165,43 @@ class NWPManager:
|
|
|
205
165
|
"""
|
|
206
166
|
df = self._get_nwp_parameter(provider, parameter, coordinate)
|
|
207
167
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
168
|
+
df = df.sort_values(by="time_utc")
|
|
169
|
+
|
|
170
|
+
if parameter == NWPParameter.TEMPERATURE:
|
|
171
|
+
column_names = "temperature_K"
|
|
172
|
+
interpolated_function = functions.interpolate_temperature(
|
|
173
|
+
times=df["time_utc"], temperature=df[column_names]
|
|
174
|
+
)
|
|
175
|
+
elif parameter == NWPParameter.SOLAR:
|
|
176
|
+
column_names = "global_radiation_W_m2"
|
|
177
|
+
interpolated_function = functions.interpolate_irradiance(
|
|
178
|
+
coordinate=coordinate,
|
|
179
|
+
times=df["time_utc"],
|
|
180
|
+
radiation_avg=df[column_names].iloc[1:],
|
|
181
|
+
)
|
|
182
|
+
elif parameter == NWPParameter.WIND:
|
|
183
|
+
column_names = ["wind_u_m_s", "wind_v_m_s"]
|
|
184
|
+
interpolated_function = functions.interpolate_wind_components(
|
|
185
|
+
times=df["time_utc"],
|
|
186
|
+
wind_components=df[column_names],
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
df_interpolated = self.time_interval.to_range(freq=self.resolution).to_frame(
|
|
190
|
+
name="time_utc"
|
|
211
191
|
)
|
|
212
192
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
# it makes best sense to interpolate from
|
|
216
|
-
# midpoint to midpoint. Otherwise, we just
|
|
217
|
-
# interpolate regularly.
|
|
218
|
-
case "interval_average":
|
|
219
|
-
shift = -1 / 2
|
|
220
|
-
case "instantanous":
|
|
221
|
-
shift = 0
|
|
222
|
-
|
|
223
|
-
df_shifted = pdz.shift_time(df, on="time_utc", period=shift * nwp_resolution)
|
|
224
|
-
|
|
225
|
-
# Interpolate
|
|
226
|
-
df_resampled = pdz.resample(
|
|
227
|
-
df_shifted, on="time_utc", resolution=self.resolution / 2
|
|
228
|
-
).interpolate(interpolation_method)
|
|
229
|
-
|
|
230
|
-
# Shift back time, so that the output time series again represents
|
|
231
|
-
# the value by the endpoint.
|
|
232
|
-
df_re_shifted = pdz.shift_time(
|
|
233
|
-
df_resampled, on="time_utc", period=-shift * self.resolution
|
|
193
|
+
df_interpolated[column_names] = interpolated_function(
|
|
194
|
+
df_interpolated["time_utc"]
|
|
234
195
|
)
|
|
235
196
|
|
|
236
|
-
#
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
197
|
+
# disallow extrapolation
|
|
198
|
+
df_interpolated = df_interpolated[
|
|
199
|
+
df_interpolated["time_utc"].between(
|
|
200
|
+
df["time_utc"].min(), df["time_utc"].max()
|
|
201
|
+
)
|
|
240
202
|
]
|
|
241
203
|
|
|
242
|
-
return
|
|
204
|
+
return df_interpolated
|
|
243
205
|
|
|
244
206
|
def get_nwp_parameter(
|
|
245
207
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|