foxes 1.2.2__py3-none-any.whl → 1.2.3__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.
Potentially problematic release.
This version of foxes might be problematic. Click here for more details.
- examples/field_data_nc/run.py +11 -4
- examples/streamline_wakes/run.py +6 -3
- foxes/algorithms/downwind/downwind.py +1 -0
- foxes/config/__init__.py +1 -1
- foxes/config/config.py +80 -14
- foxes/constants.py +12 -1
- foxes/core/algorithm.py +13 -8
- foxes/core/engine.py +30 -0
- foxes/core/farm_controller.py +41 -24
- foxes/core/states.py +1 -1
- foxes/core/wind_farm.py +109 -0
- foxes/engines/dask.py +88 -4
- foxes/engines/default.py +45 -2
- foxes/engines/mpi.py +5 -16
- foxes/engines/multiprocess.py +1 -10
- foxes/engines/numpy.py +30 -0
- foxes/engines/pool.py +48 -0
- foxes/engines/ray.py +1 -1
- foxes/engines/single.py +30 -0
- foxes/input/farm_layout/from_csv.py +2 -2
- foxes/input/farm_layout/from_file.py +2 -2
- foxes/input/farm_layout/from_json.py +2 -2
- foxes/input/states/__init__.py +0 -1
- foxes/input/states/create/random_abl_states.py +2 -2
- foxes/input/states/field_data_nc.py +286 -141
- foxes/input/states/multi_height.py +3 -3
- foxes/input/states/states_table.py +3 -3
- foxes/input/yaml/dict.py +83 -46
- foxes/input/yaml/windio/__init__.py +2 -1
- foxes/input/yaml/windio/read_attributes.py +17 -34
- foxes/input/yaml/windio/read_farm.py +57 -3
- foxes/input/yaml/windio/read_outputs.py +116 -56
- foxes/input/yaml/windio/{get_states.py → read_site.py} +69 -0
- foxes/input/yaml/windio/windio.py +42 -119
- foxes/input/yaml/yaml.py +3 -3
- foxes/models/model_book.py +1 -0
- foxes/models/point_models/__init__.py +1 -0
- foxes/models/point_models/ustar2ti.py +84 -0
- foxes/models/turbine_models/lookup_table.py +2 -2
- foxes/models/turbine_models/sector_management.py +2 -2
- foxes/models/turbine_models/table_factors.py +2 -2
- foxes/models/turbine_types/CpCt_file.py +2 -2
- foxes/models/turbine_types/CpCt_from_two.py +3 -3
- foxes/models/turbine_types/PCt_file.py +2 -2
- foxes/models/turbine_types/PCt_from_two.py +3 -3
- foxes/models/turbine_types/TBL_file.py +2 -2
- foxes/models/turbine_types/wsrho2PCt_from_two.py +3 -3
- foxes/models/turbine_types/wsti2PCt_from_two.py +3 -3
- foxes/output/__init__.py +1 -0
- foxes/output/output.py +5 -3
- foxes/output/slice_data.py +1 -1
- foxes/output/slices_data.py +323 -0
- foxes/output/state_turbine_table.py +11 -0
- foxes/utils/load.py +12 -4
- foxes/utils/xarray_utils.py +14 -3
- foxes/variables.py +5 -0
- {foxes-1.2.2.dist-info → foxes-1.2.3.dist-info}/METADATA +6 -2
- {foxes-1.2.2.dist-info → foxes-1.2.3.dist-info}/RECORD +62 -61
- foxes/input/states/slice_data_nc.py +0 -687
- {foxes-1.2.2.dist-info → foxes-1.2.3.dist-info}/LICENSE +0 -0
- {foxes-1.2.2.dist-info → foxes-1.2.3.dist-info}/WHEEL +0 -0
- {foxes-1.2.2.dist-info → foxes-1.2.3.dist-info}/entry_points.txt +0 -0
- {foxes-1.2.2.dist-info → foxes-1.2.3.dist-info}/top_level.txt +0 -0
|
@@ -1,687 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import xarray as xr
|
|
4
|
-
from scipy.interpolate import interpn
|
|
5
|
-
|
|
6
|
-
from foxes.core import States
|
|
7
|
-
from foxes.utils import wd2uv, uv2wd, import_module
|
|
8
|
-
from foxes.data import STATES, StaticData
|
|
9
|
-
from foxes.config import config, get_path
|
|
10
|
-
import foxes.variables as FV
|
|
11
|
-
import foxes.constants as FC
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class SliceDataNC(States):
|
|
15
|
-
"""
|
|
16
|
-
Heterogeneous ambient states on a regular
|
|
17
|
-
horizontal grid in NetCDF format, independent
|
|
18
|
-
of height.
|
|
19
|
-
|
|
20
|
-
Attributes
|
|
21
|
-
----------
|
|
22
|
-
data_source: str or xarray.Dataset
|
|
23
|
-
The data or the file search pattern, should end with
|
|
24
|
-
suffix '.nc'. One or many files.
|
|
25
|
-
ovars: list of str
|
|
26
|
-
The output variables
|
|
27
|
-
var2ncvar: dict
|
|
28
|
-
Mapping from variable names to variable names
|
|
29
|
-
in the nc file
|
|
30
|
-
fixed_vars: dict
|
|
31
|
-
Uniform values for output variables, instead
|
|
32
|
-
of reading from data
|
|
33
|
-
states_coord: str
|
|
34
|
-
The states coordinate name in the data
|
|
35
|
-
x_coord: str
|
|
36
|
-
The x coordinate name in the data
|
|
37
|
-
y_coord: str
|
|
38
|
-
The y coordinate name in the data
|
|
39
|
-
pre_load: bool
|
|
40
|
-
Flag for loading all data into memory during
|
|
41
|
-
initialization
|
|
42
|
-
weight_ncvar: str
|
|
43
|
-
Name of the weight data variable in the nc file(s)
|
|
44
|
-
bounds_error: bool
|
|
45
|
-
Flag for raising errors if bounds are exceeded
|
|
46
|
-
fill_value: number
|
|
47
|
-
Fill value in case of exceeding bounds, if no bounds error
|
|
48
|
-
time_format: str
|
|
49
|
-
The datetime parsing format string
|
|
50
|
-
interp_nans: bool
|
|
51
|
-
Linearly interpolate nan values
|
|
52
|
-
interpn_pars: dict, optional
|
|
53
|
-
Additional parameters for scipy.interpolate.interpn
|
|
54
|
-
|
|
55
|
-
:group: input.states
|
|
56
|
-
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
def __init__(
|
|
60
|
-
self,
|
|
61
|
-
data_source,
|
|
62
|
-
output_vars,
|
|
63
|
-
var2ncvar={},
|
|
64
|
-
fixed_vars={},
|
|
65
|
-
states_coord="Time",
|
|
66
|
-
x_coord="UTMX",
|
|
67
|
-
y_coord="UTMY",
|
|
68
|
-
pre_load=True,
|
|
69
|
-
weight_ncvar=None,
|
|
70
|
-
time_format="%Y-%m-%d_%H:%M:%S",
|
|
71
|
-
sel=None,
|
|
72
|
-
isel=None,
|
|
73
|
-
interp_nans=False,
|
|
74
|
-
verbosity=1,
|
|
75
|
-
**interpn_pars,
|
|
76
|
-
):
|
|
77
|
-
"""
|
|
78
|
-
Constructor.
|
|
79
|
-
|
|
80
|
-
Parameters
|
|
81
|
-
----------
|
|
82
|
-
data_source: str or xarray.Dataset
|
|
83
|
-
The data or the file search pattern, should end with
|
|
84
|
-
suffix '.nc'. One or many files.
|
|
85
|
-
output_vars: list of str
|
|
86
|
-
The output variables
|
|
87
|
-
var2ncvar: dict, optional
|
|
88
|
-
Mapping from variable names to variable names
|
|
89
|
-
in the nc file
|
|
90
|
-
fixed_vars: dict, optional
|
|
91
|
-
Uniform values for output variables, instead
|
|
92
|
-
of reading from data
|
|
93
|
-
states_coord: str
|
|
94
|
-
The states coordinate name in the data
|
|
95
|
-
x_coord: str
|
|
96
|
-
The x coordinate name in the data
|
|
97
|
-
y_coord: str
|
|
98
|
-
The y coordinate name in the data
|
|
99
|
-
pre_load: bool
|
|
100
|
-
Flag for loading all data into memory during
|
|
101
|
-
initialization
|
|
102
|
-
weight_ncvar: str, optional
|
|
103
|
-
Name of the weight data variable in the nc file(s)
|
|
104
|
-
time_format: str
|
|
105
|
-
The datetime parsing format string
|
|
106
|
-
sel: dict, optional
|
|
107
|
-
Subset selection via xr.Dataset.sel()
|
|
108
|
-
isel: dict, optional
|
|
109
|
-
Subset selection via xr.Dataset.isel()
|
|
110
|
-
interp_nans: bool
|
|
111
|
-
Linearly interpolate nan values
|
|
112
|
-
verbosity: int
|
|
113
|
-
Verbosity level for pre_load file reading
|
|
114
|
-
interpn_pars: dict, optional
|
|
115
|
-
Additional parameters for scipy.interpolate.interpn
|
|
116
|
-
|
|
117
|
-
"""
|
|
118
|
-
super().__init__()
|
|
119
|
-
|
|
120
|
-
self.states_coord = states_coord
|
|
121
|
-
self.ovars = output_vars
|
|
122
|
-
self.fixed_vars = fixed_vars
|
|
123
|
-
self.x_coord = x_coord
|
|
124
|
-
self.y_coord = y_coord
|
|
125
|
-
self.weight_ncvar = weight_ncvar
|
|
126
|
-
self.pre_load = pre_load
|
|
127
|
-
self.time_format = time_format
|
|
128
|
-
self.sel = sel
|
|
129
|
-
self.isel = isel
|
|
130
|
-
self.interpn_pars = interpn_pars
|
|
131
|
-
self.interp_nans = interp_nans
|
|
132
|
-
|
|
133
|
-
self.var2ncvar = {
|
|
134
|
-
v: var2ncvar.get(v, v) for v in output_vars if v not in fixed_vars
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
self._N = None
|
|
138
|
-
|
|
139
|
-
self.__data_source = data_source
|
|
140
|
-
self.__weights = None
|
|
141
|
-
self.__inds = None
|
|
142
|
-
|
|
143
|
-
# pre-load file reading:
|
|
144
|
-
if not isinstance(self.data_source, xr.Dataset):
|
|
145
|
-
if "*" in str(self.data_source):
|
|
146
|
-
pass
|
|
147
|
-
else:
|
|
148
|
-
self.__data_source = get_path(self.data_source)
|
|
149
|
-
if not self.data_source.is_file():
|
|
150
|
-
self.__data_source = StaticData().get_file_path(
|
|
151
|
-
STATES, self.data_source.name, check_raw=False
|
|
152
|
-
)
|
|
153
|
-
if verbosity:
|
|
154
|
-
if pre_load:
|
|
155
|
-
print(
|
|
156
|
-
f"States '{self.name}': Reading data from '{self.data_source}'"
|
|
157
|
-
)
|
|
158
|
-
else:
|
|
159
|
-
print(
|
|
160
|
-
f"States '{self.name}': Reading index from '{self.data_source}'"
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
def _read_ds():
|
|
164
|
-
self._data_source = get_path(self.data_source)
|
|
165
|
-
if self.data_source.is_file():
|
|
166
|
-
return xr.open_dataset(self.data_source)
|
|
167
|
-
else:
|
|
168
|
-
# try to read multiple files, needs dask:
|
|
169
|
-
try:
|
|
170
|
-
return xr.open_mfdataset(
|
|
171
|
-
str(self.data_source),
|
|
172
|
-
parallel=False,
|
|
173
|
-
concat_dim=self.states_coord,
|
|
174
|
-
combine="nested",
|
|
175
|
-
data_vars="minimal",
|
|
176
|
-
coords="minimal",
|
|
177
|
-
compat="override",
|
|
178
|
-
)
|
|
179
|
-
except ValueError as e:
|
|
180
|
-
import_module("dask", hint="pip install dask")
|
|
181
|
-
raise e
|
|
182
|
-
|
|
183
|
-
self.__data_source = _read_ds()
|
|
184
|
-
|
|
185
|
-
if sel is not None:
|
|
186
|
-
self.__data_source = self.data_source.sel(self.sel)
|
|
187
|
-
if isel is not None:
|
|
188
|
-
self.__data_source = self.data_source.isel(self.isel)
|
|
189
|
-
if pre_load:
|
|
190
|
-
self.__data_source.load()
|
|
191
|
-
|
|
192
|
-
self._get_inds(self.data_source)
|
|
193
|
-
|
|
194
|
-
@property
|
|
195
|
-
def data_source(self):
|
|
196
|
-
"""
|
|
197
|
-
The data source
|
|
198
|
-
|
|
199
|
-
Returns
|
|
200
|
-
-------
|
|
201
|
-
s: object
|
|
202
|
-
The data source
|
|
203
|
-
|
|
204
|
-
"""
|
|
205
|
-
if self.pre_load and self.running:
|
|
206
|
-
raise ValueError(
|
|
207
|
-
f"States '{self.name}': Cannot acces data_source while running"
|
|
208
|
-
)
|
|
209
|
-
return self.__data_source
|
|
210
|
-
|
|
211
|
-
def _get_inds(self, ds):
|
|
212
|
-
"""
|
|
213
|
-
Helper function for index and weights
|
|
214
|
-
reading
|
|
215
|
-
"""
|
|
216
|
-
for c in [self.states_coord, self.x_coord, self.y_coord]:
|
|
217
|
-
if not c in ds:
|
|
218
|
-
raise KeyError(
|
|
219
|
-
f"States '{self.name}': Missing coordinate '{c}' in data"
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
self.__inds = ds[self.states_coord].to_numpy()
|
|
223
|
-
if self.time_format is not None:
|
|
224
|
-
self.__inds = pd.to_datetime(
|
|
225
|
-
self.__inds, format=self.time_format
|
|
226
|
-
).to_numpy()
|
|
227
|
-
self._N = len(self.__inds)
|
|
228
|
-
|
|
229
|
-
if self.weight_ncvar is not None:
|
|
230
|
-
self.__weights = ds[self.weight_ncvar].to_numpy()
|
|
231
|
-
|
|
232
|
-
for v in self.ovars:
|
|
233
|
-
if v in self.var2ncvar:
|
|
234
|
-
ncv = self.var2ncvar[v]
|
|
235
|
-
if not ncv in ds:
|
|
236
|
-
raise KeyError(
|
|
237
|
-
f"States '{self.name}': nc variable '{ncv}' not found in data, found: {sorted(list(ds.keys()))}"
|
|
238
|
-
)
|
|
239
|
-
elif v not in self.fixed_vars:
|
|
240
|
-
raise ValueError(
|
|
241
|
-
f"States '{self.name}': Variable '{v}' neither found in var2ncvar not in fixed_vars"
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
def _get_data(self, ds, verbosity):
|
|
245
|
-
"""
|
|
246
|
-
Helper function for data extraction
|
|
247
|
-
"""
|
|
248
|
-
x = ds[self.x_coord].to_numpy()
|
|
249
|
-
y = ds[self.y_coord].to_numpy()
|
|
250
|
-
n_x = len(x)
|
|
251
|
-
n_y = len(y)
|
|
252
|
-
n_sts = ds.sizes[self.states_coord]
|
|
253
|
-
|
|
254
|
-
cor_sxy = (self.states_coord, self.x_coord, self.y_coord)
|
|
255
|
-
cor_syx = (self.states_coord, self.y_coord, self.x_coord)
|
|
256
|
-
cor_s = (self.states_coord,)
|
|
257
|
-
vars_syx = []
|
|
258
|
-
vars_s = []
|
|
259
|
-
for v, ncv in self.var2ncvar.items():
|
|
260
|
-
if ds[ncv].dims == cor_syx or ds[ncv].dims == cor_sxy:
|
|
261
|
-
vars_syx.append(v)
|
|
262
|
-
elif ds[ncv].dims == cor_s:
|
|
263
|
-
vars_s.append(v)
|
|
264
|
-
else:
|
|
265
|
-
raise ValueError(
|
|
266
|
-
f"States '{self.name}': Wrong coordinate order for variable '{ncv}': Found {ds[ncv].dims}, expecting {cor_sxy}, {cor_syx}, or {cor_s}"
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
data = np.zeros(
|
|
270
|
-
(n_sts, n_y, n_x, len(self.var2ncvar)), dtype=config.dtype_double
|
|
271
|
-
)
|
|
272
|
-
for v in vars_syx:
|
|
273
|
-
ncv = self.var2ncvar[v]
|
|
274
|
-
if ds[ncv].dims == cor_syx:
|
|
275
|
-
data[..., self._dkys[v]] = ds[ncv][:]
|
|
276
|
-
else:
|
|
277
|
-
data[..., self._dkys[v]] = np.swapaxes(ds[ncv].to_numpy(), 1, 2)
|
|
278
|
-
for v in vars_s:
|
|
279
|
-
ncv = self.var2ncvar[v]
|
|
280
|
-
data[..., self._dkys[v]] = ds[ncv].to_numpy()[:, None, None]
|
|
281
|
-
if FV.WD in self.fixed_vars:
|
|
282
|
-
data[..., self._dkys[FV.WD]] = np.full(
|
|
283
|
-
(n_sts, n_y, n_x), self.fixed_vars[FV.WD], dtype=config.dtype_double
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
if verbosity > 1:
|
|
287
|
-
print(f"\n{self.name}: Data ranges")
|
|
288
|
-
for v, i in self._dkys.items():
|
|
289
|
-
d = data[..., i]
|
|
290
|
-
nn = np.sum(np.isnan(d))
|
|
291
|
-
print(
|
|
292
|
-
f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100*nn/len(d.flat):.2f}%)"
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
return data
|
|
296
|
-
|
|
297
|
-
def output_point_vars(self, algo):
|
|
298
|
-
"""
|
|
299
|
-
The variables which are being modified by the model.
|
|
300
|
-
|
|
301
|
-
Parameters
|
|
302
|
-
----------
|
|
303
|
-
algo: foxes.core.Algorithm
|
|
304
|
-
The calculation algorithm
|
|
305
|
-
|
|
306
|
-
Returns
|
|
307
|
-
-------
|
|
308
|
-
output_vars: list of str
|
|
309
|
-
The output variable names
|
|
310
|
-
|
|
311
|
-
"""
|
|
312
|
-
return self.ovars
|
|
313
|
-
|
|
314
|
-
def load_data(self, algo, verbosity=0):
|
|
315
|
-
"""
|
|
316
|
-
Load and/or create all model data that is subject to chunking.
|
|
317
|
-
|
|
318
|
-
Such data should not be stored under self, for memory reasons. The
|
|
319
|
-
data returned here will automatically be chunked and then provided
|
|
320
|
-
as part of the mdata object during calculations.
|
|
321
|
-
|
|
322
|
-
Parameters
|
|
323
|
-
----------
|
|
324
|
-
algo: foxes.core.Algorithm
|
|
325
|
-
The calculation algorithm
|
|
326
|
-
verbosity: int
|
|
327
|
-
The verbosity level, 0 = silent
|
|
328
|
-
|
|
329
|
-
Returns
|
|
330
|
-
-------
|
|
331
|
-
idata: dict
|
|
332
|
-
The dict has exactly two entries: `data_vars`,
|
|
333
|
-
a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
|
|
334
|
-
and `coords`, a dict with entries `dim_name_str -> dim_array`
|
|
335
|
-
|
|
336
|
-
"""
|
|
337
|
-
|
|
338
|
-
if (FV.WS in self.ovars and FV.WD not in self.ovars) or (
|
|
339
|
-
FV.WS not in self.ovars and FV.WD in self.ovars
|
|
340
|
-
):
|
|
341
|
-
raise KeyError(
|
|
342
|
-
f"States '{self.name}': Missing '{FV.WS}' or '{FV.WD}' in output variables {self.ovars}"
|
|
343
|
-
)
|
|
344
|
-
|
|
345
|
-
# ensure WD and WS get the first two slots of data:
|
|
346
|
-
self._dkys = {}
|
|
347
|
-
if FV.WS in self.ovars:
|
|
348
|
-
self._dkys[FV.WD] = 0
|
|
349
|
-
if FV.WS in self.var2ncvar:
|
|
350
|
-
self._dkys[FV.WS] = 1
|
|
351
|
-
for v in self.var2ncvar:
|
|
352
|
-
if v not in self._dkys:
|
|
353
|
-
self._dkys[v] = len(self._dkys)
|
|
354
|
-
self._n_dvars = len(self._dkys)
|
|
355
|
-
|
|
356
|
-
if self.__weights is None:
|
|
357
|
-
self.__weights = np.full(
|
|
358
|
-
(self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
|
|
359
|
-
)
|
|
360
|
-
|
|
361
|
-
idata = super().load_data(algo, verbosity)
|
|
362
|
-
|
|
363
|
-
if self.pre_load:
|
|
364
|
-
self.X = self.var(FV.X)
|
|
365
|
-
self.Y = self.var(FV.Y)
|
|
366
|
-
self.VARS = self.var("vars")
|
|
367
|
-
self.DATA = self.var("data")
|
|
368
|
-
|
|
369
|
-
ds = self.data_source
|
|
370
|
-
|
|
371
|
-
y = ds[self.y_coord].to_numpy()
|
|
372
|
-
x = ds[self.x_coord].to_numpy()
|
|
373
|
-
v = list(self._dkys.keys())
|
|
374
|
-
coos = (FC.STATE, self.Y, self.X, self.VARS)
|
|
375
|
-
data = self._get_data(ds, verbosity)
|
|
376
|
-
data = (coos, data)
|
|
377
|
-
|
|
378
|
-
idata["coords"][self.Y] = y
|
|
379
|
-
idata["coords"][self.X] = x
|
|
380
|
-
idata["coords"][self.VARS] = v
|
|
381
|
-
idata["data_vars"][self.DATA] = data
|
|
382
|
-
|
|
383
|
-
return idata
|
|
384
|
-
|
|
385
|
-
def set_running(
|
|
386
|
-
self,
|
|
387
|
-
algo,
|
|
388
|
-
data_stash,
|
|
389
|
-
sel=None,
|
|
390
|
-
isel=None,
|
|
391
|
-
verbosity=0,
|
|
392
|
-
):
|
|
393
|
-
"""
|
|
394
|
-
Sets this model status to running, and moves
|
|
395
|
-
all large data to stash.
|
|
396
|
-
|
|
397
|
-
The stashed data will be returned by the
|
|
398
|
-
unset_running() function after running calculations.
|
|
399
|
-
|
|
400
|
-
Parameters
|
|
401
|
-
----------
|
|
402
|
-
algo: foxes.core.Algorithm
|
|
403
|
-
The calculation algorithm
|
|
404
|
-
data_stash: dict
|
|
405
|
-
Large data stash, this function adds data here.
|
|
406
|
-
Key: model name. Value: dict, large model data
|
|
407
|
-
sel: dict, optional
|
|
408
|
-
The subset selection dictionary
|
|
409
|
-
isel: dict, optional
|
|
410
|
-
The index subset selection dictionary
|
|
411
|
-
verbosity: int
|
|
412
|
-
The verbosity level, 0 = silent
|
|
413
|
-
|
|
414
|
-
"""
|
|
415
|
-
super().set_running(algo, data_stash, sel, isel, verbosity)
|
|
416
|
-
|
|
417
|
-
data_stash[self.name] = dict(
|
|
418
|
-
weights=self.__weights,
|
|
419
|
-
inds=self.__inds,
|
|
420
|
-
)
|
|
421
|
-
del self.__weights, self.__inds
|
|
422
|
-
|
|
423
|
-
if self.pre_load:
|
|
424
|
-
data_stash[self.name]["data_source"] = self.__data_source
|
|
425
|
-
del self.__data_source
|
|
426
|
-
|
|
427
|
-
def unset_running(
|
|
428
|
-
self,
|
|
429
|
-
algo,
|
|
430
|
-
data_stash,
|
|
431
|
-
sel=None,
|
|
432
|
-
isel=None,
|
|
433
|
-
verbosity=0,
|
|
434
|
-
):
|
|
435
|
-
"""
|
|
436
|
-
Sets this model status to not running, recovering large data
|
|
437
|
-
from stash
|
|
438
|
-
|
|
439
|
-
Parameters
|
|
440
|
-
----------
|
|
441
|
-
algo: foxes.core.Algorithm
|
|
442
|
-
The calculation algorithm
|
|
443
|
-
data_stash: dict
|
|
444
|
-
Large data stash, this function adds data here.
|
|
445
|
-
Key: model name. Value: dict, large model data
|
|
446
|
-
sel: dict, optional
|
|
447
|
-
The subset selection dictionary
|
|
448
|
-
isel: dict, optional
|
|
449
|
-
The index subset selection dictionary
|
|
450
|
-
verbosity: int
|
|
451
|
-
The verbosity level, 0 = silent
|
|
452
|
-
|
|
453
|
-
"""
|
|
454
|
-
super().unset_running(algo, data_stash, sel, isel, verbosity)
|
|
455
|
-
|
|
456
|
-
data = data_stash[self.name]
|
|
457
|
-
self.__weights = data.pop("weights")
|
|
458
|
-
self.__inds = data.pop("inds")
|
|
459
|
-
|
|
460
|
-
if self.pre_load:
|
|
461
|
-
self.__data_source = data.pop("data_source")
|
|
462
|
-
|
|
463
|
-
def size(self):
|
|
464
|
-
"""
|
|
465
|
-
The total number of states.
|
|
466
|
-
|
|
467
|
-
Returns
|
|
468
|
-
-------
|
|
469
|
-
int:
|
|
470
|
-
The total number of states
|
|
471
|
-
|
|
472
|
-
"""
|
|
473
|
-
return self._N
|
|
474
|
-
|
|
475
|
-
def index(self):
|
|
476
|
-
"""
|
|
477
|
-
The index list
|
|
478
|
-
|
|
479
|
-
Returns
|
|
480
|
-
-------
|
|
481
|
-
indices: array_like
|
|
482
|
-
The index labels of states, or None for default integers
|
|
483
|
-
|
|
484
|
-
"""
|
|
485
|
-
if self.running:
|
|
486
|
-
raise ValueError(f"States '{self.name}': Cannot acces index while running")
|
|
487
|
-
return self.__inds
|
|
488
|
-
|
|
489
|
-
def output_point_vars(self, algo):
|
|
490
|
-
"""
|
|
491
|
-
The variables which are being modified by the model.
|
|
492
|
-
|
|
493
|
-
Parameters
|
|
494
|
-
----------
|
|
495
|
-
algo: foxes.core.Algorithm
|
|
496
|
-
The calculation algorithm
|
|
497
|
-
|
|
498
|
-
Returns
|
|
499
|
-
-------
|
|
500
|
-
output_vars: list of str
|
|
501
|
-
The output variable names
|
|
502
|
-
|
|
503
|
-
"""
|
|
504
|
-
return self.ovars
|
|
505
|
-
|
|
506
|
-
def weights(self, algo):
|
|
507
|
-
"""
|
|
508
|
-
The statistical weights of all states.
|
|
509
|
-
|
|
510
|
-
Parameters
|
|
511
|
-
----------
|
|
512
|
-
algo: foxes.core.Algorithm
|
|
513
|
-
The calculation algorithm
|
|
514
|
-
|
|
515
|
-
Returns
|
|
516
|
-
-------
|
|
517
|
-
weights: numpy.ndarray
|
|
518
|
-
The weights, shape: (n_states, n_turbines)
|
|
519
|
-
|
|
520
|
-
"""
|
|
521
|
-
if self.running:
|
|
522
|
-
raise ValueError(
|
|
523
|
-
f"States '{self.name}': Cannot acces weights while running"
|
|
524
|
-
)
|
|
525
|
-
return self.__weights
|
|
526
|
-
|
|
527
|
-
def calculate(self, algo, mdata, fdata, tdata):
|
|
528
|
-
""" "
|
|
529
|
-
The main model calculation.
|
|
530
|
-
|
|
531
|
-
This function is executed on a single chunk of data,
|
|
532
|
-
all computations should be based on numpy arrays.
|
|
533
|
-
|
|
534
|
-
Parameters
|
|
535
|
-
----------
|
|
536
|
-
algo: foxes.core.Algorithm
|
|
537
|
-
The calculation algorithm
|
|
538
|
-
mdata: foxes.core.MData
|
|
539
|
-
The model data
|
|
540
|
-
fdata: foxes.core.FData
|
|
541
|
-
The farm data
|
|
542
|
-
tdata: foxes.core.TData
|
|
543
|
-
The target point data
|
|
544
|
-
|
|
545
|
-
Returns
|
|
546
|
-
-------
|
|
547
|
-
results: dict
|
|
548
|
-
The resulting data, keys: output variable str.
|
|
549
|
-
Values: numpy.ndarray with shape
|
|
550
|
-
(n_states, n_targets, n_tpoints)
|
|
551
|
-
|
|
552
|
-
"""
|
|
553
|
-
# prepare:
|
|
554
|
-
n_states = tdata.n_states
|
|
555
|
-
n_targets = tdata.n_targets
|
|
556
|
-
n_tpoints = tdata.n_tpoints
|
|
557
|
-
points = tdata[FC.TARGETS].reshape(n_states, n_targets * n_tpoints, 3)
|
|
558
|
-
n_pts = points.shape[1]
|
|
559
|
-
n_states = fdata.n_states
|
|
560
|
-
|
|
561
|
-
# pick pre-loaded data:
|
|
562
|
-
if self.pre_load:
|
|
563
|
-
x = mdata[self.X]
|
|
564
|
-
y = mdata[self.Y]
|
|
565
|
-
data = mdata[self.DATA].copy()
|
|
566
|
-
|
|
567
|
-
# read data for this chunk:
|
|
568
|
-
else:
|
|
569
|
-
i0 = mdata.states_i0(counter=True)
|
|
570
|
-
s = slice(i0, i0 + n_states)
|
|
571
|
-
ds = self.data_source.isel({self.states_coord: s}).load()
|
|
572
|
-
|
|
573
|
-
x = ds[self.x_coord].to_numpy()
|
|
574
|
-
y = ds[self.y_coord].to_numpy()
|
|
575
|
-
data = self._get_data(ds, verbosity=0)
|
|
576
|
-
|
|
577
|
-
del ds
|
|
578
|
-
n_y = len(y)
|
|
579
|
-
n_x = len(x)
|
|
580
|
-
|
|
581
|
-
# translate WS, WD into U, V:
|
|
582
|
-
if FV.WD in self.ovars and FV.WS in self.ovars:
|
|
583
|
-
wd = data[..., self._dkys[FV.WD]]
|
|
584
|
-
ws = (
|
|
585
|
-
data[..., self._dkys[FV.WS]]
|
|
586
|
-
if FV.WS in self._dkys
|
|
587
|
-
else self.fixed_vars[FV.WS]
|
|
588
|
-
)
|
|
589
|
-
wdwsi = [self._dkys[FV.WD], self._dkys[FV.WS]]
|
|
590
|
-
data[..., wdwsi] = wd2uv(wd, ws, axis=-1)
|
|
591
|
-
del ws, wd
|
|
592
|
-
|
|
593
|
-
# prepare points:
|
|
594
|
-
sts = np.arange(n_states)
|
|
595
|
-
pts = np.append(
|
|
596
|
-
points, np.zeros((n_states, n_pts, 1), dtype=config.dtype_double), axis=2
|
|
597
|
-
)
|
|
598
|
-
pts[:, :, 3] = sts[:, None]
|
|
599
|
-
pts = pts.reshape(n_states * n_pts, 3)
|
|
600
|
-
pts = np.flip(pts, axis=1)
|
|
601
|
-
gvars = (sts, y, x)
|
|
602
|
-
|
|
603
|
-
# interpolate nan values:
|
|
604
|
-
if self.interp_nans and np.any(np.isnan(data)):
|
|
605
|
-
df = pd.DataFrame(
|
|
606
|
-
index=pd.MultiIndex.from_product(gvars, names=["state", "y", "x"]),
|
|
607
|
-
data={
|
|
608
|
-
v: data[..., vi].reshape(n_states * n_y * n_x)
|
|
609
|
-
for v, vi in self._dkys.items()
|
|
610
|
-
},
|
|
611
|
-
)
|
|
612
|
-
df.interpolate(
|
|
613
|
-
axis=0, method="linear", limit_direction="forward", inplace=True
|
|
614
|
-
)
|
|
615
|
-
df.interpolate(
|
|
616
|
-
axis=0, method="linear", limit_direction="backward", inplace=True
|
|
617
|
-
)
|
|
618
|
-
data = df.to_numpy().reshape(n_states, n_y, n_x, self._n_dvars)
|
|
619
|
-
del df
|
|
620
|
-
|
|
621
|
-
# interpolate:
|
|
622
|
-
try:
|
|
623
|
-
ipars = dict(bounds_error=True, fill_value=None)
|
|
624
|
-
ipars.update(self.interpn_pars)
|
|
625
|
-
data = interpn(gvars, data, pts, **ipars).reshape(
|
|
626
|
-
n_states, n_pts, self._n_dvars
|
|
627
|
-
)
|
|
628
|
-
except ValueError as e:
|
|
629
|
-
print(f"\nStates '{self.name}': Interpolation error")
|
|
630
|
-
print("INPUT VARS: (state, y, x)")
|
|
631
|
-
print(
|
|
632
|
-
"DATA BOUNDS:",
|
|
633
|
-
[float(np.min(d)) for d in gvars],
|
|
634
|
-
[float(np.max(d)) for d in gvars],
|
|
635
|
-
)
|
|
636
|
-
print(
|
|
637
|
-
"EVAL BOUNDS:",
|
|
638
|
-
[float(np.min(p)) for p in pts.T],
|
|
639
|
-
[float(np.max(p)) for p in pts.T],
|
|
640
|
-
)
|
|
641
|
-
print(
|
|
642
|
-
"\nMaybe you want to try the option 'bounds_error=False'? This will extrapolate the data.\n"
|
|
643
|
-
)
|
|
644
|
-
raise e
|
|
645
|
-
del pts, x, y, gvars
|
|
646
|
-
|
|
647
|
-
# interpolate nan values:
|
|
648
|
-
if self.interp_nans and np.any(np.isnan(data)):
|
|
649
|
-
df = pd.DataFrame(
|
|
650
|
-
index=pd.MultiIndex.from_product(
|
|
651
|
-
(sts, range(n_pts)), names=["state", "point"]
|
|
652
|
-
),
|
|
653
|
-
data={
|
|
654
|
-
v: data[:, :, vi].reshape(n_states * n_pts)
|
|
655
|
-
for v, vi in self._dkys.items()
|
|
656
|
-
},
|
|
657
|
-
)
|
|
658
|
-
df["x"] = points[:, :, 0].reshape(n_states * n_pts)
|
|
659
|
-
df["y"] = points[:, :, 1].reshape(n_states * n_pts)
|
|
660
|
-
df = df.reset_index().set_index(["state", "x", "y"])
|
|
661
|
-
df.interpolate(
|
|
662
|
-
axis=0, method="linear", limit_direction="forward", inplace=True
|
|
663
|
-
)
|
|
664
|
-
df.interpolate(
|
|
665
|
-
axis=0, method="linear", limit_direction="backward", inplace=True
|
|
666
|
-
)
|
|
667
|
-
df = df.reset_index().drop(["x", "y"], axis=1).set_index(["state", "point"])
|
|
668
|
-
data = df.to_numpy().reshape(n_states, n_pts, self._n_dvars)
|
|
669
|
-
del df
|
|
670
|
-
|
|
671
|
-
# set output:
|
|
672
|
-
out = {}
|
|
673
|
-
if FV.WD in self.ovars and FV.WS in self.ovars:
|
|
674
|
-
uv = data[..., wdwsi]
|
|
675
|
-
out[FV.WS] = np.linalg.norm(uv, axis=-1)
|
|
676
|
-
out[FV.WD] = uv2wd(uv, axis=-1)
|
|
677
|
-
del uv
|
|
678
|
-
for v in self.ovars:
|
|
679
|
-
if v not in out:
|
|
680
|
-
if v in self._dkys:
|
|
681
|
-
out[v] = data[..., self._dkys[v]]
|
|
682
|
-
else:
|
|
683
|
-
out[v] = np.full(
|
|
684
|
-
(n_states, n_pts), self.fixed_vars[v], dtype=config.dtype_double
|
|
685
|
-
)
|
|
686
|
-
|
|
687
|
-
return {v: d.reshape(n_states, n_targets, n_tpoints) for v, d in out.items()}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|