foxes 1.3__py3-none-any.whl → 1.5__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/field_data_nc/run.py +1 -1
- examples/induction/run.py +3 -3
- examples/multi_height/run.py +1 -1
- examples/power_mask/run.py +2 -2
- examples/quickstart/run.py +0 -1
- 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 +29 -6
- 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 +19 -9
- foxes/__init__.py +21 -17
- foxes/algorithms/__init__.py +6 -6
- foxes/algorithms/downwind/__init__.py +2 -2
- foxes/algorithms/downwind/downwind.py +49 -17
- foxes/algorithms/downwind/models/__init__.py +6 -6
- foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
- foxes/algorithms/downwind/models/init_farm_data.py +58 -29
- foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
- foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
- 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 +9 -5
- foxes/algorithms/sequential/__init__.py +3 -3
- foxes/algorithms/sequential/models/__init__.py +2 -2
- foxes/algorithms/sequential/sequential.py +3 -4
- foxes/config/__init__.py +5 -1
- foxes/constants.py +16 -0
- foxes/core/__init__.py +45 -22
- foxes/core/algorithm.py +5 -6
- foxes/core/data.py +94 -22
- foxes/core/data_calc_model.py +4 -2
- foxes/core/engine.py +42 -53
- foxes/core/farm_controller.py +2 -2
- foxes/core/farm_data_model.py +16 -13
- foxes/core/ground_model.py +4 -13
- foxes/core/model.py +24 -6
- foxes/core/partial_wakes_model.py +147 -10
- foxes/core/point_data_model.py +21 -17
- foxes/core/rotor_model.py +4 -3
- foxes/core/states.py +2 -3
- 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/point_cloud_100.nc +0 -0
- foxes/data/states/weibull_cloud_4.nc +0 -0
- foxes/data/states/weibull_grid.nc +0 -0
- 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 +42 -20
- foxes/engines/default.py +2 -2
- foxes/engines/numpy.py +11 -13
- foxes/engines/pool.py +20 -11
- foxes/engines/single.py +8 -6
- foxes/input/__init__.py +3 -3
- foxes/input/farm_layout/__init__.py +9 -8
- foxes/input/farm_layout/from_arrays.py +68 -0
- foxes/input/farm_layout/from_csv.py +1 -1
- foxes/input/farm_layout/ring.py +0 -1
- foxes/input/states/__init__.py +28 -12
- foxes/input/states/create/__init__.py +3 -2
- foxes/input/states/dataset_states.py +710 -0
- foxes/input/states/field_data.py +531 -0
- foxes/input/states/multi_height.py +11 -6
- foxes/input/states/one_point_flow.py +1 -4
- foxes/input/states/point_cloud_data.py +618 -0
- foxes/input/states/scan.py +2 -0
- foxes/input/states/single.py +3 -1
- foxes/input/states/states_table.py +23 -30
- foxes/input/states/weibull_sectors.py +330 -0
- foxes/input/states/wrg_states.py +8 -6
- foxes/input/yaml/__init__.py +9 -3
- foxes/input/yaml/dict.py +42 -41
- foxes/input/yaml/windio/__init__.py +10 -5
- foxes/input/yaml/windio/read_attributes.py +42 -29
- foxes/input/yaml/windio/read_farm.py +17 -15
- foxes/input/yaml/windio/read_fields.py +4 -2
- foxes/input/yaml/windio/read_outputs.py +25 -15
- foxes/input/yaml/windio/read_site.py +172 -11
- foxes/input/yaml/windio/windio.py +23 -11
- foxes/input/yaml/yaml.py +1 -0
- 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 +190 -63
- 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 +41 -11
- foxes/models/partial_wakes/segregated.py +2 -25
- foxes/models/partial_wakes/top_hat.py +27 -2
- foxes/models/point_models/__init__.py +4 -4
- foxes/models/rotor_models/__init__.py +4 -3
- foxes/models/rotor_models/centre.py +1 -1
- foxes/models/rotor_models/direct_infusion.py +241 -0
- foxes/models/turbine_models/__init__.py +11 -11
- foxes/models/turbine_models/calculator.py +16 -3
- foxes/models/turbine_models/kTI_model.py +1 -0
- foxes/models/turbine_models/lookup_table.py +2 -0
- foxes/models/turbine_models/power_mask.py +1 -0
- foxes/models/turbine_models/rotor_centre_calc.py +2 -0
- foxes/models/turbine_models/sector_management.py +1 -0
- foxes/models/turbine_models/set_farm_vars.py +3 -9
- foxes/models/turbine_models/table_factors.py +2 -0
- foxes/models/turbine_models/thrust2ct.py +1 -0
- foxes/models/turbine_models/yaw2yawm.py +2 -0
- foxes/models/turbine_models/yawm2yaw.py +2 -0
- foxes/models/turbine_types/PCt_file.py +2 -6
- foxes/models/turbine_types/PCt_from_two.py +1 -2
- foxes/models/turbine_types/__init__.py +10 -9
- foxes/models/turbine_types/calculator_type.py +123 -0
- foxes/models/turbine_types/null_type.py +1 -0
- foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
- foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
- 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 +41 -7
- foxes/models/wake_frames/streamlines.py +8 -6
- foxes/models/wake_frames/timelines.py +9 -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 +4 -2
- foxes/output/farm_results_eval.py +19 -16
- foxes/output/flow_plots_2d/__init__.py +2 -2
- foxes/output/flow_plots_2d/flow_plots.py +18 -0
- foxes/output/flow_plots_2d/get_fig.py +5 -2
- foxes/output/output.py +6 -1
- foxes/output/results_writer.py +1 -1
- foxes/output/rose_plot.py +13 -3
- foxes/output/rotor_point_plots.py +3 -0
- 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/state_turbine_map.py +3 -0
- foxes/output/turbine_type_curves.py +10 -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 +49 -37
- foxes/utils/exec_python.py +5 -5
- foxes/utils/factory.py +3 -5
- 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.3.dist-info → foxes-1.5.dist-info}/METADATA +34 -63
- foxes-1.5.dist-info/RECORD +328 -0
- {foxes-1.3.dist-info → foxes-1.5.dist-info}/WHEEL +1 -1
- 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 +1 -1
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
- 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 +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
- 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 +0 -1
- foxes/input/states/field_data_nc.py +0 -847
- foxes/output/round.py +0 -10
- foxes/utils/pandas_helpers.py +0 -178
- foxes-1.3.dist-info/RECORD +0 -313
- {foxes-1.3.dist-info → foxes-1.5.dist-info}/entry_points.txt +0 -0
- {foxes-1.3.dist-info → foxes-1.5.dist-info/licenses}/LICENSE +0 -0
- {foxes-1.3.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
@@ -83,7 +83,7 @@ class StatesTable(States):
|
|
|
83
83
|
super().__init__()
|
|
84
84
|
|
|
85
85
|
self.ovars = list(output_vars)
|
|
86
|
-
self.rpars =
|
|
86
|
+
self.rpars = read_pars
|
|
87
87
|
self.var2col = var2col
|
|
88
88
|
self.fixed_vars = fixed_vars
|
|
89
89
|
self.profdicts = profiles
|
|
@@ -98,7 +98,7 @@ class StatesTable(States):
|
|
|
98
98
|
self._N = None
|
|
99
99
|
self._tvars = None
|
|
100
100
|
self._profiles = None
|
|
101
|
-
self.
|
|
101
|
+
self._data = data_source
|
|
102
102
|
|
|
103
103
|
@property
|
|
104
104
|
def data_source(self):
|
|
@@ -115,7 +115,7 @@ class StatesTable(States):
|
|
|
115
115
|
raise ValueError(
|
|
116
116
|
f"States '{self.name}': Cannot access data_source while running"
|
|
117
117
|
)
|
|
118
|
-
return self.
|
|
118
|
+
return self._data
|
|
119
119
|
|
|
120
120
|
def reset(self, algo=None, states_sel=None, states_loc=None, verbosity=0):
|
|
121
121
|
"""
|
|
@@ -153,7 +153,6 @@ class StatesTable(States):
|
|
|
153
153
|
|
|
154
154
|
"""
|
|
155
155
|
self._profiles = {}
|
|
156
|
-
self._tvars = set(self.ovars)
|
|
157
156
|
for v, d in self.profdicts.items():
|
|
158
157
|
if isinstance(d, str):
|
|
159
158
|
self._profiles[v] = VerticalProfile.new(d)
|
|
@@ -166,9 +165,7 @@ class StatesTable(States):
|
|
|
166
165
|
raise TypeError(
|
|
167
166
|
f"States '{self.name}': Wrong profile type '{type(d).__name__}' for variable '{v}'. Expecting VerticalProfile, str or dict"
|
|
168
167
|
)
|
|
169
|
-
|
|
170
|
-
self._tvars -= set(self.fixed_vars.keys())
|
|
171
|
-
self._tvars = list(self._tvars)
|
|
168
|
+
|
|
172
169
|
super().initialize(algo, verbosity)
|
|
173
170
|
|
|
174
171
|
def sub_models(self):
|
|
@@ -213,13 +210,13 @@ class StatesTable(States):
|
|
|
213
210
|
if isinstance(self.data_source, pd.DataFrame):
|
|
214
211
|
data = self.data_source
|
|
215
212
|
else:
|
|
216
|
-
self.
|
|
213
|
+
self._data = get_input_path(self.data_source)
|
|
217
214
|
if not self.data_source.is_file():
|
|
218
215
|
if verbosity > 0:
|
|
219
216
|
print(
|
|
220
217
|
f"States '{self.name}': Reading static data '{self.data_source}' from context '{STATES}'"
|
|
221
218
|
)
|
|
222
|
-
self.
|
|
219
|
+
self._data = algo.dbook.get_file_path(
|
|
223
220
|
STATES, self.data_source.name, check_raw=False
|
|
224
221
|
)
|
|
225
222
|
if verbosity > 0:
|
|
@@ -245,6 +242,12 @@ class StatesTable(States):
|
|
|
245
242
|
f"Weight variable '{col_w}' defined in var2col, but not found in states table columns {data.columns}"
|
|
246
243
|
)
|
|
247
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)
|
|
250
|
+
|
|
248
251
|
tcols = []
|
|
249
252
|
for v in self._tvars:
|
|
250
253
|
c = self.var2col.get(v, v)
|
|
@@ -340,10 +343,10 @@ class StatesTable(States):
|
|
|
340
343
|
super().set_running(algo, data_stash, sel, isel, verbosity)
|
|
341
344
|
|
|
342
345
|
data_stash[self.name] = dict(
|
|
343
|
-
data_source=self.
|
|
346
|
+
data_source=self._data,
|
|
344
347
|
inds=self.__inds,
|
|
345
348
|
)
|
|
346
|
-
del self.
|
|
349
|
+
del self._data, self.__inds
|
|
347
350
|
|
|
348
351
|
def unset_running(
|
|
349
352
|
self,
|
|
@@ -375,7 +378,7 @@ class StatesTable(States):
|
|
|
375
378
|
super().unset_running(algo, data_stash, sel, isel, verbosity)
|
|
376
379
|
|
|
377
380
|
data = data_stash[self.name]
|
|
378
|
-
self.
|
|
381
|
+
self._data = data.pop("data_source")
|
|
379
382
|
self.__inds = data.pop("inds")
|
|
380
383
|
|
|
381
384
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
@@ -404,23 +407,13 @@ class StatesTable(States):
|
|
|
404
407
|
(n_states, n_targets, n_tpoints)
|
|
405
408
|
|
|
406
409
|
"""
|
|
410
|
+
self.ensure_output_vars(algo, tdata)
|
|
411
|
+
|
|
407
412
|
for i, v in enumerate(self._tvars):
|
|
408
|
-
|
|
409
|
-
tdata[v][:] = mdata[self.DATA][:, i, None, None]
|
|
410
|
-
else:
|
|
411
|
-
tdata[v] = np.zeros(
|
|
412
|
-
(tdata.n_states, tdata.n_targets, tdata.n_tpoints),
|
|
413
|
-
dtype=config.dtype_double,
|
|
414
|
-
)
|
|
415
|
-
tdata[v][:] = mdata[self.DATA][:, i, None, None]
|
|
416
|
-
tdata.dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
413
|
+
tdata[v][:] = mdata[self.DATA][:, i, None, None]
|
|
417
414
|
|
|
418
415
|
for v, f in self.fixed_vars.items():
|
|
419
|
-
tdata[v] =
|
|
420
|
-
(tdata.n_states, tdata.n_targets, tdata.n_tpoints),
|
|
421
|
-
f,
|
|
422
|
-
dtype=config.dtype_double,
|
|
423
|
-
)
|
|
416
|
+
tdata[v][:] = f
|
|
424
417
|
|
|
425
418
|
z = tdata[FC.TARGETS][..., 2]
|
|
426
419
|
for v, p in self._profiles.items():
|
|
@@ -569,7 +562,7 @@ class TabStates(StatesTable):
|
|
|
569
562
|
|
|
570
563
|
sel = weights > 0
|
|
571
564
|
|
|
572
|
-
self.
|
|
565
|
+
self._data = pd.DataFrame(
|
|
573
566
|
index=np.arange(np.sum(sel)),
|
|
574
567
|
data={
|
|
575
568
|
FV.WS: ws[sel],
|
|
@@ -577,7 +570,7 @@ class TabStates(StatesTable):
|
|
|
577
570
|
FV.WEIGHT: weights[sel],
|
|
578
571
|
},
|
|
579
572
|
)
|
|
580
|
-
self.
|
|
573
|
+
self._data.index.name = FC.STATE
|
|
581
574
|
|
|
582
575
|
return super().load_data(algo, verbosity)
|
|
583
576
|
|
|
@@ -0,0 +1,330 @@
|
|
|
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
|
+
rpars: dict
|
|
33
|
+
Additional parameters for reading the file
|
|
34
|
+
RDICT: dict
|
|
35
|
+
Default xarray file reading parameters
|
|
36
|
+
|
|
37
|
+
:group: input.states
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
RDICT = {}
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
data_source,
|
|
46
|
+
output_vars,
|
|
47
|
+
ws_bins=None,
|
|
48
|
+
var2ncvar={},
|
|
49
|
+
sel=None,
|
|
50
|
+
isel=None,
|
|
51
|
+
read_pars={},
|
|
52
|
+
**kwargs,
|
|
53
|
+
):
|
|
54
|
+
"""
|
|
55
|
+
Constructor.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
data_source: str or xarray.Dataset or pandas.DataFrame
|
|
60
|
+
Either path to NetCDF or csv file or data
|
|
61
|
+
output_vars: list of str
|
|
62
|
+
The output variables
|
|
63
|
+
ws_bins: list of float, optional
|
|
64
|
+
The wind speed bins, including
|
|
65
|
+
lower and upper bounds
|
|
66
|
+
var2ncvar: dict
|
|
67
|
+
Mapping from variable names to variable names
|
|
68
|
+
in the nc file
|
|
69
|
+
sel: dict, optional
|
|
70
|
+
Subset selection via xr.Dataset.sel()
|
|
71
|
+
isel: dict, optional
|
|
72
|
+
Subset selection via xr.Dataset.isel()
|
|
73
|
+
read_pars: dict
|
|
74
|
+
Additional parameters for reading the file
|
|
75
|
+
kwargs: dict, optional
|
|
76
|
+
Additional arguments for the base class
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
super().__init__(data_source, output_vars, var2col={}, **kwargs)
|
|
80
|
+
self.ws_bins = None if ws_bins is None else np.asarray(ws_bins)
|
|
81
|
+
self.var2ncvar = var2ncvar
|
|
82
|
+
self.sel = sel if sel is not None else {}
|
|
83
|
+
self.isel = isel if isel is not None else {}
|
|
84
|
+
self.rpars = read_pars
|
|
85
|
+
|
|
86
|
+
if FV.WS not in self.ovars:
|
|
87
|
+
raise ValueError(
|
|
88
|
+
f"States '{self.name}': Expecting output variable '{FV.WS}', got {self.ovars}"
|
|
89
|
+
)
|
|
90
|
+
for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT]:
|
|
91
|
+
if v in self.ovars:
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"States '{self.name}': Cannot have '{v}' as output variable"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
self._original_data = None
|
|
97
|
+
|
|
98
|
+
def __repr__(self):
|
|
99
|
+
return f"{type(self).__name__}(n_wd={self._n_wd}, n_ws={self._n_ws})"
|
|
100
|
+
|
|
101
|
+
def _read_data(self, algo, point_coord=None, verbosity=0):
|
|
102
|
+
"""
|
|
103
|
+
Extracts data from file or Dataset.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
algo: foxes.core.Algorithm
|
|
108
|
+
The calculation algorithm
|
|
109
|
+
point_coord: str, optional
|
|
110
|
+
The coordinate name representing the point index
|
|
111
|
+
verbosity: int
|
|
112
|
+
The verbosity level, 0 = silent
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
data: xarray.Dataset
|
|
117
|
+
The input data
|
|
118
|
+
|
|
119
|
+
"""
|
|
120
|
+
# store original data
|
|
121
|
+
if self._original_data is not None:
|
|
122
|
+
self._data = self._original_data
|
|
123
|
+
self._original_data = None
|
|
124
|
+
|
|
125
|
+
# read file or grab data
|
|
126
|
+
cwd = self.var2ncvar.get(FV.WD, FV.WD)
|
|
127
|
+
if isinstance(self.data_source, (str, PathLike)):
|
|
128
|
+
fpath = get_input_path(self.data_source)
|
|
129
|
+
if not fpath.is_file():
|
|
130
|
+
if verbosity > 0:
|
|
131
|
+
print(
|
|
132
|
+
f"States '{self.name}': Reading static data '{fpath}' from context '{STATES}'"
|
|
133
|
+
)
|
|
134
|
+
fpath = algo.dbook.get_file_path(STATES, fpath.name, check_raw=False)
|
|
135
|
+
if verbosity > 0:
|
|
136
|
+
print(f"Path: {fpath}")
|
|
137
|
+
elif verbosity > 0:
|
|
138
|
+
print(f"States '{self.name}': Reading file {fpath}")
|
|
139
|
+
rpars = dict(self.RDICT, **self.rpars)
|
|
140
|
+
if fpath.suffix == ".nc":
|
|
141
|
+
data = open_dataset(fpath, engine=config.nc_engine, **rpars)
|
|
142
|
+
else:
|
|
143
|
+
data = PandasFileHelper().read_file(fpath, **rpars)
|
|
144
|
+
data.index.name = cwd
|
|
145
|
+
data = data.to_xarray()
|
|
146
|
+
self._original_data = data
|
|
147
|
+
|
|
148
|
+
elif isinstance(self.data_source, Dataset):
|
|
149
|
+
data = self.data_source
|
|
150
|
+
|
|
151
|
+
elif isinstance(self.data_source, pd.DataFrame):
|
|
152
|
+
data = self.data_source
|
|
153
|
+
data.index.name = cwd
|
|
154
|
+
data = data.to_xarray()
|
|
155
|
+
|
|
156
|
+
# optionally select a subset
|
|
157
|
+
if self.isel is not None and len(self.isel):
|
|
158
|
+
data = data.isel(**self.isel)
|
|
159
|
+
if self.sel is not None and len(self.sel):
|
|
160
|
+
data = data.sel(**self.sel)
|
|
161
|
+
|
|
162
|
+
# remove wd 360 from the end, if wd 0 is given:
|
|
163
|
+
wd = data[cwd].to_numpy()
|
|
164
|
+
if wd[0] == 0.0 and wd[-1] == 360.0:
|
|
165
|
+
data = data.isel({cwd: np.s_[:-1]})
|
|
166
|
+
|
|
167
|
+
# construct wind speed bins and bin deltas
|
|
168
|
+
cws = self.var2ncvar.get(FV.WS, FV.WS)
|
|
169
|
+
if self.ws_bins is not None:
|
|
170
|
+
wsb = self.ws_bins
|
|
171
|
+
wss = 0.5 * (wsb[:-1] + wsb[1:])
|
|
172
|
+
elif cws in data:
|
|
173
|
+
wss = data[cws].to_numpy()
|
|
174
|
+
wsb = np.zeros((len(wss) + 1,), dtype=config.dtype_double)
|
|
175
|
+
wsb[1:-1] = 0.5 * (wss[1:] + wss[:-1])
|
|
176
|
+
wsb[0] = wss[0] - 0.5 * wsb[1]
|
|
177
|
+
wsb[-1] = wss[-1] + 0.5 * wsb[-2]
|
|
178
|
+
self.ws_bins = wsb
|
|
179
|
+
else:
|
|
180
|
+
raise ValueError(
|
|
181
|
+
f"States '{self.name}': Expecting ws_bins argument, since '{cws}' not found in data"
|
|
182
|
+
)
|
|
183
|
+
wsd = wsb[1:] - wsb[:-1]
|
|
184
|
+
n_ws = len(wss)
|
|
185
|
+
del wsb
|
|
186
|
+
|
|
187
|
+
# prepare data binning
|
|
188
|
+
if self._original_data is None:
|
|
189
|
+
self._original_data = self.data_source
|
|
190
|
+
cpt = (
|
|
191
|
+
self.var2ncvar.get(FC.POINT, FC.POINT) if point_coord is not None else None
|
|
192
|
+
)
|
|
193
|
+
n_wd = data.sizes[cwd]
|
|
194
|
+
self.BIN_WD = self.var("bin_wd")
|
|
195
|
+
self.BIN_WS = self.var("bin_ws")
|
|
196
|
+
self.POINT = self.var("point")
|
|
197
|
+
if cpt is None:
|
|
198
|
+
n_pt = 0
|
|
199
|
+
shp = (n_wd, n_ws)
|
|
200
|
+
dms = (self.BIN_WD, self.BIN_WS)
|
|
201
|
+
else:
|
|
202
|
+
n_pt = data.sizes[cpt]
|
|
203
|
+
shp = (n_wd, n_ws, n_pt)
|
|
204
|
+
dms = (self.BIN_WD, self.BIN_WS, self.POINT)
|
|
205
|
+
|
|
206
|
+
# create binned data
|
|
207
|
+
self._data = {
|
|
208
|
+
FV.WD: np.zeros(shp, dtype=config.dtype_double),
|
|
209
|
+
FV.WS: np.zeros(shp, dtype=config.dtype_double),
|
|
210
|
+
}
|
|
211
|
+
if cpt is None:
|
|
212
|
+
self._data[FV.WD][:] = data[cwd].to_numpy()[:, None]
|
|
213
|
+
self._data[FV.WS][:] = wss[None, :]
|
|
214
|
+
else:
|
|
215
|
+
self._data[FV.WD][:] = data[cwd].to_numpy()[:, None, None]
|
|
216
|
+
self._data[FV.WS][:] = wss[None, :, None]
|
|
217
|
+
for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT] + self.ovars:
|
|
218
|
+
if v not in [FV.WS, FV.WD] and v not in self.fixed_vars:
|
|
219
|
+
w = self.var2ncvar.get(v, v)
|
|
220
|
+
if w not in data:
|
|
221
|
+
raise KeyError(
|
|
222
|
+
f"States '{self.name}': Missing variable '{w}' in data, found {list(data.data_vars.keys())}"
|
|
223
|
+
)
|
|
224
|
+
d = data[w]
|
|
225
|
+
iws = d.dims.index(cws) if cws in d.dims else -1
|
|
226
|
+
iwd = d.dims.index(cwd) if cwd in d.dims else -1
|
|
227
|
+
ipt = d.dims.index(cpt) if cpt is not None and cpt in d.dims else -1
|
|
228
|
+
d = d.to_numpy()
|
|
229
|
+
if v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT]:
|
|
230
|
+
if cws in data[w].dims:
|
|
231
|
+
raise ValueError(
|
|
232
|
+
f"States '{self.name}': Cannot have '{cws}' as dimension in variable '{v}', got {data[w].dims}"
|
|
233
|
+
)
|
|
234
|
+
if cwd not in data[w].dims:
|
|
235
|
+
raise ValueError(
|
|
236
|
+
f"States '{self.name}': Expecting '{cwd}' as dimension in variable '{v}', got {data[w].dims}"
|
|
237
|
+
)
|
|
238
|
+
if iws < 0 and iwd < 0 and ipt < 0:
|
|
239
|
+
self.fixed_vars[v] = d.to_numpy()
|
|
240
|
+
elif iws >= 0 and iwd >= 0 and ipt >= 0:
|
|
241
|
+
self._data[v] = np.moveaxis(d, [iwd, iws, ipt], [0, 1, 2])
|
|
242
|
+
elif iws >= 0 and iwd >= 0 and ipt < 0:
|
|
243
|
+
if cpt is None:
|
|
244
|
+
self._data[v] = np.moveaxis(d, [iwd, iws], [0, 1])
|
|
245
|
+
else:
|
|
246
|
+
self._data[v] = np.zeros(shp, dtype=config.dtype_double)
|
|
247
|
+
self._data[v][:] = np.moveaxis(d, [iwd, iws], [0, 1])[
|
|
248
|
+
:, :, None
|
|
249
|
+
]
|
|
250
|
+
elif iws >= 0 and iwd < 0 and ipt >= 0:
|
|
251
|
+
self._data[v] = np.zeros(shp, dtype=config.dtype_double)
|
|
252
|
+
self._data[v][:] = np.moveaxis(d, [iws, ipt], [0, 1])[None, :, :]
|
|
253
|
+
elif iws < 0 and iwd >= 0 and ipt >= 0:
|
|
254
|
+
self._data[v] = np.zeros(shp, dtype=config.dtype_double)
|
|
255
|
+
self._data[v][:] = np.moveaxis(d, [iwd, ipt], [0, 1])[:, None, :]
|
|
256
|
+
elif iws >= 0 and iwd < 0 and ipt < 0:
|
|
257
|
+
self._data[v] = np.zeros(shp, dtype=config.dtype_double)
|
|
258
|
+
if cpt is None:
|
|
259
|
+
self._data[v][:] = d[None, :]
|
|
260
|
+
else:
|
|
261
|
+
self._data[v][:] = d[None, :, None]
|
|
262
|
+
elif iws < 0 and iwd >= 0 and ipt < 0:
|
|
263
|
+
self._data[v] = np.zeros(shp, dtype=config.dtype_double)
|
|
264
|
+
if cpt is None:
|
|
265
|
+
self._data[v][:] = d[:, None]
|
|
266
|
+
else:
|
|
267
|
+
self._data[v][:] = d[:, None, None]
|
|
268
|
+
elif iws < 0 and iwd < 0 and ipt >= 0:
|
|
269
|
+
self._data[v] = np.zeros(shp, dtype=config.dtype_double)
|
|
270
|
+
self._data[v][:] = d[None, None, :]
|
|
271
|
+
|
|
272
|
+
# compute Weibull weights
|
|
273
|
+
self._data[FV.WEIGHT] *= weibull_weights(
|
|
274
|
+
ws=wss[None, :, None] if cpt is not None else wss[None, :],
|
|
275
|
+
ws_deltas=wsd[None, :, None] if cpt is not None else wsd[None, :],
|
|
276
|
+
A=self._data.pop(FV.WEIBULL_A),
|
|
277
|
+
k=self._data.pop(FV.WEIBULL_k),
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# translate binned data to states
|
|
281
|
+
self._n_pt = n_pt
|
|
282
|
+
self._n_wd = n_wd
|
|
283
|
+
self._n_ws = n_ws
|
|
284
|
+
self._N = n_wd * n_ws
|
|
285
|
+
self._data = Dataset(
|
|
286
|
+
data_vars={v: (dms, d) for v, d in self._data.items()},
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
return data
|
|
290
|
+
|
|
291
|
+
def load_data(self, algo, verbosity=0):
|
|
292
|
+
"""
|
|
293
|
+
Load and/or create all model data that is subject to chunking.
|
|
294
|
+
|
|
295
|
+
Such data should not be stored under self, for memory reasons. The
|
|
296
|
+
data returned here will automatically be chunked and then provided
|
|
297
|
+
as part of the mdata object during calculations.
|
|
298
|
+
|
|
299
|
+
Parameters
|
|
300
|
+
----------
|
|
301
|
+
algo: foxes.core.Algorithm
|
|
302
|
+
The calculation algorithm
|
|
303
|
+
verbosity: int
|
|
304
|
+
The verbosity level, 0 = silent
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
idata: dict
|
|
309
|
+
The dict has exactly two entries: `data_vars`,
|
|
310
|
+
a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
|
|
311
|
+
and `coords`, a dict with entries `dim_name_str -> dim_array`
|
|
312
|
+
|
|
313
|
+
"""
|
|
314
|
+
self._read_data(algo, verbosity=0)
|
|
315
|
+
|
|
316
|
+
tmp = {}
|
|
317
|
+
for v, d in self._data.data_vars.items():
|
|
318
|
+
if self.POINT in d.dims:
|
|
319
|
+
raise TypeError(
|
|
320
|
+
f"States '{self.name}': Variable '{v}' has unsupported dimension '{self.POINT}', dims = {d.dims}"
|
|
321
|
+
)
|
|
322
|
+
else:
|
|
323
|
+
tmp[v] = d.to_numpy().reshape(self._N)
|
|
324
|
+
self._data = tmp
|
|
325
|
+
del tmp
|
|
326
|
+
|
|
327
|
+
self._data = pd.DataFrame(data=self._data, index=np.arange(self._N))
|
|
328
|
+
self._data.index.name = FC.STATE
|
|
329
|
+
|
|
330
|
+
return super().load_data(algo, verbosity)
|
foxes/input/states/wrg_states.py
CHANGED
|
@@ -3,7 +3,7 @@ from scipy.interpolate import interpn
|
|
|
3
3
|
|
|
4
4
|
from foxes.core.states import States
|
|
5
5
|
from foxes.config import config, get_input_path
|
|
6
|
-
from foxes.utils
|
|
6
|
+
from foxes.utils import ReaderWRG, weibull_weights
|
|
7
7
|
from foxes.data import STATES
|
|
8
8
|
import foxes.variables as FV
|
|
9
9
|
import foxes.constants as FC
|
|
@@ -132,7 +132,7 @@ class WRGStates(States):
|
|
|
132
132
|
self._y = p0[1] + np.arange(ny) * res
|
|
133
133
|
self._y = self._y[sy]
|
|
134
134
|
if len(self._x) < 2 or len(self._y) < 2:
|
|
135
|
-
raise ValueError(
|
|
135
|
+
raise ValueError("No overlap between data bounds and farm bounds")
|
|
136
136
|
p0[0] = np.min(self._x)
|
|
137
137
|
p0[1] = np.min(self._y)
|
|
138
138
|
p1[0] = np.max(self._x)
|
|
@@ -229,8 +229,8 @@ class WRGStates(States):
|
|
|
229
229
|
(n_states, n_targets, n_tpoints)
|
|
230
230
|
|
|
231
231
|
"""
|
|
232
|
-
|
|
233
232
|
# prepare:
|
|
233
|
+
self.ensure_output_vars(algo, tdata)
|
|
234
234
|
n_states = tdata.n_states
|
|
235
235
|
n_targets = tdata.n_targets
|
|
236
236
|
n_tpoints = tdata.n_tpoints
|
|
@@ -293,9 +293,11 @@ class WRGStates(States):
|
|
|
293
293
|
dims=(FC.STATE, FC.TARGET, FC.TPOINT),
|
|
294
294
|
)
|
|
295
295
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
296
|
+
tdata[FV.WEIGHT] *= weibull_weights(
|
|
297
|
+
ws=out[FV.WS],
|
|
298
|
+
ws_deltas=wsd[:, None, None],
|
|
299
|
+
A=A,
|
|
300
|
+
k=k,
|
|
299
301
|
)
|
|
300
302
|
|
|
301
303
|
return out
|
foxes/input/yaml/__init__.py
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
from .dict import read_dict
|
|
2
|
-
from .
|
|
3
|
-
from .
|
|
1
|
+
from .dict import read_dict as read_dict
|
|
2
|
+
from .dict import run_dict as run_dict
|
|
3
|
+
from .dict import run_outputs as run_outputs
|
|
4
|
+
from .dict import run_obj_function as run_obj_function
|
|
5
|
+
from .dict import get_output_obj as get_output_obj
|
|
6
|
+
|
|
7
|
+
from .yaml import foxes_yaml as foxes_yaml
|
|
8
|
+
from .windio.windio import read_windio as read_windio
|
|
9
|
+
from .windio.windio import foxes_windio as foxes_windio
|