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/utils/dict.py
CHANGED
|
@@ -32,6 +32,6 @@ class Dict(dict):
|
|
|
32
32
|
try:
|
|
33
33
|
return super().__getitem__(key)
|
|
34
34
|
except KeyError:
|
|
35
|
-
k = ", ".join(sorted(
|
|
35
|
+
k = ", ".join(sorted([f"{s}" for s in self.keys()]))
|
|
36
36
|
e = f"{self.name}: Cannot find key '{key}'. Known keys: {k}"
|
|
37
37
|
raise KeyError(e)
|
foxes/utils/factory.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
1
3
|
from .dict import Dict
|
|
2
4
|
import foxes.variables as FV
|
|
3
5
|
|
|
@@ -23,6 +25,8 @@ class Factory:
|
|
|
23
25
|
hints: dict
|
|
24
26
|
Hints for print_toc, only for variables for which the
|
|
25
27
|
options are functions or missing
|
|
28
|
+
example: str
|
|
29
|
+
An example name
|
|
26
30
|
options: dict
|
|
27
31
|
For each variable, e.g. A, B or C, the list or dict
|
|
28
32
|
or function that maps a str to the actual value
|
|
@@ -39,6 +43,7 @@ class Factory:
|
|
|
39
43
|
kwargs={},
|
|
40
44
|
var2arg={},
|
|
41
45
|
hints={},
|
|
46
|
+
example_vars=None,
|
|
42
47
|
**options,
|
|
43
48
|
):
|
|
44
49
|
"""
|
|
@@ -60,6 +65,8 @@ class Factory:
|
|
|
60
65
|
hints: dict
|
|
61
66
|
Hints for print_toc, only for variables for which the
|
|
62
67
|
options are functions or missing
|
|
68
|
+
example_vars: dict, optional
|
|
69
|
+
Variable values for creating an example
|
|
63
70
|
options: dict
|
|
64
71
|
For each variable, e.g. A, B or C, the list or dict
|
|
65
72
|
or function that maps a str to the actual value
|
|
@@ -122,6 +129,30 @@ class Factory:
|
|
|
122
129
|
f"Factory '{name_template}': Variable '{v}' has option of type '{type(v).__name__}'. Only list, tuple, dict or function are supported"
|
|
123
130
|
)
|
|
124
131
|
|
|
132
|
+
exvars = dict(
|
|
133
|
+
n=5,
|
|
134
|
+
n2=9,
|
|
135
|
+
superposition="linear",
|
|
136
|
+
kTI=0.2,
|
|
137
|
+
kb=0.001,
|
|
138
|
+
step=100,
|
|
139
|
+
dx=100,
|
|
140
|
+
dt="10s",
|
|
141
|
+
)
|
|
142
|
+
if example_vars is not None:
|
|
143
|
+
exvars.update(example_vars)
|
|
144
|
+
try:
|
|
145
|
+
self.example = ""
|
|
146
|
+
for i, v in enumerate(self._vars):
|
|
147
|
+
self.example += f"{self._pre[i]}{exvars[v]}"
|
|
148
|
+
self.example += self._pre[-1]
|
|
149
|
+
if not self.check_match(self.example, error=False):
|
|
150
|
+
raise ValueError(
|
|
151
|
+
f"Example '{self.example}' does not match template '{self.name_template}'"
|
|
152
|
+
)
|
|
153
|
+
except KeyError:
|
|
154
|
+
self.example = None
|
|
155
|
+
|
|
125
156
|
@property
|
|
126
157
|
def name_prefix(self):
|
|
127
158
|
"""
|
|
@@ -171,56 +202,77 @@ class Factory:
|
|
|
171
202
|
s += f"\n {v} from {list(self.options[v])}"
|
|
172
203
|
else:
|
|
173
204
|
s += f"\n {v}={self.hints.get(v, '(value)')}"
|
|
205
|
+
if self.example is not None:
|
|
206
|
+
s += f"\nExample: {self.example}"
|
|
174
207
|
return s
|
|
175
208
|
|
|
176
|
-
def
|
|
209
|
+
def get_examples(self, **var_values):
|
|
177
210
|
"""
|
|
178
|
-
|
|
211
|
+
Create example names from given values
|
|
179
212
|
|
|
180
213
|
Parameters
|
|
181
214
|
----------
|
|
182
|
-
|
|
183
|
-
|
|
215
|
+
var_values: dict
|
|
216
|
+
Variables values. Key: Variable,
|
|
217
|
+
value: list or value
|
|
184
218
|
|
|
185
219
|
Returns
|
|
186
220
|
-------
|
|
187
|
-
|
|
188
|
-
|
|
221
|
+
examples: list of str
|
|
222
|
+
The examples
|
|
189
223
|
|
|
190
224
|
"""
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
q = self._pre[vi + 1]
|
|
201
|
-
if q != "":
|
|
202
|
-
i = data_str.find(q)
|
|
203
|
-
j = i + len(q)
|
|
204
|
-
if i < 0 or len(data_str) <= j:
|
|
205
|
-
return False
|
|
225
|
+
|
|
226
|
+
def gete(i, vals, vars, values, examples):
|
|
227
|
+
if i >= len(vars):
|
|
228
|
+
e = ""
|
|
229
|
+
for i, v in enumerate(self._vars):
|
|
230
|
+
e += f"{self._pre[i]}{vals[v]}"
|
|
231
|
+
e += self._pre[-1]
|
|
232
|
+
self.check_match(e, error=True)
|
|
233
|
+
examples.append(e)
|
|
206
234
|
else:
|
|
207
|
-
|
|
235
|
+
v = vars[i]
|
|
236
|
+
if v in self._vars:
|
|
237
|
+
vls = np.atleast_1d(values[i])
|
|
238
|
+
for x in vls:
|
|
239
|
+
vals[v] = x
|
|
240
|
+
gete(i + 1, vals, vars, values, examples)
|
|
241
|
+
else:
|
|
242
|
+
gete(i + 1, vals, vars, values, examples)
|
|
243
|
+
|
|
244
|
+
examples = []
|
|
245
|
+
gete(
|
|
246
|
+
0,
|
|
247
|
+
{},
|
|
248
|
+
list(var_values.keys()),
|
|
249
|
+
list(var_values.values()),
|
|
250
|
+
examples,
|
|
251
|
+
)
|
|
208
252
|
|
|
209
|
-
return
|
|
253
|
+
return examples
|
|
210
254
|
|
|
211
|
-
def
|
|
255
|
+
def check_match(self, name, error=False, ret_pars=False):
|
|
212
256
|
"""
|
|
213
|
-
|
|
257
|
+
Tests if a name matches the template and constructs
|
|
258
|
+
parameters
|
|
214
259
|
|
|
215
260
|
Parameters
|
|
216
261
|
----------
|
|
217
262
|
name: str
|
|
218
|
-
The name
|
|
263
|
+
The name to be checked
|
|
264
|
+
error: bool
|
|
265
|
+
Flag for raising a Value error in case of
|
|
266
|
+
mismatch
|
|
267
|
+
ret_pars: bool
|
|
268
|
+
Flag for returning the parameters
|
|
219
269
|
|
|
220
270
|
Returns
|
|
221
271
|
-------
|
|
222
|
-
|
|
223
|
-
|
|
272
|
+
success: bool
|
|
273
|
+
True if the template is matched
|
|
274
|
+
pars: dict, optional
|
|
275
|
+
The constructed parameters
|
|
224
276
|
|
|
225
277
|
"""
|
|
226
278
|
j = 0
|
|
@@ -229,9 +281,14 @@ class Factory:
|
|
|
229
281
|
if len(p) > 0:
|
|
230
282
|
i = name[j:].find(p)
|
|
231
283
|
if i < 0 or (pi == 0 and i > 0):
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
284
|
+
if error:
|
|
285
|
+
raise ValueError(
|
|
286
|
+
f"Factory '{self.name_template}': Name '{name}' not matching template"
|
|
287
|
+
)
|
|
288
|
+
elif ret_pars:
|
|
289
|
+
return False, {}
|
|
290
|
+
else:
|
|
291
|
+
return False
|
|
235
292
|
w = name[j : j + i]
|
|
236
293
|
j += i + len(p)
|
|
237
294
|
else:
|
|
@@ -239,21 +296,41 @@ class Factory:
|
|
|
239
296
|
if pi > 0:
|
|
240
297
|
wlist.append(w)
|
|
241
298
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
299
|
+
if ret_pars:
|
|
300
|
+
kwargs = {}
|
|
301
|
+
for vi, v in enumerate(self.variables):
|
|
302
|
+
w = self.var2arg.get(v, v)
|
|
303
|
+
data = wlist[vi]
|
|
304
|
+
if v in self.options:
|
|
305
|
+
o = self.options[v]
|
|
306
|
+
if hasattr(o, "__call__"):
|
|
307
|
+
kwargs[w] = o(data)
|
|
308
|
+
else:
|
|
309
|
+
kwargs[w] = self.options[v][data]
|
|
250
310
|
else:
|
|
251
|
-
kwargs[w] =
|
|
252
|
-
else:
|
|
253
|
-
kwargs[w] = data
|
|
311
|
+
kwargs[w] = data
|
|
254
312
|
|
|
255
|
-
|
|
313
|
+
kwargs.update(self.kwargs)
|
|
314
|
+
return True, kwargs
|
|
315
|
+
|
|
316
|
+
return True
|
|
317
|
+
|
|
318
|
+
def construct(self, name):
|
|
319
|
+
"""
|
|
320
|
+
Create an object of the base class.
|
|
321
|
+
|
|
322
|
+
Parameters
|
|
323
|
+
----------
|
|
324
|
+
name: str
|
|
325
|
+
The name, matching the template
|
|
256
326
|
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
obj: object
|
|
330
|
+
The instance of the base class
|
|
331
|
+
|
|
332
|
+
"""
|
|
333
|
+
__, kwargs = self.check_match(name, error=True, ret_pars=True)
|
|
257
334
|
return self.base(*self.args, **kwargs)
|
|
258
335
|
|
|
259
336
|
|
|
@@ -299,14 +376,20 @@ class WakeKFactory:
|
|
|
299
376
|
i0 = name_template.find("_[wake_k]")
|
|
300
377
|
i1 = i0 + len("_[wake_k]")
|
|
301
378
|
kw = kwargs.pop("kwargs", {})
|
|
379
|
+
v2a = kwargs.pop("var2arg", {})
|
|
302
380
|
|
|
303
381
|
if i0 < 0:
|
|
304
382
|
raise ValueError(
|
|
305
383
|
f"String '_[wake_k]' not found in name template '{name_template}'"
|
|
306
384
|
)
|
|
307
385
|
|
|
386
|
+
exvars = dict(k=0.04, ka=0.2, ambka=0.4, kb=0.001)
|
|
387
|
+
if "example_vars" in kwargs:
|
|
388
|
+
exvars.update(kwargs.pop("example_vars"))
|
|
389
|
+
|
|
308
390
|
# add case ka, kb:
|
|
309
|
-
|
|
391
|
+
t0 = name_template[:i0]
|
|
392
|
+
t = t0 + "_ka<ka>_kb<kb>"
|
|
310
393
|
if len(name_template) > i1:
|
|
311
394
|
t += name_template[i1:]
|
|
312
395
|
h = hints.copy()
|
|
@@ -323,17 +406,20 @@ class WakeKFactory:
|
|
|
323
406
|
**kwargs,
|
|
324
407
|
ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
325
408
|
kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
409
|
+
example_vars=exvars,
|
|
326
410
|
)
|
|
327
411
|
)
|
|
328
412
|
|
|
329
|
-
# add case ambient
|
|
330
|
-
t = name_template[:i0] + "_ambka<
|
|
413
|
+
# add case ambient ambka, kb:
|
|
414
|
+
t = name_template[:i0] + "_ambka<ambka>_kb<kb>"
|
|
331
415
|
if len(name_template) > i1:
|
|
332
416
|
t += name_template[i1:]
|
|
333
417
|
h = hints.copy()
|
|
334
|
-
h["
|
|
418
|
+
h["ambka"] = "(Value, e.g. 04 for 0.4)"
|
|
335
419
|
h["kb"] = "(Value, e.g. 001 for 0.01)"
|
|
336
420
|
kw["ti_var"] = FV.AMB_TI
|
|
421
|
+
hv2a = v2a.copy()
|
|
422
|
+
hv2a["ambka"] = "ka"
|
|
337
423
|
self.factories.append(
|
|
338
424
|
Factory(
|
|
339
425
|
base,
|
|
@@ -341,9 +427,11 @@ class WakeKFactory:
|
|
|
341
427
|
*args,
|
|
342
428
|
hints=h,
|
|
343
429
|
kwargs=kw.copy(),
|
|
430
|
+
var2arg=hv2a,
|
|
344
431
|
**kwargs,
|
|
345
|
-
|
|
432
|
+
ambka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
346
433
|
kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
434
|
+
example_vars=exvars,
|
|
347
435
|
)
|
|
348
436
|
)
|
|
349
437
|
|
|
@@ -363,16 +451,19 @@ class WakeKFactory:
|
|
|
363
451
|
kwargs=kw.copy(),
|
|
364
452
|
**kwargs,
|
|
365
453
|
ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
454
|
+
example_vars=exvars,
|
|
366
455
|
)
|
|
367
456
|
)
|
|
368
457
|
|
|
369
|
-
# add case
|
|
370
|
-
t = name_template[:i0] + "_ambka<
|
|
458
|
+
# add case ambka:
|
|
459
|
+
t = name_template[:i0] + "_ambka<ambka>"
|
|
371
460
|
if len(name_template) > i1:
|
|
372
461
|
t += name_template[i1:]
|
|
373
462
|
h = hints.copy()
|
|
374
|
-
h["
|
|
463
|
+
h["ambka"] = "(Value, e.g. 04 for 0.4)"
|
|
375
464
|
kw["ti_var"] = FV.AMB_TI
|
|
465
|
+
hv2a = v2a.copy()
|
|
466
|
+
hv2a["ambka"] = "ka"
|
|
376
467
|
self.factories.append(
|
|
377
468
|
Factory(
|
|
378
469
|
base,
|
|
@@ -380,8 +471,10 @@ class WakeKFactory:
|
|
|
380
471
|
*args,
|
|
381
472
|
hints=h,
|
|
382
473
|
kwargs=kw.copy(),
|
|
474
|
+
var2arg=hv2a,
|
|
383
475
|
**kwargs,
|
|
384
|
-
|
|
476
|
+
ambka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
477
|
+
example_vars=exvars,
|
|
385
478
|
)
|
|
386
479
|
)
|
|
387
480
|
|
|
@@ -401,6 +494,7 @@ class WakeKFactory:
|
|
|
401
494
|
kwargs=kw.copy(),
|
|
402
495
|
**kwargs,
|
|
403
496
|
k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
497
|
+
example_vars=exvars,
|
|
404
498
|
)
|
|
405
499
|
)
|
|
406
500
|
|
|
@@ -417,6 +511,7 @@ class WakeKFactory:
|
|
|
417
511
|
hints=hints,
|
|
418
512
|
kwargs=kw.copy(),
|
|
419
513
|
**kwargs,
|
|
514
|
+
example_vars=exvars,
|
|
420
515
|
)
|
|
421
516
|
)
|
|
422
517
|
|
foxes/utils/pandas_helpers.py
CHANGED
|
@@ -41,7 +41,7 @@ class PandasFileHelper:
|
|
|
41
41
|
"csv.gz": {},
|
|
42
42
|
"csv.bz2": {},
|
|
43
43
|
"csv.zip": {},
|
|
44
|
-
"h5": {"key": "
|
|
44
|
+
"h5": {"key": "foxes", "mode": "w"},
|
|
45
45
|
"nc": {},
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -133,12 +133,13 @@ class PandasFileHelper:
|
|
|
133
133
|
format_dict: dict
|
|
134
134
|
Dictionary with format entries for
|
|
135
135
|
columns, e.g. '{:.4f}'
|
|
136
|
-
|
|
136
|
+
kwargs: dict, optional
|
|
137
137
|
Parameters forwarded to the pandas writing method.
|
|
138
138
|
|
|
139
139
|
"""
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
digits = {c: FV.get_default_digits(c) for c in data.columns}
|
|
142
|
+
fdict = {c: "{:." + str(d) + "f}" for c, d in digits.items() if d is not None}
|
|
142
143
|
fdict.update(format_dict)
|
|
143
144
|
|
|
144
145
|
out = pd.DataFrame(index=data.index)
|
foxes/utils/wind_dir.py
CHANGED
|
@@ -24,7 +24,6 @@ def wd2wdvec(wd, ws=1.0, axis=-1):
|
|
|
24
24
|
:group: utils
|
|
25
25
|
|
|
26
26
|
"""
|
|
27
|
-
|
|
28
27
|
wdr = wd * np.pi / 180.0
|
|
29
28
|
n = np.stack([np.sin(wdr), np.cos(wdr)], axis=axis)
|
|
30
29
|
|
|
@@ -79,7 +78,6 @@ def uv2wd(uv, axis=-1):
|
|
|
79
78
|
:group: utils
|
|
80
79
|
|
|
81
80
|
"""
|
|
82
|
-
|
|
83
81
|
if axis == -1:
|
|
84
82
|
u = uv[..., 0]
|
|
85
83
|
v = uv[..., 1]
|
foxes/utils/xarray_utils.py
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import netCDF4
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from foxes.variables import get_default_digits
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def write_nc(ds, fpath, round={}, complevel=9, verbosity=1, **kwargs):
|
|
2
8
|
"""
|
|
3
9
|
Writes a dataset to netCFD file
|
|
4
10
|
|
|
@@ -6,9 +12,9 @@ def write_nc(ds, fpath, round="auto", complevel=5, verbosity=1, **kwargs):
|
|
|
6
12
|
----------
|
|
7
13
|
fpath: str
|
|
8
14
|
Path to the output file, should be nc
|
|
9
|
-
round: dict
|
|
10
|
-
The rounding
|
|
11
|
-
|
|
15
|
+
round: dict
|
|
16
|
+
The rounding digits, falling back to defaults
|
|
17
|
+
if variable not found
|
|
12
18
|
complevel: int
|
|
13
19
|
The compression level
|
|
14
20
|
verbosity: int
|
|
@@ -17,21 +23,27 @@ def write_nc(ds, fpath, round="auto", complevel=5, verbosity=1, **kwargs):
|
|
|
17
23
|
Additional parameters for xarray.to_netcdf
|
|
18
24
|
|
|
19
25
|
"""
|
|
20
|
-
|
|
26
|
+
fpath = Path(fpath)
|
|
21
27
|
if round is not None:
|
|
22
28
|
for v in ds.coords.keys():
|
|
23
|
-
|
|
29
|
+
d = round.get(v, get_default_digits(v))
|
|
30
|
+
if d is not None:
|
|
24
31
|
if verbosity > 1:
|
|
25
|
-
print(f"Rounding {v} to {
|
|
26
|
-
ds[v].data = ds[v].data.round(decimals=
|
|
32
|
+
print(f"File {fpath.name}: Rounding {v} to {d} decimals")
|
|
33
|
+
ds[v].data = ds[v].data.round(decimals=d)
|
|
27
34
|
for v in ds.data_vars.keys():
|
|
28
|
-
|
|
35
|
+
d = round.get(v, get_default_digits(v))
|
|
36
|
+
if d is not None:
|
|
29
37
|
if verbosity > 1:
|
|
30
|
-
print(f"Rounding {v} to {
|
|
31
|
-
ds[v].data = ds[v].data.round(decimals=
|
|
38
|
+
print(f"File {fpath.name}: Rounding {v} to {d} decimals")
|
|
39
|
+
ds[v].data = ds[v].data.round(decimals=d)
|
|
40
|
+
|
|
41
|
+
enc = None
|
|
42
|
+
if complevel is not None and complevel > 0:
|
|
43
|
+
if verbosity > 1:
|
|
44
|
+
print(f"File {fpath.name}: Compression level = {complevel}")
|
|
45
|
+
enc = {k: {"zlib": True, "complevel": complevel} for k in ds.data_vars}
|
|
32
46
|
|
|
33
47
|
if verbosity > 0:
|
|
34
48
|
print("Writing file", fpath)
|
|
35
|
-
|
|
36
|
-
enc = {k: {"zlib": True, "complevel": complevel} for k in ds.data_vars}
|
|
37
49
|
ds.to_netcdf(fpath, encoding=enc, **kwargs)
|
foxes/variables.py
CHANGED
|
@@ -276,3 +276,40 @@ PA_BETA = "PA_beta"
|
|
|
276
276
|
""" The beta parameter of the PorteAgel wake model
|
|
277
277
|
:group: foxes.variables
|
|
278
278
|
"""
|
|
279
|
+
|
|
280
|
+
DEFAULT_DIGITS = {
|
|
281
|
+
WD: 3,
|
|
282
|
+
WS: 4,
|
|
283
|
+
TI: 6,
|
|
284
|
+
RHO: 5,
|
|
285
|
+
P: 3,
|
|
286
|
+
CT: 6,
|
|
287
|
+
T: 3,
|
|
288
|
+
YLD: 3,
|
|
289
|
+
CAP: 5,
|
|
290
|
+
EFF: 5,
|
|
291
|
+
}
|
|
292
|
+
""" The default output digits
|
|
293
|
+
:group: foxes.variables
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def get_default_digits(variable):
|
|
298
|
+
"""
|
|
299
|
+
Gets the default numbber of output digits
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
variable: str
|
|
304
|
+
The variable name
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
digits: int
|
|
309
|
+
The default number of output digits
|
|
310
|
+
|
|
311
|
+
"""
|
|
312
|
+
v = amb2var.get(variable, variable)
|
|
313
|
+
if v in [REWS, REWS2, REWS3]:
|
|
314
|
+
v = WS
|
|
315
|
+
return DEFAULT_DIGITS.get(v, None)
|
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: foxes
|
|
3
|
-
Version: 0
|
|
3
|
+
Version: 1.0
|
|
4
4
|
Summary: Farm Optimization and eXtended yield Evaluation Software
|
|
5
|
-
Author:
|
|
6
|
-
|
|
7
|
-
License: MIT
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
Author: Jonas Schulte
|
|
6
|
+
Maintainer: Jonas Schulte
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2022 FraunhoferIWES
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Homepage, https://github.com/FraunhoferIWES/foxes
|
|
10
30
|
Project-URL: Documentation, https://fraunhoferiwes.github.io/foxes.docs/index.html
|
|
31
|
+
Project-URL: Repository, https://github.com/FraunhoferIWES/foxes.git
|
|
32
|
+
Project-URL: Bug Tracker, https://github.com/FraunhoferIWES/foxes/issues
|
|
33
|
+
Project-URL: Changelog, https://github.com/FraunhoferIWES/foxes/blob/main/CHANGELOG.md
|
|
11
34
|
Keywords: Wind farm,Wake modelling,Wind farm optimization
|
|
12
35
|
Classifier: Topic :: Scientific/Engineering
|
|
13
36
|
Classifier: Intended Audience :: Developers
|
|
@@ -28,40 +51,51 @@ Requires-Dist: matplotlib
|
|
|
28
51
|
Requires-Dist: numpy
|
|
29
52
|
Requires-Dist: pandas
|
|
30
53
|
Requires-Dist: xarray
|
|
31
|
-
Requires-Dist: dask
|
|
32
|
-
Requires-Dist: distributed
|
|
33
54
|
Requires-Dist: scipy
|
|
34
55
|
Requires-Dist: netcdf4
|
|
35
56
|
Requires-Dist: windrose
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
Requires-Dist:
|
|
42
|
-
Requires-Dist:
|
|
43
|
-
Requires-Dist:
|
|
44
|
-
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist:
|
|
47
|
-
Requires-Dist:
|
|
48
|
-
Requires-Dist:
|
|
57
|
+
Requires-Dist: cycler
|
|
58
|
+
Requires-Dist: tqdm
|
|
59
|
+
Requires-Dist: pyyaml
|
|
60
|
+
Provides-Extra: dask
|
|
61
|
+
Requires-Dist: dask; extra == "dask"
|
|
62
|
+
Requires-Dist: distributed; extra == "dask"
|
|
63
|
+
Requires-Dist: dask-jobqueue; extra == "dask"
|
|
64
|
+
Requires-Dist: setuptools; extra == "dask"
|
|
65
|
+
Provides-Extra: dev
|
|
66
|
+
Requires-Dist: flake8; extra == "dev"
|
|
67
|
+
Requires-Dist: pytest; extra == "dev"
|
|
68
|
+
Requires-Dist: jupyter; extra == "dev"
|
|
69
|
+
Requires-Dist: objsize; extra == "dev"
|
|
70
|
+
Requires-Dist: black; extra == "dev"
|
|
49
71
|
Provides-Extra: doc
|
|
50
|
-
Requires-Dist: sphinx
|
|
51
|
-
Requires-Dist: sphinx-immaterial
|
|
52
|
-
Requires-Dist: nbsphinx
|
|
53
|
-
Requires-Dist: ipykernel
|
|
54
|
-
Requires-Dist: ipywidgets
|
|
55
|
-
Requires-Dist: m2r2
|
|
56
|
-
Requires-Dist: lxml-html-clean
|
|
72
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
73
|
+
Requires-Dist: sphinx-immaterial; extra == "doc"
|
|
74
|
+
Requires-Dist: nbsphinx; extra == "doc"
|
|
75
|
+
Requires-Dist: ipykernel; extra == "doc"
|
|
76
|
+
Requires-Dist: ipywidgets; extra == "doc"
|
|
77
|
+
Requires-Dist: m2r2; extra == "doc"
|
|
78
|
+
Requires-Dist: lxml-html-clean; extra == "doc"
|
|
79
|
+
Provides-Extra: eng
|
|
80
|
+
Requires-Dist: multiprocess; extra == "eng"
|
|
81
|
+
Requires-Dist: dask; extra == "eng"
|
|
82
|
+
Requires-Dist: distributed; extra == "eng"
|
|
83
|
+
Requires-Dist: dask-jobqueue; extra == "eng"
|
|
84
|
+
Requires-Dist: setuptools; extra == "eng"
|
|
85
|
+
Requires-Dist: mpi4py; extra == "eng"
|
|
86
|
+
Provides-Extra: eng0
|
|
87
|
+
Requires-Dist: multiprocess; extra == "eng0"
|
|
88
|
+
Requires-Dist: dask; extra == "eng0"
|
|
89
|
+
Requires-Dist: distributed; extra == "eng0"
|
|
90
|
+
Requires-Dist: dask-jobqueue; extra == "eng0"
|
|
91
|
+
Requires-Dist: setuptools; extra == "eng0"
|
|
57
92
|
Provides-Extra: io
|
|
58
|
-
Requires-Dist: windio
|
|
93
|
+
Requires-Dist: windio>=1; extra == "io"
|
|
59
94
|
Provides-Extra: opt
|
|
60
|
-
Requires-Dist: foxes-opt
|
|
61
|
-
Provides-Extra: scripts
|
|
95
|
+
Requires-Dist: foxes-opt; extra == "opt"
|
|
62
96
|
Provides-Extra: test
|
|
63
|
-
Requires-Dist: flake8
|
|
64
|
-
Requires-Dist: pytest
|
|
97
|
+
Requires-Dist: flake8; extra == "test"
|
|
98
|
+
Requires-Dist: pytest; extra == "test"
|
|
65
99
|
|
|
66
100
|
# Welcome to foxes
|
|
67
101
|
|
|
@@ -76,7 +110,11 @@ The software `foxes` is a modular wind farm simulation and wake modelling toolbo
|
|
|
76
110
|
- Wake model studies, comparison and validation,
|
|
77
111
|
- Wind farm simulations invoking complex model chains.
|
|
78
112
|
|
|
79
|
-
The
|
|
113
|
+
The fast performance of `foxes` is owed to vectorization and parallelization,
|
|
114
|
+
and it is intended to be used for large wind farms and large timeseries inflow data.
|
|
115
|
+
The parallelization on local or remote clusters is supported, based on
|
|
116
|
+
[dask.distributed](https://distributed.dask.org/en/stable/).
|
|
117
|
+
The wind farm
|
|
80
118
|
optimization capabilities invoke the [iwopy](https://github.com/FraunhoferIWES/iwopy) package which
|
|
81
119
|
as well supports vectorization.
|
|
82
120
|
|