foxes 1.3__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 +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 +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 +21 -17
- foxes/algorithms/__init__.py +6 -6
- foxes/algorithms/downwind/__init__.py +2 -2
- foxes/algorithms/downwind/downwind.py +44 -12
- 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 +0 -1
- foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
- 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 +0 -1
- foxes/core/data.py +19 -18
- foxes/core/engine.py +9 -13
- foxes/core/farm_controller.py +2 -2
- 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 +3 -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/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 -12
- foxes/input/states/create/__init__.py +3 -2
- foxes/input/states/field_data_nc.py +10 -24
- foxes/input/states/multi_height.py +9 -6
- foxes/input/states/one_point_flow.py +0 -4
- foxes/input/states/single.py +1 -1
- foxes/input/states/states_table.py +10 -7
- foxes/input/states/weibull_sectors.py +225 -0
- foxes/input/states/wrg_states.py +7 -5
- 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 +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 +3 -3
- 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 +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 +2 -2
- foxes/output/farm_results_eval.py +15 -15
- foxes/output/flow_plots_2d/__init__.py +2 -2
- foxes/output/flow_plots_2d/get_fig.py +4 -2
- foxes/output/rose_plot.py +3 -3
- 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/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.3.dist-info → foxes-1.4.dist-info}/METADATA +6 -15
- foxes-1.4.dist-info/RECORD +320 -0
- {foxes-1.3.dist-info → foxes-1.4.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/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.4.dist-info}/entry_points.txt +0 -0
- {foxes-1.3.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
- {foxes-1.3.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
foxes/input/states/__init__.py
CHANGED
|
@@ -2,18 +2,28 @@
|
|
|
2
2
|
Atmospheric input states.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .single import SingleStateStates
|
|
6
|
-
from .scan import ScanStates
|
|
7
|
-
from .
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
|
|
5
|
+
from .single import SingleStateStates as SingleStateStates
|
|
6
|
+
from .scan import ScanStates as ScanStates
|
|
7
|
+
from .field_data_nc import FieldDataNC as FieldDataNC
|
|
8
|
+
from .wrg_states import WRGStates as WRGStates
|
|
9
|
+
from .weibull_sectors import WeibullSectors as WeibullSectors
|
|
10
|
+
|
|
11
|
+
from .states_table import StatesTable as StatesTable
|
|
12
|
+
from .states_table import Timeseries as Timeseries
|
|
13
|
+
from .states_table import TabStates as TabStates
|
|
14
|
+
|
|
15
|
+
from .multi_height import MultiHeightStates as MultiHeightStates
|
|
16
|
+
from .multi_height import MultiHeightTimeseries as MultiHeightTimeseries
|
|
17
|
+
from .multi_height import MultiHeightNCStates as MultiHeightNCStates
|
|
18
|
+
from .multi_height import MultiHeightNCTimeseries as MultiHeightNCTimeseries
|
|
19
|
+
|
|
20
|
+
from .one_point_flow import OnePointFlowStates as OnePointFlowStates
|
|
21
|
+
from .one_point_flow import OnePointFlowTimeseries as OnePointFlowTimeseries
|
|
22
|
+
from .one_point_flow import (
|
|
23
|
+
OnePointFlowMultiHeightTimeseries as OnePointFlowMultiHeightTimeseries,
|
|
24
|
+
)
|
|
11
25
|
from .one_point_flow import (
|
|
12
|
-
|
|
13
|
-
OnePointFlowTimeseries,
|
|
14
|
-
OnePointFlowMultiHeightTimeseries,
|
|
15
|
-
OnePointFlowMultiHeightNCTimeseries,
|
|
26
|
+
OnePointFlowMultiHeightNCTimeseries as OnePointFlowMultiHeightNCTimeseries,
|
|
16
27
|
)
|
|
17
|
-
from .wrg_states import WRGStates
|
|
18
28
|
|
|
19
|
-
from . import create
|
|
29
|
+
from . import create as create
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
from .random_abl_states import create_random_abl_states
|
|
2
|
-
from .
|
|
1
|
+
from .random_abl_states import create_random_abl_states as create_random_abl_states
|
|
2
|
+
from .random_abl_states import write_random_abl_states as write_random_abl_states
|
|
3
|
+
from .random_timeseries import random_timseries_data as random_timseries_data
|
|
@@ -303,7 +303,7 @@ class FieldDataNC(States):
|
|
|
303
303
|
d = data[..., i]
|
|
304
304
|
nn = np.sum(np.isnan(d))
|
|
305
305
|
print(
|
|
306
|
-
f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100*nn/len(d.flat):.2f}%)"
|
|
306
|
+
f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100 * nn / len(d.flat):.2f}%)"
|
|
307
307
|
)
|
|
308
308
|
|
|
309
309
|
return sts, h, y, x, data, weights
|
|
@@ -352,7 +352,6 @@ class FieldDataNC(States):
|
|
|
352
352
|
# pre-load file reading:
|
|
353
353
|
coords = [self.states_coord, self.h_coord, self.y_coord, self.x_coord]
|
|
354
354
|
if not isinstance(self.data_source, xr.Dataset):
|
|
355
|
-
|
|
356
355
|
# check variables:
|
|
357
356
|
for v in self.ovars:
|
|
358
357
|
if v == FV.WEIGHT and self.weight_ncvar is None:
|
|
@@ -422,7 +421,6 @@ class FieldDataNC(States):
|
|
|
422
421
|
)
|
|
423
422
|
|
|
424
423
|
if self.load_mode in ["preload", "lazy"]:
|
|
425
|
-
|
|
426
424
|
if self.load_mode == "lazy":
|
|
427
425
|
try:
|
|
428
426
|
self.__data_source = [ds.chunk() for ds in self.__data_source]
|
|
@@ -460,6 +458,11 @@ class FieldDataNC(States):
|
|
|
460
458
|
self.__inds, format=self.time_format
|
|
461
459
|
).to_numpy()
|
|
462
460
|
|
|
461
|
+
# given data is already Dataset:
|
|
462
|
+
else:
|
|
463
|
+
self.__inds = self.data_source[self.states_coord].to_numpy()
|
|
464
|
+
self._N = len(self.__inds)
|
|
465
|
+
|
|
463
466
|
# ensure WD and WS get the first two slots of data:
|
|
464
467
|
self._dkys = {}
|
|
465
468
|
if FV.WS in self.ovars:
|
|
@@ -601,23 +604,6 @@ class FieldDataNC(States):
|
|
|
601
604
|
raise ValueError(f"States '{self.name}': Cannot access index while running")
|
|
602
605
|
return self.__inds
|
|
603
606
|
|
|
604
|
-
def output_point_vars(self, algo):
|
|
605
|
-
"""
|
|
606
|
-
The variables which are being modified by the model.
|
|
607
|
-
|
|
608
|
-
Parameters
|
|
609
|
-
----------
|
|
610
|
-
algo: foxes.core.Algorithm
|
|
611
|
-
The calculation algorithm
|
|
612
|
-
|
|
613
|
-
Returns
|
|
614
|
-
-------
|
|
615
|
-
output_vars: list of str
|
|
616
|
-
The output variable names
|
|
617
|
-
|
|
618
|
-
"""
|
|
619
|
-
return self.ovars
|
|
620
|
-
|
|
621
607
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
622
608
|
"""
|
|
623
609
|
The main model calculation.
|
|
@@ -706,9 +692,9 @@ class FieldDataNC(States):
|
|
|
706
692
|
i0 += b - a
|
|
707
693
|
j0 = j1
|
|
708
694
|
|
|
709
|
-
assert (
|
|
710
|
-
i0
|
|
711
|
-
)
|
|
695
|
+
assert i0 == i1, (
|
|
696
|
+
f"States '{self.name}': Missing states for load_mode '{self.load_mode}': (i0, i1) = {(i0, i1)}"
|
|
697
|
+
)
|
|
712
698
|
|
|
713
699
|
data = xr.concat(data, dim=self.states_coord)
|
|
714
700
|
__, h, y, x, data, weights = self._get_data(data, coords, verbosity=0)
|
|
@@ -830,7 +816,7 @@ class FieldDataNC(States):
|
|
|
830
816
|
if v != FV.WEIGHT and v not in out:
|
|
831
817
|
if v in self._dkys:
|
|
832
818
|
out[v] = data[..., self._dkys[v]]
|
|
833
|
-
|
|
819
|
+
elif v in self.fixed_vars:
|
|
834
820
|
out[v] = np.full(
|
|
835
821
|
(n_states, n_pts), self.fixed_vars[v], dtype=config.dtype_double
|
|
836
822
|
)
|
|
@@ -36,7 +36,7 @@ class MultiHeightStates(States):
|
|
|
36
36
|
fixed_vars: dict, optional
|
|
37
37
|
Fixed uniform variable values, instead of
|
|
38
38
|
reading from data
|
|
39
|
-
|
|
39
|
+
read_pars: dict, optional
|
|
40
40
|
pandas file reading parameters
|
|
41
41
|
states_sel: slice or range or list of int
|
|
42
42
|
States subset selection
|
|
@@ -58,7 +58,7 @@ class MultiHeightStates(States):
|
|
|
58
58
|
heights,
|
|
59
59
|
var2col={},
|
|
60
60
|
fixed_vars={},
|
|
61
|
-
|
|
61
|
+
read_pars={},
|
|
62
62
|
states_sel=None,
|
|
63
63
|
states_loc=None,
|
|
64
64
|
**ipars,
|
|
@@ -79,7 +79,7 @@ class MultiHeightStates(States):
|
|
|
79
79
|
fixed_vars: dict, optional
|
|
80
80
|
Fixed uniform variable values, instead of
|
|
81
81
|
reading from data
|
|
82
|
-
|
|
82
|
+
read_pars: dict, optional
|
|
83
83
|
pandas file reading parameters
|
|
84
84
|
states_sel: slice or range or list of int, optional
|
|
85
85
|
States subset selection
|
|
@@ -93,7 +93,7 @@ class MultiHeightStates(States):
|
|
|
93
93
|
|
|
94
94
|
self.ovars = list(output_vars)
|
|
95
95
|
self.heights = np.array(heights, dtype=config.dtype_double)
|
|
96
|
-
self.rpars =
|
|
96
|
+
self.rpars = read_pars
|
|
97
97
|
self.var2col = var2col
|
|
98
98
|
self.fixed_vars = fixed_vars
|
|
99
99
|
self.ipars = ipars
|
|
@@ -572,7 +572,7 @@ class MultiHeightNCStates(MultiHeightStates):
|
|
|
572
572
|
data_source,
|
|
573
573
|
*args,
|
|
574
574
|
heights=[],
|
|
575
|
-
|
|
575
|
+
read_pars=None,
|
|
576
576
|
**kwargs,
|
|
577
577
|
)
|
|
578
578
|
self.state_coord = state_coord
|
|
@@ -631,7 +631,10 @@ class MultiHeightNCStates(MultiHeightStates):
|
|
|
631
631
|
self._inds = data.coords[self.state_coord].to_numpy()
|
|
632
632
|
|
|
633
633
|
if self._format_times_func == "default":
|
|
634
|
-
|
|
634
|
+
|
|
635
|
+
def format_times_func(t):
|
|
636
|
+
"""little helper function to convert times to datetime64"""
|
|
637
|
+
return t.astype("datetime64[ns]")
|
|
635
638
|
else:
|
|
636
639
|
format_times_func = self._format_times_func
|
|
637
640
|
if format_times_func is not None:
|
|
@@ -260,7 +260,6 @@ class OnePointFlowStates(States):
|
|
|
260
260
|
self.timelines_data = data.pop("data")
|
|
261
261
|
|
|
262
262
|
def calc_states_indices(self, algo, mdata, points, hi, ref_xy):
|
|
263
|
-
|
|
264
263
|
n_states, n_points = points.shape[:2]
|
|
265
264
|
dxy = self.timelines_data["dxy"].to_numpy()[hi]
|
|
266
265
|
|
|
@@ -301,7 +300,6 @@ class OnePointFlowStates(States):
|
|
|
301
300
|
sel = np.isnan(coeffs)
|
|
302
301
|
tshift = 0
|
|
303
302
|
while np.any(sel):
|
|
304
|
-
|
|
305
303
|
trs = trace_si[sel]
|
|
306
304
|
hdxy = -dxy[trs]
|
|
307
305
|
trace_p[sel] += hdxy
|
|
@@ -326,7 +324,6 @@ class OnePointFlowStates(States):
|
|
|
326
324
|
sel &= trace_si < algo.n_states
|
|
327
325
|
tshift = 1
|
|
328
326
|
while np.any(sel):
|
|
329
|
-
|
|
330
327
|
trs = trace_si[sel]
|
|
331
328
|
hdxy = dxy[trs]
|
|
332
329
|
trace_p[sel] += hdxy
|
|
@@ -420,7 +417,6 @@ class OnePointFlowStates(States):
|
|
|
420
417
|
|
|
421
418
|
# interpolate to heights:
|
|
422
419
|
if n_heights > 1:
|
|
423
|
-
|
|
424
420
|
ar_states = np.arange(n_states)
|
|
425
421
|
ar_points = np.arange(n_points)
|
|
426
422
|
|
foxes/input/states/single.py
CHANGED
|
@@ -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
|
|
@@ -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):
|
|
@@ -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)
|
|
@@ -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)
|
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)
|
|
@@ -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
|
foxes/input/yaml/dict.py
CHANGED
|
@@ -75,13 +75,13 @@ def read_dict(
|
|
|
75
75
|
print(*args, **kwargs)
|
|
76
76
|
|
|
77
77
|
# set working directory:
|
|
78
|
-
|
|
78
|
+
ld = 0
|
|
79
79
|
for c, d in zip(
|
|
80
80
|
[FC.WORK_DIR, FC.INPUT_DIR, FC.OUTPUT_DIR], [work_dir, input_dir, output_dir]
|
|
81
81
|
):
|
|
82
82
|
if d is not None:
|
|
83
83
|
config[c] = d
|
|
84
|
-
|
|
84
|
+
ld = max(ld, len(str(d)))
|
|
85
85
|
_print("\n--------------------- Reading foxes parameter dict ---------------------")
|
|
86
86
|
_print("Working directory :", config.work_dir)
|
|
87
87
|
_print("Input directory :", config.input_dir)
|
|
@@ -95,9 +95,9 @@ def read_dict(
|
|
|
95
95
|
else:
|
|
96
96
|
states = algo.states
|
|
97
97
|
else:
|
|
98
|
-
assert (
|
|
99
|
-
algo
|
|
100
|
-
)
|
|
98
|
+
assert algo is None, (
|
|
99
|
+
"Cannot handle both the algo and the states argument, please drop one"
|
|
100
|
+
)
|
|
101
101
|
|
|
102
102
|
# create model book:
|
|
103
103
|
if mbook is None:
|
|
@@ -119,9 +119,9 @@ def read_dict(
|
|
|
119
119
|
else:
|
|
120
120
|
mbook = algo.mbook
|
|
121
121
|
else:
|
|
122
|
-
assert (
|
|
123
|
-
algo
|
|
124
|
-
)
|
|
122
|
+
assert algo is None, (
|
|
123
|
+
"Cannot handle both the algo and the mbook argument, please drop one"
|
|
124
|
+
)
|
|
125
125
|
|
|
126
126
|
# create farm:
|
|
127
127
|
if farm is None:
|
|
@@ -129,8 +129,8 @@ def read_dict(
|
|
|
129
129
|
_print("Creating wind farm")
|
|
130
130
|
fdict = idict.get_item("wind_farm")
|
|
131
131
|
lyts = [
|
|
132
|
-
Dict(
|
|
133
|
-
for i,
|
|
132
|
+
Dict(lo, name=f"{fdict.name}.layout{i}")
|
|
133
|
+
for i, lo in enumerate(fdict.pop_item("layouts"))
|
|
134
134
|
]
|
|
135
135
|
farm = WindFarm(**fdict)
|
|
136
136
|
for lyt in lyts:
|
|
@@ -141,9 +141,9 @@ def read_dict(
|
|
|
141
141
|
else:
|
|
142
142
|
farm = algo.farm
|
|
143
143
|
else:
|
|
144
|
-
assert (
|
|
145
|
-
algo
|
|
146
|
-
)
|
|
144
|
+
assert algo is None, (
|
|
145
|
+
"Cannot handle both the algo and the farm argument, please drop one"
|
|
146
|
+
)
|
|
147
147
|
|
|
148
148
|
# create engine:
|
|
149
149
|
engine = None
|
|
@@ -321,12 +321,12 @@ def run_obj_function(
|
|
|
321
321
|
|
|
322
322
|
def _set_label(rlabels, k, r):
|
|
323
323
|
if k not in ["", "none", "None", "_", "__"]:
|
|
324
|
-
assert (
|
|
325
|
-
|
|
326
|
-
)
|
|
327
|
-
assert (
|
|
328
|
-
"
|
|
329
|
-
)
|
|
324
|
+
assert k[0] == "$", (
|
|
325
|
+
f"Output {i} of type '{ocls}', function '{fname}': result labels must start with '$', got '{k}'"
|
|
326
|
+
)
|
|
327
|
+
assert "[" not in k and "]" not in k and "," not in k, (
|
|
328
|
+
f"Output {i} of type '{ocls}', function '{fname}': result labels cannot contain '[' or ']' or comma, got '{k}'"
|
|
329
|
+
)
|
|
330
330
|
_print(f" result label {k}: {type(r).__name__}")
|
|
331
331
|
rlabels[k] = r
|
|
332
332
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
from .windio import foxes_windio
|
|
2
|
-
from .
|
|
3
|
-
|
|
4
|
-
from .read_farm import read_layout
|
|
5
|
-
from .
|
|
1
|
+
from .windio import foxes_windio as foxes_windio
|
|
2
|
+
from .windio import read_windio as read_windio
|
|
3
|
+
|
|
4
|
+
from .read_farm import read_layout as read_layout
|
|
5
|
+
from .read_farm import read_turbine_types as read_turbine_types
|
|
6
|
+
from .read_farm import read_farm as read_farm
|
|
7
|
+
|
|
8
|
+
from .read_site import read_site as read_site
|
|
9
|
+
from .read_fields import read_wind_resource_field as read_wind_resource_field
|
|
10
|
+
from .read_attributes import read_attributes as read_attributes
|
|
@@ -202,7 +202,7 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
|
|
|
202
202
|
elif background_averaging in ["none", "None", None]:
|
|
203
203
|
algo_dict["rotor_model"] = None
|
|
204
204
|
elif background_averaging == "grid":
|
|
205
|
-
algo_dict["rotor_model"] = f"grid{nx*ny}"
|
|
205
|
+
algo_dict["rotor_model"] = f"grid{nx * ny}"
|
|
206
206
|
else:
|
|
207
207
|
algo_dict["rotor_model"] = background_averaging
|
|
208
208
|
|
|
@@ -215,7 +215,7 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
|
|
|
215
215
|
algo_dict["partial_wakes"] = "rotor_points"
|
|
216
216
|
else:
|
|
217
217
|
if grid == "grid":
|
|
218
|
-
algo_dict["partial_wakes"] = f"grid{nx*ny}"
|
|
218
|
+
algo_dict["partial_wakes"] = f"grid{nx * ny}"
|
|
219
219
|
else:
|
|
220
220
|
algo_dict["partial_wakes"] = grid
|
|
221
221
|
else:
|