foxes 0.6.1__py3-none-any.whl → 0.7__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.
- foxes/VERSION +1 -1
- foxes/algorithms/downwind/downwind.py +131 -65
- foxes/algorithms/downwind/models/__init__.py +2 -1
- foxes/algorithms/downwind/models/farm_wakes_calc.py +87 -55
- foxes/algorithms/downwind/models/init_farm_data.py +134 -0
- foxes/algorithms/downwind/models/point_wakes_calc.py +54 -65
- foxes/algorithms/downwind/models/{calc_order.py → reorder_farm_output.py} +28 -26
- foxes/algorithms/iterative/iterative.py +100 -51
- foxes/algorithms/iterative/models/convergence.py +3 -3
- foxes/algorithms/iterative/models/farm_wakes_calc.py +55 -48
- foxes/algorithms/sequential/models/seq_state.py +7 -6
- foxes/algorithms/sequential/sequential.py +81 -44
- foxes/constants.py +33 -18
- foxes/core/__init__.py +2 -2
- foxes/core/algorithm.py +31 -12
- foxes/core/data.py +335 -41
- foxes/core/data_calc_model.py +27 -23
- foxes/core/farm_controller.py +27 -28
- foxes/core/farm_data_model.py +26 -4
- foxes/core/model.py +186 -129
- foxes/core/partial_wakes_model.py +84 -81
- foxes/core/point_data_model.py +51 -18
- foxes/core/rotor_model.py +59 -77
- foxes/core/states.py +6 -6
- foxes/core/turbine_model.py +4 -4
- foxes/core/turbine_type.py +24 -0
- foxes/core/vertical_profile.py +3 -3
- foxes/core/wake_frame.py +91 -50
- foxes/core/wake_model.py +74 -43
- foxes/core/wake_superposition.py +29 -26
- foxes/input/farm_layout/__init__.py +1 -0
- foxes/input/farm_layout/from_random.py +49 -0
- foxes/input/states/__init__.py +1 -1
- foxes/input/states/create/__init__.py +1 -0
- foxes/input/states/create/random_abl_states.py +6 -2
- foxes/input/states/create/random_timeseries.py +56 -0
- foxes/input/states/field_data_nc.py +12 -8
- foxes/input/states/multi_height.py +24 -14
- foxes/input/states/scan_ws.py +13 -17
- foxes/input/states/single.py +28 -20
- foxes/input/states/states_table.py +22 -18
- foxes/models/axial_induction_models/betz.py +1 -1
- foxes/models/farm_models/turbine2farm.py +2 -2
- foxes/models/model_book.py +40 -14
- foxes/models/partial_wakes/__init__.py +2 -2
- foxes/models/partial_wakes/axiwake.py +73 -200
- foxes/models/partial_wakes/centre.py +40 -0
- foxes/models/partial_wakes/grid.py +7 -63
- foxes/models/partial_wakes/rotor_points.py +53 -147
- foxes/models/partial_wakes/segregated.py +158 -0
- foxes/models/partial_wakes/top_hat.py +88 -196
- foxes/models/point_models/set_uniform_data.py +4 -4
- foxes/models/point_models/tke2ti.py +4 -4
- foxes/models/point_models/wake_deltas.py +4 -4
- foxes/models/rotor_models/centre.py +15 -19
- foxes/models/rotor_models/grid.py +2 -1
- foxes/models/rotor_models/levels.py +2 -1
- foxes/models/turbine_models/__init__.py +0 -1
- foxes/models/turbine_models/calculator.py +11 -7
- foxes/models/turbine_models/kTI_model.py +13 -11
- foxes/models/turbine_models/lookup_table.py +22 -9
- foxes/models/turbine_models/power_mask.py +81 -51
- foxes/models/turbine_models/rotor_centre_calc.py +17 -20
- foxes/models/turbine_models/sector_management.py +5 -6
- foxes/models/turbine_models/set_farm_vars.py +49 -20
- foxes/models/turbine_models/table_factors.py +5 -5
- foxes/models/turbine_models/thrust2ct.py +9 -5
- foxes/models/turbine_models/yaw2yawm.py +7 -13
- foxes/models/turbine_models/yawm2yaw.py +7 -11
- foxes/models/turbine_types/PCt_file.py +84 -3
- foxes/models/turbine_types/PCt_from_two.py +7 -3
- foxes/models/turbine_types/null_type.py +2 -2
- foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -2
- foxes/models/turbine_types/wsti2PCt_from_two.py +6 -2
- foxes/models/wake_frames/farm_order.py +26 -22
- foxes/models/wake_frames/rotor_wd.py +32 -31
- foxes/models/wake_frames/seq_dynamic_wakes.py +112 -64
- foxes/models/wake_frames/streamlines.py +51 -47
- foxes/models/wake_frames/timelines.py +59 -47
- foxes/models/wake_frames/yawed_wakes.py +63 -40
- foxes/models/wake_models/axisymmetric.py +31 -35
- foxes/models/wake_models/dist_sliced.py +50 -56
- foxes/models/wake_models/gaussian.py +33 -35
- foxes/models/wake_models/induction/rankine_half_body.py +79 -87
- foxes/models/wake_models/induction/rathmann.py +56 -63
- foxes/models/wake_models/induction/self_similar.py +59 -62
- foxes/models/wake_models/ti/crespo_hernandez.py +83 -74
- foxes/models/wake_models/ti/iec_ti.py +65 -75
- foxes/models/wake_models/top_hat.py +60 -69
- foxes/models/wake_models/wake_mirror.py +49 -54
- foxes/models/wake_models/wind/bastankhah14.py +44 -66
- foxes/models/wake_models/wind/bastankhah16.py +84 -111
- foxes/models/wake_models/wind/jensen.py +67 -89
- foxes/models/wake_models/wind/turbopark.py +93 -133
- foxes/models/wake_superpositions/ti_linear.py +33 -27
- foxes/models/wake_superpositions/ti_max.py +33 -27
- foxes/models/wake_superpositions/ti_pow.py +35 -27
- foxes/models/wake_superpositions/ti_quadratic.py +33 -27
- foxes/models/wake_superpositions/ws_linear.py +39 -32
- foxes/models/wake_superpositions/ws_max.py +40 -33
- foxes/models/wake_superpositions/ws_pow.py +39 -32
- foxes/models/wake_superpositions/ws_product.py +35 -28
- foxes/models/wake_superpositions/ws_quadratic.py +39 -32
- foxes/opt/constraints/min_dist.py +1 -1
- foxes/opt/objectives/farm_vars.py +1 -1
- foxes/opt/problems/layout/farm_layout.py +38 -97
- foxes/output/__init__.py +1 -0
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/flow_plots_2d/flow_plots.py +2 -0
- foxes/output/flow_plots_2d/get_fig.py +2 -0
- foxes/output/grids.py +1 -1
- foxes/output/rose_plot.py +3 -3
- foxes/output/rotor_point_plots.py +117 -0
- foxes/output/turbine_type_curves.py +2 -2
- foxes/utils/__init__.py +2 -1
- foxes/utils/load.py +29 -0
- foxes/utils/random_xy.py +56 -0
- foxes/utils/runners/runners.py +13 -1
- foxes/utils/windrose_plot.py +1 -1
- foxes/variables.py +10 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/METADATA +13 -7
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/RECORD +126 -122
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/WHEEL +1 -1
- foxes/models/partial_wakes/distsliced.py +0 -322
- foxes/models/partial_wakes/mapped.py +0 -252
- foxes/models/turbine_models/set_XYHD.py +0 -130
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/LICENSE +0 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/top_level.txt +0 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/zip-safe +0 -0
foxes/core/farm_data_model.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
+
import numpy as np
|
|
2
3
|
|
|
3
4
|
from .data_calc_model import DataCalcModel
|
|
4
5
|
import foxes.constants as FC
|
|
@@ -51,6 +52,27 @@ class FarmDataModel(DataCalcModel):
|
|
|
51
52
|
"""
|
|
52
53
|
return []
|
|
53
54
|
|
|
55
|
+
def ensure_variables(self, algo, mdata, fdata):
|
|
56
|
+
"""
|
|
57
|
+
Add variables to fdata, initialized with NaN
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
algo: foxes.core.Algorithm
|
|
62
|
+
The calculation algorithm
|
|
63
|
+
mdata: foxes.core.Data
|
|
64
|
+
The model data
|
|
65
|
+
fdata: foxes.core.Data
|
|
66
|
+
The farm data
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
n_states = fdata.n_states
|
|
70
|
+
n_turbines = fdata.n_turbines
|
|
71
|
+
for v in self.output_farm_vars(algo):
|
|
72
|
+
if v not in fdata:
|
|
73
|
+
fdata[v] = np.full((n_states, n_turbines), np.nan, dtype=FC.DTYPE)
|
|
74
|
+
fdata.dims[v] = (FC.STATE, FC.TURBINE)
|
|
75
|
+
|
|
54
76
|
@abstractmethod
|
|
55
77
|
def calculate(self, algo, mdata, fdata):
|
|
56
78
|
""" "
|
|
@@ -63,9 +85,9 @@ class FarmDataModel(DataCalcModel):
|
|
|
63
85
|
----------
|
|
64
86
|
algo: foxes.core.Algorithm
|
|
65
87
|
The calculation algorithm
|
|
66
|
-
mdata: foxes.core.
|
|
88
|
+
mdata: foxes.core.MData
|
|
67
89
|
The model data
|
|
68
|
-
fdata: foxes.core.
|
|
90
|
+
fdata: foxes.core.FData
|
|
69
91
|
The farm data
|
|
70
92
|
|
|
71
93
|
Returns
|
|
@@ -218,9 +240,9 @@ class FarmDataModelList(FarmDataModel):
|
|
|
218
240
|
----------
|
|
219
241
|
algo: foxes.core.Algorithm
|
|
220
242
|
The calculation algorithm
|
|
221
|
-
mdata: foxes.core.
|
|
243
|
+
mdata: foxes.core.MData
|
|
222
244
|
The model data
|
|
223
|
-
fdata: foxes.core.
|
|
245
|
+
fdata: foxes.core.FData
|
|
224
246
|
The farm data
|
|
225
247
|
parameters: list of dict, optional
|
|
226
248
|
A list of parameter dicts, one for each model
|
foxes/core/model.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from abc import ABC
|
|
3
3
|
from itertools import count
|
|
4
|
+
from copy import deepcopy
|
|
4
5
|
|
|
5
6
|
import foxes.constants as FC
|
|
6
7
|
from .data import Data
|
|
@@ -37,8 +38,7 @@ class Model(ABC):
|
|
|
37
38
|
self.__initialized = False
|
|
38
39
|
|
|
39
40
|
def __repr__(self):
|
|
40
|
-
|
|
41
|
-
return f"{self.name} ({t})"
|
|
41
|
+
return f"{type(self).__name__}()"
|
|
42
42
|
|
|
43
43
|
@property
|
|
44
44
|
def model_id(self):
|
|
@@ -187,12 +187,12 @@ class Model(ABC):
|
|
|
187
187
|
lookup="smfp",
|
|
188
188
|
mdata=None,
|
|
189
189
|
fdata=None,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
upcast=False,
|
|
190
|
+
tdata=None,
|
|
191
|
+
downwind_index=None,
|
|
193
192
|
accept_none=False,
|
|
194
193
|
accept_nan=True,
|
|
195
194
|
algo=None,
|
|
195
|
+
upcast=False,
|
|
196
196
|
):
|
|
197
197
|
"""
|
|
198
198
|
Getter for a data entry in the model object
|
|
@@ -203,26 +203,24 @@ class Model(ABC):
|
|
|
203
203
|
variable: str
|
|
204
204
|
The variable, serves as data key
|
|
205
205
|
target: str, optional
|
|
206
|
-
The dimensions identifier for the output,
|
|
207
|
-
FC.STATE_TURBINE, FC.
|
|
206
|
+
The dimensions identifier for the output,
|
|
207
|
+
FC.STATE_TURBINE, FC.STATE_TARGET or
|
|
208
|
+
FC.STATE_TARGET_TPOINT
|
|
208
209
|
lookup: str
|
|
209
210
|
The order of data sources. Combination of:
|
|
210
211
|
's' for self,
|
|
211
212
|
'm' for mdata,
|
|
212
213
|
'f' for fdata,
|
|
213
|
-
'
|
|
214
|
+
't' for tdata,
|
|
214
215
|
'w' for wake modelling data
|
|
215
216
|
mdata: foxes.core.Data, optional
|
|
216
217
|
The model data
|
|
217
218
|
fdata: foxes.core.Data, optional
|
|
218
219
|
The farm data
|
|
219
|
-
|
|
220
|
-
The
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
wake causing turbine. Shape: (n_states,)
|
|
224
|
-
upcast: bool, optional
|
|
225
|
-
Upcast array to dims if data is scalar
|
|
220
|
+
tdata: foxes.core.Data, optional
|
|
221
|
+
The target point data
|
|
222
|
+
downwind_index: int, optional
|
|
223
|
+
The index in the downwind order
|
|
226
224
|
data_prio: bool
|
|
227
225
|
First search the data source, then the object
|
|
228
226
|
accept_none: bool
|
|
@@ -231,146 +229,235 @@ class Model(ABC):
|
|
|
231
229
|
Do not throw an error if data entry is np.nan
|
|
232
230
|
algo: foxes.core.Algorithm, optional
|
|
233
231
|
The algorithm, needed for data from previous iteration
|
|
232
|
+
upcast: bool
|
|
233
|
+
Flag for ensuring targets dimension,
|
|
234
|
+
otherwise dimension 1 is entered
|
|
234
235
|
|
|
235
236
|
"""
|
|
236
237
|
|
|
237
238
|
def _geta(a):
|
|
238
|
-
sources = [s for s in [mdata, fdata,
|
|
239
|
+
sources = [s for s in [mdata, fdata, tdata, algo, self] if s is not None]
|
|
239
240
|
for s in sources:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
241
|
+
try:
|
|
242
|
+
if a == "states_i0":
|
|
243
|
+
out = s.states_i0(counter=True, algo=algo)
|
|
244
|
+
if out is not None:
|
|
245
|
+
return out
|
|
246
|
+
else:
|
|
246
247
|
out = getattr(s, a)
|
|
247
248
|
if out is not None:
|
|
248
249
|
return out
|
|
249
|
-
|
|
250
|
-
|
|
250
|
+
except AttributeError:
|
|
251
|
+
pass
|
|
251
252
|
raise KeyError(
|
|
252
|
-
f"Model '{self.name}': Failed to determine '{a}'. Maybe add to arguments of get_data: mdata, fdata,
|
|
253
|
+
f"Model '{self.name}': Failed to determine '{a}'. Maybe add to arguments of get_data: mdata, fdata, tdata, algo?"
|
|
253
254
|
)
|
|
254
255
|
|
|
255
256
|
n_states = _geta("n_states")
|
|
256
257
|
if target == FC.STATE_TURBINE:
|
|
257
258
|
n_turbines = _geta("n_turbines")
|
|
258
259
|
dims = (FC.STATE, FC.TURBINE)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
260
|
+
shp = (n_states, n_turbines)
|
|
261
|
+
elif target == FC.STATE_TARGET:
|
|
262
|
+
n_targets = _geta("n_targets")
|
|
263
|
+
dims = (FC.STATE, FC.TARGET)
|
|
264
|
+
shp = (n_states, n_targets)
|
|
265
|
+
elif target == FC.STATE_TARGET_TPOINT:
|
|
266
|
+
n_targets = _geta("n_targets")
|
|
267
|
+
n_tpoints = _geta("n_tpoints")
|
|
268
|
+
dims = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
269
|
+
shp = (n_states, n_targets, n_tpoints)
|
|
262
270
|
else:
|
|
263
271
|
raise KeyError(
|
|
264
|
-
f"Model '{self.name}': Wrong parameter 'target = {target}'. Choices: {FC.STATE_TURBINE}, {FC.
|
|
272
|
+
f"Model '{self.name}': Wrong parameter 'target = {target}'. Choices: {FC.STATE_TURBINE}, {FC.STATE_TARGET}, {FC.STATE_TARGET_TPOINT}"
|
|
265
273
|
)
|
|
266
274
|
|
|
267
275
|
out = None
|
|
276
|
+
out_dims = None
|
|
268
277
|
for s in lookup:
|
|
269
278
|
# lookup self:
|
|
270
279
|
if s == "s" and hasattr(self, variable):
|
|
271
280
|
a = getattr(self, variable)
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
281
|
+
if a is not None:
|
|
282
|
+
if not upcast:
|
|
283
|
+
out = a
|
|
284
|
+
out_dims = None
|
|
285
|
+
elif target == FC.STATE_TURBINE:
|
|
275
286
|
out = np.full((n_states, n_turbines), np.nan, dtype=FC.DTYPE)
|
|
276
287
|
out[:] = a
|
|
277
|
-
|
|
278
|
-
|
|
288
|
+
out_dims = (FC.STATE, FC.TURBINE)
|
|
289
|
+
elif target == FC.STATE_TARGET:
|
|
290
|
+
out = np.full((n_states, n_targets), np.nan, dtype=FC.DTYPE)
|
|
279
291
|
out[:] = a
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
292
|
+
out_dims = (FC.STATE, FC.TARGET)
|
|
293
|
+
elif target == FC.STATE_TARGET_TPOINT:
|
|
294
|
+
out = np.full(
|
|
295
|
+
(n_states, n_targets, n_tpoints), np.nan, dtype=FC.DTYPE
|
|
283
296
|
)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
297
|
+
out[:] = a
|
|
298
|
+
out_dims = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
299
|
+
else:
|
|
300
|
+
raise NotImplementedError
|
|
287
301
|
|
|
288
302
|
# lookup mdata:
|
|
289
303
|
elif (
|
|
290
304
|
s == "m"
|
|
291
305
|
and mdata is not None
|
|
292
306
|
and variable in mdata
|
|
293
|
-
and
|
|
294
|
-
and tuple(mdata.dims[variable][:2]) == dims
|
|
307
|
+
and tuple(mdata.dims[variable]) == dims
|
|
295
308
|
):
|
|
296
309
|
out = mdata[variable]
|
|
310
|
+
out_dims = dims
|
|
297
311
|
|
|
298
312
|
# lookup fdata:
|
|
299
313
|
elif (
|
|
300
314
|
s == "f"
|
|
301
315
|
and fdata is not None
|
|
302
316
|
and variable in fdata
|
|
303
|
-
and
|
|
304
|
-
and tuple(fdata.dims[variable][:2]) == (FC.STATE, FC.TURBINE)
|
|
317
|
+
and tuple(fdata.dims[variable]) == (FC.STATE, FC.TURBINE)
|
|
305
318
|
):
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
out = fdata[variable]
|
|
309
|
-
|
|
310
|
-
# translate state-turbine to state-point data:
|
|
311
|
-
elif target == FC.STATE_POINT and states_source_turbine is not None:
|
|
312
|
-
# from fdata, uniform for points:
|
|
313
|
-
st_sel = (np.arange(n_states), states_source_turbine)
|
|
314
|
-
out = np.zeros((n_states, n_points), dtype=FC.DTYPE)
|
|
315
|
-
out[:] = fdata[variable][st_sel][:, None]
|
|
316
|
-
|
|
317
|
-
# from previous iteration, if requested:
|
|
318
|
-
if pdata is not None and FC.STATES_SEL in pdata:
|
|
319
|
-
if not np.all(
|
|
320
|
-
states_source_turbine == pdata[FC.STATE_SOURCE_TURBINE]
|
|
321
|
-
):
|
|
322
|
-
raise ValueError(
|
|
323
|
-
f"Model '{self.name}': Mismatch of 'states_source_turbine'. Expected {list(pdata[FC.STATE_SOURCE_TURBINE])}, got {list(states_source_turbine)}"
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
i0 = _geta("states_i0")
|
|
327
|
-
sp = pdata[FC.STATES_SEL]
|
|
328
|
-
sel = sp < i0
|
|
329
|
-
if np.any(sel):
|
|
330
|
-
if algo is None or not hasattr(algo, "prev_farm_results"):
|
|
331
|
-
raise KeyError(
|
|
332
|
-
f"Model '{self.name}': Argument algo is either not given, or not an iterative algorithm"
|
|
333
|
-
)
|
|
334
|
-
|
|
335
|
-
prev_fdata = getattr(algo, "prev_farm_results")
|
|
336
|
-
if prev_fdata is None:
|
|
337
|
-
out[sel] = 0
|
|
338
|
-
else:
|
|
339
|
-
st = np.zeros_like(sp)
|
|
340
|
-
st[:] = states_source_turbine[:, None]
|
|
341
|
-
out[sel] = prev_fdata[variable].to_numpy()[
|
|
342
|
-
sp[sel], st[sel]
|
|
343
|
-
]
|
|
319
|
+
out = fdata[variable]
|
|
320
|
+
out_dims = (FC.STATE, FC.TURBINE)
|
|
344
321
|
|
|
345
322
|
# lookup pdata:
|
|
346
323
|
elif (
|
|
347
|
-
s == "
|
|
348
|
-
and
|
|
349
|
-
and variable in
|
|
350
|
-
and
|
|
351
|
-
and tuple(pdata.dims[variable][:2]) == dims
|
|
324
|
+
s == "t"
|
|
325
|
+
and tdata is not None
|
|
326
|
+
and variable in tdata
|
|
327
|
+
and tuple(tdata.dims[variable]) == (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
352
328
|
):
|
|
353
|
-
out =
|
|
329
|
+
out = tdata[variable]
|
|
330
|
+
out_dims = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
354
331
|
|
|
355
332
|
# lookup wake modelling data:
|
|
356
333
|
elif (
|
|
357
334
|
s == "w"
|
|
358
|
-
and target == FC.STATE_POINT
|
|
359
335
|
and fdata is not None
|
|
360
|
-
and
|
|
336
|
+
and tdata is not None
|
|
361
337
|
and variable in fdata
|
|
362
|
-
and
|
|
363
|
-
and
|
|
364
|
-
and states_source_turbine is not None
|
|
338
|
+
and tuple(fdata.dims[variable]) == (FC.STATE, FC.TURBINE)
|
|
339
|
+
and downwind_index is not None
|
|
365
340
|
and algo is not None
|
|
366
341
|
):
|
|
367
|
-
out = algo.wake_frame.get_wake_modelling_data(
|
|
368
|
-
algo,
|
|
342
|
+
out, out_dims = algo.wake_frame.get_wake_modelling_data(
|
|
343
|
+
algo,
|
|
344
|
+
variable,
|
|
345
|
+
downwind_index,
|
|
346
|
+
fdata,
|
|
347
|
+
tdata=tdata,
|
|
348
|
+
target=target,
|
|
349
|
+
upcast=upcast,
|
|
369
350
|
)
|
|
370
351
|
|
|
371
352
|
if out is not None:
|
|
372
353
|
break
|
|
373
354
|
|
|
355
|
+
# cast dimensions:
|
|
356
|
+
if out_dims != dims:
|
|
357
|
+
if out_dims is None:
|
|
358
|
+
if upcast:
|
|
359
|
+
out0 = out
|
|
360
|
+
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
361
|
+
out[:] = out0
|
|
362
|
+
out_dims = dims
|
|
363
|
+
del out0
|
|
364
|
+
else:
|
|
365
|
+
out_dims = tuple([1 for _ in dims])
|
|
366
|
+
|
|
367
|
+
elif out_dims == (FC.STATE, FC.TURBINE):
|
|
368
|
+
if downwind_index is None:
|
|
369
|
+
raise KeyError(
|
|
370
|
+
f"Require downwind_index for target {target} and out dims {out_dims}"
|
|
371
|
+
)
|
|
372
|
+
out0 = out[:, downwind_index, None]
|
|
373
|
+
if len(dims) == 3:
|
|
374
|
+
out0 = out0[:, :, None]
|
|
375
|
+
if upcast:
|
|
376
|
+
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
377
|
+
out[:] = out0
|
|
378
|
+
out_dims = dims
|
|
379
|
+
else:
|
|
380
|
+
out = out0
|
|
381
|
+
out_dims = (FC.STATE, 1) if len(dims) == 2 else (FC.STATE, 1, 1)
|
|
382
|
+
del out0
|
|
383
|
+
|
|
384
|
+
elif out_dims == (FC.STATE, 1):
|
|
385
|
+
out0 = out
|
|
386
|
+
if len(dims) == 3:
|
|
387
|
+
out0 = out0[:, :, None]
|
|
388
|
+
out_dims = (FC.STATE, 1, 1)
|
|
389
|
+
if upcast:
|
|
390
|
+
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
391
|
+
out[:] = out0
|
|
392
|
+
out_dims = dims
|
|
393
|
+
else:
|
|
394
|
+
out = out0
|
|
395
|
+
del out0
|
|
396
|
+
|
|
397
|
+
elif out_dims == (FC.STATE, 1, 1):
|
|
398
|
+
out0 = out
|
|
399
|
+
if len(dims) == 2:
|
|
400
|
+
out0 = out0[:, :, 0]
|
|
401
|
+
out_dims = (FC.STATE, 1)
|
|
402
|
+
if upcast:
|
|
403
|
+
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
404
|
+
out[:] = out0
|
|
405
|
+
out_dims = dims
|
|
406
|
+
else:
|
|
407
|
+
out = out0
|
|
408
|
+
del out0
|
|
409
|
+
|
|
410
|
+
else:
|
|
411
|
+
raise NotImplementedError(
|
|
412
|
+
f"No casting implemented for target {target} and out dims {out_dims} fo upcast {upcast}"
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
# data from other chunks, only with iterations:
|
|
416
|
+
if (
|
|
417
|
+
target in [FC.STATE_TARGET, FC.STATE_TARGET_TPOINT]
|
|
418
|
+
and fdata is not None
|
|
419
|
+
and variable in fdata
|
|
420
|
+
and tdata is not None
|
|
421
|
+
and FC.STATES_SEL in tdata
|
|
422
|
+
):
|
|
423
|
+
if out_dims != dims:
|
|
424
|
+
raise ValueError(
|
|
425
|
+
f"Model '{self.name}': Iteration data found for variable '{variable}', but missing upcast: out_dims = {out_dims}, expecting {dims}"
|
|
426
|
+
)
|
|
427
|
+
if downwind_index is None:
|
|
428
|
+
raise KeyError(
|
|
429
|
+
f"Model '{self.name}': Require downwind_index for obtaining results from previous iteration"
|
|
430
|
+
)
|
|
431
|
+
if tdata[FC.STATE_SOURCE_ORDERI] != downwind_index:
|
|
432
|
+
raise ValueError(
|
|
433
|
+
f"Model '{self.name}': Expecting downwind_index {tdata[FC.STATE_SOURCE_ORDERI]}, got {downwind_index}"
|
|
434
|
+
)
|
|
435
|
+
if algo is None:
|
|
436
|
+
raise ValueError(
|
|
437
|
+
f"Model '{self.name}': Iteration data found for variable '{variable}', requiring algo"
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
i0 = _geta("states_i0")
|
|
441
|
+
sts = tdata[FC.STATES_SEL]
|
|
442
|
+
if target == FC.STATE_TARGET and tdata.n_tpoints != 1:
|
|
443
|
+
# find the mean index and round it to nearest integer:
|
|
444
|
+
sts = tdata.tpoint_mean(FC.STATES_SEL)[:, :, None]
|
|
445
|
+
sts = (sts + 0.5).astype(FC.ITYPE)
|
|
446
|
+
sel = sts < i0
|
|
447
|
+
if np.any(sel):
|
|
448
|
+
if not hasattr(algo, "prev_farm_results"):
|
|
449
|
+
raise KeyError(
|
|
450
|
+
f"Model '{self.name}': Iteration data found for variable '{variable}', requiring iterative algorithm"
|
|
451
|
+
)
|
|
452
|
+
prev_fres = getattr(algo, "prev_farm_results")
|
|
453
|
+
if prev_fres is not None:
|
|
454
|
+
prev_data = prev_fres[variable].to_numpy()[sts[sel], downwind_index]
|
|
455
|
+
if target == FC.STATE_TARGET:
|
|
456
|
+
out[sel[:, :, 0]] = prev_data
|
|
457
|
+
else:
|
|
458
|
+
out[sel] = prev_data
|
|
459
|
+
del prev_fres, prev_data
|
|
460
|
+
|
|
374
461
|
# check for None:
|
|
375
462
|
if not accept_none and out is None:
|
|
376
463
|
raise ValueError(
|
|
@@ -410,8 +497,10 @@ class Model(ABC):
|
|
|
410
497
|
data={}, dims={}, loop_dims=data.loop_dims, name=f"{self.name}_{i0}"
|
|
411
498
|
)
|
|
412
499
|
|
|
413
|
-
self._store[i0][name] = data[name]
|
|
414
|
-
self._store[i0].dims[name] =
|
|
500
|
+
self._store[i0][name] = deepcopy(data[name])
|
|
501
|
+
self._store[i0].dims[name] = (
|
|
502
|
+
deepcopy(data.dims[name]) if name in data.dims else None
|
|
503
|
+
)
|
|
415
504
|
|
|
416
505
|
def from_data_or_store(self, name, algo, data, ret_dims=False, safe=False):
|
|
417
506
|
"""
|
|
@@ -450,35 +539,3 @@ class Model(ABC):
|
|
|
450
539
|
return self._store[i0][name]
|
|
451
540
|
else:
|
|
452
541
|
return (None, None) if ret_dims else None
|
|
453
|
-
|
|
454
|
-
'''
|
|
455
|
-
@classmethod
|
|
456
|
-
def reduce_states(cls, sel_states, objs):
|
|
457
|
-
"""
|
|
458
|
-
Modifies the given objects by selecting a
|
|
459
|
-
subset of states.
|
|
460
|
-
|
|
461
|
-
Parameters
|
|
462
|
-
----------
|
|
463
|
-
sel_states: list of int
|
|
464
|
-
The states selection
|
|
465
|
-
objs: list of foxes.core.Data
|
|
466
|
-
The objects, e.g. [mdata, fdata, pdata]
|
|
467
|
-
|
|
468
|
-
Returns
|
|
469
|
-
-------
|
|
470
|
-
mobjs: list of foxes.core.Data
|
|
471
|
-
The modified objects with reduced
|
|
472
|
-
states dimension
|
|
473
|
-
|
|
474
|
-
"""
|
|
475
|
-
out = []
|
|
476
|
-
for o in objs:
|
|
477
|
-
data = {
|
|
478
|
-
v: d[sel_states] if o.dims[v][0] == FC.STATE else d
|
|
479
|
-
for v, d in o.items()
|
|
480
|
-
}
|
|
481
|
-
out.append(Data(data, o.dims, loop_dims=o.loop_dims, name=o.name))
|
|
482
|
-
|
|
483
|
-
return out
|
|
484
|
-
'''
|