foxes 0.8.2__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 +23 -13
- foxes/variables.py +37 -0
- {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/METADATA +71 -33
- foxes-1.0.dist-info/RECORD +307 -0
- {foxes-0.8.2.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/runners/__init__.py +0 -1
- foxes/utils/runners/runners.py +0 -280
- foxes-0.8.2.dist-info/RECORD +0 -247
- foxes-0.8.2.dist-info/top_level.txt +0 -1
- foxes-0.8.2.dist-info/zip-safe +0 -1
- {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/LICENSE +0 -0
foxes/input/windio/windio.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
1
|
from pathlib import Path
|
|
4
2
|
|
|
5
3
|
from foxes.core import WindFarm
|
|
@@ -9,7 +7,7 @@ from foxes.data import StaticData, WINDIO
|
|
|
9
7
|
|
|
10
8
|
from .read_fields import read_wind_resource_field
|
|
11
9
|
from .get_states import get_states
|
|
12
|
-
from .read_farm import read_layout,
|
|
10
|
+
from .read_farm import read_layout, read_turbine_types
|
|
13
11
|
from .read_attributes import read_attributes
|
|
14
12
|
from .runner import WindioRunner
|
|
15
13
|
|
|
@@ -78,19 +76,27 @@ def _read_farm(wio, algo_dict, verbosity):
|
|
|
78
76
|
ws_exp_ct = 1
|
|
79
77
|
|
|
80
78
|
# read turbine type:
|
|
81
|
-
|
|
82
|
-
ttype = read_turbine_type(turbines, algo_dict, ws_exp_P, ws_exp_ct, verbosity)
|
|
79
|
+
ttypes = read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity)
|
|
83
80
|
|
|
84
81
|
# read layouts:
|
|
85
|
-
|
|
82
|
+
wfarm = wio_farm["layouts"]
|
|
83
|
+
if isinstance(wfarm, dict):
|
|
84
|
+
layouts = Dict(wfarm, name="layouts")
|
|
85
|
+
else:
|
|
86
|
+
layouts = Dict({i: l for i, l in enumerate(wfarm)}, name="layouts")
|
|
86
87
|
if verbosity > 2:
|
|
87
88
|
print(" Reading layouts")
|
|
88
89
|
print(" Contents:", [k for k in layouts.keys()])
|
|
89
90
|
for lname, ldict in layouts.items():
|
|
90
|
-
read_layout(lname, ldict, algo_dict,
|
|
91
|
+
read_layout(lname, ldict, algo_dict, ttypes, verbosity)
|
|
91
92
|
|
|
92
93
|
|
|
93
|
-
def read_windio(
|
|
94
|
+
def read_windio(
|
|
95
|
+
windio_yaml,
|
|
96
|
+
verbosity=1,
|
|
97
|
+
algo_pars=None,
|
|
98
|
+
**runner_pars,
|
|
99
|
+
):
|
|
94
100
|
"""
|
|
95
101
|
Reads a complete WindIO case.
|
|
96
102
|
|
|
@@ -103,6 +109,10 @@ def read_windio(windio_yaml, verbosity=1):
|
|
|
103
109
|
Path to the windio yaml file
|
|
104
110
|
verbosity: int
|
|
105
111
|
The verbosity level, 0 = silent
|
|
112
|
+
algo_pars: dict, optional
|
|
113
|
+
Additional algorithm parameters
|
|
114
|
+
runner_pars: dict, optional
|
|
115
|
+
Additional parameters for the WindioRunner
|
|
106
116
|
|
|
107
117
|
Returns
|
|
108
118
|
-------
|
|
@@ -113,7 +123,6 @@ def read_windio(windio_yaml, verbosity=1):
|
|
|
113
123
|
:group: input.windio
|
|
114
124
|
|
|
115
125
|
"""
|
|
116
|
-
|
|
117
126
|
wio_file = Path(windio_yaml)
|
|
118
127
|
if not wio_file.is_file():
|
|
119
128
|
wio_file = StaticData().get_file_path(WINDIO, wio_file, check_raw=False)
|
|
@@ -128,17 +137,21 @@ def read_windio(windio_yaml, verbosity=1):
|
|
|
128
137
|
print(" Name:", wio.pop("name", None))
|
|
129
138
|
print(" Contents:", [k for k in wio.keys()])
|
|
130
139
|
|
|
131
|
-
algo_dict = Dict(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
algo_dict = Dict(algo_type="Downwind", name="algo_dict")
|
|
141
|
+
if algo_pars is not None:
|
|
142
|
+
algo_dict.update(algo_pars)
|
|
143
|
+
algo_dict.update(
|
|
144
|
+
dict(
|
|
145
|
+
mbook=ModelBook(),
|
|
146
|
+
farm=WindFarm(),
|
|
147
|
+
wake_models=[],
|
|
148
|
+
verbosity=verbosity - 3,
|
|
149
|
+
)
|
|
137
150
|
)
|
|
138
151
|
|
|
139
152
|
_read_site(wio, algo_dict, verbosity)
|
|
140
153
|
_read_farm(wio, algo_dict, verbosity)
|
|
141
|
-
|
|
154
|
+
|
|
142
155
|
out_dicts, odir = read_attributes(
|
|
143
156
|
wio,
|
|
144
157
|
algo_dict,
|
|
@@ -148,12 +161,13 @@ def read_windio(windio_yaml, verbosity=1):
|
|
|
148
161
|
if verbosity > 1:
|
|
149
162
|
print("Creating windio runner")
|
|
150
163
|
runner = WindioRunner(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
algo_dict,
|
|
165
|
+
output_dir=odir,
|
|
166
|
+
output_dicts=out_dicts,
|
|
167
|
+
wio_input_data=wio,
|
|
168
|
+
verbosity=verbosity,
|
|
169
|
+
**runner_pars,
|
|
170
|
+
)
|
|
157
171
|
|
|
158
172
|
return runner
|
|
159
173
|
|
|
@@ -70,6 +70,10 @@ class WakeMirror(GroundModel):
|
|
|
70
70
|
# prepare:
|
|
71
71
|
hh = fdata[FV.H][:, downwind_index].copy()
|
|
72
72
|
|
|
73
|
+
# DEBUG CHECK:
|
|
74
|
+
# import numpy as np
|
|
75
|
+
# assert(np.all(fdata[FV.H]==fdata[FV.TXYH[..., 2]]))
|
|
76
|
+
|
|
73
77
|
# contribution from main wake:
|
|
74
78
|
wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
|
|
75
79
|
wmodel.contribute(algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas)
|
|
@@ -78,14 +82,14 @@ class WakeMirror(GroundModel):
|
|
|
78
82
|
tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
|
|
79
83
|
for h in self.heights:
|
|
80
84
|
|
|
81
|
-
fdata[FV.
|
|
85
|
+
fdata[FV.TXYH][:, downwind_index, 2] = hh + 2 * (h - hh)
|
|
82
86
|
|
|
83
87
|
pwake.contribute(
|
|
84
88
|
algo, mdata, fdata, tdata, downwind_index, wake_deltas, wmodel
|
|
85
89
|
)
|
|
86
90
|
|
|
87
91
|
# reset heights:
|
|
88
|
-
fdata[FV.
|
|
92
|
+
fdata[FV.TXYH][:, downwind_index, 2] = hh
|
|
89
93
|
|
|
90
94
|
def contribute_to_point_wakes(
|
|
91
95
|
self,
|
|
@@ -133,7 +137,7 @@ class WakeMirror(GroundModel):
|
|
|
133
137
|
tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
|
|
134
138
|
for h in self.heights:
|
|
135
139
|
|
|
136
|
-
fdata[FV.
|
|
140
|
+
fdata[FV.TXYH][:, downwind_index, 2] = hh + 2 * (h - hh)
|
|
137
141
|
|
|
138
142
|
wcoos = algo.wake_frame.get_wake_coos(
|
|
139
143
|
algo, mdata, fdata, tdata, downwind_index
|
|
@@ -143,7 +147,7 @@ class WakeMirror(GroundModel):
|
|
|
143
147
|
)
|
|
144
148
|
|
|
145
149
|
# reset heights:
|
|
146
|
-
fdata[FV.
|
|
150
|
+
fdata[FV.TXYH][:, downwind_index, 2] = hh
|
|
147
151
|
|
|
148
152
|
|
|
149
153
|
class GroundMirror(WakeMirror):
|
foxes/models/model_book.py
CHANGED
|
@@ -85,8 +85,7 @@ class ModelBook:
|
|
|
85
85
|
self.point_models["tke2ti"] = fm.point_models.TKE2TI()
|
|
86
86
|
|
|
87
87
|
self.rotor_models = FDict(name="rotor_models")
|
|
88
|
-
|
|
89
|
-
self.rotor_models["centre"] = fm.rotor_models.CentreRotor(calc_vars=rvars)
|
|
88
|
+
self.rotor_models["centre"] = fm.rotor_models.CentreRotor()
|
|
90
89
|
|
|
91
90
|
def _n2n(n2):
|
|
92
91
|
n2 = float(n2)
|
|
@@ -100,7 +99,7 @@ class ModelBook:
|
|
|
100
99
|
self.rotor_models.add_factory(
|
|
101
100
|
fm.rotor_models.GridRotor,
|
|
102
101
|
"grid<n2>",
|
|
103
|
-
kwargs=dict(
|
|
102
|
+
kwargs=dict(reduce=True),
|
|
104
103
|
var2arg={"n2": "n"},
|
|
105
104
|
n2=_n2n,
|
|
106
105
|
hints={"n2": "(Number of points in square grid)"},
|
|
@@ -108,7 +107,7 @@ class ModelBook:
|
|
|
108
107
|
self.rotor_models.add_factory(
|
|
109
108
|
fm.rotor_models.GridRotor,
|
|
110
109
|
"grid<n2>_raw",
|
|
111
|
-
kwargs=dict(
|
|
110
|
+
kwargs=dict(reduce=False),
|
|
112
111
|
var2arg={"n2": "n"},
|
|
113
112
|
n2=_n2n,
|
|
114
113
|
hints={"n2": "(Number of points in square grid)"},
|
|
@@ -116,14 +115,14 @@ class ModelBook:
|
|
|
116
115
|
self.rotor_models.add_factory(
|
|
117
116
|
fm.rotor_models.LevelRotor,
|
|
118
117
|
"level<n>",
|
|
119
|
-
kwargs=dict(
|
|
118
|
+
kwargs=dict(reduce=True),
|
|
120
119
|
n=lambda x: int(x),
|
|
121
120
|
hints={"n": "(Number of vertical levels)"},
|
|
122
121
|
)
|
|
123
122
|
self.rotor_models.add_factory(
|
|
124
123
|
fm.rotor_models.LevelRotor,
|
|
125
124
|
"level<n>_raw",
|
|
126
|
-
kwargs=dict(
|
|
125
|
+
kwargs=dict(reduce=False),
|
|
127
126
|
n=lambda x: int(x),
|
|
128
127
|
hints={"n": "(Number of vertical levels)"},
|
|
129
128
|
)
|
|
@@ -158,14 +157,14 @@ class ModelBook:
|
|
|
158
157
|
fm.turbine_models.kTI,
|
|
159
158
|
"kTI_<kTI>",
|
|
160
159
|
kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
161
|
-
hints={"kTI": "(Value, e.g.
|
|
160
|
+
hints={"kTI": "(Value, e.g. 02 for 0.2)"},
|
|
162
161
|
)
|
|
163
162
|
self.turbine_models.add_factory(
|
|
164
163
|
fm.turbine_models.kTI,
|
|
165
164
|
"kTI_amb_<kTI>",
|
|
166
165
|
kwargs=dict(ti_var=FV.AMB_TI),
|
|
167
166
|
kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
168
|
-
hints={"kTI": "(Value, e.g.
|
|
167
|
+
hints={"kTI": "(Value, e.g. 04 for 0.4)"},
|
|
169
168
|
)
|
|
170
169
|
self.turbine_models.add_factory(
|
|
171
170
|
fm.turbine_models.kTI,
|
|
@@ -173,7 +172,7 @@ class ModelBook:
|
|
|
173
172
|
kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
174
173
|
kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
175
174
|
hints={
|
|
176
|
-
"kTI": "(Value, e.g.
|
|
175
|
+
"kTI": "(Value, e.g. 04 for 0.4)",
|
|
177
176
|
"kb": "(Value, e.g. 004 for 0.04)",
|
|
178
177
|
},
|
|
179
178
|
)
|
|
@@ -184,7 +183,7 @@ class ModelBook:
|
|
|
184
183
|
kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
185
184
|
kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
|
|
186
185
|
hints={
|
|
187
|
-
"kTI": "(Value, e.g.
|
|
186
|
+
"kTI": "(Value, e.g. 04 for 0.4)",
|
|
188
187
|
"kb": "(Value, e.g. 004 for 0.04)",
|
|
189
188
|
},
|
|
190
189
|
)
|
|
@@ -254,12 +253,24 @@ class ModelBook:
|
|
|
254
253
|
)
|
|
255
254
|
|
|
256
255
|
self.wake_frames["timelines"] = fm.wake_frames.Timelines()
|
|
256
|
+
self.wake_frames["dyn_wakes"] = fm.wake_frames.DynamicWakes()
|
|
257
|
+
self.wake_frames["seq_dyn_wakes"] = fm.wake_frames.SeqDynamicWakes()
|
|
257
258
|
|
|
258
259
|
def _todt(x):
|
|
259
260
|
if x[-1] == "s":
|
|
260
261
|
return float(x[:-1]) / 60
|
|
261
262
|
elif x[-3:] == "min":
|
|
262
263
|
return float(x[:-3])
|
|
264
|
+
else:
|
|
265
|
+
raise NotImplementedError(f"Cannot translate '{x}' into minutes")
|
|
266
|
+
|
|
267
|
+
def _tokm(x):
|
|
268
|
+
if x[-2:] == "km":
|
|
269
|
+
return float(x[:-2])
|
|
270
|
+
elif x[-1] == "m":
|
|
271
|
+
return float(x[:-1]) / 1e3
|
|
272
|
+
else:
|
|
273
|
+
raise NotImplementedError(f"Cannot translate '{x}' into km")
|
|
263
274
|
|
|
264
275
|
self.wake_frames.add_factory(
|
|
265
276
|
fm.wake_frames.Timelines,
|
|
@@ -268,6 +279,13 @@ class ModelBook:
|
|
|
268
279
|
var2arg={"dt": "dt_min"},
|
|
269
280
|
hints={"dt": "(Time step, e.g '10s', '1min' etc.)"},
|
|
270
281
|
)
|
|
282
|
+
self.wake_frames.add_factory(
|
|
283
|
+
fm.wake_frames.DynamicWakes,
|
|
284
|
+
"dyn_wakes_<length>",
|
|
285
|
+
length=_tokm,
|
|
286
|
+
var2arg={"length": "max_length_km"},
|
|
287
|
+
hints={"length": "(Maximal wake length, e.g. '5km' or '5000m')"},
|
|
288
|
+
)
|
|
271
289
|
self.wake_frames.add_factory(
|
|
272
290
|
fm.wake_frames.SeqDynamicWakes,
|
|
273
291
|
"seq_dyn_wakes_<dt>",
|
|
@@ -411,14 +429,6 @@ class ModelBook:
|
|
|
411
429
|
hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
|
|
412
430
|
)
|
|
413
431
|
|
|
414
|
-
self.wake_models.add_factory(
|
|
415
|
-
fm.wake_models.ti.IECTIWake,
|
|
416
|
-
"IECTI2005_<superposition>",
|
|
417
|
-
kwargs=dict(iec_type="2005"),
|
|
418
|
-
superposition=lambda s: f"ti_{s}",
|
|
419
|
-
hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
|
|
420
|
-
)
|
|
421
|
-
|
|
422
432
|
self.wake_models.add_factory(
|
|
423
433
|
fm.wake_models.ti.IECTIWake,
|
|
424
434
|
"IECTI2019_<superposition>",
|
|
@@ -466,6 +476,7 @@ class ModelBook:
|
|
|
466
476
|
var2arg={"height": "heights"},
|
|
467
477
|
height=lambda h: [0.0, float(h)],
|
|
468
478
|
hints={"height": "(Boundary layer wake reflection height)"},
|
|
479
|
+
example_vars={"height": 500},
|
|
469
480
|
)
|
|
470
481
|
|
|
471
482
|
self.sources = FDict(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from foxes.core import PartialWakesModel
|
|
2
|
+
import foxes.constants as FC
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class RotorPoints(PartialWakesModel):
|
|
@@ -33,10 +34,9 @@ class RotorPoints(PartialWakesModel):
|
|
|
33
34
|
The target point weights, shape: (n_tpoints,)
|
|
34
35
|
|
|
35
36
|
"""
|
|
36
|
-
rotor = algo.rotor_model
|
|
37
37
|
return (
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
algo.get_from_chunk_store(FC.ROTOR_POINTS, mdata=mdata),
|
|
39
|
+
algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata),
|
|
40
40
|
)
|
|
41
41
|
|
|
42
42
|
def finalize_wakes(
|
|
@@ -132,6 +132,10 @@ class CentreRotor(RotorModel):
|
|
|
132
132
|
n_states = mdata.n_states
|
|
133
133
|
n_turbines = algo.n_turbines
|
|
134
134
|
|
|
135
|
+
for v in [FV.REWS2, FV.REWS3]:
|
|
136
|
+
if v in fdata and v not in self.calc_vars:
|
|
137
|
+
self.calc_vars.append(v)
|
|
138
|
+
|
|
135
139
|
uvp = None
|
|
136
140
|
uv = None
|
|
137
141
|
if (
|
|
@@ -17,7 +17,7 @@ class GridRotor(RotorModel):
|
|
|
17
17
|
reduce: bool
|
|
18
18
|
Flag for reduction to points actually representing
|
|
19
19
|
an area with overlap with the circe, recalculating
|
|
20
|
-
the self.
|
|
20
|
+
the self.__weights accordingly
|
|
21
21
|
nint: int
|
|
22
22
|
Integration steps per element
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ class GridRotor(RotorModel):
|
|
|
25
25
|
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
def __init__(self, n,
|
|
28
|
+
def __init__(self, n, reduce=True, nint=200, **kwargs):
|
|
29
29
|
"""
|
|
30
30
|
Constructor.
|
|
31
31
|
|
|
@@ -34,20 +34,19 @@ class GridRotor(RotorModel):
|
|
|
34
34
|
n: int
|
|
35
35
|
The number of points along one direction,
|
|
36
36
|
maximal number of points is N = n * n
|
|
37
|
-
calc_vars: list of str
|
|
38
|
-
The variables that are calculated by the model
|
|
39
|
-
(Their ambients are added automatically)
|
|
40
37
|
reduce: bool
|
|
41
38
|
Flag for reduction to points actually representing
|
|
42
39
|
an area with overlap with the circe, recalculating
|
|
43
|
-
the self.
|
|
40
|
+
the self.__weights accordingly
|
|
44
41
|
nint: int
|
|
45
42
|
Integration steps per element
|
|
46
43
|
name: str, optional
|
|
47
44
|
The model name
|
|
45
|
+
kwargs: dict, optional
|
|
46
|
+
Addition parameters for the base model
|
|
48
47
|
|
|
49
48
|
"""
|
|
50
|
-
super().__init__(
|
|
49
|
+
super().__init__(**kwargs)
|
|
51
50
|
|
|
52
51
|
self.n = n
|
|
53
52
|
self.reduce = reduce
|
|
@@ -76,12 +75,12 @@ class GridRotor(RotorModel):
|
|
|
76
75
|
x = [-1.0 + (i + 0.5) * delta for i in range(self.n)]
|
|
77
76
|
x, y = np.meshgrid(x, x, indexing="ij")
|
|
78
77
|
|
|
79
|
-
self.
|
|
80
|
-
self.
|
|
81
|
-
self.
|
|
78
|
+
self.__dpoints = np.zeros([N, 3], dtype=FC.DTYPE)
|
|
79
|
+
self.__dpoints[:, 1] = x.reshape(N)
|
|
80
|
+
self.__dpoints[:, 2] = y.reshape(N)
|
|
82
81
|
|
|
83
82
|
if self.reduce:
|
|
84
|
-
self.
|
|
83
|
+
self.__weights = np.zeros((self.n, self.n), dtype=FC.DTYPE)
|
|
85
84
|
for i in range(0, self.n):
|
|
86
85
|
for j in range(0, self.n):
|
|
87
86
|
d = delta / self.nint
|
|
@@ -95,18 +94,18 @@ class GridRotor(RotorModel):
|
|
|
95
94
|
pts[:, :, 0], pts[:, :, 1] = np.meshgrid(hx, hy, indexing="ij")
|
|
96
95
|
|
|
97
96
|
d = np.linalg.norm(pts, axis=2)
|
|
98
|
-
self.
|
|
97
|
+
self.__weights[i, j] = np.sum(d <= 1.0) / self.nint**2
|
|
99
98
|
|
|
100
|
-
self.
|
|
101
|
-
sel = self.
|
|
102
|
-
self.
|
|
103
|
-
self.
|
|
104
|
-
self.
|
|
99
|
+
self.__weights = self.__weights.reshape(N)
|
|
100
|
+
sel = self.__weights > 0.0
|
|
101
|
+
self.__dpoints = self.__dpoints[sel]
|
|
102
|
+
self.__weights = self.__weights[sel]
|
|
103
|
+
self.__weights /= np.sum(self.__weights)
|
|
105
104
|
|
|
106
105
|
else:
|
|
107
|
-
self.
|
|
108
|
-
self.
|
|
109
|
-
self.
|
|
106
|
+
self.__dpoints[:, 1] = x.reshape(N)
|
|
107
|
+
self.__dpoints[:, 2] = y.reshape(N)
|
|
108
|
+
self.__weights = np.ones(N, dtype=FC.DTYPE) / N
|
|
110
109
|
|
|
111
110
|
def n_rotor_points(self):
|
|
112
111
|
"""
|
|
@@ -118,7 +117,7 @@ class GridRotor(RotorModel):
|
|
|
118
117
|
The number of rotor points
|
|
119
118
|
|
|
120
119
|
"""
|
|
121
|
-
return len(self.
|
|
120
|
+
return len(self.__weights)
|
|
122
121
|
|
|
123
122
|
def design_points(self):
|
|
124
123
|
"""
|
|
@@ -137,7 +136,7 @@ class GridRotor(RotorModel):
|
|
|
137
136
|
The design points, shape: (n_points, 3)
|
|
138
137
|
|
|
139
138
|
"""
|
|
140
|
-
return self.
|
|
139
|
+
return self.__dpoints
|
|
141
140
|
|
|
142
141
|
def rotor_point_weights(self):
|
|
143
142
|
"""
|
|
@@ -150,4 +149,4 @@ class GridRotor(RotorModel):
|
|
|
150
149
|
add to one, shape: (n_rpoints,)
|
|
151
150
|
|
|
152
151
|
"""
|
|
153
|
-
return self.
|
|
152
|
+
return self.__weights
|
|
@@ -24,7 +24,7 @@ class LevelRotor(RotorModel):
|
|
|
24
24
|
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self, n,
|
|
27
|
+
def __init__(self, n, reduce=True, nint=200, **kwargs):
|
|
28
28
|
"""
|
|
29
29
|
Constructor.
|
|
30
30
|
|
|
@@ -32,9 +32,6 @@ class LevelRotor(RotorModel):
|
|
|
32
32
|
----------
|
|
33
33
|
n: int
|
|
34
34
|
The number of points along the vertical direction
|
|
35
|
-
calc_vars: list of str
|
|
36
|
-
The variables that are calculated by the model
|
|
37
|
-
(Their ambients are added automatically)
|
|
38
35
|
reduce: bool
|
|
39
36
|
Flag for calculating the weight of every element according
|
|
40
37
|
to the rotor diameter at the respective height level
|
|
@@ -42,9 +39,11 @@ class LevelRotor(RotorModel):
|
|
|
42
39
|
Integration steps per element
|
|
43
40
|
name: str, optional
|
|
44
41
|
The model name
|
|
42
|
+
kwargs: dict, optional
|
|
43
|
+
Addition parameters for the base model
|
|
45
44
|
|
|
46
45
|
"""
|
|
47
|
-
super().__init__(
|
|
46
|
+
super().__init__(**kwargs)
|
|
48
47
|
|
|
49
48
|
self.n = n
|
|
50
49
|
self.reduce = reduce
|
|
@@ -36,6 +36,7 @@ class LookupTable(TurbineModel):
|
|
|
36
36
|
varmap={},
|
|
37
37
|
pd_file_read_pars={},
|
|
38
38
|
xr_interp_args={},
|
|
39
|
+
interpn_args={},
|
|
39
40
|
**kwargs,
|
|
40
41
|
):
|
|
41
42
|
"""
|
|
@@ -56,6 +57,8 @@ class LookupTable(TurbineModel):
|
|
|
56
57
|
Parameters for pandas file reading
|
|
57
58
|
xr_interp_args: dict
|
|
58
59
|
Parameters for xarray interpolation method
|
|
60
|
+
interpn_args: dict
|
|
61
|
+
Parameters for scipy intern or interp1d
|
|
59
62
|
kwargs: dict, optional
|
|
60
63
|
Additional parameters, added as default
|
|
61
64
|
values if not in data
|
|
@@ -70,6 +73,7 @@ class LookupTable(TurbineModel):
|
|
|
70
73
|
|
|
71
74
|
self._rpars = pd_file_read_pars
|
|
72
75
|
self._xargs = xr_interp_args
|
|
76
|
+
self._iargs = interpn_args
|
|
73
77
|
self._data = None
|
|
74
78
|
|
|
75
79
|
for v, d in kwargs.items():
|
|
@@ -184,7 +188,7 @@ class LookupTable(TurbineModel):
|
|
|
184
188
|
"""
|
|
185
189
|
data = {
|
|
186
190
|
v: self.get_data(
|
|
187
|
-
|
|
191
|
+
v,
|
|
188
192
|
FC.STATE_TURBINE,
|
|
189
193
|
lookup="fs",
|
|
190
194
|
fdata=fdata,
|
|
@@ -192,6 +196,7 @@ class LookupTable(TurbineModel):
|
|
|
192
196
|
)[st_sel]
|
|
193
197
|
for v in self.input_vars
|
|
194
198
|
}
|
|
199
|
+
|
|
195
200
|
dims = {
|
|
196
201
|
v: ("_z") if len(data[v].shape) == 1 else ("_z", "_u")
|
|
197
202
|
for v in self.input_vars
|
|
@@ -205,7 +210,27 @@ class LookupTable(TurbineModel):
|
|
|
205
210
|
}
|
|
206
211
|
del data, dims
|
|
207
212
|
|
|
208
|
-
|
|
213
|
+
iargs = dict(bounds_error=True)
|
|
214
|
+
iargs.update(self._iargs)
|
|
215
|
+
try:
|
|
216
|
+
odata = self._data.interp(**indata, kwargs=iargs, **self._xargs)
|
|
217
|
+
except ValueError as e:
|
|
218
|
+
print("\nBOUNDS ERROR", self.name)
|
|
219
|
+
print("Variables:", list(indata.keys()))
|
|
220
|
+
print(
|
|
221
|
+
"DATA min/max:",
|
|
222
|
+
[float(np.min(self._data[v].to_numpy())) for v in indata.keys()],
|
|
223
|
+
[float(np.max(self._data[v].to_numpy())) for v in indata.keys()],
|
|
224
|
+
)
|
|
225
|
+
print(
|
|
226
|
+
"EVAL min/max:",
|
|
227
|
+
[float(np.min(d.to_numpy())) for d in indata.values()],
|
|
228
|
+
[float(np.max(d.to_numpy())) for d in indata.values()],
|
|
229
|
+
)
|
|
230
|
+
print(
|
|
231
|
+
"\nMaybe you want to try the options 'bounds_error=False, fill_value=None'? This will extrapolate the data.\n"
|
|
232
|
+
)
|
|
233
|
+
raise e
|
|
209
234
|
|
|
210
235
|
out = {}
|
|
211
236
|
for v in self.output_vars:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
|
-
from foxes.core import TurbineModel,
|
|
3
|
+
from foxes.core import TurbineModel, TData
|
|
4
4
|
import foxes.variables as FV
|
|
5
5
|
import foxes.constants as FC
|
|
6
6
|
|
|
@@ -108,7 +108,7 @@ class RotorCentreCalc(TurbineModel):
|
|
|
108
108
|
|
|
109
109
|
"""
|
|
110
110
|
# prepare target point data:
|
|
111
|
-
tdata =
|
|
111
|
+
tdata = TData.from_points(
|
|
112
112
|
fdata[FV.TXYH],
|
|
113
113
|
data={
|
|
114
114
|
v: np.zeros_like(fdata[FV.X][:, :, None])
|
|
@@ -131,6 +131,7 @@ class RotorCentreCalc(TurbineModel):
|
|
|
131
131
|
# extract results:
|
|
132
132
|
out = {v: fdata[v] for v in self.calc_vars.keys()}
|
|
133
133
|
for v in out.keys():
|
|
134
|
-
|
|
134
|
+
w = self.calc_vars[v]
|
|
135
|
+
out[v][st_sel] = res[w][st_sel][..., 0]
|
|
135
136
|
|
|
136
137
|
return out
|