foxes 1.2.2__py3-none-any.whl → 1.2.4__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 +87 -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/__init__.py +1 -0
- foxes/utils/load.py +12 -4
- foxes/utils/wrg_utils.py +79 -0
- foxes/utils/xarray_utils.py +14 -3
- foxes/variables.py +5 -0
- {foxes-1.2.2.dist-info → foxes-1.2.4.dist-info}/METADATA +6 -2
- {foxes-1.2.2.dist-info → foxes-1.2.4.dist-info}/RECORD +64 -62
- foxes/input/states/slice_data_nc.py +0 -687
- {foxes-1.2.2.dist-info → foxes-1.2.4.dist-info}/LICENSE +0 -0
- {foxes-1.2.2.dist-info → foxes-1.2.4.dist-info}/WHEEL +0 -0
- {foxes-1.2.2.dist-info → foxes-1.2.4.dist-info}/entry_points.txt +0 -0
- {foxes-1.2.2.dist-info → foxes-1.2.4.dist-info}/top_level.txt +0 -0
|
@@ -1,14 +1,55 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import xarray as xr
|
|
4
|
+
from copy import copy
|
|
4
5
|
from scipy.interpolate import interpn
|
|
5
6
|
|
|
6
|
-
from foxes.core import States
|
|
7
|
+
from foxes.core import States, get_engine
|
|
7
8
|
from foxes.utils import wd2uv, uv2wd, import_module
|
|
8
9
|
from foxes.data import STATES, StaticData
|
|
9
10
|
import foxes.variables as FV
|
|
10
11
|
import foxes.constants as FC
|
|
11
|
-
from foxes.config import config,
|
|
12
|
+
from foxes.config import config, get_input_path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _read_nc_file(
|
|
16
|
+
fpath,
|
|
17
|
+
coords,
|
|
18
|
+
vars,
|
|
19
|
+
weight_var,
|
|
20
|
+
nc_engine,
|
|
21
|
+
sel,
|
|
22
|
+
isel,
|
|
23
|
+
minimal,
|
|
24
|
+
):
|
|
25
|
+
"""Helper function for nc file reading"""
|
|
26
|
+
data = xr.open_dataset(fpath, engine=nc_engine)
|
|
27
|
+
for c in coords:
|
|
28
|
+
if c is not None and c not in data:
|
|
29
|
+
raise KeyError(
|
|
30
|
+
f"Missing coordinate '{c}' in file {fpath}, got: {list(data.coords.keys())}"
|
|
31
|
+
)
|
|
32
|
+
if minimal:
|
|
33
|
+
weights = None
|
|
34
|
+
if weight_var is not None:
|
|
35
|
+
if weight_var not in data.data_vars:
|
|
36
|
+
raise KeyError(
|
|
37
|
+
f"Missing weight var '{weight_var}' in file {fpath}, found: {list(data.data_vars.keys())}"
|
|
38
|
+
)
|
|
39
|
+
if data[weight_var].dims != (coords[0],):
|
|
40
|
+
raise ValueError(
|
|
41
|
+
f"Wrong dimensions for variable '{weight_var}' in file {fpath}. Expecting {(coords[0],)}, got {data[weight_var].dims}"
|
|
42
|
+
)
|
|
43
|
+
weights = data[weight_var].to_numpy()
|
|
44
|
+
return data[coords[0]].to_numpy(), weights
|
|
45
|
+
else:
|
|
46
|
+
data = data[vars]
|
|
47
|
+
data.attrs = {}
|
|
48
|
+
if isel is not None and len(isel):
|
|
49
|
+
data = data.isel(**isel)
|
|
50
|
+
if sel is not None and len(sel):
|
|
51
|
+
data = data.sel(**sel)
|
|
52
|
+
return data
|
|
12
53
|
|
|
13
54
|
|
|
14
55
|
class FieldDataNC(States):
|
|
@@ -37,9 +78,13 @@ class FieldDataNC(States):
|
|
|
37
78
|
The y coordinate name in the data
|
|
38
79
|
h_coord: str
|
|
39
80
|
The height coordinate name in the data
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
initialization
|
|
81
|
+
load_mode: str
|
|
82
|
+
The load mode, choices: preload, lazy, fly.
|
|
83
|
+
preload loads all data during initialization,
|
|
84
|
+
lazy lazy-loads the data using dask, and fly
|
|
85
|
+
reads only states index and weights during initialization
|
|
86
|
+
and then opens the relevant files again within
|
|
87
|
+
the chunk calculation
|
|
43
88
|
weight_ncvar: str
|
|
44
89
|
Name of the weight data variable in the nc file(s)
|
|
45
90
|
bounds_error: bool
|
|
@@ -52,6 +97,9 @@ class FieldDataNC(States):
|
|
|
52
97
|
Linearly interpolate nan values
|
|
53
98
|
interpn_pars: dict, optional
|
|
54
99
|
Additional parameters for scipy.interpolate.interpn
|
|
100
|
+
bounds_extra_space: float or str
|
|
101
|
+
The extra space, either float in m,
|
|
102
|
+
or str for units of D, e.g. '2.5D'
|
|
55
103
|
|
|
56
104
|
:group: input.states
|
|
57
105
|
|
|
@@ -67,13 +115,13 @@ class FieldDataNC(States):
|
|
|
67
115
|
x_coord="UTMX",
|
|
68
116
|
y_coord="UTMY",
|
|
69
117
|
h_coord="height",
|
|
70
|
-
|
|
118
|
+
load_mode="preload",
|
|
71
119
|
weight_ncvar=None,
|
|
72
120
|
time_format="%Y-%m-%d_%H:%M:%S",
|
|
73
121
|
sel=None,
|
|
74
122
|
isel=None,
|
|
75
123
|
interp_nans=False,
|
|
76
|
-
|
|
124
|
+
bounds_extra_space=1000,
|
|
77
125
|
**interpn_pars,
|
|
78
126
|
):
|
|
79
127
|
"""
|
|
@@ -98,11 +146,15 @@ class FieldDataNC(States):
|
|
|
98
146
|
The x coordinate name in the data
|
|
99
147
|
y_coord: str
|
|
100
148
|
The y coordinate name in the data
|
|
101
|
-
h_coord: str
|
|
149
|
+
h_coord: str, optional
|
|
102
150
|
The height coordinate name in the data
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
initialization
|
|
151
|
+
load_mode: str
|
|
152
|
+
The load mode, choices: preload, lazy, fly.
|
|
153
|
+
preload loads all data during initialization,
|
|
154
|
+
lazy lazy-loads the data using dask, and fly
|
|
155
|
+
reads only states index and weights during initialization
|
|
156
|
+
and then opens the relevant files again within
|
|
157
|
+
the chunk calculation
|
|
106
158
|
weight_ncvar: str, optional
|
|
107
159
|
Name of the weight data variable in the nc file(s)
|
|
108
160
|
time_format: str
|
|
@@ -113,8 +165,9 @@ class FieldDataNC(States):
|
|
|
113
165
|
Subset selection via xr.Dataset.isel()
|
|
114
166
|
interp_nans: bool
|
|
115
167
|
Linearly interpolate nan values
|
|
116
|
-
|
|
117
|
-
|
|
168
|
+
bounds_extra_space: float or str, optional
|
|
169
|
+
The extra space, either float in m,
|
|
170
|
+
or str for units of D, e.g. '2.5D'
|
|
118
171
|
interpn_pars: dict, optional
|
|
119
172
|
Additional parameters for scipy.interpolate.interpn
|
|
120
173
|
|
|
@@ -128,12 +181,13 @@ class FieldDataNC(States):
|
|
|
128
181
|
self.y_coord = y_coord
|
|
129
182
|
self.h_coord = h_coord
|
|
130
183
|
self.weight_ncvar = weight_ncvar
|
|
131
|
-
self.
|
|
184
|
+
self.load_mode = load_mode
|
|
132
185
|
self.time_format = time_format
|
|
133
|
-
self.sel = sel
|
|
134
|
-
self.isel = isel
|
|
186
|
+
self.sel = sel if sel is not None else {}
|
|
187
|
+
self.isel = isel if isel is not None else {}
|
|
135
188
|
self.interpn_pars = interpn_pars
|
|
136
189
|
self.interp_nans = interp_nans
|
|
190
|
+
self.bounds_extra_space = bounds_extra_space
|
|
137
191
|
|
|
138
192
|
self.var2ncvar = {
|
|
139
193
|
v: var2ncvar.get(v, v) for v in output_vars if v not in fixed_vars
|
|
@@ -145,57 +199,6 @@ class FieldDataNC(States):
|
|
|
145
199
|
self.__weights = None
|
|
146
200
|
self.__inds = None
|
|
147
201
|
|
|
148
|
-
# pre-load file reading:
|
|
149
|
-
if not isinstance(self.data_source, xr.Dataset):
|
|
150
|
-
if "*" in str(self.data_source):
|
|
151
|
-
pass
|
|
152
|
-
else:
|
|
153
|
-
self.__data_source = get_path(self.data_source)
|
|
154
|
-
if not self.data_source.is_file():
|
|
155
|
-
self.__data_source = StaticData().get_file_path(
|
|
156
|
-
STATES, self.data_source.name, check_raw=False
|
|
157
|
-
)
|
|
158
|
-
if verbosity:
|
|
159
|
-
if pre_load:
|
|
160
|
-
print(
|
|
161
|
-
f"States '{self.name}': Reading data from '{self.data_source}'"
|
|
162
|
-
)
|
|
163
|
-
else:
|
|
164
|
-
print(
|
|
165
|
-
f"States '{self.name}': Reading index from '{self.data_source}'"
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
def _read_ds():
|
|
169
|
-
fpath = get_path(self.data_source)
|
|
170
|
-
if fpath.is_file():
|
|
171
|
-
return xr.open_dataset(fpath)
|
|
172
|
-
else:
|
|
173
|
-
# try to read multiple files, needs dask:
|
|
174
|
-
try:
|
|
175
|
-
return xr.open_mfdataset(
|
|
176
|
-
str(fpath),
|
|
177
|
-
parallel=False,
|
|
178
|
-
concat_dim=self.states_coord,
|
|
179
|
-
combine="nested",
|
|
180
|
-
data_vars="minimal",
|
|
181
|
-
coords="minimal",
|
|
182
|
-
compat="override",
|
|
183
|
-
)
|
|
184
|
-
except ValueError as e:
|
|
185
|
-
import_module("dask", hint="pip install dask")
|
|
186
|
-
raise e
|
|
187
|
-
|
|
188
|
-
self.__data_source = _read_ds()
|
|
189
|
-
|
|
190
|
-
if sel is not None:
|
|
191
|
-
self.__data_source = self.data_source.sel(self.sel)
|
|
192
|
-
if isel is not None:
|
|
193
|
-
self.__data_source = self.data_source.isel(self.isel)
|
|
194
|
-
if pre_load:
|
|
195
|
-
self.__data_source.load()
|
|
196
|
-
|
|
197
|
-
self._get_inds(self.data_source)
|
|
198
|
-
|
|
199
202
|
@property
|
|
200
203
|
def data_source(self):
|
|
201
204
|
"""
|
|
@@ -207,56 +210,34 @@ class FieldDataNC(States):
|
|
|
207
210
|
The data source
|
|
208
211
|
|
|
209
212
|
"""
|
|
210
|
-
if self.
|
|
213
|
+
if self.load_mode in ["preload", "fly"] and self.running:
|
|
211
214
|
raise ValueError(
|
|
212
|
-
f"States '{self.name}': Cannot access data_source while running"
|
|
215
|
+
f"States '{self.name}': Cannot access data_source while running for load mode '{self.load_mode}'"
|
|
213
216
|
)
|
|
214
217
|
return self.__data_source
|
|
215
218
|
|
|
216
|
-
def
|
|
217
|
-
"""
|
|
218
|
-
Helper function for index and weights
|
|
219
|
-
reading
|
|
220
|
-
"""
|
|
221
|
-
for c in [self.states_coord, self.x_coord, self.y_coord, self.h_coord]:
|
|
222
|
-
if not c in ds:
|
|
223
|
-
raise KeyError(
|
|
224
|
-
f"States '{self.name}': Missing coordinate '{c}' in data"
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
self.__inds = ds[self.states_coord].to_numpy()
|
|
228
|
-
if self.time_format is not None:
|
|
229
|
-
self.__inds = pd.to_datetime(
|
|
230
|
-
self.__inds, format=self.time_format
|
|
231
|
-
).to_numpy()
|
|
232
|
-
self._N = len(self.__inds)
|
|
233
|
-
|
|
234
|
-
if self.weight_ncvar is not None:
|
|
235
|
-
self.__weights = ds[self.weight_ncvar].to_numpy()
|
|
236
|
-
|
|
237
|
-
for v in self.ovars:
|
|
238
|
-
if v in self.var2ncvar:
|
|
239
|
-
ncv = self.var2ncvar[v]
|
|
240
|
-
if not ncv in ds:
|
|
241
|
-
raise KeyError(
|
|
242
|
-
f"States '{self.name}': nc variable '{ncv}' not found in data, found: {sorted(list(ds.keys()))}"
|
|
243
|
-
)
|
|
244
|
-
elif v not in self.fixed_vars:
|
|
245
|
-
raise ValueError(
|
|
246
|
-
f"States '{self.name}': Variable '{v}' neither found in var2ncvar not in fixed_vars"
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
def _get_data(self, ds, verbosity):
|
|
219
|
+
def _get_data(self, ds, coords, verbosity):
|
|
250
220
|
"""
|
|
251
221
|
Helper function for data extraction
|
|
252
222
|
"""
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
223
|
+
for ci, c in enumerate(coords):
|
|
224
|
+
found = False
|
|
225
|
+
if c is not None:
|
|
226
|
+
for v in ds.data_vars.values():
|
|
227
|
+
if c in v.dims:
|
|
228
|
+
found = True
|
|
229
|
+
break
|
|
230
|
+
if not found:
|
|
231
|
+
coords[ci] = None
|
|
232
|
+
|
|
233
|
+
dlst = []
|
|
234
|
+
for c in coords:
|
|
235
|
+
if c is not None:
|
|
236
|
+
dlst.append(np.atleast_1d(ds[c].to_numpy()))
|
|
237
|
+
else:
|
|
238
|
+
dlst.append(np.array([0], dtype=config.dtype_double))
|
|
239
|
+
sts, h, y, x = dlst
|
|
240
|
+
n_sts, n_h, n_y, n_x = [len(u) for u in dlst]
|
|
260
241
|
|
|
261
242
|
cor_shxy = (self.states_coord, self.h_coord, self.x_coord, self.y_coord)
|
|
262
243
|
cor_shyx = (self.states_coord, self.h_coord, self.y_coord, self.x_coord)
|
|
@@ -278,8 +259,13 @@ class FieldDataNC(States):
|
|
|
278
259
|
elif ds[ncv].dims == cor_s:
|
|
279
260
|
vars_s.append(v)
|
|
280
261
|
else:
|
|
262
|
+
expc = [
|
|
263
|
+
c
|
|
264
|
+
for c in [cor_shxy, cor_shyx, cor_sxy, cor_syx, cor_sh, cor_s]
|
|
265
|
+
if None not in c
|
|
266
|
+
]
|
|
281
267
|
raise ValueError(
|
|
282
|
-
f"States '{self.name}': Wrong
|
|
268
|
+
f"States '{self.name}': Wrong coordinates for variable '{ncv}': Found {ds[ncv].dims}, expecting one of {expc}"
|
|
283
269
|
)
|
|
284
270
|
|
|
285
271
|
data = np.zeros(
|
|
@@ -321,7 +307,7 @@ class FieldDataNC(States):
|
|
|
321
307
|
f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100*nn/len(d.flat):.2f}%)"
|
|
322
308
|
)
|
|
323
309
|
|
|
324
|
-
return data
|
|
310
|
+
return sts, h, y, x, data
|
|
325
311
|
|
|
326
312
|
def output_point_vars(self, algo):
|
|
327
313
|
"""
|
|
@@ -364,13 +350,129 @@ class FieldDataNC(States):
|
|
|
364
350
|
|
|
365
351
|
"""
|
|
366
352
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
):
|
|
370
|
-
|
|
371
|
-
|
|
353
|
+
# pre-load file reading:
|
|
354
|
+
coords = [self.states_coord, self.h_coord, self.y_coord, self.x_coord]
|
|
355
|
+
if not isinstance(self.data_source, xr.Dataset):
|
|
356
|
+
|
|
357
|
+
# check variables:
|
|
358
|
+
for v in self.ovars:
|
|
359
|
+
if v not in self.var2ncvar and v not in self.fixed_vars:
|
|
360
|
+
raise ValueError(
|
|
361
|
+
f"States '{self.name}': Variable '{v}' neither found in var2ncvar not in fixed_vars"
|
|
362
|
+
)
|
|
363
|
+
if (FV.WS in self.ovars and FV.WD not in self.ovars) or (
|
|
364
|
+
FV.WS not in self.ovars and FV.WD in self.ovars
|
|
365
|
+
):
|
|
366
|
+
raise KeyError(
|
|
367
|
+
f"States '{self.name}': Missing '{FV.WS}' or '{FV.WD}' in output variables {self.ovars}"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
# check static data:
|
|
371
|
+
fpath = get_input_path(self.data_source)
|
|
372
|
+
if "*" not in str(self.data_source):
|
|
373
|
+
if not fpath.is_file():
|
|
374
|
+
fpath = StaticData().get_file_path(
|
|
375
|
+
STATES, fpath.name, check_raw=False
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
# find bounds:
|
|
379
|
+
if self.x_coord is not None and self.x_coord not in self.sel:
|
|
380
|
+
xy_min, xy_max = algo.farm.get_xy_bounds(
|
|
381
|
+
extra_space=self.bounds_extra_space, algo=algo
|
|
382
|
+
)
|
|
383
|
+
if verbosity > 0:
|
|
384
|
+
print(
|
|
385
|
+
f"States '{self.name}': Restricting to bounds {xy_min} - {xy_max}"
|
|
386
|
+
)
|
|
387
|
+
self.sel.update(
|
|
388
|
+
{
|
|
389
|
+
self.x_coord: slice(xy_min[0], xy_max[1]),
|
|
390
|
+
self.y_coord: slice(xy_min[1], xy_max[1]),
|
|
391
|
+
}
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
# read files:
|
|
395
|
+
if verbosity > 0:
|
|
396
|
+
if self.load_mode == "preload":
|
|
397
|
+
print(
|
|
398
|
+
f"States '{self.name}': Reading data from '{self.data_source}'"
|
|
399
|
+
)
|
|
400
|
+
elif self.load_mode == "lazy":
|
|
401
|
+
print(
|
|
402
|
+
f"States '{self.name}': Reading header from '{self.data_source}'"
|
|
403
|
+
)
|
|
404
|
+
else:
|
|
405
|
+
print(
|
|
406
|
+
f"States '{self.name}': Reading states from '{self.data_source}'"
|
|
407
|
+
)
|
|
408
|
+
files = sorted(list(fpath.resolve().parent.glob(fpath.name)))
|
|
409
|
+
vars = list(self.var2ncvar.values())
|
|
410
|
+
if self.weight_ncvar is not None:
|
|
411
|
+
vars += [self.weight_ncvar]
|
|
412
|
+
self.__data_source = get_engine().map(
|
|
413
|
+
_read_nc_file,
|
|
414
|
+
files,
|
|
415
|
+
coords=coords,
|
|
416
|
+
weight_var=self.weight_ncvar,
|
|
417
|
+
vars=vars,
|
|
418
|
+
nc_engine=config.nc_engine,
|
|
419
|
+
isel=self.isel,
|
|
420
|
+
sel=self.sel,
|
|
421
|
+
minimal=self.load_mode == "fly",
|
|
372
422
|
)
|
|
373
423
|
|
|
424
|
+
if self.load_mode in ["preload", "lazy"]:
|
|
425
|
+
|
|
426
|
+
if self.load_mode == "lazy":
|
|
427
|
+
try:
|
|
428
|
+
self.__data_source = [ds.chunk() for ds in self.__data_source]
|
|
429
|
+
except (ModuleNotFoundError, ValueError) as e:
|
|
430
|
+
import_module("dask")
|
|
431
|
+
raise e
|
|
432
|
+
self.__data_source = xr.concat(
|
|
433
|
+
self.__data_source,
|
|
434
|
+
dim=self.states_coord,
|
|
435
|
+
coords="minimal",
|
|
436
|
+
data_vars="minimal",
|
|
437
|
+
compat="equals",
|
|
438
|
+
join="exact",
|
|
439
|
+
combine_attrs="drop",
|
|
440
|
+
)
|
|
441
|
+
if self.load_mode == "preload":
|
|
442
|
+
self.__data_source.load()
|
|
443
|
+
if self.weight_ncvar is not None:
|
|
444
|
+
self.__weights = self.__data_source[self.weight_ncvar].to_numpy()
|
|
445
|
+
self.__inds = self.__data_source[self.states_coord].to_numpy()
|
|
446
|
+
self._N = len(self.__inds)
|
|
447
|
+
|
|
448
|
+
elif self.load_mode == "fly":
|
|
449
|
+
self.__inds, weights = zip(*self.__data_source)
|
|
450
|
+
self.__data_source = fpath
|
|
451
|
+
self._files_maxi = {f: len(inds) for f, inds in zip(files, self.__inds)}
|
|
452
|
+
self.__inds = np.concatenate(self.__inds, axis=0)
|
|
453
|
+
self._N = len(self.__inds)
|
|
454
|
+
if weights[0] is not None:
|
|
455
|
+
self.__weights = np.zeros(
|
|
456
|
+
(self._N, algo.n_turbines), dtype=config.dtype_double
|
|
457
|
+
)
|
|
458
|
+
self.__weights[:] = np.concatenate(weights, axis=0)[:, None]
|
|
459
|
+
del weights
|
|
460
|
+
|
|
461
|
+
else:
|
|
462
|
+
raise KeyError(
|
|
463
|
+
f"States '{self.name}': Unknown load_mode '{self.load_mode}', choices: preload, lazy, fly"
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
if self.time_format is not None:
|
|
467
|
+
self.__inds = pd.to_datetime(
|
|
468
|
+
self.__inds, format=self.time_format
|
|
469
|
+
).to_numpy()
|
|
470
|
+
|
|
471
|
+
if self.__weights is None:
|
|
472
|
+
self.__weights = np.full(
|
|
473
|
+
(self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
|
|
474
|
+
)
|
|
475
|
+
|
|
374
476
|
# ensure WD and WS get the first two slots of data:
|
|
375
477
|
self._dkys = {}
|
|
376
478
|
if FV.WS in self.ovars:
|
|
@@ -382,34 +484,25 @@ class FieldDataNC(States):
|
|
|
382
484
|
self._dkys[v] = len(self._dkys)
|
|
383
485
|
self._n_dvars = len(self._dkys)
|
|
384
486
|
|
|
385
|
-
if self.__weights is None:
|
|
386
|
-
self.__weights = np.full(
|
|
387
|
-
(self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
|
|
388
|
-
)
|
|
389
|
-
|
|
390
487
|
idata = super().load_data(algo, verbosity)
|
|
391
488
|
|
|
392
|
-
if self.
|
|
489
|
+
if self.load_mode == "preload":
|
|
393
490
|
self.X = self.var(FV.X)
|
|
394
491
|
self.Y = self.var(FV.Y)
|
|
395
492
|
self.H = self.var(FV.H)
|
|
396
493
|
self.VARS = self.var("vars")
|
|
397
494
|
self.DATA = self.var("data")
|
|
398
495
|
|
|
399
|
-
|
|
496
|
+
__, h, y, x, data = self._get_data(self.data_source, coords, verbosity)
|
|
497
|
+
self._prl_coords = coords
|
|
400
498
|
|
|
401
|
-
h = ds[self.h_coord].to_numpy()
|
|
402
|
-
y = ds[self.y_coord].to_numpy()
|
|
403
|
-
x = ds[self.x_coord].to_numpy()
|
|
404
|
-
v = list(self._dkys.keys())
|
|
405
499
|
coos = (FC.STATE, self.H, self.Y, self.X, self.VARS)
|
|
406
|
-
data = self._get_data(ds, verbosity)
|
|
407
500
|
data = (coos, data)
|
|
408
501
|
|
|
409
502
|
idata["coords"][self.H] = h
|
|
410
503
|
idata["coords"][self.Y] = y
|
|
411
504
|
idata["coords"][self.X] = x
|
|
412
|
-
idata["coords"][self.VARS] =
|
|
505
|
+
idata["coords"][self.VARS] = list(self._dkys.keys())
|
|
413
506
|
idata["data_vars"][self.DATA] = data
|
|
414
507
|
|
|
415
508
|
return idata
|
|
@@ -452,7 +545,7 @@ class FieldDataNC(States):
|
|
|
452
545
|
)
|
|
453
546
|
del self.__weights, self.__inds
|
|
454
547
|
|
|
455
|
-
if self.
|
|
548
|
+
if self.load_mode == "preload":
|
|
456
549
|
data_stash[self.name]["data_source"] = self.__data_source
|
|
457
550
|
del self.__data_source
|
|
458
551
|
|
|
@@ -489,7 +582,7 @@ class FieldDataNC(States):
|
|
|
489
582
|
self.__weights = data.pop("weights")
|
|
490
583
|
self.__inds = data.pop("inds")
|
|
491
584
|
|
|
492
|
-
if self.
|
|
585
|
+
if self.load_mode == "preload":
|
|
493
586
|
self.__data_source = data.pop("data_source")
|
|
494
587
|
|
|
495
588
|
def size(self):
|
|
@@ -589,26 +682,73 @@ class FieldDataNC(States):
|
|
|
589
682
|
points = tdata[FC.TARGETS].reshape(n_states, n_targets * n_tpoints, 3)
|
|
590
683
|
n_pts = points.shape[1]
|
|
591
684
|
n_states = fdata.n_states
|
|
685
|
+
coords = [self.states_coord, self.h_coord, self.y_coord, self.x_coord]
|
|
592
686
|
|
|
593
|
-
#
|
|
594
|
-
if self.
|
|
687
|
+
# case preload:
|
|
688
|
+
if self.load_mode == "preload":
|
|
595
689
|
x = mdata[self.X]
|
|
596
690
|
y = mdata[self.Y]
|
|
597
691
|
h = mdata[self.H]
|
|
598
692
|
data = mdata[self.DATA].copy()
|
|
693
|
+
coords = self._prl_coords
|
|
599
694
|
|
|
600
|
-
#
|
|
601
|
-
|
|
695
|
+
# case lazy:
|
|
696
|
+
elif self.load_mode == "lazy":
|
|
602
697
|
i0 = mdata.states_i0(counter=True)
|
|
603
698
|
s = slice(i0, i0 + n_states)
|
|
604
699
|
ds = self.data_source.isel({self.states_coord: s}).load()
|
|
700
|
+
__, h, y, x, data = self._get_data(ds, coords, verbosity=0)
|
|
701
|
+
del ds
|
|
605
702
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
703
|
+
# case fly:
|
|
704
|
+
elif self.load_mode == "fly":
|
|
705
|
+
vars = list(self.var2ncvar.values())
|
|
706
|
+
if self.weight_ncvar is not None:
|
|
707
|
+
vars += [self.weight_ncvar]
|
|
708
|
+
|
|
709
|
+
i0 = mdata.states_i0(counter=True)
|
|
710
|
+
i1 = i0 + n_states
|
|
711
|
+
j0 = 0
|
|
712
|
+
data = []
|
|
713
|
+
for fpath, n in self._files_maxi.items():
|
|
714
|
+
if i0 < j0:
|
|
715
|
+
break
|
|
716
|
+
else:
|
|
717
|
+
j1 = j0 + n
|
|
718
|
+
if i0 < j1:
|
|
719
|
+
a = i0 - j0
|
|
720
|
+
b = min(i1, j1) - j0
|
|
721
|
+
isel = copy(self.isel)
|
|
722
|
+
isel[self.states_coord] = slice(a, b)
|
|
723
|
+
|
|
724
|
+
data.append(
|
|
725
|
+
_read_nc_file(
|
|
726
|
+
fpath,
|
|
727
|
+
coords=coords,
|
|
728
|
+
weight_var=self.weight_ncvar,
|
|
729
|
+
vars=vars,
|
|
730
|
+
nc_engine=config.nc_engine,
|
|
731
|
+
isel=isel,
|
|
732
|
+
sel=self.sel,
|
|
733
|
+
minimal=False,
|
|
734
|
+
)
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
i0 += b - a
|
|
738
|
+
j0 = j1
|
|
739
|
+
|
|
740
|
+
assert (
|
|
741
|
+
i0 == i1
|
|
742
|
+
), f"States '{self.name}': Missing states for load_mode '{self.load_mode}': (i0, i1) = {(i0, i1)}"
|
|
743
|
+
|
|
744
|
+
data = xr.concat(data, dim=self.states_coord)
|
|
745
|
+
__, h, y, x, data = self._get_data(data, coords, verbosity=0)
|
|
746
|
+
|
|
747
|
+
else:
|
|
748
|
+
raise KeyError(
|
|
749
|
+
f"States '{self.name}': Unknown load_mode '{self.load_mode}', choices: preload, lazy, fly"
|
|
750
|
+
)
|
|
610
751
|
|
|
611
|
-
del ds
|
|
612
752
|
n_h = len(h)
|
|
613
753
|
n_y = len(y)
|
|
614
754
|
n_x = len(x)
|
|
@@ -635,6 +775,11 @@ class FieldDataNC(States):
|
|
|
635
775
|
pts = np.flip(pts, axis=1)
|
|
636
776
|
gvars = (sts, h, y, x)
|
|
637
777
|
|
|
778
|
+
# reset None coordinate data, since that should not be interpolated:
|
|
779
|
+
for i, (c, g) in enumerate(zip(coords, gvars)):
|
|
780
|
+
if c is None:
|
|
781
|
+
pts[..., i] = g[0]
|
|
782
|
+
|
|
638
783
|
# interpolate nan values:
|
|
639
784
|
if self.interp_nans and np.any(np.isnan(data)):
|
|
640
785
|
df = pd.DataFrame(
|
|
@@ -6,7 +6,7 @@ from scipy.interpolate import interp1d
|
|
|
6
6
|
from foxes.core import States
|
|
7
7
|
from foxes.utils import PandasFileHelper
|
|
8
8
|
from foxes.data import STATES
|
|
9
|
-
from foxes.config import config,
|
|
9
|
+
from foxes.config import config, get_input_path
|
|
10
10
|
from foxes.utils import wd2uv, uv2wd
|
|
11
11
|
import foxes.variables as FV
|
|
12
12
|
import foxes.constants as FC
|
|
@@ -198,7 +198,7 @@ class MultiHeightStates(States):
|
|
|
198
198
|
|
|
199
199
|
"""
|
|
200
200
|
if not isinstance(self.data_source, pd.DataFrame):
|
|
201
|
-
self._data_source =
|
|
201
|
+
self._data_source = get_input_path(self.data_source)
|
|
202
202
|
if not self.data_source.is_file():
|
|
203
203
|
if verbosity:
|
|
204
204
|
print(
|
|
@@ -625,7 +625,7 @@ class MultiHeightNCStates(MultiHeightStates):
|
|
|
625
625
|
|
|
626
626
|
"""
|
|
627
627
|
if not isinstance(self.data_source, Dataset):
|
|
628
|
-
self._data_source =
|
|
628
|
+
self._data_source = get_input_path(self.data_source)
|
|
629
629
|
if not self.data_source.is_file():
|
|
630
630
|
if verbosity:
|
|
631
631
|
print(
|
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from foxes.core import States, VerticalProfile
|
|
7
7
|
from foxes.utils import PandasFileHelper, read_tab_file
|
|
8
8
|
from foxes.data import STATES
|
|
9
|
-
from foxes.config import config,
|
|
9
|
+
from foxes.config import config, get_input_path
|
|
10
10
|
import foxes.variables as FV
|
|
11
11
|
import foxes.constants as FC
|
|
12
12
|
|
|
@@ -215,7 +215,7 @@ class StatesTable(States):
|
|
|
215
215
|
data = self.data_source
|
|
216
216
|
isorg = True
|
|
217
217
|
else:
|
|
218
|
-
self._data_source =
|
|
218
|
+
self._data_source = get_input_path(self.data_source)
|
|
219
219
|
if not self.data_source.is_file():
|
|
220
220
|
if verbosity:
|
|
221
221
|
print(
|
|
@@ -550,7 +550,7 @@ class TabStates(StatesTable):
|
|
|
550
550
|
"""
|
|
551
551
|
if self.data_source is None:
|
|
552
552
|
if self.__tab_data is None:
|
|
553
|
-
self.__tab_source =
|
|
553
|
+
self.__tab_source = get_input_path(self.__tab_source)
|
|
554
554
|
if not self.__tab_source.is_file():
|
|
555
555
|
if verbosity:
|
|
556
556
|
print(
|