foxes 0.8.2__py3-none-any.whl → 1.1.0.2__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/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 +190 -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 +247 -111
- foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
- foxes/algorithms/downwind/models/init_farm_data.py +2 -2
- foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
- foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
- foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
- foxes/algorithms/iterative/iterative.py +74 -34
- foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
- foxes/algorithms/iterative/models/urelax.py +3 -3
- foxes/algorithms/sequential/models/plugin.py +5 -5
- foxes/algorithms/sequential/models/seq_state.py +1 -1
- foxes/algorithms/sequential/sequential.py +126 -255
- foxes/constants.py +22 -7
- foxes/core/__init__.py +1 -0
- foxes/core/algorithm.py +632 -147
- foxes/core/data.py +252 -20
- foxes/core/data_calc_model.py +15 -291
- foxes/core/engine.py +640 -0
- foxes/core/farm_controller.py +38 -10
- foxes/core/farm_data_model.py +16 -1
- foxes/core/ground_model.py +2 -2
- foxes/core/model.py +249 -182
- foxes/core/partial_wakes_model.py +1 -1
- foxes/core/point_data_model.py +17 -2
- foxes/core/rotor_model.py +27 -21
- foxes/core/states.py +17 -1
- foxes/core/turbine_type.py +28 -0
- foxes/core/wake_frame.py +30 -34
- foxes/core/wake_model.py +5 -5
- foxes/core/wake_superposition.py +1 -1
- foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
- foxes/engines/__init__.py +17 -0
- foxes/engines/dask.py +982 -0
- foxes/engines/default.py +75 -0
- foxes/engines/futures.py +72 -0
- foxes/engines/mpi.py +38 -0
- foxes/engines/multiprocess.py +71 -0
- foxes/engines/numpy.py +167 -0
- foxes/engines/pool.py +249 -0
- foxes/engines/ray.py +79 -0
- foxes/engines/single.py +141 -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 +2 -2
- 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 +7 -0
- foxes/input/states/create/random_abl_states.py +1 -1
- foxes/input/states/field_data_nc.py +158 -33
- foxes/input/states/multi_height.py +128 -14
- foxes/input/states/one_point_flow.py +577 -0
- foxes/input/states/scan_ws.py +74 -3
- foxes/input/states/single.py +1 -1
- foxes/input/states/slice_data_nc.py +681 -0
- foxes/input/states/states_table.py +204 -35
- foxes/input/windio/__init__.py +2 -2
- foxes/input/windio/get_states.py +44 -23
- foxes/input/windio/read_attributes.py +48 -17
- foxes/input/windio/read_farm.py +116 -102
- foxes/input/windio/read_fields.py +16 -6
- foxes/input/windio/read_outputs.py +71 -24
- foxes/input/windio/runner.py +31 -17
- foxes/input/windio/windio.py +41 -23
- foxes/models/farm_models/turbine2farm.py +1 -1
- foxes/models/ground_models/wake_mirror.py +10 -6
- foxes/models/model_book.py +58 -20
- foxes/models/partial_wakes/axiwake.py +3 -3
- foxes/models/partial_wakes/rotor_points.py +3 -3
- foxes/models/partial_wakes/top_hat.py +2 -2
- foxes/models/point_models/set_uniform_data.py +1 -1
- foxes/models/point_models/tke2ti.py +1 -1
- foxes/models/point_models/wake_deltas.py +1 -1
- foxes/models/rotor_models/centre.py +4 -0
- foxes/models/rotor_models/grid.py +24 -25
- foxes/models/rotor_models/levels.py +4 -5
- foxes/models/turbine_models/calculator.py +4 -6
- foxes/models/turbine_models/kTI_model.py +22 -6
- foxes/models/turbine_models/lookup_table.py +30 -4
- 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 +27 -3
- foxes/models/turbine_types/PCt_from_two.py +27 -3
- foxes/models/turbine_types/TBL_file.py +80 -0
- foxes/models/turbine_types/__init__.py +2 -0
- foxes/models/turbine_types/lookup.py +316 -0
- foxes/models/turbine_types/null_type.py +51 -1
- foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
- foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
- foxes/models/vertical_profiles/__init__.py +1 -1
- 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 +25 -5
- foxes/models/wake_frames/rotor_wd.py +6 -4
- foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
- foxes/models/wake_frames/streamlines.py +21 -22
- foxes/models/wake_frames/timelines.py +330 -129
- foxes/models/wake_frames/yawed_wakes.py +7 -4
- foxes/models/wake_models/dist_sliced.py +2 -4
- foxes/models/wake_models/induction/rankine_half_body.py +5 -5
- foxes/models/wake_models/induction/rathmann.py +78 -24
- foxes/models/wake_models/induction/self_similar.py +78 -28
- foxes/models/wake_models/induction/vortex_sheet.py +86 -48
- foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
- foxes/models/wake_models/ti/iec_ti.py +40 -21
- foxes/models/wake_models/top_hat.py +1 -1
- foxes/models/wake_models/wind/bastankhah14.py +8 -6
- foxes/models/wake_models/wind/bastankhah16.py +17 -16
- foxes/models/wake_models/wind/jensen.py +4 -3
- foxes/models/wake_models/wind/turbopark.py +16 -13
- foxes/models/wake_superpositions/ti_linear.py +1 -1
- foxes/models/wake_superpositions/ti_max.py +1 -1
- foxes/models/wake_superpositions/ti_pow.py +1 -1
- foxes/models/wake_superpositions/ti_quadratic.py +1 -1
- foxes/models/wake_superpositions/ws_linear.py +8 -7
- foxes/models/wake_superpositions/ws_max.py +8 -7
- foxes/models/wake_superpositions/ws_pow.py +8 -7
- foxes/models/wake_superpositions/ws_product.py +5 -5
- foxes/models/wake_superpositions/ws_quadratic.py +8 -7
- foxes/output/__init__.py +4 -1
- foxes/output/farm_layout.py +16 -12
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/flow_plots_2d/__init__.py +0 -1
- foxes/output/flow_plots_2d/flow_plots.py +70 -30
- foxes/output/grids.py +92 -22
- foxes/output/results_writer.py +2 -2
- foxes/output/rose_plot.py +3 -3
- foxes/output/seq_plugins/__init__.py +2 -0
- foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
- foxes/output/slice_data.py +131 -111
- foxes/output/state_turbine_map.py +19 -14
- foxes/output/state_turbine_table.py +19 -19
- foxes/utils/__init__.py +1 -1
- foxes/utils/abl/neutral.py +2 -2
- foxes/utils/abl/stable.py +2 -2
- foxes/utils/abl/unstable.py +2 -2
- foxes/utils/data_book.py +1 -1
- foxes/utils/dev_utils.py +42 -0
- foxes/utils/dict.py +24 -1
- foxes/utils/exec_python.py +1 -1
- foxes/utils/factory.py +176 -53
- foxes/utils/geom2d/circle.py +1 -1
- foxes/utils/geom2d/polygon.py +1 -1
- foxes/utils/geopandas_utils.py +2 -2
- foxes/utils/load.py +2 -2
- foxes/utils/pandas_helpers.py +3 -2
- foxes/utils/wind_dir.py +0 -2
- foxes/utils/xarray_utils.py +24 -14
- foxes/variables.py +39 -2
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
- foxes-1.1.0.2.dist-info/RECORD +309 -0
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
- foxes-1.1.0.2.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/geopandas_helpers.py +0 -294
- 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.1.0.2.dist-info}/LICENSE +0 -0
|
@@ -95,7 +95,7 @@ class PartialAxiwake(PartialCentre):
|
|
|
95
95
|
The target point data
|
|
96
96
|
downwind_index: int
|
|
97
97
|
The index of the wake causing turbine
|
|
98
|
-
in the
|
|
98
|
+
in the downwind order
|
|
99
99
|
wake_deltas: dict
|
|
100
100
|
The wake deltas. Key: variable name,
|
|
101
101
|
value: numpy.ndarray with shape
|
|
@@ -127,7 +127,7 @@ class PartialAxiwake(PartialCentre):
|
|
|
127
127
|
wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
|
|
128
128
|
|
|
129
129
|
# prepare x and r coordinates:
|
|
130
|
-
x =
|
|
130
|
+
x = wcoos[..., 0, 0]
|
|
131
131
|
n = wcoos[..., 0, 1:3]
|
|
132
132
|
R = np.linalg.norm(n, axis=-1)
|
|
133
133
|
r = np.zeros((n_states, n_targets, self.n), dtype=FC.DTYPE)
|
|
@@ -145,7 +145,7 @@ class PartialAxiwake(PartialCentre):
|
|
|
145
145
|
n[:, :, 0][~sel] = 1
|
|
146
146
|
|
|
147
147
|
# case wake centre outside rotor disk:
|
|
148
|
-
sel = (x >
|
|
148
|
+
sel = (x > 1e-8) & (R > D / 2)
|
|
149
149
|
if np.any(sel):
|
|
150
150
|
n_sel = np.sum(sel)
|
|
151
151
|
Rsel = np.zeros((n_sel, self.n + 1), dtype=FC.DTYPE)
|
|
@@ -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(
|
|
@@ -121,7 +121,7 @@ class PartialTopHat(PartialCentre):
|
|
|
121
121
|
The target point data
|
|
122
122
|
downwind_index: int
|
|
123
123
|
The index of the wake causing turbine
|
|
124
|
-
in the
|
|
124
|
+
in the downwind order
|
|
125
125
|
wake_deltas: dict
|
|
126
126
|
The wake deltas. Key: variable name,
|
|
127
127
|
value: numpy.ndarray with shape
|
|
@@ -148,7 +148,7 @@ class PartialTopHat(PartialCentre):
|
|
|
148
148
|
upcast=True,
|
|
149
149
|
)
|
|
150
150
|
|
|
151
|
-
sel0 = (ct >
|
|
151
|
+
sel0 = (ct > 1e-8) & (x > 1e-8)
|
|
152
152
|
if np.any(sel0):
|
|
153
153
|
R = np.linalg.norm(yz, axis=-1)
|
|
154
154
|
del yz
|
|
@@ -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 (
|
|
@@ -16,8 +16,8 @@ class GridRotor(RotorModel):
|
|
|
16
16
|
maximal number of points is N = n * n
|
|
17
17
|
reduce: bool
|
|
18
18
|
Flag for reduction to points actually representing
|
|
19
|
-
an area with overlap with the
|
|
20
|
-
the self.
|
|
19
|
+
an area with overlap with the circle, recalculating
|
|
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
|
-
an area with overlap with the
|
|
43
|
-
the self.
|
|
39
|
+
an area with overlap with the circle, recalculating
|
|
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
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
1
|
from foxes.core import TurbineModel
|
|
4
2
|
|
|
5
3
|
|
|
@@ -10,11 +8,11 @@ class Calculator(TurbineModel):
|
|
|
10
8
|
Attributes
|
|
11
9
|
----------
|
|
12
10
|
in_vars: list of str
|
|
13
|
-
The input farm
|
|
11
|
+
The input farm variables
|
|
14
12
|
out_vars: list of str
|
|
15
13
|
The output variables
|
|
16
14
|
func: Function
|
|
17
|
-
The function: f(in0, in1, ..., stsel) -> (out0,
|
|
15
|
+
The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
|
|
18
16
|
where inX and outY are numpy.ndarrays and
|
|
19
17
|
st_sel is the state-turbine selection slice or array.
|
|
20
18
|
All arrays have shape (n_states, n_turbines).
|
|
@@ -30,11 +28,11 @@ class Calculator(TurbineModel):
|
|
|
30
28
|
Parameters
|
|
31
29
|
----------
|
|
32
30
|
in_vars: list of str
|
|
33
|
-
The input farm
|
|
31
|
+
The input farm variables
|
|
34
32
|
out_vars: list of str
|
|
35
33
|
The output variables
|
|
36
34
|
func: Function
|
|
37
|
-
The function: f(in0, in1, ..., stsel) -> (out0,
|
|
35
|
+
The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
|
|
38
36
|
where inX and outY are numpy.ndarrays and
|
|
39
37
|
st_sel is the state-turbine selection slice or array.
|
|
40
38
|
All arrays have shape (n_states, n_turbines).
|
|
@@ -101,15 +101,31 @@ class kTI(TurbineModel):
|
|
|
101
101
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
102
102
|
|
|
103
103
|
"""
|
|
104
|
+
|
|
104
105
|
kti = self.get_data(
|
|
105
|
-
FV.KTI,
|
|
106
|
-
|
|
106
|
+
FV.KTI,
|
|
107
|
+
FC.STATE_TURBINE,
|
|
108
|
+
lookup="sf",
|
|
109
|
+
fdata=fdata,
|
|
110
|
+
upcast=False,
|
|
111
|
+
selection=st_sel,
|
|
112
|
+
)
|
|
107
113
|
kb = self.get_data(
|
|
108
|
-
FV.KB,
|
|
109
|
-
|
|
114
|
+
FV.KB,
|
|
115
|
+
FC.STATE_TURBINE,
|
|
116
|
+
lookup="sf",
|
|
117
|
+
fdata=fdata,
|
|
118
|
+
upcast=False,
|
|
119
|
+
selection=st_sel,
|
|
120
|
+
)
|
|
110
121
|
ti = self.get_data(
|
|
111
|
-
self.ti_var,
|
|
112
|
-
|
|
122
|
+
self.ti_var,
|
|
123
|
+
FC.STATE_TURBINE,
|
|
124
|
+
lookup="f",
|
|
125
|
+
fdata=fdata,
|
|
126
|
+
upcast=False,
|
|
127
|
+
selection=st_sel,
|
|
128
|
+
)
|
|
113
129
|
|
|
114
130
|
k = fdata.get(
|
|
115
131
|
self.k_var, np.zeros((fdata.n_states, fdata.n_turbines), dtype=FC.DTYPE)
|
|
@@ -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,14 +188,16 @@ 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,
|
|
191
|
-
upcast=
|
|
192
|
-
|
|
195
|
+
upcast=False,
|
|
196
|
+
selection=st_sel,
|
|
197
|
+
)
|
|
193
198
|
for v in self.input_vars
|
|
194
199
|
}
|
|
200
|
+
|
|
195
201
|
dims = {
|
|
196
202
|
v: ("_z") if len(data[v].shape) == 1 else ("_z", "_u")
|
|
197
203
|
for v in self.input_vars
|
|
@@ -205,7 +211,27 @@ class LookupTable(TurbineModel):
|
|
|
205
211
|
}
|
|
206
212
|
del data, dims
|
|
207
213
|
|
|
208
|
-
|
|
214
|
+
iargs = dict(bounds_error=True)
|
|
215
|
+
iargs.update(self._iargs)
|
|
216
|
+
try:
|
|
217
|
+
odata = self._data.interp(**indata, kwargs=iargs, **self._xargs)
|
|
218
|
+
except ValueError as e:
|
|
219
|
+
print("\nBOUNDS ERROR", self.name)
|
|
220
|
+
print("Variables:", list(indata.keys()))
|
|
221
|
+
print(
|
|
222
|
+
"DATA min/max:",
|
|
223
|
+
[float(np.min(self._data[v].to_numpy())) for v in indata.keys()],
|
|
224
|
+
[float(np.max(self._data[v].to_numpy())) for v in indata.keys()],
|
|
225
|
+
)
|
|
226
|
+
print(
|
|
227
|
+
"EVAL min/max:",
|
|
228
|
+
[float(np.min(d.to_numpy())) for d in indata.values()],
|
|
229
|
+
[float(np.max(d.to_numpy())) for d in indata.values()],
|
|
230
|
+
)
|
|
231
|
+
print(
|
|
232
|
+
"\nMaybe you want to try the options 'bounds_error=False, fill_value=None'? This will extrapolate the data.\n"
|
|
233
|
+
)
|
|
234
|
+
raise e
|
|
209
235
|
|
|
210
236
|
out = {}
|
|
211
237
|
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
|
|
@@ -44,15 +44,23 @@ class SetFarmVars(TurbineModel):
|
|
|
44
44
|
The data, shape: (n_states, n_turbines)
|
|
45
45
|
|
|
46
46
|
"""
|
|
47
|
+
if self.initialized:
|
|
48
|
+
raise ValueError(
|
|
49
|
+
f"Model '{self.name}': Cannot add_var after initialization"
|
|
50
|
+
)
|
|
51
|
+
if self.running:
|
|
52
|
+
raise ValueError(f"Model '{self.name}': Cannot add_var while running")
|
|
47
53
|
self.vars.append(var)
|
|
48
|
-
self.
|
|
54
|
+
self.__vdata.append(np.asarray(data, dtype=FC.DTYPE))
|
|
49
55
|
|
|
50
56
|
def reset(self):
|
|
51
57
|
"""
|
|
52
58
|
Remove all variables.
|
|
53
59
|
"""
|
|
60
|
+
if self.running:
|
|
61
|
+
raise ValueError(f"Model '{self.name}': Cannot reset while running")
|
|
54
62
|
self.vars = []
|
|
55
|
-
self.
|
|
63
|
+
self.__vdata = []
|
|
56
64
|
|
|
57
65
|
def output_farm_vars(self, algo):
|
|
58
66
|
"""
|
|
@@ -98,7 +106,7 @@ class SetFarmVars(TurbineModel):
|
|
|
98
106
|
|
|
99
107
|
for i, v in enumerate(self.vars):
|
|
100
108
|
data = np.full((algo.n_states, algo.n_turbines), np.nan, dtype=FC.DTYPE)
|
|
101
|
-
vdata = self.
|
|
109
|
+
vdata = self.__vdata[i]
|
|
102
110
|
|
|
103
111
|
# handle special case of call during vectorized optimization:
|
|
104
112
|
if (
|
|
@@ -110,14 +118,105 @@ class SetFarmVars(TurbineModel):
|
|
|
110
118
|
n_ost = algo.states.states.size()
|
|
111
119
|
n_trb = algo.n_turbines
|
|
112
120
|
vdata = np.zeros((n_pop, n_ost, n_trb), dtype=FC.DTYPE)
|
|
113
|
-
vdata[:] = self.
|
|
121
|
+
vdata[:] = self.__vdata[i][None, :]
|
|
114
122
|
vdata = vdata.reshape(n_pop * n_ost, n_trb)
|
|
115
123
|
|
|
116
124
|
data[:] = vdata
|
|
117
125
|
idata["data_vars"][self.var(v)] = ((FC.STATE, FC.TURBINE), data)
|
|
118
126
|
|
|
127
|
+
# special case of turbine positions:
|
|
128
|
+
if v in [FV.X, FV.Y]:
|
|
129
|
+
i = [FV.X, FV.Y].index(v)
|
|
130
|
+
for ti in range(algo.n_turbines):
|
|
131
|
+
t = algo.farm.turbines[ti]
|
|
132
|
+
if len(t.xy.shape) == 1:
|
|
133
|
+
xy = np.zeros((algo.n_states, 2), dtype=FC.DTYPE)
|
|
134
|
+
xy[:] = t.xy[None, :]
|
|
135
|
+
t.xy = xy
|
|
136
|
+
t.xy[:, i] = np.where(
|
|
137
|
+
np.isnan(data[:, ti]), t.xy[:, i], data[:, ti]
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# special case of rotor diameter and hub height:
|
|
141
|
+
if v in [FV.D, FV.H]:
|
|
142
|
+
for ti in range(algo.n_turbines):
|
|
143
|
+
t = algo.farm.turbines[ti]
|
|
144
|
+
x = np.zeros(algo.n_states, dtype=FC.DTYPE)
|
|
145
|
+
if v == FV.D:
|
|
146
|
+
x[:] = t.D
|
|
147
|
+
t.D = x
|
|
148
|
+
else:
|
|
149
|
+
x[:] = t.H
|
|
150
|
+
t.H = x
|
|
151
|
+
x[:] = np.where(np.isnan(data[:, ti]), x, data[:, ti])
|
|
152
|
+
|
|
119
153
|
return idata
|
|
120
154
|
|
|
155
|
+
def set_running(
|
|
156
|
+
self,
|
|
157
|
+
algo,
|
|
158
|
+
data_stash,
|
|
159
|
+
sel=None,
|
|
160
|
+
isel=None,
|
|
161
|
+
verbosity=0,
|
|
162
|
+
):
|
|
163
|
+
"""
|
|
164
|
+
Sets this model status to running, and moves
|
|
165
|
+
all large data to stash.
|
|
166
|
+
|
|
167
|
+
The stashed data will be returned by the
|
|
168
|
+
unset_running() function after running calculations.
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
algo: foxes.core.Algorithm
|
|
173
|
+
The calculation algorithm
|
|
174
|
+
data_stash: dict
|
|
175
|
+
Large data stash, this function adds data here.
|
|
176
|
+
Key: model name. Value: dict, large model data
|
|
177
|
+
sel: dict, optional
|
|
178
|
+
The subset selection dictionary
|
|
179
|
+
isel: dict, optional
|
|
180
|
+
The index subset selection dictionary
|
|
181
|
+
verbosity: int
|
|
182
|
+
The verbosity level, 0 = silent
|
|
183
|
+
|
|
184
|
+
"""
|
|
185
|
+
super().set_running(algo, data_stash, sel, isel, verbosity)
|
|
186
|
+
|
|
187
|
+
data_stash[self.name]["vdata"] = self.__vdata
|
|
188
|
+
del self.__vdata
|
|
189
|
+
|
|
190
|
+
def unset_running(
|
|
191
|
+
self,
|
|
192
|
+
algo,
|
|
193
|
+
data_stash,
|
|
194
|
+
sel=None,
|
|
195
|
+
isel=None,
|
|
196
|
+
verbosity=0,
|
|
197
|
+
):
|
|
198
|
+
"""
|
|
199
|
+
Sets this model status to not running, recovering large data
|
|
200
|
+
from stash
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
algo: foxes.core.Algorithm
|
|
205
|
+
The calculation algorithm
|
|
206
|
+
data_stash: dict
|
|
207
|
+
Large data stash, this function adds data here.
|
|
208
|
+
Key: model name. Value: dict, large model data
|
|
209
|
+
sel: dict, optional
|
|
210
|
+
The subset selection dictionary
|
|
211
|
+
isel: dict, optional
|
|
212
|
+
The index subset selection dictionary
|
|
213
|
+
verbosity: int
|
|
214
|
+
The verbosity level, 0 = silent
|
|
215
|
+
|
|
216
|
+
"""
|
|
217
|
+
super().unset_running(algo, data_stash, sel, isel, verbosity)
|
|
218
|
+
self.__vdata = data_stash[self.name].pop("vdata")
|
|
219
|
+
|
|
121
220
|
def calculate(self, algo, mdata, fdata, st_sel):
|
|
122
221
|
"""
|
|
123
222
|
The main model calculation.
|
|
@@ -159,36 +258,6 @@ class SetFarmVars(TurbineModel):
|
|
|
159
258
|
hsel = ~np.isnan(data)
|
|
160
259
|
tsel = bsel & hsel
|
|
161
260
|
|
|
162
|
-
# special case of turbine positions:
|
|
163
|
-
if v in [FV.X, FV.Y]:
|
|
164
|
-
i = [FV.X, FV.Y].index(v)
|
|
165
|
-
for ti in np.where(tsel)[1]:
|
|
166
|
-
t = algo.farm.turbines[ti]
|
|
167
|
-
if len(t.xy.shape) == 1:
|
|
168
|
-
xy = np.zeros((algo.n_states, 2), dtype=FC.DTYPE)
|
|
169
|
-
xy[:] = t.xy[None, :]
|
|
170
|
-
t.xy = xy
|
|
171
|
-
i0 = fdata.states_i0()
|
|
172
|
-
hsel = tsel[:, ti]
|
|
173
|
-
ssel = i0 + np.where(hsel)[0]
|
|
174
|
-
t.xy[ssel, i] = data[hsel, ti]
|
|
175
|
-
|
|
176
|
-
# special case of rotor diameter and hub height:
|
|
177
|
-
if v in [FV.D, FV.H]:
|
|
178
|
-
for ti in np.where(tsel)[1]:
|
|
179
|
-
t = algo.farm.turbines[ti]
|
|
180
|
-
x = np.zeros(algo.n_states, dtype=FC.DTYPE)
|
|
181
|
-
if v == FV.D:
|
|
182
|
-
x[:] = t.D
|
|
183
|
-
t.D = x
|
|
184
|
-
else:
|
|
185
|
-
x[:] = t.H
|
|
186
|
-
t.H = x
|
|
187
|
-
i0 = fdata.states_i0()
|
|
188
|
-
hsel = tsel[:, ti]
|
|
189
|
-
ssel = i0 + np.where(hsel)[0]
|
|
190
|
-
x[ssel] = data[hsel, ti]
|
|
191
|
-
|
|
192
261
|
fdata[v][tsel] = data[tsel]
|
|
193
262
|
|
|
194
263
|
return {v: fdata[v] for v in self.vars}
|
|
@@ -25,7 +25,7 @@ class PCtFile(TurbineType):
|
|
|
25
25
|
col_ct: str
|
|
26
26
|
The ct column
|
|
27
27
|
rho: float
|
|
28
|
-
The air
|
|
28
|
+
The air density for which the data is valid
|
|
29
29
|
or None for no correction
|
|
30
30
|
WSCT: str
|
|
31
31
|
The wind speed variable for ct lookup
|
|
@@ -66,7 +66,7 @@ class PCtFile(TurbineType):
|
|
|
66
66
|
col_ct: str
|
|
67
67
|
The ct column
|
|
68
68
|
rho: float, optional
|
|
69
|
-
The air
|
|
69
|
+
The air density for which the data is valid
|
|
70
70
|
or None for no correction
|
|
71
71
|
p_ct: float
|
|
72
72
|
The exponent for yaw dependency of ct
|
|
@@ -106,6 +106,30 @@ class PCtFile(TurbineType):
|
|
|
106
106
|
a += f", var_ws_ct={self.WSCT}, var_ws_P={self.WSP}"
|
|
107
107
|
return f"{type(self).__name__}({a})"
|
|
108
108
|
|
|
109
|
+
def needs_rews2(self):
|
|
110
|
+
"""
|
|
111
|
+
Returns flag for requiring REWS2 variable
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
flag: bool
|
|
116
|
+
True if REWS2 is required
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
return self.WSCT == FV.REWS2 or self.WSP == FV.REWS2
|
|
120
|
+
|
|
121
|
+
def needs_rews3(self):
|
|
122
|
+
"""
|
|
123
|
+
Returns flag for requiring REWS3 variable
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
flag: bool
|
|
128
|
+
True if REWS3 is required
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
return self.WSCT == FV.REWS3 or self.WSP == FV.REWS3
|
|
132
|
+
|
|
109
133
|
def output_farm_vars(self, algo):
|
|
110
134
|
"""
|
|
111
135
|
The variables which are being modified by the model.
|
|
@@ -252,7 +276,7 @@ class PCtFile(TurbineType):
|
|
|
252
276
|
super().modify_cutin(modify_ct, modify_P)
|
|
253
277
|
|
|
254
278
|
def calculate(self, algo, mdata, fdata, st_sel):
|
|
255
|
-
"""
|
|
279
|
+
"""
|
|
256
280
|
The main model calculation.
|
|
257
281
|
|
|
258
282
|
This function is executed on a single chunk of data,
|