foxes 1.2.5__py3-none-any.whl → 1.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/quickstart/run.py +17 -0
- foxes/__init__.py +1 -1
- foxes/algorithms/downwind/downwind.py +9 -15
- foxes/algorithms/downwind/models/farm_wakes_calc.py +13 -7
- foxes/algorithms/downwind/models/init_farm_data.py +4 -4
- foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +1 -1
- foxes/algorithms/iterative/models/farm_wakes_calc.py +6 -3
- foxes/algorithms/sequential/models/seq_state.py +0 -18
- foxes/algorithms/sequential/sequential.py +5 -18
- foxes/constants.py +6 -0
- foxes/core/data.py +44 -18
- foxes/core/engine.py +19 -1
- foxes/core/farm_data_model.py +1 -0
- foxes/core/rotor_model.py +42 -38
- foxes/core/states.py +2 -47
- foxes/input/states/__init__.py +1 -0
- foxes/input/states/field_data_nc.py +39 -61
- foxes/input/states/multi_height.py +31 -54
- foxes/input/states/one_point_flow.py +22 -21
- foxes/input/states/scan.py +6 -19
- foxes/input/states/single.py +5 -17
- foxes/input/states/states_table.py +15 -37
- foxes/input/states/wrg_states.py +148 -36
- foxes/models/partial_wakes/rotor_points.py +8 -2
- foxes/models/partial_wakes/segregated.py +9 -4
- foxes/models/rotor_models/centre.py +6 -4
- foxes/models/wake_frames/seq_dynamic_wakes.py +5 -2
- foxes/models/wake_frames/timelines.py +10 -0
- foxes/output/farm_layout.py +12 -4
- foxes/output/farm_results_eval.py +36 -12
- foxes/output/rose_plot.py +20 -2
- foxes/output/slice_data.py +16 -19
- {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/METADATA +10 -8
- {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/RECORD +52 -51
- {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/WHEEL +1 -1
- tests/0_consistency/iterative/test_iterative.py +2 -3
- tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -2
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -3
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -3
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -3
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -3
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -2
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -3
- tests/3_examples/test_examples.py +3 -2
- {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/LICENSE +0 -0
- {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/entry_points.txt +0 -0
- {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/top_level.txt +0 -0
foxes/core/rotor_model.py
CHANGED
|
@@ -60,6 +60,10 @@ class RotorModel(FarmDataModel):
|
|
|
60
60
|
"""
|
|
61
61
|
if self.calc_vars is None:
|
|
62
62
|
vrs = algo.states.output_point_vars(algo)
|
|
63
|
+
assert (
|
|
64
|
+
FV.WEIGHT not in vrs
|
|
65
|
+
), f"Rotor '{self.name}': States '{algo.states.name}' output_point_vars contain '{FV.WEIGHT}', please remove"
|
|
66
|
+
|
|
63
67
|
if FV.WS in vrs:
|
|
64
68
|
self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
|
|
65
69
|
else:
|
|
@@ -72,6 +76,9 @@ class RotorModel(FarmDataModel):
|
|
|
72
76
|
|
|
73
77
|
self.calc_vars = sorted(self.calc_vars)
|
|
74
78
|
|
|
79
|
+
if FV.WEIGHT not in self.calc_vars:
|
|
80
|
+
self.calc_vars.append(FV.WEIGHT)
|
|
81
|
+
|
|
75
82
|
return self.calc_vars
|
|
76
83
|
|
|
77
84
|
@abstractmethod
|
|
@@ -174,9 +181,7 @@ class RotorModel(FarmDataModel):
|
|
|
174
181
|
elif res.shape[1] == 1:
|
|
175
182
|
fdata[v][:, downwind_index] = res[:, 0]
|
|
176
183
|
else:
|
|
177
|
-
|
|
178
|
-
f"Rotor model '{self.name}': downwind_index is not None, but results shape for '{v}' has more than one turbine, {res.shape}"
|
|
179
|
-
)
|
|
184
|
+
fdata[v, downwind_index] = res[:, downwind_index]
|
|
180
185
|
|
|
181
186
|
def eval_rpoint_results(
|
|
182
187
|
self,
|
|
@@ -184,7 +189,7 @@ class RotorModel(FarmDataModel):
|
|
|
184
189
|
mdata,
|
|
185
190
|
fdata,
|
|
186
191
|
tdata,
|
|
187
|
-
|
|
192
|
+
rpoint_weights,
|
|
188
193
|
downwind_index=None,
|
|
189
194
|
copy_to_ambient=False,
|
|
190
195
|
):
|
|
@@ -207,7 +212,7 @@ class RotorModel(FarmDataModel):
|
|
|
207
212
|
The farm data
|
|
208
213
|
tdata: foxes.core.TData
|
|
209
214
|
The target point data
|
|
210
|
-
|
|
215
|
+
rpoint_weights: numpy.ndarray
|
|
211
216
|
The rotor point weights, shape: (n_rpoints,)
|
|
212
217
|
downwind_index: int, optional
|
|
213
218
|
The index in the downwind order
|
|
@@ -233,7 +238,7 @@ class RotorModel(FarmDataModel):
|
|
|
233
238
|
wd = tdata[FV.WD]
|
|
234
239
|
ws = tdata[FV.WS]
|
|
235
240
|
uvp = wd2uv(wd, ws, axis=-1)
|
|
236
|
-
uv = np.einsum("stpd,p->std", uvp,
|
|
241
|
+
uv = np.einsum("stpd,p->std", uvp, rpoint_weights)
|
|
237
242
|
|
|
238
243
|
wd = None
|
|
239
244
|
vdone = []
|
|
@@ -243,7 +248,6 @@ class RotorModel(FarmDataModel):
|
|
|
243
248
|
wd = uv2wd(uv, axis=-1)
|
|
244
249
|
self._set_res(fdata, v, wd, downwind_index)
|
|
245
250
|
vdone.append(v)
|
|
246
|
-
|
|
247
251
|
elif v == FV.WS:
|
|
248
252
|
ws = np.linalg.norm(uv, axis=-1)
|
|
249
253
|
self._set_res(fdata, v, ws, downwind_index)
|
|
@@ -265,7 +269,7 @@ class RotorModel(FarmDataModel):
|
|
|
265
269
|
|
|
266
270
|
for v in self.calc_vars:
|
|
267
271
|
if v == FV.REWS:
|
|
268
|
-
rews = np.maximum(np.einsum("stp,p->st", wsp,
|
|
272
|
+
rews = np.maximum(np.einsum("stp,p->st", wsp, rpoint_weights), 0.0)
|
|
269
273
|
self._set_res(fdata, v, rews, downwind_index)
|
|
270
274
|
del rews
|
|
271
275
|
vdone.append(v)
|
|
@@ -278,12 +282,14 @@ class RotorModel(FarmDataModel):
|
|
|
278
282
|
if uvp.shape[2] > 1:
|
|
279
283
|
rews2 = np.sqrt(
|
|
280
284
|
np.maximum(
|
|
281
|
-
np.einsum(
|
|
285
|
+
np.einsum(
|
|
286
|
+
"stp,p->st", np.sign(wsp) * wsp**2, rpoint_weights
|
|
287
|
+
),
|
|
282
288
|
0.0,
|
|
283
289
|
)
|
|
284
290
|
)
|
|
285
291
|
else:
|
|
286
|
-
rews2 = np.sqrt(np.einsum("stp,p->st", wsp**2,
|
|
292
|
+
rews2 = np.sqrt(np.einsum("stp,p->st", wsp**2, rpoint_weights))
|
|
287
293
|
self._set_res(fdata, v, rews2, downwind_index)
|
|
288
294
|
del rews2
|
|
289
295
|
vdone.append(v)
|
|
@@ -295,10 +301,12 @@ class RotorModel(FarmDataModel):
|
|
|
295
301
|
# turbine axis direction:
|
|
296
302
|
if uvp.shape[2] > 1:
|
|
297
303
|
rews3 = np.maximum(
|
|
298
|
-
np.einsum("stp,p->st", wsp**3,
|
|
304
|
+
np.einsum("stp,p->st", wsp**3, rpoint_weights), 0.0
|
|
299
305
|
) ** (1.0 / 3.0)
|
|
300
306
|
else:
|
|
301
|
-
rews3 = (np.einsum("stp,p->st", wsp**3,
|
|
307
|
+
rews3 = (np.einsum("stp,p->st", wsp**3, rpoint_weights)) ** (
|
|
308
|
+
1.0 / 3.0
|
|
309
|
+
)
|
|
302
310
|
self._set_res(fdata, v, rews3, downwind_index)
|
|
303
311
|
del rews3
|
|
304
312
|
vdone.append(v)
|
|
@@ -307,8 +315,10 @@ class RotorModel(FarmDataModel):
|
|
|
307
315
|
del uvp
|
|
308
316
|
|
|
309
317
|
for v in self.calc_vars:
|
|
310
|
-
if v not in vdone
|
|
311
|
-
|
|
318
|
+
if v not in vdone and (
|
|
319
|
+
fdata[v].shape[1] > 1 or downwind_index is None or downwind_index == 0
|
|
320
|
+
):
|
|
321
|
+
res = np.einsum("stp,p->st", tdata[v], rpoint_weights)
|
|
312
322
|
self._set_res(fdata, v, res, downwind_index)
|
|
313
323
|
if copy_to_ambient and v in FV.var2amb:
|
|
314
324
|
fdata[FV.var2amb[v]] = fdata[v].copy()
|
|
@@ -319,10 +329,8 @@ class RotorModel(FarmDataModel):
|
|
|
319
329
|
mdata,
|
|
320
330
|
fdata,
|
|
321
331
|
rpoints=None,
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
store_rweights=False,
|
|
325
|
-
store_amb_res=False,
|
|
332
|
+
rpoint_weights=None,
|
|
333
|
+
store=False,
|
|
326
334
|
downwind_index=None,
|
|
327
335
|
):
|
|
328
336
|
"""
|
|
@@ -339,16 +347,11 @@ class RotorModel(FarmDataModel):
|
|
|
339
347
|
rpoints: numpy.ndarray, optional
|
|
340
348
|
The rotor points, or None for automatic for
|
|
341
349
|
this rotor. Shape: (n_states, n_turbines, n_rpoints, 3)
|
|
342
|
-
|
|
350
|
+
rpoint_weights: numpy.ndarray, optional
|
|
343
351
|
The rotor point weights, or None for automatic
|
|
344
352
|
for this rotor. Shape: (n_rpoints,)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
store_rweights: bool, optional
|
|
348
|
-
Switch for storing rotor point weights to mdata
|
|
349
|
-
store_amb_res: bool, optional
|
|
350
|
-
Switch for storing ambient rotor point reults as they
|
|
351
|
-
come from the states to mdata
|
|
353
|
+
store: bool, optional
|
|
354
|
+
Flag for storing ambient rotor point results
|
|
352
355
|
downwind_index: int, optional
|
|
353
356
|
Only compute for index in the downwind order
|
|
354
357
|
|
|
@@ -364,18 +367,12 @@ class RotorModel(FarmDataModel):
|
|
|
364
367
|
rpoints = mdata.get(
|
|
365
368
|
FC.ROTOR_POINTS, self.get_rotor_points(algo, mdata, fdata)
|
|
366
369
|
)
|
|
367
|
-
if store_rpoints:
|
|
368
|
-
algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
|
|
369
|
-
|
|
370
370
|
if downwind_index is not None:
|
|
371
371
|
rpoints = rpoints[:, downwind_index, None]
|
|
372
|
+
if rpoint_weights is None:
|
|
373
|
+
rpoint_weights = mdata.get_item(FC.TWEIGHTS, self.rotor_point_weights())
|
|
372
374
|
|
|
373
|
-
|
|
374
|
-
weights = mdata.get(FC.TWEIGHTS, self.rotor_point_weights())
|
|
375
|
-
if store_rweights:
|
|
376
|
-
algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, weights, mdata=mdata)
|
|
377
|
-
|
|
378
|
-
tdata = TData.from_tpoints(rpoints, weights)
|
|
375
|
+
tdata = TData.from_tpoints(rpoints, rpoint_weights)
|
|
379
376
|
svars = algo.states.output_point_vars(algo)
|
|
380
377
|
for v in svars:
|
|
381
378
|
tdata.add(
|
|
@@ -386,16 +383,23 @@ class RotorModel(FarmDataModel):
|
|
|
386
383
|
|
|
387
384
|
sres = algo.states.calculate(algo, mdata, fdata, tdata)
|
|
388
385
|
tdata.update(sres)
|
|
386
|
+
if FV.WEIGHT not in tdata:
|
|
387
|
+
raise KeyError(
|
|
388
|
+
f"Rotor '{self.name}': States '{algo.states.name}' failed to provide '{FV.WEIGHT}' in tdata"
|
|
389
|
+
)
|
|
389
390
|
|
|
390
|
-
if
|
|
391
|
-
algo.add_to_chunk_store(FC.
|
|
391
|
+
if store:
|
|
392
|
+
algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
|
|
393
|
+
algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, rpoint_weights, mdata=mdata)
|
|
394
|
+
algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres, mdata=mdata)
|
|
395
|
+
algo.add_to_chunk_store(FC.WEIGHT_RES, tdata[FV.WEIGHT], mdata=mdata)
|
|
392
396
|
|
|
393
397
|
self.eval_rpoint_results(
|
|
394
398
|
algo,
|
|
395
399
|
mdata,
|
|
396
400
|
fdata,
|
|
397
401
|
tdata,
|
|
398
|
-
|
|
402
|
+
rpoint_weights,
|
|
399
403
|
downwind_index,
|
|
400
404
|
copy_to_ambient=True,
|
|
401
405
|
)
|
foxes/core/states.py
CHANGED
|
@@ -43,24 +43,6 @@ class States(PointDataModel):
|
|
|
43
43
|
"""
|
|
44
44
|
return list(range(self.size()))
|
|
45
45
|
|
|
46
|
-
@abstractmethod
|
|
47
|
-
def weights(self, algo):
|
|
48
|
-
"""
|
|
49
|
-
The statistical weights of all states.
|
|
50
|
-
|
|
51
|
-
Parameters
|
|
52
|
-
----------
|
|
53
|
-
algo: foxes.core.Algorithm
|
|
54
|
-
The calculation algorithm
|
|
55
|
-
|
|
56
|
-
Returns
|
|
57
|
-
-------
|
|
58
|
-
weights: numpy.ndarray
|
|
59
|
-
The weights, shape: (n_states, n_turbines)
|
|
60
|
-
|
|
61
|
-
"""
|
|
62
|
-
pass
|
|
63
|
-
|
|
64
46
|
def reset(self, algo=None, states_sel=None, states_loc=None, verbosity=0):
|
|
65
47
|
"""
|
|
66
48
|
Reset the states, optionally select states
|
|
@@ -106,19 +88,9 @@ class States(PointDataModel):
|
|
|
106
88
|
if sinds is not None:
|
|
107
89
|
idata["coords"][FC.STATE] = sinds
|
|
108
90
|
|
|
109
|
-
weights = self.weights(algo)
|
|
110
|
-
if len(weights.shape) != 2:
|
|
111
|
-
raise ValueError(
|
|
112
|
-
f"States '{self.name}': Wrong weights dimension, expecing ({FC.STATE}, {FC.TURBINE}), got shape {weights.shape}"
|
|
113
|
-
)
|
|
114
|
-
if weights.shape[1] != algo.n_turbines:
|
|
115
|
-
raise ValueError(
|
|
116
|
-
f"States '{self.name}': Wrong size of second axis dimension '{FC.TURBINE}': Expecting {algo.n_turbines}, got {weights.shape[1]}"
|
|
117
|
-
)
|
|
118
|
-
idata["data_vars"][FV.WEIGHT] = ((FC.STATE, FC.TURBINE), weights)
|
|
119
|
-
|
|
120
91
|
return idata
|
|
121
92
|
|
|
93
|
+
@abstractmethod
|
|
122
94
|
def output_point_vars(self, algo):
|
|
123
95
|
"""
|
|
124
96
|
The variables which are being modified by the model.
|
|
@@ -134,7 +106,7 @@ class States(PointDataModel):
|
|
|
134
106
|
The output variable names
|
|
135
107
|
|
|
136
108
|
"""
|
|
137
|
-
|
|
109
|
+
pass
|
|
138
110
|
|
|
139
111
|
def __add__(self, s):
|
|
140
112
|
if isinstance(s, list):
|
|
@@ -245,23 +217,6 @@ class ExtendedStates(States):
|
|
|
245
217
|
"""
|
|
246
218
|
return self.states.index()
|
|
247
219
|
|
|
248
|
-
def weights(self, algo):
|
|
249
|
-
"""
|
|
250
|
-
The statistical weights of all states.
|
|
251
|
-
|
|
252
|
-
Parameters
|
|
253
|
-
----------
|
|
254
|
-
algo: foxes.core.Algorithm
|
|
255
|
-
The calculation algorithm
|
|
256
|
-
|
|
257
|
-
Returns
|
|
258
|
-
-------
|
|
259
|
-
weights: numpy.ndarray
|
|
260
|
-
The weights, shape: (n_states, n_turbines)
|
|
261
|
-
|
|
262
|
-
"""
|
|
263
|
-
return self.states.weights(algo)
|
|
264
|
-
|
|
265
220
|
def output_point_vars(self, algo):
|
|
266
221
|
"""
|
|
267
222
|
The variables which are being modified by the model.
|
foxes/input/states/__init__.py
CHANGED
|
@@ -16,7 +16,6 @@ def _read_nc_file(
|
|
|
16
16
|
fpath,
|
|
17
17
|
coords,
|
|
18
18
|
vars,
|
|
19
|
-
weight_var,
|
|
20
19
|
nc_engine,
|
|
21
20
|
sel,
|
|
22
21
|
isel,
|
|
@@ -30,18 +29,7 @@ def _read_nc_file(
|
|
|
30
29
|
f"Missing coordinate '{c}' in file {fpath}, got: {list(data.coords.keys())}"
|
|
31
30
|
)
|
|
32
31
|
if minimal:
|
|
33
|
-
|
|
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
|
|
32
|
+
return data[coords[0]].to_numpy()
|
|
45
33
|
else:
|
|
46
34
|
data = data[vars]
|
|
47
35
|
data.attrs = {}
|
|
@@ -175,7 +163,7 @@ class FieldDataNC(States):
|
|
|
175
163
|
super().__init__()
|
|
176
164
|
|
|
177
165
|
self.states_coord = states_coord
|
|
178
|
-
self.ovars = output_vars
|
|
166
|
+
self.ovars = list(output_vars)
|
|
179
167
|
self.fixed_vars = fixed_vars
|
|
180
168
|
self.x_coord = x_coord
|
|
181
169
|
self.y_coord = y_coord
|
|
@@ -196,7 +184,6 @@ class FieldDataNC(States):
|
|
|
196
184
|
self._N = None
|
|
197
185
|
|
|
198
186
|
self.__data_source = data_source
|
|
199
|
-
self.__weights = None
|
|
200
187
|
self.__inds = None
|
|
201
188
|
|
|
202
189
|
@property
|
|
@@ -298,6 +285,18 @@ class FieldDataNC(States):
|
|
|
298
285
|
dtype=config.dtype_double,
|
|
299
286
|
)
|
|
300
287
|
|
|
288
|
+
weights = None
|
|
289
|
+
if self.weight_ncvar is not None:
|
|
290
|
+
if self.weight_ncvar not in ds.data_vars:
|
|
291
|
+
raise KeyError(
|
|
292
|
+
f"States '{self.name}': Missing weights variable '{self.weight_ncvar}' in data, found {sorted(list(ds.data_vars.keys()))}"
|
|
293
|
+
)
|
|
294
|
+
if ds[self.weight_ncvar].dims != (self.states_coord,):
|
|
295
|
+
raise ValueError(
|
|
296
|
+
f"States '{self.name}': Weights variable '{self.weight_ncvar}' has wrong dimensions. Expecting {(self.states_coord,)}, got {ds[self.weight_ncvar].dims}"
|
|
297
|
+
)
|
|
298
|
+
weights = ds[self.weight_ncvar].to_numpy()
|
|
299
|
+
|
|
301
300
|
if verbosity > 1:
|
|
302
301
|
print(f"\n{self.name}: Data ranges")
|
|
303
302
|
for v, i in self._dkys.items():
|
|
@@ -307,7 +306,7 @@ class FieldDataNC(States):
|
|
|
307
306
|
f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100*nn/len(d.flat):.2f}%)"
|
|
308
307
|
)
|
|
309
308
|
|
|
310
|
-
return sts, h, y, x, data
|
|
309
|
+
return sts, h, y, x, data, weights
|
|
311
310
|
|
|
312
311
|
def output_point_vars(self, algo):
|
|
313
312
|
"""
|
|
@@ -356,7 +355,9 @@ class FieldDataNC(States):
|
|
|
356
355
|
|
|
357
356
|
# check variables:
|
|
358
357
|
for v in self.ovars:
|
|
359
|
-
if v
|
|
358
|
+
if v == FV.WEIGHT and self.weight_ncvar is None:
|
|
359
|
+
pass
|
|
360
|
+
elif v not in self.var2ncvar and v not in self.fixed_vars:
|
|
360
361
|
raise ValueError(
|
|
361
362
|
f"States '{self.name}': Variable '{v}' neither found in var2ncvar not in fixed_vars"
|
|
362
363
|
)
|
|
@@ -413,7 +414,6 @@ class FieldDataNC(States):
|
|
|
413
414
|
_read_nc_file,
|
|
414
415
|
files,
|
|
415
416
|
coords=coords,
|
|
416
|
-
weight_var=self.weight_ncvar,
|
|
417
417
|
vars=vars,
|
|
418
418
|
nc_engine=config.nc_engine,
|
|
419
419
|
isel=self.isel,
|
|
@@ -440,23 +440,15 @@ class FieldDataNC(States):
|
|
|
440
440
|
)
|
|
441
441
|
if self.load_mode == "preload":
|
|
442
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
443
|
self.__inds = self.__data_source[self.states_coord].to_numpy()
|
|
446
444
|
self._N = len(self.__inds)
|
|
447
445
|
|
|
448
446
|
elif self.load_mode == "fly":
|
|
449
|
-
self.__inds
|
|
447
|
+
self.__inds = self.__data_source
|
|
450
448
|
self.__data_source = fpath
|
|
451
449
|
self._files_maxi = {f: len(inds) for f, inds in zip(files, self.__inds)}
|
|
452
450
|
self.__inds = np.concatenate(self.__inds, axis=0)
|
|
453
451
|
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
452
|
|
|
461
453
|
else:
|
|
462
454
|
raise KeyError(
|
|
@@ -468,11 +460,6 @@ class FieldDataNC(States):
|
|
|
468
460
|
self.__inds, format=self.time_format
|
|
469
461
|
).to_numpy()
|
|
470
462
|
|
|
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
|
-
|
|
476
463
|
# ensure WD and WS get the first two slots of data:
|
|
477
464
|
self._dkys = {}
|
|
478
465
|
if FV.WS in self.ovars:
|
|
@@ -492,8 +479,11 @@ class FieldDataNC(States):
|
|
|
492
479
|
self.H = self.var(FV.H)
|
|
493
480
|
self.VARS = self.var("vars")
|
|
494
481
|
self.DATA = self.var("data")
|
|
482
|
+
self.WEIGHT = self.var(FV.WEIGHT)
|
|
495
483
|
|
|
496
|
-
__, h, y, x, data = self._get_data(
|
|
484
|
+
__, h, y, x, data, weights = self._get_data(
|
|
485
|
+
self.data_source, coords, verbosity
|
|
486
|
+
)
|
|
497
487
|
self._prl_coords = coords
|
|
498
488
|
|
|
499
489
|
coos = (FC.STATE, self.H, self.Y, self.X, self.VARS)
|
|
@@ -504,6 +494,8 @@ class FieldDataNC(States):
|
|
|
504
494
|
idata["coords"][self.X] = x
|
|
505
495
|
idata["coords"][self.VARS] = list(self._dkys.keys())
|
|
506
496
|
idata["data_vars"][self.DATA] = data
|
|
497
|
+
if weights is not None:
|
|
498
|
+
idata["data_vars"][self.WEIGHT] = ((FC.STATE,), weights)
|
|
507
499
|
|
|
508
500
|
return idata
|
|
509
501
|
|
|
@@ -540,10 +532,9 @@ class FieldDataNC(States):
|
|
|
540
532
|
super().set_running(algo, data_stash, sel, isel, verbosity)
|
|
541
533
|
|
|
542
534
|
data_stash[self.name] = dict(
|
|
543
|
-
weights=self.__weights,
|
|
544
535
|
inds=self.__inds,
|
|
545
536
|
)
|
|
546
|
-
del self.
|
|
537
|
+
del self.__inds
|
|
547
538
|
|
|
548
539
|
if self.load_mode == "preload":
|
|
549
540
|
data_stash[self.name]["data_source"] = self.__data_source
|
|
@@ -579,7 +570,6 @@ class FieldDataNC(States):
|
|
|
579
570
|
super().unset_running(algo, data_stash, sel, isel, verbosity)
|
|
580
571
|
|
|
581
572
|
data = data_stash[self.name]
|
|
582
|
-
self.__weights = data.pop("weights")
|
|
583
573
|
self.__inds = data.pop("inds")
|
|
584
574
|
|
|
585
575
|
if self.load_mode == "preload":
|
|
@@ -628,27 +618,6 @@ class FieldDataNC(States):
|
|
|
628
618
|
"""
|
|
629
619
|
return self.ovars
|
|
630
620
|
|
|
631
|
-
def weights(self, algo):
|
|
632
|
-
"""
|
|
633
|
-
The statistical weights of all states.
|
|
634
|
-
|
|
635
|
-
Parameters
|
|
636
|
-
----------
|
|
637
|
-
algo: foxes.core.Algorithm
|
|
638
|
-
The calculation algorithm
|
|
639
|
-
|
|
640
|
-
Returns
|
|
641
|
-
-------
|
|
642
|
-
weights: numpy.ndarray
|
|
643
|
-
The weights, shape: (n_states, n_turbines)
|
|
644
|
-
|
|
645
|
-
"""
|
|
646
|
-
if self.running:
|
|
647
|
-
raise ValueError(
|
|
648
|
-
f"States '{self.name}': Cannot access weights while running"
|
|
649
|
-
)
|
|
650
|
-
return self.__weights
|
|
651
|
-
|
|
652
621
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
653
622
|
"""
|
|
654
623
|
The main model calculation.
|
|
@@ -690,6 +659,7 @@ class FieldDataNC(States):
|
|
|
690
659
|
y = mdata[self.Y]
|
|
691
660
|
h = mdata[self.H]
|
|
692
661
|
data = mdata[self.DATA].copy()
|
|
662
|
+
weights = mdata.get(self.WEIGHT, None)
|
|
693
663
|
coords = self._prl_coords
|
|
694
664
|
|
|
695
665
|
# case lazy:
|
|
@@ -697,7 +667,7 @@ class FieldDataNC(States):
|
|
|
697
667
|
i0 = mdata.states_i0(counter=True)
|
|
698
668
|
s = slice(i0, i0 + n_states)
|
|
699
669
|
ds = self.data_source.isel({self.states_coord: s}).load()
|
|
700
|
-
__, h, y, x, data = self._get_data(ds, coords, verbosity=0)
|
|
670
|
+
__, h, y, x, data, weights = self._get_data(ds, coords, verbosity=0)
|
|
701
671
|
del ds
|
|
702
672
|
|
|
703
673
|
# case fly:
|
|
@@ -725,7 +695,6 @@ class FieldDataNC(States):
|
|
|
725
695
|
_read_nc_file(
|
|
726
696
|
fpath,
|
|
727
697
|
coords=coords,
|
|
728
|
-
weight_var=self.weight_ncvar,
|
|
729
698
|
vars=vars,
|
|
730
699
|
nc_engine=config.nc_engine,
|
|
731
700
|
isel=isel,
|
|
@@ -742,7 +711,7 @@ class FieldDataNC(States):
|
|
|
742
711
|
), f"States '{self.name}': Missing states for load_mode '{self.load_mode}': (i0, i1) = {(i0, i1)}"
|
|
743
712
|
|
|
744
713
|
data = xr.concat(data, dim=self.states_coord)
|
|
745
|
-
__, h, y, x, data = self._get_data(data, coords, verbosity=0)
|
|
714
|
+
__, h, y, x, data, weights = self._get_data(data, coords, verbosity=0)
|
|
746
715
|
|
|
747
716
|
else:
|
|
748
717
|
raise KeyError(
|
|
@@ -858,7 +827,7 @@ class FieldDataNC(States):
|
|
|
858
827
|
out[FV.WD] = uv2wd(uv, axis=-1)
|
|
859
828
|
del uv
|
|
860
829
|
for v in self.ovars:
|
|
861
|
-
if v not in out:
|
|
830
|
+
if v != FV.WEIGHT and v not in out:
|
|
862
831
|
if v in self._dkys:
|
|
863
832
|
out[v] = data[..., self._dkys[v]]
|
|
864
833
|
else:
|
|
@@ -866,4 +835,13 @@ class FieldDataNC(States):
|
|
|
866
835
|
(n_states, n_pts), self.fixed_vars[v], dtype=config.dtype_double
|
|
867
836
|
)
|
|
868
837
|
|
|
838
|
+
# add weights:
|
|
839
|
+
if weights is not None:
|
|
840
|
+
tdata[FV.WEIGHT] = weights[:, None, None]
|
|
841
|
+
else:
|
|
842
|
+
tdata[FV.WEIGHT] = np.full(
|
|
843
|
+
(mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
|
|
844
|
+
)
|
|
845
|
+
tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
846
|
+
|
|
869
847
|
return {v: d.reshape(n_states, n_targets, n_tpoints) for v, d in out.items()}
|