foxes 0.6.1__py3-none-any.whl → 0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of foxes might be problematic. Click here for more details.
- foxes/VERSION +1 -1
- foxes/algorithms/downwind/downwind.py +131 -65
- foxes/algorithms/downwind/models/__init__.py +2 -1
- foxes/algorithms/downwind/models/farm_wakes_calc.py +87 -55
- foxes/algorithms/downwind/models/init_farm_data.py +134 -0
- foxes/algorithms/downwind/models/point_wakes_calc.py +54 -65
- foxes/algorithms/downwind/models/{calc_order.py → reorder_farm_output.py} +28 -26
- foxes/algorithms/iterative/iterative.py +100 -51
- foxes/algorithms/iterative/models/convergence.py +3 -3
- foxes/algorithms/iterative/models/farm_wakes_calc.py +55 -48
- foxes/algorithms/sequential/models/seq_state.py +7 -6
- foxes/algorithms/sequential/sequential.py +81 -44
- foxes/constants.py +33 -18
- foxes/core/__init__.py +2 -2
- foxes/core/algorithm.py +31 -12
- foxes/core/data.py +335 -41
- foxes/core/data_calc_model.py +27 -23
- foxes/core/farm_controller.py +27 -28
- foxes/core/farm_data_model.py +26 -4
- foxes/core/model.py +186 -129
- foxes/core/partial_wakes_model.py +84 -81
- foxes/core/point_data_model.py +51 -18
- foxes/core/rotor_model.py +59 -77
- foxes/core/states.py +6 -6
- foxes/core/turbine_model.py +4 -4
- foxes/core/turbine_type.py +24 -0
- foxes/core/vertical_profile.py +3 -3
- foxes/core/wake_frame.py +91 -50
- foxes/core/wake_model.py +74 -43
- foxes/core/wake_superposition.py +29 -26
- foxes/input/farm_layout/__init__.py +1 -0
- foxes/input/farm_layout/from_random.py +49 -0
- foxes/input/states/__init__.py +1 -1
- foxes/input/states/create/__init__.py +1 -0
- foxes/input/states/create/random_abl_states.py +6 -2
- foxes/input/states/create/random_timeseries.py +56 -0
- foxes/input/states/field_data_nc.py +12 -8
- foxes/input/states/multi_height.py +24 -14
- foxes/input/states/scan_ws.py +13 -17
- foxes/input/states/single.py +28 -20
- foxes/input/states/states_table.py +22 -18
- foxes/models/axial_induction_models/betz.py +1 -1
- foxes/models/farm_models/turbine2farm.py +2 -2
- foxes/models/model_book.py +40 -14
- foxes/models/partial_wakes/__init__.py +2 -2
- foxes/models/partial_wakes/axiwake.py +73 -200
- foxes/models/partial_wakes/centre.py +40 -0
- foxes/models/partial_wakes/grid.py +7 -63
- foxes/models/partial_wakes/rotor_points.py +53 -147
- foxes/models/partial_wakes/segregated.py +158 -0
- foxes/models/partial_wakes/top_hat.py +88 -196
- foxes/models/point_models/set_uniform_data.py +4 -4
- foxes/models/point_models/tke2ti.py +4 -4
- foxes/models/point_models/wake_deltas.py +4 -4
- foxes/models/rotor_models/centre.py +15 -19
- foxes/models/rotor_models/grid.py +2 -1
- foxes/models/rotor_models/levels.py +2 -1
- foxes/models/turbine_models/__init__.py +0 -1
- foxes/models/turbine_models/calculator.py +11 -7
- foxes/models/turbine_models/kTI_model.py +13 -11
- foxes/models/turbine_models/lookup_table.py +22 -9
- foxes/models/turbine_models/power_mask.py +81 -51
- foxes/models/turbine_models/rotor_centre_calc.py +17 -20
- foxes/models/turbine_models/sector_management.py +5 -6
- foxes/models/turbine_models/set_farm_vars.py +49 -20
- foxes/models/turbine_models/table_factors.py +5 -5
- foxes/models/turbine_models/thrust2ct.py +9 -5
- foxes/models/turbine_models/yaw2yawm.py +7 -13
- foxes/models/turbine_models/yawm2yaw.py +7 -11
- foxes/models/turbine_types/PCt_file.py +84 -3
- foxes/models/turbine_types/PCt_from_two.py +7 -3
- foxes/models/turbine_types/null_type.py +2 -2
- foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -2
- foxes/models/turbine_types/wsti2PCt_from_two.py +6 -2
- foxes/models/wake_frames/farm_order.py +26 -22
- foxes/models/wake_frames/rotor_wd.py +32 -31
- foxes/models/wake_frames/seq_dynamic_wakes.py +112 -64
- foxes/models/wake_frames/streamlines.py +51 -47
- foxes/models/wake_frames/timelines.py +59 -47
- foxes/models/wake_frames/yawed_wakes.py +63 -40
- foxes/models/wake_models/axisymmetric.py +31 -35
- foxes/models/wake_models/dist_sliced.py +50 -56
- foxes/models/wake_models/gaussian.py +33 -35
- foxes/models/wake_models/induction/rankine_half_body.py +79 -87
- foxes/models/wake_models/induction/rathmann.py +56 -63
- foxes/models/wake_models/induction/self_similar.py +59 -62
- foxes/models/wake_models/ti/crespo_hernandez.py +83 -74
- foxes/models/wake_models/ti/iec_ti.py +65 -75
- foxes/models/wake_models/top_hat.py +60 -69
- foxes/models/wake_models/wake_mirror.py +49 -54
- foxes/models/wake_models/wind/bastankhah14.py +44 -66
- foxes/models/wake_models/wind/bastankhah16.py +84 -111
- foxes/models/wake_models/wind/jensen.py +67 -89
- foxes/models/wake_models/wind/turbopark.py +93 -133
- foxes/models/wake_superpositions/ti_linear.py +33 -27
- foxes/models/wake_superpositions/ti_max.py +33 -27
- foxes/models/wake_superpositions/ti_pow.py +35 -27
- foxes/models/wake_superpositions/ti_quadratic.py +33 -27
- foxes/models/wake_superpositions/ws_linear.py +39 -32
- foxes/models/wake_superpositions/ws_max.py +40 -33
- foxes/models/wake_superpositions/ws_pow.py +39 -32
- foxes/models/wake_superpositions/ws_product.py +35 -28
- foxes/models/wake_superpositions/ws_quadratic.py +39 -32
- foxes/opt/constraints/min_dist.py +1 -1
- foxes/opt/objectives/farm_vars.py +1 -1
- foxes/opt/problems/layout/farm_layout.py +38 -97
- foxes/output/__init__.py +1 -0
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/flow_plots_2d/flow_plots.py +2 -0
- foxes/output/flow_plots_2d/get_fig.py +2 -0
- foxes/output/grids.py +1 -1
- foxes/output/rose_plot.py +3 -3
- foxes/output/rotor_point_plots.py +117 -0
- foxes/output/turbine_type_curves.py +2 -2
- foxes/utils/__init__.py +2 -1
- foxes/utils/load.py +29 -0
- foxes/utils/random_xy.py +56 -0
- foxes/utils/runners/runners.py +13 -1
- foxes/utils/windrose_plot.py +1 -1
- foxes/variables.py +10 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/METADATA +13 -7
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/RECORD +126 -122
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/WHEEL +1 -1
- foxes/models/partial_wakes/distsliced.py +0 -322
- foxes/models/partial_wakes/mapped.py +0 -252
- foxes/models/turbine_models/set_XYHD.py +0 -130
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/LICENSE +0 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/top_level.txt +0 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/zip-safe +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
from copy import deepcopy
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
from foxes.core import FarmDataModel
|
|
4
|
+
from foxes.core import FarmDataModel, TData
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class FarmWakesCalculation(FarmDataModel):
|
|
@@ -60,22 +60,7 @@ class FarmWakesCalculation(FarmDataModel):
|
|
|
60
60
|
All sub models
|
|
61
61
|
|
|
62
62
|
"""
|
|
63
|
-
return [
|
|
64
|
-
|
|
65
|
-
def initialize(self, algo, verbosity=0):
|
|
66
|
-
"""
|
|
67
|
-
Initializes the model.
|
|
68
|
-
|
|
69
|
-
Parameters
|
|
70
|
-
----------
|
|
71
|
-
algo: foxes.core.Algorithm
|
|
72
|
-
The calculation algorithm
|
|
73
|
-
verbosity: int
|
|
74
|
-
The verbosity level, 0 = silent
|
|
75
|
-
|
|
76
|
-
"""
|
|
77
|
-
self.pwakes = algo.partial_wakes_model
|
|
78
|
-
super().initialize(algo, verbosity)
|
|
63
|
+
return [] if self.urelax is None else [self.urelax]
|
|
79
64
|
|
|
80
65
|
def calculate(self, algo, mdata, fdata):
|
|
81
66
|
""" "
|
|
@@ -100,35 +85,57 @@ class FarmWakesCalculation(FarmDataModel):
|
|
|
100
85
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
101
86
|
|
|
102
87
|
"""
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
88
|
+
# collect ambient rotor results and weights:
|
|
89
|
+
rotor = algo.rotor_model
|
|
90
|
+
weights = rotor.from_data_or_store(rotor.RWEIGHTS, algo, mdata)
|
|
91
|
+
amb_res = rotor.from_data_or_store(rotor.AMBRES, algo, mdata)
|
|
92
|
+
|
|
93
|
+
# generate all wake evaluation points
|
|
94
|
+
# (n_states, n_order, n_rpoints)
|
|
95
|
+
pwake2tdata = {}
|
|
96
|
+
for wname, wmodel in algo.wake_models.items():
|
|
97
|
+
pwake = algo.partial_wakes[wname]
|
|
98
|
+
if pwake.name not in pwake2tdata:
|
|
99
|
+
tpoints, tweights = pwake.get_wake_points(algo, mdata, fdata)
|
|
100
|
+
pwake2tdata[pwake.name] = TData.from_tpoints(tpoints, tweights)
|
|
101
|
+
|
|
102
|
+
def _get_wdata(tdatap, wdeltas, s):
|
|
103
|
+
"""Helper function for wake data extraction"""
|
|
104
|
+
tdata = tdatap.get_slice(s, keep=True)
|
|
105
|
+
wdelta = {v: d[s] for v, d in wdeltas.items()}
|
|
106
|
+
return tdata, wdelta
|
|
107
|
+
|
|
108
|
+
wake_res = deepcopy(amb_res)
|
|
109
|
+
n_turbines = mdata.n_turbines
|
|
110
|
+
for wname, wmodel in algo.wake_models.items():
|
|
111
|
+
pwake = algo.partial_wakes[wname]
|
|
112
|
+
tdatap = pwake2tdata[pwake.name]
|
|
113
|
+
wdeltas = pwake.new_wake_deltas(algo, mdata, fdata, tdatap, wmodel)
|
|
114
|
+
|
|
115
|
+
for oi in range(n_turbines):
|
|
116
|
+
|
|
117
|
+
if oi > 0:
|
|
118
|
+
tdata, wdelta = _get_wdata(tdatap, wdeltas, np.s_[:, :oi])
|
|
119
|
+
pwake.contribute(algo, mdata, fdata, tdata, oi, wdelta, wmodel)
|
|
120
|
+
|
|
121
|
+
if oi < n_turbines - 1:
|
|
122
|
+
tdata, wdelta = _get_wdata(tdatap, wdeltas, np.s_[:, oi + 1 :])
|
|
123
|
+
pwake.contribute(algo, mdata, fdata, tdata, oi, wdelta, wmodel)
|
|
124
|
+
|
|
125
|
+
for oi in range(n_turbines):
|
|
126
|
+
wres = pwake.finalize_wakes(
|
|
127
|
+
algo, mdata, fdata, tdatap, amb_res, weights, wdeltas, wmodel, oi
|
|
128
|
+
)
|
|
129
|
+
for v, d in wres.items():
|
|
130
|
+
if v in wake_res:
|
|
131
|
+
wake_res[v][:, oi] += d
|
|
132
|
+
|
|
133
|
+
del pwake, tdatap, wdeltas
|
|
134
|
+
|
|
135
|
+
rotor.eval_rpoint_results(algo, mdata, fdata, wake_res, weights)
|
|
136
|
+
res = algo.farm_controller.calculate(algo, mdata, fdata, pre_rotor=False)
|
|
137
|
+
if self.urelax is not None:
|
|
138
|
+
res = self.urelax.calculate(algo, mdata, fdata, res)
|
|
139
|
+
fdata.update(res)
|
|
133
140
|
|
|
134
141
|
return {v: fdata[v] for v in self.output_farm_vars(algo)}
|
|
@@ -134,8 +134,8 @@ class SeqState(States):
|
|
|
134
134
|
"""
|
|
135
135
|
return self.states.output_point_vars(algo)
|
|
136
136
|
|
|
137
|
-
def calculate(self, algo, mdata, fdata,
|
|
138
|
-
"""
|
|
137
|
+
def calculate(self, algo, mdata, fdata, tdata):
|
|
138
|
+
""" "
|
|
139
139
|
The main model calculation.
|
|
140
140
|
|
|
141
141
|
This function is executed on a single chunk of data,
|
|
@@ -149,14 +149,15 @@ class SeqState(States):
|
|
|
149
149
|
The model data
|
|
150
150
|
fdata: foxes.core.Data
|
|
151
151
|
The farm data
|
|
152
|
-
|
|
153
|
-
The point data
|
|
152
|
+
tdata: foxes.core.Data
|
|
153
|
+
The target point data
|
|
154
154
|
|
|
155
155
|
Returns
|
|
156
156
|
-------
|
|
157
157
|
results: dict
|
|
158
158
|
The resulting data, keys: output variable str.
|
|
159
|
-
Values: numpy.ndarray with shape
|
|
159
|
+
Values: numpy.ndarray with shape
|
|
160
|
+
(n_states, n_targets, n_tpoints)
|
|
160
161
|
|
|
161
162
|
"""
|
|
162
|
-
return self.states.calculate(algo, mdata, fdata,
|
|
163
|
+
return self.states.calculate(algo, mdata, fdata, tdata)
|
|
@@ -4,7 +4,7 @@ from xarray import Dataset
|
|
|
4
4
|
from foxes.algorithms.downwind.downwind import Downwind
|
|
5
5
|
import foxes.constants as FC
|
|
6
6
|
import foxes.variables as FV
|
|
7
|
-
from foxes.core.data import
|
|
7
|
+
from foxes.core.data import MData, FData, TData
|
|
8
8
|
|
|
9
9
|
from . import models as mdls
|
|
10
10
|
|
|
@@ -30,7 +30,8 @@ class Sequential(Downwind):
|
|
|
30
30
|
The points of interest, shape: (n_states, n_points, 3)
|
|
31
31
|
plugins: list of foxes.algorithm.sequential.SequentialIterPlugin
|
|
32
32
|
The plugins, updated with every iteration
|
|
33
|
-
|
|
33
|
+
outputs: list of str
|
|
34
|
+
The output variables
|
|
34
35
|
:group: algorithms.sequential
|
|
35
36
|
|
|
36
37
|
"""
|
|
@@ -58,15 +59,15 @@ class Sequential(Downwind):
|
|
|
58
59
|
|
|
59
60
|
def __init__(
|
|
60
61
|
self,
|
|
61
|
-
mbook,
|
|
62
62
|
farm,
|
|
63
63
|
states,
|
|
64
64
|
*args,
|
|
65
65
|
points=None,
|
|
66
66
|
ambient=False,
|
|
67
67
|
calc_pars={},
|
|
68
|
-
chunks={FC.STATE: None, FC.POINT:
|
|
68
|
+
chunks={FC.STATE: None, FC.POINT: 4000},
|
|
69
69
|
plugins=[],
|
|
70
|
+
outputs=None,
|
|
70
71
|
**kwargs,
|
|
71
72
|
):
|
|
72
73
|
"""
|
|
@@ -74,8 +75,6 @@ class Sequential(Downwind):
|
|
|
74
75
|
|
|
75
76
|
Parameters
|
|
76
77
|
----------
|
|
77
|
-
mbook: foxes.ModelBook
|
|
78
|
-
The model book
|
|
79
78
|
farm: foxes.WindFarm
|
|
80
79
|
The wind farm
|
|
81
80
|
states: foxes.core.States
|
|
@@ -93,18 +92,19 @@ class Sequential(Downwind):
|
|
|
93
92
|
The xarray.Dataset chunk parameters
|
|
94
93
|
plugins: list of foxes.algorithm.sequential.SequentialIterPlugin
|
|
95
94
|
The plugins, updated with every iteration
|
|
95
|
+
outputs: list of str, optional
|
|
96
|
+
The output variables
|
|
96
97
|
kwargs: dict, optional
|
|
97
98
|
Additional arguments for Downwind
|
|
98
99
|
|
|
99
100
|
"""
|
|
100
|
-
super().__init__(
|
|
101
|
-
mbook, farm, mdls.SeqState(states), *args, chunks=chunks, **kwargs
|
|
102
|
-
)
|
|
101
|
+
super().__init__(farm, mdls.SeqState(states), *args, chunks=chunks, **kwargs)
|
|
103
102
|
self.ambient = ambient
|
|
104
103
|
self.calc_pars = calc_pars
|
|
105
104
|
self.states0 = self.states.states
|
|
106
105
|
self.points = points
|
|
107
106
|
self.plugins = plugins
|
|
107
|
+
self.outputs = outputs if outputs is not None else self.DEFAULT_FARM_OUTPUTS
|
|
108
108
|
|
|
109
109
|
self._i = None
|
|
110
110
|
|
|
@@ -135,7 +135,7 @@ class Sequential(Downwind):
|
|
|
135
135
|
self._counter = 0
|
|
136
136
|
|
|
137
137
|
self._mlist, self._calc_pars = self._collect_farm_models(
|
|
138
|
-
self.calc_pars, self.ambient
|
|
138
|
+
self.outputs, self.calc_pars, self.ambient
|
|
139
139
|
)
|
|
140
140
|
if not self._mlist.initialized:
|
|
141
141
|
self._mlist.initialize(self, self.verbosity)
|
|
@@ -155,14 +155,14 @@ class Sequential(Downwind):
|
|
|
155
155
|
print(f"Output farm variables:", ", ".join(self.farm_vars))
|
|
156
156
|
print()
|
|
157
157
|
|
|
158
|
-
self._mdata =
|
|
158
|
+
self._mdata = MData(
|
|
159
159
|
data={v: d[1] for v, d in self._mdata["data_vars"].items()},
|
|
160
160
|
dims={v: d[0] for v, d in self._mdata["data_vars"].items()},
|
|
161
161
|
loop_dims=[FC.STATE],
|
|
162
162
|
name="mdata",
|
|
163
163
|
)
|
|
164
164
|
|
|
165
|
-
self._fdata =
|
|
165
|
+
self._fdata = FData(
|
|
166
166
|
data={
|
|
167
167
|
v: np.zeros((self.n_states, self.n_turbines), dtype=FC.DTYPE)
|
|
168
168
|
for v in self.farm_vars
|
|
@@ -182,14 +182,13 @@ class Sequential(Downwind):
|
|
|
182
182
|
self.print(f"\nOutput point variables:", ", ".join(self._pvars), "\n")
|
|
183
183
|
|
|
184
184
|
n_points = self.points.shape[1]
|
|
185
|
-
self.
|
|
185
|
+
self._tdata = TData.from_points(
|
|
186
186
|
self.points,
|
|
187
187
|
data={
|
|
188
|
-
v: np.zeros((self.n_states, n_points), dtype=FC.DTYPE)
|
|
188
|
+
v: np.zeros((self.n_states, n_points, 1), dtype=FC.DTYPE)
|
|
189
189
|
for v in self._pvars
|
|
190
190
|
},
|
|
191
|
-
dims={v: (FC.STATE, FC.
|
|
192
|
-
name="pdata",
|
|
191
|
+
dims={v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in self._pvars},
|
|
193
192
|
)
|
|
194
193
|
|
|
195
194
|
for p in self.plugins:
|
|
@@ -207,7 +206,7 @@ class Sequential(Downwind):
|
|
|
207
206
|
self.states._indx = self._inds[self._i]
|
|
208
207
|
self.states._weight = self._weights[self._i]
|
|
209
208
|
|
|
210
|
-
mdata =
|
|
209
|
+
mdata = MData(
|
|
211
210
|
data={
|
|
212
211
|
v: d[self._i, None] if self._mdata.dims[v][0] == FC.STATE else d
|
|
213
212
|
for v, d in self._mdata.items()
|
|
@@ -217,7 +216,7 @@ class Sequential(Downwind):
|
|
|
217
216
|
name="mdata",
|
|
218
217
|
)
|
|
219
218
|
|
|
220
|
-
fdata =
|
|
219
|
+
fdata = FData(
|
|
221
220
|
data={
|
|
222
221
|
v: np.zeros((1, self.n_turbines), dtype=FC.DTYPE)
|
|
223
222
|
for v in self.farm_vars
|
|
@@ -234,7 +233,7 @@ class Sequential(Downwind):
|
|
|
234
233
|
self._fdata[v][self._i] = d[0]
|
|
235
234
|
|
|
236
235
|
fres = Dataset(
|
|
237
|
-
coords={FC.STATE: [self.index]
|
|
236
|
+
coords={FC.STATE: [self.index]},
|
|
238
237
|
data_vars={v: ((FC.STATE, FC.TURBINE), d) for v, d in fres.items()},
|
|
239
238
|
)
|
|
240
239
|
fres[FC.TNAME] = ((FC.TURBINE,), self.farm.turbine_names)
|
|
@@ -250,25 +249,28 @@ class Sequential(Downwind):
|
|
|
250
249
|
|
|
251
250
|
else:
|
|
252
251
|
n_points = self.points.shape[1]
|
|
253
|
-
|
|
252
|
+
tdata = TData.from_points(
|
|
254
253
|
self.points[self.counter, None],
|
|
255
254
|
data={
|
|
256
|
-
v: np.zeros((1, n_points), dtype=FC.DTYPE)
|
|
255
|
+
v: np.zeros((1, n_points, 1), dtype=FC.DTYPE)
|
|
256
|
+
for v in self._pvars
|
|
257
257
|
},
|
|
258
|
-
dims={v: (FC.STATE, FC.
|
|
259
|
-
name="pdata",
|
|
258
|
+
dims={v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in self._pvars},
|
|
260
259
|
)
|
|
261
260
|
|
|
262
261
|
pres = self._plist.calculate(
|
|
263
|
-
self, mdata, fdata,
|
|
262
|
+
self, mdata, fdata, tdata, parameters=self._calc_pars_p
|
|
264
263
|
)
|
|
265
264
|
|
|
266
265
|
for v, d in pres.items():
|
|
267
|
-
self.
|
|
266
|
+
self._tdata[v][self._i] = d[0]
|
|
268
267
|
|
|
269
268
|
pres = Dataset(
|
|
270
|
-
coords={FC.STATE: [self.index]
|
|
271
|
-
data_vars={
|
|
269
|
+
coords={FC.STATE: [self.index]},
|
|
270
|
+
data_vars={
|
|
271
|
+
v: ((FC.STATE, FC.TARGET, FC.TPOINT), d)
|
|
272
|
+
for v, d in pres.items()
|
|
273
|
+
},
|
|
272
274
|
)
|
|
273
275
|
|
|
274
276
|
for p in self.plugins:
|
|
@@ -330,6 +332,26 @@ class Sequential(Downwind):
|
|
|
330
332
|
"""
|
|
331
333
|
return self.states._indx if self.iterating else None
|
|
332
334
|
|
|
335
|
+
def states_i0(self, counter, algo=None):
|
|
336
|
+
"""
|
|
337
|
+
Returns counter or index
|
|
338
|
+
|
|
339
|
+
Parameters
|
|
340
|
+
----------
|
|
341
|
+
counter: bool
|
|
342
|
+
Flag for counter
|
|
343
|
+
algo: object, optional
|
|
344
|
+
Dummy argument, due to consistency with
|
|
345
|
+
foxes.core.Data.states_i0
|
|
346
|
+
|
|
347
|
+
Returns
|
|
348
|
+
-------
|
|
349
|
+
i0: int
|
|
350
|
+
The counter or index
|
|
351
|
+
|
|
352
|
+
"""
|
|
353
|
+
return self.counter if counter else self.index
|
|
354
|
+
|
|
333
355
|
@property
|
|
334
356
|
def weight(self):
|
|
335
357
|
"""
|
|
@@ -350,7 +372,7 @@ class Sequential(Downwind):
|
|
|
350
372
|
|
|
351
373
|
Returns
|
|
352
374
|
-------
|
|
353
|
-
d: foxes.core.
|
|
375
|
+
d: foxes.core.MData
|
|
354
376
|
The current model data
|
|
355
377
|
|
|
356
378
|
"""
|
|
@@ -363,24 +385,24 @@ class Sequential(Downwind):
|
|
|
363
385
|
|
|
364
386
|
Returns
|
|
365
387
|
-------
|
|
366
|
-
d: foxes.core.
|
|
388
|
+
d: foxes.core.FData
|
|
367
389
|
The current farm data
|
|
368
390
|
|
|
369
391
|
"""
|
|
370
392
|
return self._fdata
|
|
371
393
|
|
|
372
394
|
@property
|
|
373
|
-
def
|
|
395
|
+
def tdata(self):
|
|
374
396
|
"""
|
|
375
397
|
Get the current point data
|
|
376
398
|
|
|
377
399
|
Returns
|
|
378
400
|
-------
|
|
379
|
-
d: foxes.core.
|
|
401
|
+
d: foxes.core.TData
|
|
380
402
|
The current point data
|
|
381
403
|
|
|
382
404
|
"""
|
|
383
|
-
return self.
|
|
405
|
+
return self._tdata if self.points is not None and self.iterating else None
|
|
384
406
|
|
|
385
407
|
@property
|
|
386
408
|
def farm_results(self):
|
|
@@ -404,6 +426,19 @@ class Sequential(Downwind):
|
|
|
404
426
|
|
|
405
427
|
return results
|
|
406
428
|
|
|
429
|
+
@property
|
|
430
|
+
def prev_farm_results(self):
|
|
431
|
+
"""
|
|
432
|
+
Alias for farm_results
|
|
433
|
+
|
|
434
|
+
Returns
|
|
435
|
+
-------
|
|
436
|
+
results: xarray.Dataset
|
|
437
|
+
The overall farm results
|
|
438
|
+
|
|
439
|
+
"""
|
|
440
|
+
return self.farm_results
|
|
441
|
+
|
|
407
442
|
@property
|
|
408
443
|
def cur_farm_results(self):
|
|
409
444
|
"""
|
|
@@ -449,7 +484,7 @@ class Sequential(Downwind):
|
|
|
449
484
|
FC.POINT: np.arange(n_points),
|
|
450
485
|
FC.XYH: np.arange(3),
|
|
451
486
|
},
|
|
452
|
-
data_vars={v: (self.
|
|
487
|
+
data_vars={v: (self._tdata.dims[v], d) for v, d in self._tdata.items()},
|
|
453
488
|
)
|
|
454
489
|
|
|
455
490
|
return results
|
|
@@ -477,7 +512,7 @@ class Sequential(Downwind):
|
|
|
477
512
|
FC.XYH: np.arange(3),
|
|
478
513
|
},
|
|
479
514
|
data_vars={
|
|
480
|
-
v: (self.
|
|
515
|
+
v: (self._tdata.dims[v], d[i, None]) for v, d in self._tdata.items()
|
|
481
516
|
},
|
|
482
517
|
)
|
|
483
518
|
|
|
@@ -501,13 +536,13 @@ class Sequential(Downwind):
|
|
|
501
536
|
pvars = plist.output_point_vars(self)
|
|
502
537
|
|
|
503
538
|
mdata = self.get_models_idata()
|
|
504
|
-
mdata =
|
|
539
|
+
mdata = MData(
|
|
505
540
|
data={v: d[1] for v, d in mdata["data_vars"].items()},
|
|
506
541
|
dims={v: d[0] for v, d in mdata["data_vars"].items()},
|
|
507
542
|
loop_dims=[FC.STATE],
|
|
508
543
|
name="mdata",
|
|
509
544
|
)
|
|
510
|
-
mdata =
|
|
545
|
+
mdata = MData(
|
|
511
546
|
data={
|
|
512
547
|
v: d[self.states.counter, None] if mdata.dims[v][0] == FC.STATE else d
|
|
513
548
|
for v, d in mdata.items()
|
|
@@ -517,24 +552,26 @@ class Sequential(Downwind):
|
|
|
517
552
|
name="mdata",
|
|
518
553
|
)
|
|
519
554
|
|
|
520
|
-
fdata =
|
|
555
|
+
fdata = FData(
|
|
521
556
|
data={v: farm_results[v].to_numpy() for v in self.farm_vars},
|
|
522
557
|
dims={v: (FC.STATE, FC.TURBINE) for v in self.farm_vars},
|
|
523
558
|
loop_dims=[FC.STATE],
|
|
524
559
|
name="fdata",
|
|
525
560
|
)
|
|
526
561
|
|
|
527
|
-
|
|
562
|
+
tdata = TData.from_points(
|
|
528
563
|
points[0, None],
|
|
529
|
-
data={v: np.zeros((1, n_points), dtype=FC.DTYPE) for v in pvars},
|
|
530
|
-
dims={v: (FC.STATE, FC.
|
|
531
|
-
name="
|
|
564
|
+
data={v: np.zeros((1, n_points, 1), dtype=FC.DTYPE) for v in pvars},
|
|
565
|
+
dims={v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in pvars},
|
|
566
|
+
name="tdata",
|
|
532
567
|
)
|
|
533
568
|
|
|
534
|
-
pres = plist.calculate(self, mdata, fdata,
|
|
569
|
+
pres = plist.calculate(self, mdata, fdata, tdata, parameters=calc_pars)
|
|
535
570
|
pres = Dataset(
|
|
536
|
-
coords={FC.STATE: self.states.index()
|
|
537
|
-
data_vars={
|
|
571
|
+
coords={FC.STATE: self.states.index()},
|
|
572
|
+
data_vars={
|
|
573
|
+
v: ((FC.STATE, FC.TARGET, FC.TPOINT), d) for v, d in pres.items()
|
|
574
|
+
},
|
|
538
575
|
)
|
|
539
576
|
|
|
540
577
|
# plist.finalize(self, self.verbosity)
|
foxes/constants.py
CHANGED
|
@@ -25,33 +25,43 @@ TNAME = "tname"
|
|
|
25
25
|
:group: foxes.constants
|
|
26
26
|
"""
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
"""
|
|
28
|
+
TARGET = "target"
|
|
29
|
+
""" Target identifier
|
|
30
30
|
:group: foxes.constants
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
"""
|
|
33
|
+
TARGETS = "targets"
|
|
34
|
+
""" Targets identifier
|
|
35
35
|
:group: foxes.constants
|
|
36
36
|
"""
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
"""
|
|
38
|
+
TPOINT = "target_point"
|
|
39
|
+
""" Target point identifier
|
|
40
40
|
:group: foxes.constants
|
|
41
41
|
"""
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
"""
|
|
43
|
+
TPOINTS = "target_points"
|
|
44
|
+
""" Points per target identifier
|
|
45
45
|
:group: foxes.constants
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
"""
|
|
48
|
+
TWEIGHTS = "tpoint_weights"
|
|
49
|
+
""" Target point weights identifier
|
|
50
50
|
:group: foxes.constants
|
|
51
51
|
"""
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
"""
|
|
53
|
+
POINT = "point"
|
|
54
|
+
""" Point identifier
|
|
55
|
+
:group: foxes.constants
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
POINTS = "points"
|
|
59
|
+
""" Points identifier
|
|
60
|
+
:group: foxes.constants
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
AMB_TARGET_RESULTS = "amb_target_res"
|
|
64
|
+
""" Identified for ambient target results
|
|
55
65
|
:group: foxes.constants
|
|
56
66
|
"""
|
|
57
67
|
|
|
@@ -81,18 +91,23 @@ STATES_SEL = "states_sel"
|
|
|
81
91
|
:group: foxes.constants
|
|
82
92
|
"""
|
|
83
93
|
|
|
84
|
-
|
|
85
|
-
"""Identifier for
|
|
94
|
+
STATE_TURBINE = "state-turbine"
|
|
95
|
+
"""Identifier for state-turbine dimensions
|
|
96
|
+
:group: foxes.constants
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
STATE_TARGET = "state-target"
|
|
100
|
+
"""Identifier for state-target dimensions
|
|
86
101
|
:group: foxes.constants
|
|
87
102
|
"""
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
"""Identifier for state-
|
|
104
|
+
STATE_TARGET_TPOINT = "state-target-tpoint"
|
|
105
|
+
"""Identifier for state-target-tpoints dimensions
|
|
91
106
|
:group: foxes.constants
|
|
92
107
|
"""
|
|
93
108
|
|
|
94
|
-
|
|
95
|
-
"""Identifier for
|
|
109
|
+
STATE_SOURCE_ORDERI = "state-source-orderi"
|
|
110
|
+
"""Identifier for order index of wake causing turbines
|
|
96
111
|
:group: foxes.constants
|
|
97
112
|
"""
|
|
98
113
|
|
foxes/core/__init__.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Abstract classes and core functionality.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .data import Data
|
|
5
|
+
from .data import Data, MData, FData, TData
|
|
6
6
|
from .model import Model
|
|
7
7
|
from .data_calc_model import DataCalcModel
|
|
8
8
|
from .states import States, ExtendedStates
|
|
@@ -18,7 +18,7 @@ from .farm_controller import FarmController
|
|
|
18
18
|
from .turbine import Turbine
|
|
19
19
|
from .partial_wakes_model import PartialWakesModel
|
|
20
20
|
from .wake_frame import WakeFrame
|
|
21
|
-
from .wake_model import WakeModel
|
|
21
|
+
from .wake_model import WakeModel, TurbineInductionModel
|
|
22
22
|
from .wake_superposition import WakeSuperposition
|
|
23
23
|
from .vertical_profile import VerticalProfile
|
|
24
24
|
from .axial_induction_model import AxialInductionModel
|
foxes/core/algorithm.py
CHANGED
|
@@ -63,6 +63,9 @@ class Algorithm(Model):
|
|
|
63
63
|
self.n_turbines = farm.n_turbines
|
|
64
64
|
self.dbook = StaticData() if dbook is None else dbook
|
|
65
65
|
|
|
66
|
+
if chunks is not None and FC.TARGET not in chunks:
|
|
67
|
+
self.chunks[FC.TARGET] = chunks.get(FC.POINT, None)
|
|
68
|
+
|
|
66
69
|
self._idata_mem = Dict()
|
|
67
70
|
|
|
68
71
|
def print(self, *args, vlim=1, **kwargs):
|
|
@@ -115,15 +118,24 @@ class Algorithm(Model):
|
|
|
115
118
|
raise ValueError(
|
|
116
119
|
f"Input {mtype} data entry '{v}': Dimension '{FC.STATE}' not at first position, got {t[0]}"
|
|
117
120
|
)
|
|
118
|
-
if FC.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if t[0]
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
if FC.TURBINE in t[0]:
|
|
122
|
+
if t[0][1] != FC.TURBINE:
|
|
123
|
+
raise ValueError(
|
|
124
|
+
f"Input {mtype} data entry '{v}': Dimension '{FC.TURBINE}' not at second position, got {t[0]}"
|
|
125
|
+
)
|
|
126
|
+
if FC.TARGET in t[0]:
|
|
127
|
+
if t[0][1] != FC.TARGET:
|
|
128
|
+
raise ValueError(
|
|
129
|
+
f"Input {mtype} data entry '{v}': Dimension '{FC.TARGET}' not at second position, got {t[0]}"
|
|
130
|
+
)
|
|
131
|
+
if len(t[0]) < 3 or t[0][2] != FC.TPOINT:
|
|
132
|
+
raise KeyError(
|
|
133
|
+
f"Input {mtype} data entry '{v}': Expecting dimension '{FC.TPOINT}' as third entry. Got {t[0]}"
|
|
134
|
+
)
|
|
135
|
+
elif FC.TURBINE in t[0]:
|
|
136
|
+
raise ValueError(
|
|
137
|
+
f"Input {mtype} data entry '{v}': Dimension '{FC.TURBINE}' requires combination with dimension '{FC.STATE}'"
|
|
138
|
+
)
|
|
127
139
|
for d, s in zip(t[0], t[1].shape):
|
|
128
140
|
if d not in sizes:
|
|
129
141
|
sizes[d] = s
|
|
@@ -153,9 +165,9 @@ class Algorithm(Model):
|
|
|
153
165
|
raise ValueError(
|
|
154
166
|
f"Dimension '{FC.TURBINE}' cannot be chunked, got chunks {self.chunks}"
|
|
155
167
|
)
|
|
156
|
-
if FC.
|
|
168
|
+
if FC.TPOINT in self.chunks.keys():
|
|
157
169
|
raise ValueError(
|
|
158
|
-
f"Dimension '{FC.
|
|
170
|
+
f"Dimension '{FC.TPOINT}' cannot be chunked, got chunks {self.chunks}"
|
|
159
171
|
)
|
|
160
172
|
xrdata = xrdata.chunk(
|
|
161
173
|
chunks={c: v for c, v in self.chunks.items() if c in sizes}
|
|
@@ -376,7 +388,14 @@ class Algorithm(Model):
|
|
|
376
388
|
raise ValueError(
|
|
377
389
|
f"points have wrong dimensions, expecting ({self.n_states}, {points.shape[1]}, 3), got {points.shape}"
|
|
378
390
|
)
|
|
379
|
-
idata["data_vars"][FC.
|
|
391
|
+
idata["data_vars"][FC.TARGETS] = (
|
|
392
|
+
(FC.STATE, FC.TARGET, FC.TPOINT, FC.XYH),
|
|
393
|
+
points[:, :, None, :],
|
|
394
|
+
)
|
|
395
|
+
idata["data_vars"][FC.TWEIGHTS] = (
|
|
396
|
+
(FC.TPOINT,),
|
|
397
|
+
np.array([1.0], dtype=FC.DTYPE),
|
|
398
|
+
)
|
|
380
399
|
|
|
381
400
|
sizes = self.__get_sizes(idata, "point")
|
|
382
401
|
return self.__get_xrdata(idata, sizes)
|