foxes 1.2.5__py3-none-any.whl → 1.4__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 +3 -3
- examples/abl_states/run.py +2 -2
- examples/compare_rotors_pwakes/run.py +1 -1
- examples/compare_wakes/run.py +1 -2
- examples/dyn_wakes/run.py +29 -6
- examples/induction/run.py +3 -3
- examples/multi_height/run.py +1 -1
- examples/power_mask/run.py +2 -2
- examples/quickstart/run.py +16 -0
- examples/random_timeseries/run.py +3 -4
- examples/scan_row/run.py +3 -3
- examples/sequential/run.py +33 -10
- examples/single_state/run.py +3 -4
- examples/states_lookup_table/run.py +3 -3
- examples/streamline_wakes/run.py +27 -4
- examples/tab_file/run.py +3 -3
- examples/timelines/run.py +29 -5
- examples/timeseries/run.py +3 -3
- examples/timeseries_slurm/run.py +3 -3
- examples/wind_rose/run.py +3 -3
- examples/yawed_wake/run.py +16 -8
- foxes/__init__.py +22 -18
- foxes/algorithms/__init__.py +6 -6
- foxes/algorithms/downwind/__init__.py +2 -2
- foxes/algorithms/downwind/downwind.py +53 -27
- foxes/algorithms/downwind/models/__init__.py +6 -6
- foxes/algorithms/downwind/models/farm_wakes_calc.py +22 -14
- foxes/algorithms/downwind/models/init_farm_data.py +4 -5
- foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
- foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +7 -7
- foxes/algorithms/iterative/__init__.py +7 -3
- foxes/algorithms/iterative/iterative.py +1 -2
- foxes/algorithms/iterative/models/__init__.py +7 -3
- foxes/algorithms/iterative/models/farm_wakes_calc.py +15 -8
- foxes/algorithms/sequential/__init__.py +3 -3
- foxes/algorithms/sequential/models/__init__.py +2 -2
- foxes/algorithms/sequential/models/seq_state.py +0 -18
- foxes/algorithms/sequential/sequential.py +8 -22
- foxes/config/__init__.py +5 -1
- foxes/constants.py +22 -0
- foxes/core/__init__.py +45 -22
- foxes/core/algorithm.py +0 -1
- foxes/core/data.py +56 -29
- foxes/core/engine.py +28 -14
- foxes/core/farm_controller.py +2 -2
- foxes/core/farm_data_model.py +1 -0
- foxes/core/ground_model.py +4 -13
- foxes/core/model.py +5 -5
- foxes/core/partial_wakes_model.py +147 -10
- foxes/core/point_data_model.py +2 -3
- foxes/core/rotor_model.py +42 -38
- foxes/core/states.py +4 -50
- foxes/core/turbine.py +2 -1
- foxes/core/wake_deflection.py +130 -0
- foxes/core/wake_model.py +222 -9
- foxes/core/wake_superposition.py +122 -4
- foxes/core/wind_farm.py +6 -6
- foxes/data/__init__.py +7 -2
- foxes/data/states/weibull_sectors_12.csv +13 -0
- foxes/data/states/weibull_sectors_12.nc +0 -0
- foxes/engines/__init__.py +14 -15
- foxes/engines/dask.py +39 -14
- foxes/engines/numpy.py +0 -3
- foxes/input/__init__.py +3 -3
- foxes/input/farm_layout/__init__.py +8 -8
- foxes/input/farm_layout/from_csv.py +1 -1
- foxes/input/farm_layout/ring.py +0 -1
- foxes/input/states/__init__.py +22 -11
- foxes/input/states/create/__init__.py +3 -2
- foxes/input/states/field_data_nc.py +48 -84
- foxes/input/states/multi_height.py +40 -60
- foxes/input/states/one_point_flow.py +22 -25
- foxes/input/states/scan.py +6 -19
- foxes/input/states/single.py +6 -18
- foxes/input/states/states_table.py +25 -44
- foxes/input/states/weibull_sectors.py +225 -0
- foxes/input/states/wrg_states.py +151 -37
- foxes/input/yaml/__init__.py +9 -3
- foxes/input/yaml/dict.py +19 -19
- foxes/input/yaml/windio/__init__.py +10 -5
- foxes/input/yaml/windio/read_attributes.py +2 -2
- foxes/input/yaml/windio/read_farm.py +5 -5
- foxes/input/yaml/windio/read_fields.py +4 -2
- foxes/input/yaml/windio/read_site.py +52 -0
- foxes/input/yaml/windio/windio.py +1 -1
- foxes/models/__init__.py +15 -14
- foxes/models/axial_induction/__init__.py +2 -2
- foxes/models/farm_controllers/__init__.py +1 -1
- foxes/models/farm_models/__init__.py +1 -1
- foxes/models/ground_models/__init__.py +3 -2
- foxes/models/ground_models/wake_mirror.py +3 -3
- foxes/models/model_book.py +175 -49
- foxes/models/partial_wakes/__init__.py +6 -6
- foxes/models/partial_wakes/axiwake.py +30 -5
- foxes/models/partial_wakes/centre.py +47 -0
- foxes/models/partial_wakes/rotor_points.py +45 -9
- foxes/models/partial_wakes/segregated.py +2 -20
- foxes/models/partial_wakes/top_hat.py +27 -2
- foxes/models/point_models/__init__.py +4 -4
- foxes/models/rotor_models/__init__.py +3 -3
- foxes/models/rotor_models/centre.py +6 -4
- foxes/models/turbine_models/__init__.py +11 -11
- foxes/models/turbine_models/set_farm_vars.py +0 -1
- foxes/models/turbine_types/PCt_file.py +0 -2
- foxes/models/turbine_types/PCt_from_two.py +0 -2
- foxes/models/turbine_types/__init__.py +9 -9
- foxes/models/vertical_profiles/__init__.py +7 -7
- foxes/models/wake_deflections/__init__.py +3 -0
- foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
- foxes/models/wake_deflections/jimenez.py +277 -0
- foxes/models/wake_deflections/no_deflection.py +94 -0
- foxes/models/wake_frames/__init__.py +6 -7
- foxes/models/wake_frames/dynamic_wakes.py +12 -3
- foxes/models/wake_frames/rotor_wd.py +3 -1
- foxes/models/wake_frames/seq_dynamic_wakes.py +45 -8
- foxes/models/wake_frames/streamlines.py +8 -6
- foxes/models/wake_frames/timelines.py +19 -3
- foxes/models/wake_models/__init__.py +7 -7
- foxes/models/wake_models/dist_sliced.py +50 -84
- foxes/models/wake_models/gaussian.py +20 -0
- foxes/models/wake_models/induction/__init__.py +5 -5
- foxes/models/wake_models/induction/rankine_half_body.py +30 -71
- foxes/models/wake_models/induction/rathmann.py +65 -64
- foxes/models/wake_models/induction/self_similar.py +65 -68
- foxes/models/wake_models/induction/self_similar2020.py +0 -3
- foxes/models/wake_models/induction/vortex_sheet.py +71 -75
- foxes/models/wake_models/ti/__init__.py +2 -2
- foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
- foxes/models/wake_models/ti/iec_ti.py +6 -4
- foxes/models/wake_models/top_hat.py +58 -7
- foxes/models/wake_models/wind/__init__.py +6 -4
- foxes/models/wake_models/wind/bastankhah14.py +25 -7
- foxes/models/wake_models/wind/bastankhah16.py +35 -3
- foxes/models/wake_models/wind/jensen.py +15 -2
- foxes/models/wake_models/wind/turbopark.py +28 -2
- foxes/models/wake_superpositions/__init__.py +18 -9
- foxes/models/wake_superpositions/ti_linear.py +4 -4
- foxes/models/wake_superpositions/ti_max.py +4 -4
- foxes/models/wake_superpositions/ti_pow.py +4 -4
- foxes/models/wake_superpositions/ti_quadratic.py +4 -4
- foxes/models/wake_superpositions/wind_vector.py +257 -0
- foxes/models/wake_superpositions/ws_linear.py +9 -10
- foxes/models/wake_superpositions/ws_max.py +8 -8
- foxes/models/wake_superpositions/ws_pow.py +8 -8
- foxes/models/wake_superpositions/ws_product.py +4 -4
- foxes/models/wake_superpositions/ws_quadratic.py +8 -8
- foxes/output/__init__.py +21 -19
- foxes/output/farm_layout.py +14 -6
- foxes/output/farm_results_eval.py +51 -27
- foxes/output/flow_plots_2d/__init__.py +2 -2
- foxes/output/flow_plots_2d/get_fig.py +4 -2
- foxes/output/rose_plot.py +23 -5
- foxes/output/seq_plugins/__init__.py +2 -2
- foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
- foxes/output/slice_data.py +16 -19
- foxes/output/turbine_type_curves.py +7 -8
- foxes/utils/__init__.py +37 -19
- foxes/utils/abl/__init__.py +4 -4
- foxes/utils/cubic_roots.py +1 -1
- foxes/utils/data_book.py +4 -3
- foxes/utils/dict.py +3 -3
- foxes/utils/exec_python.py +5 -5
- foxes/utils/factory.py +1 -3
- foxes/utils/geom2d/__init__.py +7 -5
- foxes/utils/geopandas_utils.py +2 -2
- foxes/utils/pandas_utils.py +4 -3
- foxes/utils/tab_files.py +0 -1
- foxes/utils/weibull.py +28 -0
- foxes/utils/wrg_utils.py +3 -1
- foxes/utils/xarray_utils.py +9 -2
- foxes/variables.py +67 -9
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/METADATA +14 -21
- foxes-1.4.dist-info/RECORD +320 -0
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
- tests/0_consistency/iterative/test_iterative.py +2 -3
- tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
- tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
- tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -3
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -4
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -4
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -4
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -4
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -3
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -4
- tests/3_examples/test_examples.py +3 -2
- foxes/output/round.py +0 -10
- foxes/utils/pandas_helpers.py +0 -178
- foxes-1.2.5.dist-info/RECORD +0 -312
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
|
@@ -101,9 +101,13 @@ class OnePointFlowStates(States):
|
|
|
101
101
|
"""
|
|
102
102
|
return [self.base_states]
|
|
103
103
|
|
|
104
|
-
def
|
|
104
|
+
def load_data(self, algo, verbosity=0):
|
|
105
105
|
"""
|
|
106
|
-
|
|
106
|
+
Load and/or create all model data that is subject to chunking.
|
|
107
|
+
|
|
108
|
+
Such data should not be stored under self, for memory reasons. The
|
|
109
|
+
data returned here will automatically be chunked and then provided
|
|
110
|
+
as part of the mdata object during calculations.
|
|
107
111
|
|
|
108
112
|
Parameters
|
|
109
113
|
----------
|
|
@@ -112,8 +116,14 @@ class OnePointFlowStates(States):
|
|
|
112
116
|
verbosity: int
|
|
113
117
|
The verbosity level, 0 = silent
|
|
114
118
|
|
|
119
|
+
Returns
|
|
120
|
+
-------
|
|
121
|
+
idata: dict
|
|
122
|
+
The dict has exactly two entries: `data_vars`,
|
|
123
|
+
a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
|
|
124
|
+
and `coords`, a dict with entries `dim_name_str -> dim_array`
|
|
125
|
+
|
|
115
126
|
"""
|
|
116
|
-
super().initialize(algo, verbosity)
|
|
117
127
|
|
|
118
128
|
# find heights:
|
|
119
129
|
if self.heights is None:
|
|
@@ -127,10 +137,14 @@ class OnePointFlowStates(States):
|
|
|
127
137
|
)
|
|
128
138
|
|
|
129
139
|
# pre-calc data:
|
|
130
|
-
|
|
140
|
+
self.WEIGHT = self.var(FV.WEIGHT)
|
|
141
|
+
idata = super().load_data(algo, verbosity)
|
|
142
|
+
idata["data_vars"][self.WEIGHT] = Timelines._precalc_data(
|
|
131
143
|
self, algo, self.base_states, self.heights, verbosity, needs_res=True
|
|
132
144
|
)
|
|
133
145
|
|
|
146
|
+
return idata
|
|
147
|
+
|
|
134
148
|
def size(self):
|
|
135
149
|
"""
|
|
136
150
|
The total number of states.
|
|
@@ -172,23 +186,6 @@ class OnePointFlowStates(States):
|
|
|
172
186
|
"""
|
|
173
187
|
return self.base_states.output_point_vars(algo)
|
|
174
188
|
|
|
175
|
-
def weights(self, algo):
|
|
176
|
-
"""
|
|
177
|
-
The statistical weights of all states.
|
|
178
|
-
|
|
179
|
-
Parameters
|
|
180
|
-
----------
|
|
181
|
-
algo: foxes.core.Algorithm
|
|
182
|
-
The calculation algorithm
|
|
183
|
-
|
|
184
|
-
Returns
|
|
185
|
-
-------
|
|
186
|
-
weights: numpy.ndarray
|
|
187
|
-
The weights, shape: (n_states, n_turbines)
|
|
188
|
-
|
|
189
|
-
"""
|
|
190
|
-
return self.base_states.weights(algo)
|
|
191
|
-
|
|
192
189
|
def set_running(
|
|
193
190
|
self,
|
|
194
191
|
algo,
|
|
@@ -263,7 +260,6 @@ class OnePointFlowStates(States):
|
|
|
263
260
|
self.timelines_data = data.pop("data")
|
|
264
261
|
|
|
265
262
|
def calc_states_indices(self, algo, mdata, points, hi, ref_xy):
|
|
266
|
-
|
|
267
263
|
n_states, n_points = points.shape[:2]
|
|
268
264
|
dxy = self.timelines_data["dxy"].to_numpy()[hi]
|
|
269
265
|
|
|
@@ -304,7 +300,6 @@ class OnePointFlowStates(States):
|
|
|
304
300
|
sel = np.isnan(coeffs)
|
|
305
301
|
tshift = 0
|
|
306
302
|
while np.any(sel):
|
|
307
|
-
|
|
308
303
|
trs = trace_si[sel]
|
|
309
304
|
hdxy = -dxy[trs]
|
|
310
305
|
trace_p[sel] += hdxy
|
|
@@ -329,7 +324,6 @@ class OnePointFlowStates(States):
|
|
|
329
324
|
sel &= trace_si < algo.n_states
|
|
330
325
|
tshift = 1
|
|
331
326
|
while np.any(sel):
|
|
332
|
-
|
|
333
327
|
trs = trace_si[sel]
|
|
334
328
|
hdxy = dxy[trs]
|
|
335
329
|
trace_p[sel] += hdxy
|
|
@@ -423,7 +417,6 @@ class OnePointFlowStates(States):
|
|
|
423
417
|
|
|
424
418
|
# interpolate to heights:
|
|
425
419
|
if n_heights > 1:
|
|
426
|
-
|
|
427
420
|
ar_states = np.arange(n_states)
|
|
428
421
|
ar_points = np.arange(n_points)
|
|
429
422
|
|
|
@@ -488,6 +481,10 @@ class OnePointFlowStates(States):
|
|
|
488
481
|
results = {FV.WD: uv2wd(uv), FV.WS: np.linalg.norm(uv, axis=-1)}
|
|
489
482
|
del uv
|
|
490
483
|
|
|
484
|
+
# set weights:
|
|
485
|
+
tdata[FV.WEIGHT] = mdata[self.WEIGHT][:, None, None]
|
|
486
|
+
tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
487
|
+
|
|
491
488
|
return {
|
|
492
489
|
v: d.reshape(n_states, n_targets, n_tpoints) for v, d in results.items()
|
|
493
490
|
}
|
foxes/input/states/scan.py
CHANGED
|
@@ -176,25 +176,6 @@ class ScanStates(States):
|
|
|
176
176
|
"""
|
|
177
177
|
return self._vars
|
|
178
178
|
|
|
179
|
-
def weights(self, algo):
|
|
180
|
-
"""
|
|
181
|
-
The statistical weights of all states.
|
|
182
|
-
|
|
183
|
-
Parameters
|
|
184
|
-
----------
|
|
185
|
-
algo: foxes.core.Algorithm
|
|
186
|
-
The calculation algorithm
|
|
187
|
-
|
|
188
|
-
Returns
|
|
189
|
-
-------
|
|
190
|
-
weights: numpy.ndarray
|
|
191
|
-
The weights, shape: (n_states, n_turbines)
|
|
192
|
-
|
|
193
|
-
"""
|
|
194
|
-
return np.full(
|
|
195
|
-
(self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
|
|
196
|
-
)
|
|
197
|
-
|
|
198
179
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
199
180
|
"""
|
|
200
181
|
The main model calculation.
|
|
@@ -226,4 +207,10 @@ class ScanStates(States):
|
|
|
226
207
|
tdata[v] = np.zeros_like(tdata[FC.TARGETS][..., 0])
|
|
227
208
|
tdata[v][:] = mdata[self.DATA][:, None, None, i]
|
|
228
209
|
|
|
210
|
+
# add weights:
|
|
211
|
+
tdata[FV.WEIGHT] = np.full(
|
|
212
|
+
(mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
|
|
213
|
+
)
|
|
214
|
+
tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
215
|
+
|
|
229
216
|
return {v: tdata[v] for v in self.output_point_vars(algo)}
|
foxes/input/states/single.py
CHANGED
|
@@ -75,7 +75,7 @@ class SingleStateStates(States):
|
|
|
75
75
|
and not len(profiles)
|
|
76
76
|
):
|
|
77
77
|
raise KeyError(
|
|
78
|
-
|
|
78
|
+
"Expecting at least one parameter: ws, wd, ti, rho, profiles"
|
|
79
79
|
)
|
|
80
80
|
|
|
81
81
|
def sub_models(self):
|
|
@@ -157,23 +157,6 @@ class SingleStateStates(States):
|
|
|
157
157
|
|
|
158
158
|
return list(out)
|
|
159
159
|
|
|
160
|
-
def weights(self, algo):
|
|
161
|
-
"""
|
|
162
|
-
The statistical weights of all states.
|
|
163
|
-
|
|
164
|
-
Parameters
|
|
165
|
-
----------
|
|
166
|
-
algo: foxes.core.Algorithm
|
|
167
|
-
The calculation algorithm
|
|
168
|
-
|
|
169
|
-
Returns
|
|
170
|
-
-------
|
|
171
|
-
weights: numpy.ndarray
|
|
172
|
-
The weights, shape: (n_states, n_turbines)
|
|
173
|
-
|
|
174
|
-
"""
|
|
175
|
-
return np.ones((1, algo.n_turbines), dtype=config.dtype_double)
|
|
176
|
-
|
|
177
160
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
178
161
|
"""
|
|
179
162
|
The main model calculation.
|
|
@@ -233,4 +216,9 @@ class SingleStateStates(States):
|
|
|
233
216
|
pres = p.calculate(tdata, z)
|
|
234
217
|
tdata[v] = pres
|
|
235
218
|
|
|
219
|
+
tdata[FV.WEIGHT] = np.full(
|
|
220
|
+
(mdata.n_states, 1, 1), 1.0, dtype=config.dtype_double
|
|
221
|
+
)
|
|
222
|
+
tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
223
|
+
|
|
236
224
|
return {v: tdata[v] for v in self.output_point_vars(algo)}
|
|
@@ -51,7 +51,7 @@ class StatesTable(States):
|
|
|
51
51
|
var2col={},
|
|
52
52
|
fixed_vars={},
|
|
53
53
|
profiles={},
|
|
54
|
-
|
|
54
|
+
read_pars={},
|
|
55
55
|
states_sel=None,
|
|
56
56
|
states_loc=None,
|
|
57
57
|
):
|
|
@@ -72,7 +72,7 @@ class StatesTable(States):
|
|
|
72
72
|
profiles: dict
|
|
73
73
|
Key: output variable name str, Value: str or dict
|
|
74
74
|
or `foxes.core.VerticalProfile`
|
|
75
|
-
|
|
75
|
+
read_pars: dict
|
|
76
76
|
pandas file reading parameters
|
|
77
77
|
states_sel: slice or range or list of int, optional
|
|
78
78
|
States subset selection
|
|
@@ -82,8 +82,8 @@ class StatesTable(States):
|
|
|
82
82
|
"""
|
|
83
83
|
super().__init__()
|
|
84
84
|
|
|
85
|
-
self.ovars = output_vars
|
|
86
|
-
self.rpars =
|
|
85
|
+
self.ovars = list(output_vars)
|
|
86
|
+
self.rpars = read_pars
|
|
87
87
|
self.var2col = var2col
|
|
88
88
|
self.fixed_vars = fixed_vars
|
|
89
89
|
self.profdicts = profiles
|
|
@@ -98,9 +98,7 @@ class StatesTable(States):
|
|
|
98
98
|
self._N = None
|
|
99
99
|
self._tvars = None
|
|
100
100
|
self._profiles = None
|
|
101
|
-
|
|
102
101
|
self._data_source = data_source
|
|
103
|
-
self.__weights = None
|
|
104
102
|
|
|
105
103
|
@property
|
|
106
104
|
def data_source(self):
|
|
@@ -155,7 +153,6 @@ class StatesTable(States):
|
|
|
155
153
|
|
|
156
154
|
"""
|
|
157
155
|
self._profiles = {}
|
|
158
|
-
self._tvars = set(self.ovars)
|
|
159
156
|
for v, d in self.profdicts.items():
|
|
160
157
|
if isinstance(d, str):
|
|
161
158
|
self._profiles[v] = VerticalProfile.new(d)
|
|
@@ -168,9 +165,7 @@ class StatesTable(States):
|
|
|
168
165
|
raise TypeError(
|
|
169
166
|
f"States '{self.name}': Wrong profile type '{type(d).__name__}' for variable '{v}'. Expecting VerticalProfile, str or dict"
|
|
170
167
|
)
|
|
171
|
-
|
|
172
|
-
self._tvars -= set(self.fixed_vars.keys())
|
|
173
|
-
self._tvars = list(self._tvars)
|
|
168
|
+
|
|
174
169
|
super().initialize(algo, verbosity)
|
|
175
170
|
|
|
176
171
|
def sub_models(self):
|
|
@@ -210,10 +205,10 @@ class StatesTable(States):
|
|
|
210
205
|
"""
|
|
211
206
|
self.VARS = self.var("vars")
|
|
212
207
|
self.DATA = self.var("data")
|
|
208
|
+
self.WEIGHT = self.var(FV.WEIGHT)
|
|
213
209
|
|
|
214
210
|
if isinstance(self.data_source, pd.DataFrame):
|
|
215
211
|
data = self.data_source
|
|
216
|
-
isorg = True
|
|
217
212
|
else:
|
|
218
213
|
self._data_source = get_input_path(self.data_source)
|
|
219
214
|
if not self.data_source.is_file():
|
|
@@ -230,7 +225,6 @@ class StatesTable(States):
|
|
|
230
225
|
print(f"States '{self.name}': Reading file {self.data_source}")
|
|
231
226
|
rpars = dict(self.RDICT, **self.rpars)
|
|
232
227
|
data = PandasFileHelper().read_file(self.data_source, **rpars)
|
|
233
|
-
isorg = False
|
|
234
228
|
|
|
235
229
|
if self.states_sel is not None:
|
|
236
230
|
data = data.iloc[self.states_sel]
|
|
@@ -240,18 +234,19 @@ class StatesTable(States):
|
|
|
240
234
|
self.__inds = data.index.to_numpy()
|
|
241
235
|
|
|
242
236
|
col_w = self.var2col.get(FV.WEIGHT, FV.WEIGHT)
|
|
243
|
-
|
|
237
|
+
weights = None
|
|
244
238
|
if col_w in data:
|
|
245
|
-
|
|
239
|
+
weights = data[col_w].to_numpy()
|
|
246
240
|
elif FV.WEIGHT in self.var2col:
|
|
247
241
|
raise KeyError(
|
|
248
242
|
f"Weight variable '{col_w}' defined in var2col, but not found in states table columns {data.columns}"
|
|
249
243
|
)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
244
|
+
|
|
245
|
+
self._tvars = set(self.ovars)
|
|
246
|
+
for v in self.profdicts.keys():
|
|
247
|
+
self._tvars.update(self._profiles[v].input_vars())
|
|
248
|
+
self._tvars -= set(self.fixed_vars.keys())
|
|
249
|
+
self._tvars = list(self._tvars)
|
|
255
250
|
|
|
256
251
|
tcols = []
|
|
257
252
|
for v in self._tvars:
|
|
@@ -267,6 +262,8 @@ class StatesTable(States):
|
|
|
267
262
|
idata = super().load_data(algo, verbosity)
|
|
268
263
|
idata["coords"][self.VARS] = self._tvars
|
|
269
264
|
idata["data_vars"][self.DATA] = ((FC.STATE, self.VARS), data.to_numpy())
|
|
265
|
+
if weights is not None:
|
|
266
|
+
idata["data_vars"][self.WEIGHT] = (FC.STATE, weights)
|
|
270
267
|
|
|
271
268
|
return idata
|
|
272
269
|
|
|
@@ -313,27 +310,6 @@ class StatesTable(States):
|
|
|
313
310
|
"""
|
|
314
311
|
return self.ovars
|
|
315
312
|
|
|
316
|
-
def weights(self, algo):
|
|
317
|
-
"""
|
|
318
|
-
The statistical weights of all states.
|
|
319
|
-
|
|
320
|
-
Parameters
|
|
321
|
-
----------
|
|
322
|
-
algo: foxes.core.Algorithm
|
|
323
|
-
The calculation algorithm
|
|
324
|
-
|
|
325
|
-
Returns
|
|
326
|
-
-------
|
|
327
|
-
weights: numpy.ndarray
|
|
328
|
-
The weights, shape: (n_states, n_turbines)
|
|
329
|
-
|
|
330
|
-
"""
|
|
331
|
-
if self.running:
|
|
332
|
-
raise ValueError(
|
|
333
|
-
f"States '{self.name}': Cannot access weights while running"
|
|
334
|
-
)
|
|
335
|
-
return self.__weights
|
|
336
|
-
|
|
337
313
|
def set_running(
|
|
338
314
|
self,
|
|
339
315
|
algo,
|
|
@@ -368,10 +344,9 @@ class StatesTable(States):
|
|
|
368
344
|
|
|
369
345
|
data_stash[self.name] = dict(
|
|
370
346
|
data_source=self._data_source,
|
|
371
|
-
weights=self.__weights,
|
|
372
347
|
inds=self.__inds,
|
|
373
348
|
)
|
|
374
|
-
del self._data_source, self.
|
|
349
|
+
del self._data_source, self.__inds
|
|
375
350
|
|
|
376
351
|
def unset_running(
|
|
377
352
|
self,
|
|
@@ -404,7 +379,6 @@ class StatesTable(States):
|
|
|
404
379
|
|
|
405
380
|
data = data_stash[self.name]
|
|
406
381
|
self._data_source = data.pop("data_source")
|
|
407
|
-
self.__weights = data.pop("weights")
|
|
408
382
|
self.__inds = data.pop("inds")
|
|
409
383
|
|
|
410
384
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
@@ -455,6 +429,14 @@ class StatesTable(States):
|
|
|
455
429
|
for v, p in self._profiles.items():
|
|
456
430
|
tdata[v] = p.calculate(tdata, z)
|
|
457
431
|
|
|
432
|
+
if self.WEIGHT in mdata:
|
|
433
|
+
tdata[FV.WEIGHT] = mdata[self.WEIGHT][:, None, None]
|
|
434
|
+
else:
|
|
435
|
+
tdata[FV.WEIGHT] = np.full(
|
|
436
|
+
(mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
|
|
437
|
+
)
|
|
438
|
+
tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
439
|
+
|
|
458
440
|
return {v: tdata[v] for v in self.output_point_vars(algo)}
|
|
459
441
|
|
|
460
442
|
def finalize(self, algo, verbosity=0):
|
|
@@ -469,7 +451,6 @@ class StatesTable(States):
|
|
|
469
451
|
The verbosity level
|
|
470
452
|
|
|
471
453
|
"""
|
|
472
|
-
self.__weights = None
|
|
473
454
|
self._N = None
|
|
474
455
|
self._tvars = None
|
|
475
456
|
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from os import PathLike
|
|
4
|
+
from xarray import Dataset, open_dataset
|
|
5
|
+
|
|
6
|
+
from foxes.data import STATES
|
|
7
|
+
from foxes.utils import PandasFileHelper, weibull_weights
|
|
8
|
+
from foxes.config import config, get_input_path
|
|
9
|
+
import foxes.variables as FV
|
|
10
|
+
import foxes.constants as FC
|
|
11
|
+
|
|
12
|
+
from .states_table import StatesTable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class WeibullSectors(StatesTable):
|
|
16
|
+
"""
|
|
17
|
+
States with wind speed from Weibull parameters
|
|
18
|
+
from a NetCDF file
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
ws_bins: numpy.ndarray
|
|
23
|
+
The wind speed bins, including
|
|
24
|
+
lower and upper bounds, shape: (n_ws_bins+1,)
|
|
25
|
+
var2ncvar: dict
|
|
26
|
+
Mapping from variable names to variable names
|
|
27
|
+
in the nc file
|
|
28
|
+
sel: dict
|
|
29
|
+
Subset selection via xr.Dataset.sel()
|
|
30
|
+
isel: dict
|
|
31
|
+
Subset selection via xr.Dataset.isel()
|
|
32
|
+
RDICT: dict
|
|
33
|
+
Default xarray file reading parameters
|
|
34
|
+
|
|
35
|
+
:group: input.states
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
RDICT = {}
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
data_source,
|
|
44
|
+
output_vars,
|
|
45
|
+
ws_bins=None,
|
|
46
|
+
var2ncvar={},
|
|
47
|
+
sel=None,
|
|
48
|
+
isel=None,
|
|
49
|
+
**kwargs,
|
|
50
|
+
):
|
|
51
|
+
"""
|
|
52
|
+
Constructor.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
data_source: str or xarray.Dataset or pandas.DataFrame
|
|
57
|
+
Either path to NetCDF or csv file or data
|
|
58
|
+
output_vars: list of str
|
|
59
|
+
The output variables
|
|
60
|
+
ws_bins: list of float, optional
|
|
61
|
+
The wind speed bins, including
|
|
62
|
+
lower and upper bounds
|
|
63
|
+
var2ncvar: dict
|
|
64
|
+
Mapping from variable names to variable names
|
|
65
|
+
in the nc file
|
|
66
|
+
sel: dict, optional
|
|
67
|
+
Subset selection via xr.Dataset.sel()
|
|
68
|
+
isel: dict, optional
|
|
69
|
+
Subset selection via xr.Dataset.isel()
|
|
70
|
+
kwargs: dict, optional
|
|
71
|
+
Additional arguments for the base class
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
super().__init__(data_source, output_vars, var2col={}, **kwargs)
|
|
75
|
+
self.ws_bins = None if ws_bins is None else np.asarray(ws_bins)
|
|
76
|
+
self.var2ncvar = var2ncvar
|
|
77
|
+
self.sel = sel if sel is not None else {}
|
|
78
|
+
self.isel = isel if isel is not None else {}
|
|
79
|
+
|
|
80
|
+
if FV.WS not in self.ovars:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"States '{self.name}': Expecting output variable '{FV.WS}', got {self.ovars}"
|
|
83
|
+
)
|
|
84
|
+
for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT]:
|
|
85
|
+
if v in self.ovars:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
f"States '{self.name}': Cannot have '{v}' as output variable"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
self._original_data_source = None
|
|
91
|
+
|
|
92
|
+
def __repr__(self):
|
|
93
|
+
return f"{type(self).__name__}(ws_bins={self._n_ws})"
|
|
94
|
+
|
|
95
|
+
def load_data(self, algo, verbosity=0):
|
|
96
|
+
"""
|
|
97
|
+
Load and/or create all model data that is subject to chunking.
|
|
98
|
+
|
|
99
|
+
Such data should not be stored under self, for memory reasons. The
|
|
100
|
+
data returned here will automatically be chunked and then provided
|
|
101
|
+
as part of the mdata object during calculations.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
algo: foxes.core.Algorithm
|
|
106
|
+
The calculation algorithm
|
|
107
|
+
verbosity: int
|
|
108
|
+
The verbosity level, 0 = silent
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
idata: dict
|
|
113
|
+
The dict has exactly two entries: `data_vars`,
|
|
114
|
+
a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
|
|
115
|
+
and `coords`, a dict with entries `dim_name_str -> dim_array`
|
|
116
|
+
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
if self._original_data_source is not None:
|
|
120
|
+
self._data_source = self._original_data_source
|
|
121
|
+
self._original_data_source = None
|
|
122
|
+
|
|
123
|
+
if isinstance(self.data_source, (str, PathLike)):
|
|
124
|
+
fpath = get_input_path(self.data_source)
|
|
125
|
+
if not fpath.is_file():
|
|
126
|
+
if verbosity > 0:
|
|
127
|
+
print(
|
|
128
|
+
f"States '{self.name}': Reading static data '{fpath}' from context '{STATES}'"
|
|
129
|
+
)
|
|
130
|
+
fpath = algo.dbook.get_file_path(STATES, fpath.name, check_raw=False)
|
|
131
|
+
if verbosity > 0:
|
|
132
|
+
print(f"Path: {fpath}")
|
|
133
|
+
elif verbosity:
|
|
134
|
+
print(f"States '{self.name}': Reading file {fpath}")
|
|
135
|
+
rpars = dict(self.RDICT, **self.rpars)
|
|
136
|
+
if fpath.suffix == ".nc":
|
|
137
|
+
data = open_dataset(fpath, engine=config.nc_engine, **rpars)
|
|
138
|
+
else:
|
|
139
|
+
data = PandasFileHelper().read_file(fpath, **rpars).to_xarray()
|
|
140
|
+
self._original_data_source = data
|
|
141
|
+
|
|
142
|
+
elif isinstance(self.data_source, Dataset):
|
|
143
|
+
data = self.data_source
|
|
144
|
+
|
|
145
|
+
elif isinstance(self.data_source, pd.DataFrame):
|
|
146
|
+
data = self.data_source.to_xarray()
|
|
147
|
+
|
|
148
|
+
if self.isel is not None and len(self.isel):
|
|
149
|
+
data = data.isel(**self.isel)
|
|
150
|
+
if self.sel is not None and len(self.sel):
|
|
151
|
+
data = data.sel(**self.sel)
|
|
152
|
+
|
|
153
|
+
wsn = self.var2ncvar.get(FV.WS, FV.WS)
|
|
154
|
+
if self.ws_bins is not None:
|
|
155
|
+
wsb = self.ws_bins
|
|
156
|
+
elif wsn in data:
|
|
157
|
+
wsb = data[wsn].to_numpy()
|
|
158
|
+
else:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
f"States '{self.name}': Expecting ws_bins argument, since '{wsn}' not found in data"
|
|
161
|
+
)
|
|
162
|
+
wss = 0.5 * (wsb[:-1] + wsb[1:])
|
|
163
|
+
wsd = wsb[1:] - wsb[:-1]
|
|
164
|
+
n_ws = len(wss)
|
|
165
|
+
self._n_ws = n_ws
|
|
166
|
+
del wsb
|
|
167
|
+
|
|
168
|
+
secn = None
|
|
169
|
+
n_secs = None
|
|
170
|
+
if self._original_data_source is None:
|
|
171
|
+
self._original_data_source = self.data_source
|
|
172
|
+
self._data_source = {}
|
|
173
|
+
for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT] + self.ovars:
|
|
174
|
+
if v != FV.WS and v not in self.fixed_vars:
|
|
175
|
+
c = self.var2ncvar.get(v, v)
|
|
176
|
+
if c not in data:
|
|
177
|
+
raise KeyError(
|
|
178
|
+
f"States '{self.name}': Missing variable '{c}' in data, found {list(data.data_vars.keys())}"
|
|
179
|
+
)
|
|
180
|
+
d = data[c]
|
|
181
|
+
if len(d.dims) == 0:
|
|
182
|
+
self.fixed_vars[v] = float(d.to_numpy())
|
|
183
|
+
continue
|
|
184
|
+
elif len(d.dims) != 1:
|
|
185
|
+
raise ValueError(
|
|
186
|
+
f"States '{self.name}': Expecting single dimension for variable '{c}', got {d.dims}"
|
|
187
|
+
)
|
|
188
|
+
elif secn is None:
|
|
189
|
+
secn = d.dims[0]
|
|
190
|
+
n_secs = data.sizes[secn]
|
|
191
|
+
elif d.dims[0] != secn:
|
|
192
|
+
raise ValueError(
|
|
193
|
+
f"States '{self.name}': Expecting dimension '{secn}' for variable '{c}', got {d.dims}"
|
|
194
|
+
)
|
|
195
|
+
self._data_source[v] = np.zeros(
|
|
196
|
+
(n_secs, n_ws), dtype=config.dtype_double
|
|
197
|
+
)
|
|
198
|
+
self._data_source[v][:] = d.to_numpy()[:, None]
|
|
199
|
+
self._data_source[FV.WS] = np.zeros((n_secs, n_ws), dtype=config.dtype_double)
|
|
200
|
+
self._data_source[FV.WS][:] = wss[None, :]
|
|
201
|
+
del wss
|
|
202
|
+
|
|
203
|
+
self._data_source[FV.WEIGHT] *= weibull_weights(
|
|
204
|
+
ws=self._data_source[FV.WS],
|
|
205
|
+
ws_deltas=wsd[None, :],
|
|
206
|
+
A=self._data_source.pop(FV.WEIBULL_A),
|
|
207
|
+
k=self._data_source.pop(FV.WEIBULL_k),
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# remove wd 360 from the end, if wd 0 is given:
|
|
211
|
+
if FV.WD in self._data_source:
|
|
212
|
+
if np.all(self._data_source[FV.WD][0] == 0.0) and np.all(
|
|
213
|
+
self._data_source[FV.WD][-1] == 360.0
|
|
214
|
+
):
|
|
215
|
+
for v in self._data_source.keys():
|
|
216
|
+
self._data_source[v] = self._data_source[v][:-1]
|
|
217
|
+
n_secs -= 1
|
|
218
|
+
|
|
219
|
+
N = n_secs * n_ws
|
|
220
|
+
for v in self._data_source.keys():
|
|
221
|
+
self._data_source[v] = self._data_source[v].reshape(N)
|
|
222
|
+
self._data_source = pd.DataFrame(data=self._data_source, index=np.arange(N))
|
|
223
|
+
self._data_source.index.name = FC.STATE
|
|
224
|
+
|
|
225
|
+
return super().load_data(algo, verbosity)
|