foxes 0.8.1__py3-none-any.whl → 1.0__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.
- docs/source/conf.py +353 -0
- examples/abl_states/run.py +160 -0
- examples/compare_rotors_pwakes/run.py +217 -0
- examples/compare_wakes/run.py +241 -0
- examples/dyn_wakes/run.py +311 -0
- examples/field_data_nc/run.py +121 -0
- examples/induction_RHB/run.py +201 -0
- examples/multi_height/run.py +113 -0
- examples/power_mask/run.py +249 -0
- examples/random_timeseries/run.py +210 -0
- examples/scan_row/run.py +193 -0
- examples/sector_management/run.py +162 -0
- examples/sequential/run.py +209 -0
- examples/single_state/run.py +201 -0
- examples/states_lookup_table/run.py +137 -0
- examples/streamline_wakes/run.py +138 -0
- examples/tab_file/run.py +142 -0
- examples/timelines/run.py +267 -0
- examples/timeseries/run.py +183 -0
- examples/timeseries_slurm/run.py +185 -0
- examples/wind_rose/run.py +141 -0
- examples/windio/run.py +29 -0
- examples/yawed_wake/run.py +196 -0
- foxes/__init__.py +4 -8
- foxes/algorithms/__init__.py +1 -1
- foxes/algorithms/downwind/downwind.py +232 -101
- foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -6
- foxes/algorithms/downwind/models/init_farm_data.py +1 -1
- foxes/algorithms/downwind/models/point_wakes_calc.py +5 -6
- foxes/algorithms/downwind/models/reorder_farm_output.py +0 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +4 -2
- foxes/algorithms/iterative/iterative.py +73 -33
- foxes/algorithms/iterative/models/farm_wakes_calc.py +11 -6
- foxes/algorithms/sequential/models/plugin.py +1 -1
- foxes/algorithms/sequential/sequential.py +126 -255
- foxes/constants.py +17 -2
- foxes/core/__init__.py +1 -0
- foxes/core/algorithm.py +631 -146
- foxes/core/data.py +252 -20
- foxes/core/data_calc_model.py +13 -289
- foxes/core/engine.py +630 -0
- foxes/core/farm_controller.py +37 -9
- foxes/core/farm_data_model.py +15 -0
- foxes/core/model.py +133 -80
- foxes/core/point_data_model.py +15 -0
- foxes/core/rotor_model.py +27 -21
- foxes/core/states.py +16 -0
- foxes/core/turbine_type.py +28 -0
- foxes/core/wake_frame.py +22 -4
- foxes/core/wake_model.py +2 -3
- foxes/data/windio/windio_5turbines_timeseries.yaml +23 -1
- foxes/engines/__init__.py +16 -0
- foxes/engines/dask.py +975 -0
- foxes/engines/default.py +75 -0
- foxes/engines/futures.py +72 -0
- foxes/engines/mpi.py +38 -0
- foxes/engines/multiprocess.py +74 -0
- foxes/engines/numpy.py +185 -0
- foxes/engines/pool.py +263 -0
- foxes/engines/single.py +139 -0
- foxes/input/farm_layout/__init__.py +1 -0
- foxes/input/farm_layout/from_csv.py +4 -0
- foxes/input/farm_layout/from_json.py +1 -1
- foxes/input/farm_layout/grid.py +2 -2
- foxes/input/farm_layout/ring.py +65 -0
- foxes/input/farm_layout/row.py +2 -2
- foxes/input/states/__init__.py +6 -0
- foxes/input/states/create/random_abl_states.py +1 -1
- foxes/input/states/field_data_nc.py +157 -32
- foxes/input/states/multi_height.py +127 -13
- foxes/input/states/one_point_flow.py +577 -0
- foxes/input/states/scan_ws.py +73 -2
- foxes/input/states/states_table.py +204 -35
- foxes/input/windio/__init__.py +1 -1
- foxes/input/windio/get_states.py +44 -23
- foxes/input/windio/read_attributes.py +41 -16
- foxes/input/windio/read_farm.py +116 -102
- foxes/input/windio/read_fields.py +13 -6
- foxes/input/windio/read_outputs.py +63 -22
- foxes/input/windio/runner.py +31 -17
- foxes/input/windio/windio.py +36 -22
- foxes/models/ground_models/wake_mirror.py +8 -4
- foxes/models/model_book.py +29 -18
- foxes/models/partial_wakes/rotor_points.py +3 -3
- foxes/models/rotor_models/centre.py +4 -0
- foxes/models/rotor_models/grid.py +22 -23
- foxes/models/rotor_models/levels.py +4 -5
- foxes/models/turbine_models/calculator.py +0 -2
- foxes/models/turbine_models/lookup_table.py +27 -2
- foxes/models/turbine_models/rotor_centre_calc.py +4 -3
- foxes/models/turbine_models/set_farm_vars.py +103 -34
- foxes/models/turbine_types/PCt_file.py +24 -0
- foxes/models/turbine_types/PCt_from_two.py +24 -0
- foxes/models/turbine_types/__init__.py +1 -0
- foxes/models/turbine_types/lookup.py +316 -0
- foxes/models/turbine_types/null_type.py +50 -0
- foxes/models/turbine_types/wsrho2PCt_from_two.py +24 -0
- foxes/models/turbine_types/wsti2PCt_from_two.py +24 -0
- foxes/models/vertical_profiles/data_profile.py +1 -1
- foxes/models/wake_frames/__init__.py +1 -0
- foxes/models/wake_frames/dynamic_wakes.py +424 -0
- foxes/models/wake_frames/farm_order.py +23 -3
- foxes/models/wake_frames/rotor_wd.py +4 -2
- foxes/models/wake_frames/seq_dynamic_wakes.py +56 -63
- foxes/models/wake_frames/streamlines.py +19 -20
- foxes/models/wake_frames/timelines.py +328 -127
- foxes/models/wake_frames/yawed_wakes.py +4 -1
- foxes/models/wake_models/dist_sliced.py +1 -3
- foxes/models/wake_models/induction/rankine_half_body.py +4 -4
- foxes/models/wake_models/induction/rathmann.py +2 -2
- foxes/models/wake_models/induction/self_similar.py +2 -2
- foxes/models/wake_models/induction/vortex_sheet.py +2 -2
- foxes/models/wake_models/ti/iec_ti.py +34 -17
- foxes/models/wake_models/top_hat.py +1 -1
- foxes/models/wake_models/wind/bastankhah14.py +2 -2
- foxes/models/wake_models/wind/bastankhah16.py +8 -7
- foxes/models/wake_models/wind/jensen.py +1 -1
- foxes/models/wake_models/wind/turbopark.py +2 -2
- foxes/output/__init__.py +4 -1
- foxes/output/farm_layout.py +2 -2
- foxes/output/flow_plots_2d/__init__.py +0 -1
- foxes/output/flow_plots_2d/flow_plots.py +70 -30
- foxes/output/grids.py +91 -21
- foxes/output/seq_plugins/__init__.py +2 -0
- foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +62 -20
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
- foxes/output/slice_data.py +131 -111
- foxes/output/state_turbine_map.py +18 -13
- foxes/output/state_turbine_table.py +19 -19
- foxes/utils/__init__.py +1 -1
- foxes/utils/dev_utils.py +42 -0
- foxes/utils/dict.py +1 -1
- foxes/utils/factory.py +147 -52
- foxes/utils/pandas_helpers.py +4 -3
- foxes/utils/wind_dir.py +0 -2
- foxes/utils/xarray_utils.py +25 -13
- foxes/variables.py +37 -0
- {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/METADATA +72 -34
- foxes-1.0.dist-info/RECORD +307 -0
- {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/WHEEL +1 -1
- foxes-1.0.dist-info/top_level.txt +4 -0
- tests/0_consistency/iterative/test_iterative.py +92 -0
- tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
- tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
- tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
- tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
- tests/3_examples/test_examples.py +34 -0
- foxes/VERSION +0 -1
- foxes/output/flow_plots_2d.py +0 -0
- foxes/utils/plotly_helpers.py +0 -19
- foxes/utils/runners/__init__.py +0 -1
- foxes/utils/runners/runners.py +0 -280
- foxes-0.8.1.dist-info/RECORD +0 -248
- foxes-0.8.1.dist-info/top_level.txt +0 -1
- foxes-0.8.1.dist-info/zip-safe +0 -1
- {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/LICENSE +0 -0
foxes/core/farm_data_model.py
CHANGED
|
@@ -52,6 +52,18 @@ class FarmDataModel(DataCalcModel):
|
|
|
52
52
|
"""
|
|
53
53
|
return []
|
|
54
54
|
|
|
55
|
+
def output_coords(self):
|
|
56
|
+
"""
|
|
57
|
+
Gets the coordinates of all output arrays
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
dims: tuple of str
|
|
62
|
+
The coordinates of all output arrays
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
return (FC.STATE, FC.TURBINE)
|
|
66
|
+
|
|
55
67
|
def ensure_variables(self, algo, mdata, fdata):
|
|
56
68
|
"""
|
|
57
69
|
Add variables to fdata, initialized with NaN
|
|
@@ -171,6 +183,9 @@ class FarmDataModelList(FarmDataModel):
|
|
|
171
183
|
super().__init__()
|
|
172
184
|
self.models = models
|
|
173
185
|
|
|
186
|
+
def __repr__(self):
|
|
187
|
+
return f"{type(self).__name__}({[m.name for m in self.models]})"
|
|
188
|
+
|
|
174
189
|
def append(self, model):
|
|
175
190
|
"""
|
|
176
191
|
Add a model to the list
|
foxes/core/model.py
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from abc import ABC
|
|
3
3
|
from itertools import count
|
|
4
|
-
from copy import deepcopy
|
|
5
4
|
|
|
6
5
|
import foxes.constants as FC
|
|
7
|
-
from .data import Data
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
class Model(ABC):
|
|
@@ -35,8 +33,8 @@ class Model(ABC):
|
|
|
35
33
|
if self._id > 0:
|
|
36
34
|
self.name += f"_instance{self._id}"
|
|
37
35
|
|
|
38
|
-
self._store = {}
|
|
39
36
|
self.__initialized = False
|
|
37
|
+
self.__running = False
|
|
40
38
|
|
|
41
39
|
def __repr__(self):
|
|
42
40
|
return f"{type(self).__name__}()"
|
|
@@ -119,6 +117,10 @@ class Model(ABC):
|
|
|
119
117
|
and `coords`, a dict with entries `dim_name_str -> dim_array`
|
|
120
118
|
|
|
121
119
|
"""
|
|
120
|
+
if self.initialized:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
f"Model '{self.name}': Cannot call load_data after initialization"
|
|
123
|
+
)
|
|
122
124
|
return {"coords": {}, "data_vars": {}}
|
|
123
125
|
|
|
124
126
|
def initialize(self, algo, verbosity=0, force=False):
|
|
@@ -135,6 +137,8 @@ class Model(ABC):
|
|
|
135
137
|
Overwrite existing data
|
|
136
138
|
|
|
137
139
|
"""
|
|
140
|
+
if self.running:
|
|
141
|
+
raise ValueError(f"Model '{self.name}': Cannot initialize while running")
|
|
138
142
|
if not self.initialized:
|
|
139
143
|
pr = False
|
|
140
144
|
for m in self.sub_models():
|
|
@@ -152,6 +156,103 @@ class Model(ABC):
|
|
|
152
156
|
|
|
153
157
|
self.__initialized = True
|
|
154
158
|
|
|
159
|
+
@property
|
|
160
|
+
def running(self):
|
|
161
|
+
"""
|
|
162
|
+
Flag for currently running models
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
flag: bool
|
|
167
|
+
True if currently running
|
|
168
|
+
|
|
169
|
+
"""
|
|
170
|
+
return self.__running
|
|
171
|
+
|
|
172
|
+
def set_running(
|
|
173
|
+
self,
|
|
174
|
+
algo,
|
|
175
|
+
data_stash,
|
|
176
|
+
sel=None,
|
|
177
|
+
isel=None,
|
|
178
|
+
verbosity=0,
|
|
179
|
+
):
|
|
180
|
+
"""
|
|
181
|
+
Sets this model status to running, and moves
|
|
182
|
+
all large data to stash.
|
|
183
|
+
|
|
184
|
+
The stashed data will be returned by the
|
|
185
|
+
unset_running() function after running calculations.
|
|
186
|
+
|
|
187
|
+
Parameters
|
|
188
|
+
----------
|
|
189
|
+
algo: foxes.core.Algorithm
|
|
190
|
+
The calculation algorithm
|
|
191
|
+
data_stash: dict
|
|
192
|
+
Large data stash, this function adds data here.
|
|
193
|
+
Key: model name. Value: dict, large model data
|
|
194
|
+
sel: dict, optional
|
|
195
|
+
The subset selection dictionary
|
|
196
|
+
isel: dict, optional
|
|
197
|
+
The index subset selection dictionary
|
|
198
|
+
verbosity: int
|
|
199
|
+
The verbosity level, 0 = silent
|
|
200
|
+
|
|
201
|
+
"""
|
|
202
|
+
if self.running:
|
|
203
|
+
raise ValueError(
|
|
204
|
+
f"Model '{self.name}': Cannot call set_running while running"
|
|
205
|
+
)
|
|
206
|
+
for m in self.sub_models():
|
|
207
|
+
if not m.running:
|
|
208
|
+
m.set_running(algo, data_stash, sel, isel, verbosity=verbosity)
|
|
209
|
+
|
|
210
|
+
if verbosity > 0:
|
|
211
|
+
print(f"Model '{self.name}': running")
|
|
212
|
+
if self.name not in data_stash:
|
|
213
|
+
data_stash[self.name] = {}
|
|
214
|
+
|
|
215
|
+
self.__running = True
|
|
216
|
+
|
|
217
|
+
def unset_running(
|
|
218
|
+
self,
|
|
219
|
+
algo,
|
|
220
|
+
data_stash,
|
|
221
|
+
sel=None,
|
|
222
|
+
isel=None,
|
|
223
|
+
verbosity=0,
|
|
224
|
+
):
|
|
225
|
+
"""
|
|
226
|
+
Sets this model status to not running, recovering large data
|
|
227
|
+
from stash
|
|
228
|
+
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
231
|
+
algo: foxes.core.Algorithm
|
|
232
|
+
The calculation algorithm
|
|
233
|
+
data_stash: dict
|
|
234
|
+
Large data stash, this function adds data here.
|
|
235
|
+
Key: model name. Value: dict, large model data
|
|
236
|
+
sel: dict, optional
|
|
237
|
+
The subset selection dictionary
|
|
238
|
+
isel: dict, optional
|
|
239
|
+
The index subset selection dictionary
|
|
240
|
+
verbosity: int
|
|
241
|
+
The verbosity level, 0 = silent
|
|
242
|
+
|
|
243
|
+
"""
|
|
244
|
+
if not self.running:
|
|
245
|
+
raise ValueError(
|
|
246
|
+
f"Model '{self.name}': Cannot call unset_running when not running"
|
|
247
|
+
)
|
|
248
|
+
for m in self.sub_models():
|
|
249
|
+
if m.running:
|
|
250
|
+
m.unset_running(algo, data_stash, sel, isel, verbosity=verbosity)
|
|
251
|
+
|
|
252
|
+
if verbosity > 0:
|
|
253
|
+
print(f"Model '{self.name}': not running")
|
|
254
|
+
self.__running = False
|
|
255
|
+
|
|
155
256
|
def finalize(self, algo, verbosity=0):
|
|
156
257
|
"""
|
|
157
258
|
Finalizes the model.
|
|
@@ -164,6 +265,8 @@ class Model(ABC):
|
|
|
164
265
|
The verbosity level, 0 = silent
|
|
165
266
|
|
|
166
267
|
"""
|
|
268
|
+
if self.running:
|
|
269
|
+
raise ValueError(f"Model '{self.name}': Cannot finalize while running")
|
|
167
270
|
if self.initialized:
|
|
168
271
|
pr = False
|
|
169
272
|
for m in self.sub_models():
|
|
@@ -178,7 +281,6 @@ class Model(ABC):
|
|
|
178
281
|
print(f"Finalizing model '{self.name}'")
|
|
179
282
|
algo.del_model_data(self)
|
|
180
283
|
|
|
181
|
-
self._store = {}
|
|
182
284
|
self.__initialized = False
|
|
183
285
|
|
|
184
286
|
def get_data(
|
|
@@ -241,7 +343,7 @@ class Model(ABC):
|
|
|
241
343
|
for s in sources:
|
|
242
344
|
try:
|
|
243
345
|
if a == "states_i0":
|
|
244
|
-
out = s.states_i0(counter=True
|
|
346
|
+
out = s.states_i0(counter=True)
|
|
245
347
|
if out is not None:
|
|
246
348
|
return out
|
|
247
349
|
else:
|
|
@@ -353,6 +455,12 @@ class Model(ABC):
|
|
|
353
455
|
if out is not None:
|
|
354
456
|
break
|
|
355
457
|
|
|
458
|
+
# check for None:
|
|
459
|
+
if not accept_none and out is None:
|
|
460
|
+
raise ValueError(
|
|
461
|
+
f"Model '{self.name}': Variable '{variable}' is requested but not found."
|
|
462
|
+
)
|
|
463
|
+
|
|
356
464
|
# cast dimensions:
|
|
357
465
|
if out_dims != dims:
|
|
358
466
|
if out_dims is None:
|
|
@@ -438,7 +546,12 @@ class Model(ABC):
|
|
|
438
546
|
f"Model '{self.name}': Iteration data found for variable '{variable}', requiring algo"
|
|
439
547
|
)
|
|
440
548
|
|
|
441
|
-
|
|
549
|
+
from foxes.algorithms.sequential import Sequential
|
|
550
|
+
|
|
551
|
+
if isinstance(algo, Sequential):
|
|
552
|
+
i0 = algo.states.counter
|
|
553
|
+
else:
|
|
554
|
+
i0 = _geta("states_i0")
|
|
442
555
|
sts = tdata[FC.STATES_SEL]
|
|
443
556
|
if target == FC.STATE_TARGET and tdata.n_tpoints != 1:
|
|
444
557
|
# find the mean index and round it to nearest integer:
|
|
@@ -446,27 +559,31 @@ class Model(ABC):
|
|
|
446
559
|
sts = (sts + 0.5).astype(FC.ITYPE)
|
|
447
560
|
sel = sts < i0
|
|
448
561
|
if np.any(sel):
|
|
449
|
-
if not hasattr(algo, "
|
|
562
|
+
if not hasattr(algo, "farm_results_downwind"):
|
|
450
563
|
raise KeyError(
|
|
451
564
|
f"Model '{self.name}': Iteration data found for variable '{variable}', requiring iterative algorithm"
|
|
452
565
|
)
|
|
453
|
-
prev_fres = getattr(algo, "
|
|
566
|
+
prev_fres = getattr(algo, "farm_results_downwind")
|
|
454
567
|
if prev_fres is not None:
|
|
455
568
|
prev_data = prev_fres[variable].to_numpy()[sts[sel], downwind_index]
|
|
456
569
|
if target == FC.STATE_TARGET:
|
|
457
570
|
out[sel[:, :, 0]] = prev_data
|
|
458
571
|
else:
|
|
459
572
|
out[sel] = prev_data
|
|
460
|
-
del
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
573
|
+
del prev_data
|
|
574
|
+
del prev_fres
|
|
575
|
+
if np.any(~sel):
|
|
576
|
+
sts = sts[~sel] - i0
|
|
577
|
+
sel_data = fdata[variable][sts, downwind_index]
|
|
578
|
+
if target == FC.STATE_TARGET:
|
|
579
|
+
out[~sel[:, :, 0]] = sel_data
|
|
580
|
+
else:
|
|
581
|
+
out[~sel] = sel_data
|
|
582
|
+
del sel_data
|
|
583
|
+
del sel, sts
|
|
467
584
|
|
|
468
585
|
# check for nan:
|
|
469
|
-
|
|
586
|
+
if not accept_nan:
|
|
470
587
|
try:
|
|
471
588
|
if np.all(np.isnan(np.atleast_1d(out))):
|
|
472
589
|
raise ValueError(
|
|
@@ -476,67 +593,3 @@ class Model(ABC):
|
|
|
476
593
|
pass
|
|
477
594
|
|
|
478
595
|
return out
|
|
479
|
-
|
|
480
|
-
def data_to_store(self, name, algo, data):
|
|
481
|
-
"""
|
|
482
|
-
Adds data from mdata to the local store, intended
|
|
483
|
-
for iterative runs.
|
|
484
|
-
|
|
485
|
-
Parameters
|
|
486
|
-
----------
|
|
487
|
-
name: str
|
|
488
|
-
The data name
|
|
489
|
-
algo: foxes.core.Algorithm
|
|
490
|
-
The algorithm
|
|
491
|
-
data: foxes.utils.Data
|
|
492
|
-
The mdata, fdata or pdata object
|
|
493
|
-
|
|
494
|
-
"""
|
|
495
|
-
i0 = data.states_i0(counter=True, algo=algo)
|
|
496
|
-
if i0 not in self._store:
|
|
497
|
-
self._store[i0] = Data(
|
|
498
|
-
data={}, dims={}, loop_dims=data.loop_dims, name=f"{self.name}_{i0}"
|
|
499
|
-
)
|
|
500
|
-
|
|
501
|
-
self._store[i0][name] = deepcopy(data[name])
|
|
502
|
-
self._store[i0].dims[name] = (
|
|
503
|
-
deepcopy(data.dims[name]) if name in data.dims else None
|
|
504
|
-
)
|
|
505
|
-
|
|
506
|
-
def from_data_or_store(self, name, algo, data, ret_dims=False, safe=False):
|
|
507
|
-
"""
|
|
508
|
-
Get data from mdata or local store
|
|
509
|
-
|
|
510
|
-
Parameters
|
|
511
|
-
----------
|
|
512
|
-
name: str
|
|
513
|
-
The data name
|
|
514
|
-
algo: foxes.core.Algorithm
|
|
515
|
-
The algorithm
|
|
516
|
-
data: foxes.utils.Data
|
|
517
|
-
The mdata, fdata or pdata object
|
|
518
|
-
ret_dims: bool
|
|
519
|
-
Return dimensions
|
|
520
|
-
safe: bool
|
|
521
|
-
Return None instead of error if
|
|
522
|
-
not found
|
|
523
|
-
|
|
524
|
-
Returns
|
|
525
|
-
-------
|
|
526
|
-
data: numpy.ndarray
|
|
527
|
-
The data
|
|
528
|
-
dims: tuple of dims, optional
|
|
529
|
-
The data dimensions
|
|
530
|
-
|
|
531
|
-
"""
|
|
532
|
-
if name in data:
|
|
533
|
-
return (data[name], data.dims[name]) if ret_dims else data[name]
|
|
534
|
-
|
|
535
|
-
i0 = data.states_i0(counter=True, algo=algo)
|
|
536
|
-
if not safe or (i0 in self._store and name in self._store[i0]):
|
|
537
|
-
if ret_dims:
|
|
538
|
-
return self._store[i0][name], self._store[i0].dims[name]
|
|
539
|
-
else:
|
|
540
|
-
return self._store[i0][name]
|
|
541
|
-
else:
|
|
542
|
-
return (None, None) if ret_dims else None
|
foxes/core/point_data_model.py
CHANGED
|
@@ -27,6 +27,18 @@ class PointDataModel(DataCalcModel):
|
|
|
27
27
|
"""
|
|
28
28
|
return []
|
|
29
29
|
|
|
30
|
+
def output_coords(self):
|
|
31
|
+
"""
|
|
32
|
+
Gets the coordinates of all output arrays
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
dims: tuple of str
|
|
37
|
+
The coordinates of all output arrays
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
return (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
41
|
+
|
|
30
42
|
def ensure_variables(self, algo, mdata, fdata, tdata):
|
|
31
43
|
"""
|
|
32
44
|
Add variables to tdata, initialized with NaN
|
|
@@ -158,6 +170,9 @@ class PointDataModelList(PointDataModel):
|
|
|
158
170
|
super().__init__()
|
|
159
171
|
self.models = models
|
|
160
172
|
|
|
173
|
+
def __repr__(self):
|
|
174
|
+
return f"{type(self).__name__}({[m.name for m in self.models]})"
|
|
175
|
+
|
|
161
176
|
def append(self, model):
|
|
162
177
|
"""
|
|
163
178
|
Add a model to the list
|
foxes/core/rotor_model.py
CHANGED
|
@@ -27,13 +27,13 @@ class RotorModel(FarmDataModel):
|
|
|
27
27
|
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
def __init__(self, calc_vars):
|
|
30
|
+
def __init__(self, calc_vars=None):
|
|
31
31
|
"""
|
|
32
32
|
Constructor.
|
|
33
33
|
|
|
34
34
|
Parameters
|
|
35
35
|
----------
|
|
36
|
-
calc_vars: list of str
|
|
36
|
+
calc_vars: list of str, optional
|
|
37
37
|
The variables that are calculated by the model
|
|
38
38
|
(Their ambients are added automatically)
|
|
39
39
|
|
|
@@ -41,10 +41,6 @@ class RotorModel(FarmDataModel):
|
|
|
41
41
|
super().__init__()
|
|
42
42
|
self.calc_vars = calc_vars
|
|
43
43
|
|
|
44
|
-
self.RPOINTS = self.var("rpoints")
|
|
45
|
-
self.RWEIGHTS = self.var("rweights")
|
|
46
|
-
self.AMBRES = self.var("amb_res")
|
|
47
|
-
|
|
48
44
|
def output_farm_vars(self, algo):
|
|
49
45
|
"""
|
|
50
46
|
The variables which are being modified by the model.
|
|
@@ -60,12 +56,21 @@ class RotorModel(FarmDataModel):
|
|
|
60
56
|
The output variable names
|
|
61
57
|
|
|
62
58
|
"""
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
if self.calc_vars is None:
|
|
60
|
+
vrs = algo.states.output_point_vars(algo)
|
|
61
|
+
if FV.WS in vrs:
|
|
62
|
+
self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
|
|
63
|
+
else:
|
|
64
|
+
self.calc_vars = vrs
|
|
65
|
+
|
|
66
|
+
if algo.farm_controller.needs_rews2() and FV.REWS2 not in self.calc_vars:
|
|
67
|
+
self.calc_vars.append(FV.REWS2)
|
|
68
|
+
if algo.farm_controller.needs_rews3() and FV.REWS3 not in self.calc_vars:
|
|
69
|
+
self.calc_vars.append(FV.REWS3)
|
|
70
|
+
|
|
71
|
+
self.calc_vars = sorted(self.calc_vars)
|
|
72
|
+
|
|
73
|
+
return self.calc_vars
|
|
69
74
|
|
|
70
75
|
@abstractmethod
|
|
71
76
|
def n_rotor_points(self):
|
|
@@ -207,6 +212,10 @@ class RotorModel(FarmDataModel):
|
|
|
207
212
|
variables after calculation
|
|
208
213
|
|
|
209
214
|
"""
|
|
215
|
+
for v in [FV.REWS2, FV.REWS3]:
|
|
216
|
+
if v in fdata and v not in self.calc_vars:
|
|
217
|
+
self.calc_vars.append(v)
|
|
218
|
+
|
|
210
219
|
uvp = None
|
|
211
220
|
uv = None
|
|
212
221
|
if (
|
|
@@ -348,11 +357,11 @@ class RotorModel(FarmDataModel):
|
|
|
348
357
|
"""
|
|
349
358
|
|
|
350
359
|
if rpoints is None:
|
|
351
|
-
rpoints = mdata.get(
|
|
360
|
+
rpoints = mdata.get(
|
|
361
|
+
FC.ROTOR_POINTS, self.get_rotor_points(algo, mdata, fdata)
|
|
362
|
+
)
|
|
352
363
|
if store_rpoints:
|
|
353
|
-
|
|
354
|
-
mdata.dims[self.RPOINTS] = (FC.STATE, FC.TURBINE, FC.TPOINT, FC.XYH)
|
|
355
|
-
self.data_to_store(self.RPOINTS, algo, mdata)
|
|
364
|
+
algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
|
|
356
365
|
|
|
357
366
|
if downwind_index is not None:
|
|
358
367
|
rpoints = rpoints[:, downwind_index, None]
|
|
@@ -360,9 +369,7 @@ class RotorModel(FarmDataModel):
|
|
|
360
369
|
if weights is None:
|
|
361
370
|
weights = mdata.get(FC.TWEIGHTS, self.rotor_point_weights())
|
|
362
371
|
if store_rweights:
|
|
363
|
-
|
|
364
|
-
mdata.dims[self.RWEIGHTS] = (FC.TPOINT,)
|
|
365
|
-
self.data_to_store(self.RWEIGHTS, algo, mdata)
|
|
372
|
+
algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, weights, mdata=mdata)
|
|
366
373
|
|
|
367
374
|
tdata = TData.from_tpoints(rpoints, weights)
|
|
368
375
|
svars = algo.states.output_point_vars(algo)
|
|
@@ -377,8 +384,7 @@ class RotorModel(FarmDataModel):
|
|
|
377
384
|
tdata.update(sres)
|
|
378
385
|
|
|
379
386
|
if store_amb_res:
|
|
380
|
-
|
|
381
|
-
self.data_to_store(self.AMBRES, algo, mdata)
|
|
387
|
+
algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres.copy(), mdata=mdata)
|
|
382
388
|
|
|
383
389
|
self.eval_rpoint_results(
|
|
384
390
|
algo,
|
foxes/core/states.py
CHANGED
|
@@ -61,6 +61,22 @@ class States(PointDataModel):
|
|
|
61
61
|
"""
|
|
62
62
|
pass
|
|
63
63
|
|
|
64
|
+
def reset(self, algo=None, states_sel=None, states_loc=None, verbosity=0):
|
|
65
|
+
"""
|
|
66
|
+
Reset the states, optionally select states
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
states_sel: slice or range or list of int, optional
|
|
71
|
+
States subset selection
|
|
72
|
+
states_loc: list, optional
|
|
73
|
+
State index selection via pandas loc function
|
|
74
|
+
verbosity: int
|
|
75
|
+
The verbosity level, 0 = silent
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
raise NotImplementedError(f"States '{self.name}': Reset is not implemented")
|
|
79
|
+
|
|
64
80
|
def load_data(self, algo, verbosity=0):
|
|
65
81
|
"""
|
|
66
82
|
Load and/or create all model data that is subject to chunking.
|
foxes/core/turbine_type.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
1
3
|
import foxes.constants as FC
|
|
2
4
|
from foxes.utils import all_subclasses
|
|
3
5
|
|
|
@@ -64,6 +66,32 @@ class TurbineType(TurbineModel):
|
|
|
64
66
|
a = f"D={self.D}, H={self.H}, P_nominal={self.P_nominal}, P_unit={self.P_unit}"
|
|
65
67
|
return f"{type(self).__name__}({a})"
|
|
66
68
|
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def needs_rews2(self):
|
|
71
|
+
"""
|
|
72
|
+
Returns flag for requirering REWS2 variable
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
flag: bool
|
|
77
|
+
True if REWS2 is required
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
@abstractmethod
|
|
83
|
+
def needs_rews3(self):
|
|
84
|
+
"""
|
|
85
|
+
Returns flag for requirering REWS3 variable
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
flag: bool
|
|
90
|
+
True if REWS3 is required
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
pass
|
|
94
|
+
|
|
67
95
|
def modify_cutin(self, modify_ct, modify_P):
|
|
68
96
|
"""
|
|
69
97
|
Modify the data such that a discontinuity
|
foxes/core/wake_frame.py
CHANGED
|
@@ -6,7 +6,7 @@ from foxes.utils import all_subclasses
|
|
|
6
6
|
import foxes.constants as FC
|
|
7
7
|
import foxes.variables as FV
|
|
8
8
|
|
|
9
|
-
from .data import
|
|
9
|
+
from .data import TData
|
|
10
10
|
from .model import Model
|
|
11
11
|
|
|
12
12
|
|
|
@@ -21,10 +21,28 @@ class WakeFrame(Model):
|
|
|
21
21
|
They are also responsible for the calculation of
|
|
22
22
|
the turbine evaluation order.
|
|
23
23
|
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
max_length_km: float
|
|
27
|
+
The maximal wake length in km
|
|
28
|
+
|
|
24
29
|
:group: core
|
|
25
30
|
|
|
26
31
|
"""
|
|
27
32
|
|
|
33
|
+
def __init__(self, max_length_km=3e4):
|
|
34
|
+
"""
|
|
35
|
+
Constructor.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
max_length_km: float
|
|
40
|
+
The maximal wake length in km
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
super().__init__()
|
|
44
|
+
self.max_length_km = max_length_km
|
|
45
|
+
|
|
28
46
|
@abstractmethod
|
|
29
47
|
def calc_order(self, algo, mdata, fdata):
|
|
30
48
|
""" "
|
|
@@ -241,7 +259,7 @@ class WakeFrame(Model):
|
|
|
241
259
|
|
|
242
260
|
# calc evaluation points:
|
|
243
261
|
xmin = 0.0
|
|
244
|
-
xmax = np.nanmax(x)
|
|
262
|
+
xmax = min(np.nanmax(x), self.max_length_km * 1e3)
|
|
245
263
|
n_steps = int((xmax - xmin) / dx)
|
|
246
264
|
if xmin + n_steps * dx < xmax:
|
|
247
265
|
n_steps += 1
|
|
@@ -262,7 +280,7 @@ class WakeFrame(Model):
|
|
|
262
280
|
res = algo.states.calculate(algo, mdata, fdata, tdata)
|
|
263
281
|
tdata.update(res)
|
|
264
282
|
amb2var = algo.get_model("SetAmbPointResults")()
|
|
265
|
-
amb2var.initialize(algo, verbosity=0)
|
|
283
|
+
amb2var.initialize(algo, verbosity=0, force=True)
|
|
266
284
|
res = amb2var.calculate(algo, mdata, fdata, tdata)
|
|
267
285
|
tdata.update(res)
|
|
268
286
|
del res, amb2var
|
|
@@ -277,7 +295,7 @@ class WakeFrame(Model):
|
|
|
277
295
|
# calc wakes:
|
|
278
296
|
if not ambient:
|
|
279
297
|
wcalc = algo.get_model("PointWakesCalculation")(wake_models=wake_models)
|
|
280
|
-
wcalc.initialize(algo, verbosity=0)
|
|
298
|
+
wcalc.initialize(algo, verbosity=0, force=True)
|
|
281
299
|
wsrc = downwind_index if self_wake else None
|
|
282
300
|
res = wcalc.calculate(algo, mdata, fdata, tdata, downwind_index=wsrc)
|
|
283
301
|
tdata.update(res)
|
foxes/core/wake_model.py
CHANGED
|
@@ -304,9 +304,8 @@ class WakeK(Model):
|
|
|
304
304
|
The k array as returned by get_data
|
|
305
305
|
|
|
306
306
|
"""
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
elif self._ka is not None or self._kb is not None:
|
|
307
|
+
setattr(self, self.k_var, self._k)
|
|
308
|
+
if self._ka is not None or self._kb is not None:
|
|
310
309
|
if self.ti_var == FV.TI and ti is not None:
|
|
311
310
|
pass
|
|
312
311
|
elif self.ti_var == FV.AMB_TI and amb_ti is not None:
|
|
@@ -59,5 +59,27 @@ attributes:
|
|
|
59
59
|
blockage_model:
|
|
60
60
|
name: None
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
outputs:
|
|
63
|
+
output_folder: "results"
|
|
64
|
+
turbine_outputs:
|
|
65
|
+
turbine_nc_filename: 'turbine_data.nc' # dimension = states, turbine
|
|
66
|
+
output_variables: ['power', 'rotor_effective_velocity'] #'frequency'
|
|
67
|
+
#
|
|
68
|
+
flow_field:
|
|
69
|
+
report: True
|
|
70
|
+
flow_nc_filename: flow_field.nc
|
|
71
|
+
cases_run:
|
|
72
|
+
all_occurences: True
|
|
73
|
+
output_variables: ['wind_speed', 'wind_direction']
|
|
74
|
+
z_planes:
|
|
75
|
+
z_sampling: "hub_height"
|
|
76
|
+
xy_sampling: "default"
|
|
77
|
+
#
|
|
78
|
+
statistics:
|
|
79
|
+
stats_filename: None
|
|
80
|
+
AEP: False
|
|
81
|
+
AEP_per_turbine: False
|
|
82
|
+
power_percentiles:
|
|
83
|
+
report: False
|
|
84
|
+
percentiles: None
|
|
63
85
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .pool import PoolEngine
|
|
2
|
+
from .multiprocess import MultiprocessEngine
|
|
3
|
+
from .numpy import NumpyEngine
|
|
4
|
+
from .single import SingleChunkEngine
|
|
5
|
+
from .futures import ThreadsEngine, ProcessEngine
|
|
6
|
+
from .mpi import MPIEngine
|
|
7
|
+
|
|
8
|
+
from .dask import (
|
|
9
|
+
DaskBaseEngine,
|
|
10
|
+
XArrayEngine,
|
|
11
|
+
DaskEngine,
|
|
12
|
+
LocalClusterEngine,
|
|
13
|
+
SlurmClusterEngine,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .default import DefaultEngine
|