foxes 0.8.2__py3-none-any.whl → 1.1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of foxes might be problematic. Click here for more details.
- docs/source/conf.py +353 -0
- examples/abl_states/run.py +160 -0
- examples/compare_rotors_pwakes/run.py +217 -0
- examples/compare_wakes/run.py +241 -0
- examples/dyn_wakes/run.py +311 -0
- examples/field_data_nc/run.py +121 -0
- examples/induction/run.py +201 -0
- examples/multi_height/run.py +113 -0
- examples/power_mask/run.py +249 -0
- examples/random_timeseries/run.py +210 -0
- examples/scan_row/run.py +193 -0
- examples/sector_management/run.py +162 -0
- examples/sequential/run.py +209 -0
- examples/single_state/run.py +201 -0
- examples/states_lookup_table/run.py +137 -0
- examples/streamline_wakes/run.py +138 -0
- examples/tab_file/run.py +142 -0
- examples/timelines/run.py +267 -0
- examples/timeseries/run.py +190 -0
- examples/timeseries_slurm/run.py +185 -0
- examples/wind_rose/run.py +141 -0
- examples/windio/run.py +29 -0
- examples/yawed_wake/run.py +196 -0
- foxes/__init__.py +4 -8
- foxes/algorithms/__init__.py +1 -1
- foxes/algorithms/downwind/downwind.py +247 -111
- foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
- foxes/algorithms/downwind/models/init_farm_data.py +2 -2
- foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
- foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
- foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
- foxes/algorithms/iterative/iterative.py +74 -34
- foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
- foxes/algorithms/iterative/models/urelax.py +3 -3
- foxes/algorithms/sequential/models/plugin.py +5 -5
- foxes/algorithms/sequential/models/seq_state.py +1 -1
- foxes/algorithms/sequential/sequential.py +126 -255
- foxes/constants.py +22 -7
- foxes/core/__init__.py +1 -0
- foxes/core/algorithm.py +632 -147
- foxes/core/data.py +252 -20
- foxes/core/data_calc_model.py +15 -291
- foxes/core/engine.py +640 -0
- foxes/core/farm_controller.py +38 -10
- foxes/core/farm_data_model.py +16 -1
- foxes/core/ground_model.py +2 -2
- foxes/core/model.py +249 -182
- foxes/core/partial_wakes_model.py +1 -1
- foxes/core/point_data_model.py +17 -2
- foxes/core/rotor_model.py +27 -21
- foxes/core/states.py +17 -1
- foxes/core/turbine_type.py +28 -0
- foxes/core/wake_frame.py +30 -34
- foxes/core/wake_model.py +5 -5
- foxes/core/wake_superposition.py +1 -1
- foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
- foxes/engines/__init__.py +17 -0
- foxes/engines/dask.py +982 -0
- foxes/engines/default.py +75 -0
- foxes/engines/futures.py +72 -0
- foxes/engines/mpi.py +38 -0
- foxes/engines/multiprocess.py +71 -0
- foxes/engines/numpy.py +167 -0
- foxes/engines/pool.py +249 -0
- foxes/engines/ray.py +79 -0
- foxes/engines/single.py +141 -0
- foxes/input/farm_layout/__init__.py +1 -0
- foxes/input/farm_layout/from_csv.py +4 -0
- foxes/input/farm_layout/from_json.py +2 -2
- foxes/input/farm_layout/grid.py +2 -2
- foxes/input/farm_layout/ring.py +65 -0
- foxes/input/farm_layout/row.py +2 -2
- foxes/input/states/__init__.py +7 -0
- foxes/input/states/create/random_abl_states.py +1 -1
- foxes/input/states/field_data_nc.py +158 -33
- foxes/input/states/multi_height.py +128 -14
- foxes/input/states/one_point_flow.py +577 -0
- foxes/input/states/scan_ws.py +74 -3
- foxes/input/states/single.py +1 -1
- foxes/input/states/slice_data_nc.py +681 -0
- foxes/input/states/states_table.py +204 -35
- foxes/input/windio/__init__.py +2 -2
- foxes/input/windio/get_states.py +44 -23
- foxes/input/windio/read_attributes.py +48 -17
- foxes/input/windio/read_farm.py +116 -102
- foxes/input/windio/read_fields.py +16 -6
- foxes/input/windio/read_outputs.py +71 -24
- foxes/input/windio/runner.py +31 -17
- foxes/input/windio/windio.py +41 -23
- foxes/models/farm_models/turbine2farm.py +1 -1
- foxes/models/ground_models/wake_mirror.py +10 -6
- foxes/models/model_book.py +58 -20
- foxes/models/partial_wakes/axiwake.py +3 -3
- foxes/models/partial_wakes/rotor_points.py +3 -3
- foxes/models/partial_wakes/top_hat.py +2 -2
- foxes/models/point_models/set_uniform_data.py +1 -1
- foxes/models/point_models/tke2ti.py +1 -1
- foxes/models/point_models/wake_deltas.py +1 -1
- foxes/models/rotor_models/centre.py +4 -0
- foxes/models/rotor_models/grid.py +24 -25
- foxes/models/rotor_models/levels.py +4 -5
- foxes/models/turbine_models/calculator.py +4 -6
- foxes/models/turbine_models/kTI_model.py +22 -6
- foxes/models/turbine_models/lookup_table.py +30 -4
- foxes/models/turbine_models/rotor_centre_calc.py +4 -3
- foxes/models/turbine_models/set_farm_vars.py +103 -34
- foxes/models/turbine_types/PCt_file.py +27 -3
- foxes/models/turbine_types/PCt_from_two.py +27 -3
- foxes/models/turbine_types/TBL_file.py +80 -0
- foxes/models/turbine_types/__init__.py +2 -0
- foxes/models/turbine_types/lookup.py +316 -0
- foxes/models/turbine_types/null_type.py +51 -1
- foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
- foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
- foxes/models/vertical_profiles/__init__.py +1 -1
- foxes/models/vertical_profiles/data_profile.py +1 -1
- foxes/models/wake_frames/__init__.py +1 -0
- foxes/models/wake_frames/dynamic_wakes.py +424 -0
- foxes/models/wake_frames/farm_order.py +25 -5
- foxes/models/wake_frames/rotor_wd.py +6 -4
- foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
- foxes/models/wake_frames/streamlines.py +21 -22
- foxes/models/wake_frames/timelines.py +330 -129
- foxes/models/wake_frames/yawed_wakes.py +7 -4
- foxes/models/wake_models/dist_sliced.py +2 -4
- foxes/models/wake_models/induction/rankine_half_body.py +5 -5
- foxes/models/wake_models/induction/rathmann.py +78 -24
- foxes/models/wake_models/induction/self_similar.py +78 -28
- foxes/models/wake_models/induction/vortex_sheet.py +86 -48
- foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
- foxes/models/wake_models/ti/iec_ti.py +40 -21
- foxes/models/wake_models/top_hat.py +1 -1
- foxes/models/wake_models/wind/bastankhah14.py +8 -6
- foxes/models/wake_models/wind/bastankhah16.py +17 -16
- foxes/models/wake_models/wind/jensen.py +4 -3
- foxes/models/wake_models/wind/turbopark.py +16 -13
- foxes/models/wake_superpositions/ti_linear.py +1 -1
- foxes/models/wake_superpositions/ti_max.py +1 -1
- foxes/models/wake_superpositions/ti_pow.py +1 -1
- foxes/models/wake_superpositions/ti_quadratic.py +1 -1
- foxes/models/wake_superpositions/ws_linear.py +8 -7
- foxes/models/wake_superpositions/ws_max.py +8 -7
- foxes/models/wake_superpositions/ws_pow.py +8 -7
- foxes/models/wake_superpositions/ws_product.py +5 -5
- foxes/models/wake_superpositions/ws_quadratic.py +8 -7
- foxes/output/__init__.py +4 -1
- foxes/output/farm_layout.py +16 -12
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/flow_plots_2d/__init__.py +0 -1
- foxes/output/flow_plots_2d/flow_plots.py +70 -30
- foxes/output/grids.py +92 -22
- foxes/output/results_writer.py +2 -2
- foxes/output/rose_plot.py +3 -3
- foxes/output/seq_plugins/__init__.py +2 -0
- foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
- foxes/output/slice_data.py +131 -111
- foxes/output/state_turbine_map.py +19 -14
- foxes/output/state_turbine_table.py +19 -19
- foxes/utils/__init__.py +1 -1
- foxes/utils/abl/neutral.py +2 -2
- foxes/utils/abl/stable.py +2 -2
- foxes/utils/abl/unstable.py +2 -2
- foxes/utils/data_book.py +1 -1
- foxes/utils/dev_utils.py +42 -0
- foxes/utils/dict.py +24 -1
- foxes/utils/exec_python.py +1 -1
- foxes/utils/factory.py +176 -53
- foxes/utils/geom2d/circle.py +1 -1
- foxes/utils/geom2d/polygon.py +1 -1
- foxes/utils/geopandas_utils.py +2 -2
- foxes/utils/load.py +2 -2
- foxes/utils/pandas_helpers.py +3 -2
- foxes/utils/wind_dir.py +0 -2
- foxes/utils/xarray_utils.py +24 -14
- foxes/variables.py +39 -2
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
- foxes-1.1.0.2.dist-info/RECORD +309 -0
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
- foxes-1.1.0.2.dist-info/top_level.txt +4 -0
- tests/0_consistency/iterative/test_iterative.py +92 -0
- tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
- tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
- tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
- tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
- tests/3_examples/test_examples.py +34 -0
- foxes/VERSION +0 -1
- foxes/output/flow_plots_2d.py +0 -0
- foxes/utils/geopandas_helpers.py +0 -294
- foxes/utils/runners/__init__.py +0 -1
- foxes/utils/runners/runners.py +0 -280
- foxes-0.8.2.dist-info/RECORD +0 -247
- foxes-0.8.2.dist-info/top_level.txt +0 -1
- foxes-0.8.2.dist-info/zip-safe +0 -1
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/LICENSE +0 -0
|
@@ -26,7 +26,7 @@ class PCtFromTwo(TurbineType):
|
|
|
26
26
|
col_ct: str
|
|
27
27
|
The ct column
|
|
28
28
|
rho: float
|
|
29
|
-
The air
|
|
29
|
+
The air density for which the data is valid
|
|
30
30
|
or None for no correction
|
|
31
31
|
WSCT: str
|
|
32
32
|
The wind speed variable for ct lookup
|
|
@@ -76,7 +76,7 @@ class PCtFromTwo(TurbineType):
|
|
|
76
76
|
col_ct: str
|
|
77
77
|
The ct column
|
|
78
78
|
rho: float, optional
|
|
79
|
-
The air
|
|
79
|
+
The air density for which the data is valid
|
|
80
80
|
or None for no correction
|
|
81
81
|
p_ct: float
|
|
82
82
|
The exponent for yaw dependency of ct
|
|
@@ -126,6 +126,30 @@ class PCtFromTwo(TurbineType):
|
|
|
126
126
|
a += f", var_ws_ct={self.WSCT}, var_ws_P={self.WSP}"
|
|
127
127
|
return f"{type(self).__name__}({a})"
|
|
128
128
|
|
|
129
|
+
def needs_rews2(self):
|
|
130
|
+
"""
|
|
131
|
+
Returns flag for requiring REWS2 variable
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
flag: bool
|
|
136
|
+
True if REWS2 is required
|
|
137
|
+
|
|
138
|
+
"""
|
|
139
|
+
return self.WSCT == FV.REWS2 or self.WSP == FV.REWS2
|
|
140
|
+
|
|
141
|
+
def needs_rews3(self):
|
|
142
|
+
"""
|
|
143
|
+
Returns flag for requiring REWS3 variable
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
flag: bool
|
|
148
|
+
True if REWS3 is required
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
return self.WSCT == FV.REWS3 or self.WSP == FV.REWS3
|
|
152
|
+
|
|
129
153
|
def output_farm_vars(self, algo):
|
|
130
154
|
"""
|
|
131
155
|
The variables which are being modified by the model.
|
|
@@ -289,7 +313,7 @@ class PCtFromTwo(TurbineType):
|
|
|
289
313
|
super().modify_cutin(modify_ct, modify_P)
|
|
290
314
|
|
|
291
315
|
def calculate(self, algo, mdata, fdata, st_sel):
|
|
292
|
-
"""
|
|
316
|
+
"""
|
|
293
317
|
The main model calculation.
|
|
294
318
|
|
|
295
319
|
This function is executed on a single chunk of data,
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .PCt_file import PCtFile
|
|
6
|
+
from foxes.data import parse_Pct_file_name
|
|
7
|
+
import foxes.constants as FC
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TBLFile(PCtFile):
|
|
11
|
+
"""
|
|
12
|
+
Reads turbine data from a TBL file.
|
|
13
|
+
|
|
14
|
+
Examples
|
|
15
|
+
--------
|
|
16
|
+
A TBL file is a csv file with space as separator
|
|
17
|
+
and two header lines. The followind lines denote
|
|
18
|
+
wind speed, ct, P.
|
|
19
|
+
|
|
20
|
+
- first row will be ignored
|
|
21
|
+
- second row: H D ct-stand-still rated-power-in-MW
|
|
22
|
+
- further rows: ws ct P-in-kW
|
|
23
|
+
|
|
24
|
+
For example:
|
|
25
|
+
|
|
26
|
+
45
|
|
27
|
+
175.0 290.0 0.03 22.0
|
|
28
|
+
3.0 0.820 102.9
|
|
29
|
+
3.5 0.800 444.0
|
|
30
|
+
4.0 0.810 874.7
|
|
31
|
+
4.5 0.820 1418.7
|
|
32
|
+
5.0 0.820 2100.9
|
|
33
|
+
5.5 0.830 3021.2
|
|
34
|
+
6.0 0.830 3904.7
|
|
35
|
+
6.5 0.830 5061.7
|
|
36
|
+
7.0 0.810 6379.0
|
|
37
|
+
|
|
38
|
+
:group: models.turbine_types
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
tbl_file,
|
|
45
|
+
rho=1.225,
|
|
46
|
+
**parameters,
|
|
47
|
+
):
|
|
48
|
+
"""
|
|
49
|
+
Constructor.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
tbl_file: str
|
|
54
|
+
Path to the tbl file
|
|
55
|
+
rho: float
|
|
56
|
+
The air density for the curves
|
|
57
|
+
paramerers: dict, optional
|
|
58
|
+
Additional parameters for PCtFile class
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
fpath = Path(tbl_file)
|
|
62
|
+
assert fpath.suffix == ".tbl", f"Expecting *.tbl file, got '{tbl_file}'"
|
|
63
|
+
|
|
64
|
+
meta = np.genfromtxt(fpath, skip_header=1, max_rows=1)
|
|
65
|
+
sdata = pd.read_csv(
|
|
66
|
+
fpath, sep=" ", skiprows=2, header=None, names=["ws", "ct", "P"]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
super().__init__(
|
|
70
|
+
sdata,
|
|
71
|
+
col_ws="ws",
|
|
72
|
+
col_P="P",
|
|
73
|
+
col_ct="ct",
|
|
74
|
+
H=meta[0],
|
|
75
|
+
D=meta[1],
|
|
76
|
+
P_nominal=meta[3] * 1e3,
|
|
77
|
+
P_unit="kW",
|
|
78
|
+
rho=rho,
|
|
79
|
+
**parameters,
|
|
80
|
+
)
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
from foxes.core import TurbineType, FData
|
|
5
|
+
from foxes.data import parse_Pct_file_name
|
|
6
|
+
from foxes.models.turbine_models import LookupTable
|
|
7
|
+
import foxes.variables as FV
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FromLookupTable(TurbineType):
|
|
11
|
+
"""
|
|
12
|
+
Calculate power and ct by interpolating
|
|
13
|
+
by using a lookup-table
|
|
14
|
+
|
|
15
|
+
Attributes
|
|
16
|
+
----------
|
|
17
|
+
source: str or pandas.DataFrame
|
|
18
|
+
The file path, static name, or data
|
|
19
|
+
rho: float
|
|
20
|
+
The air density for which the data is valid
|
|
21
|
+
or None for no correction
|
|
22
|
+
WSCT: str
|
|
23
|
+
The wind speed variable for ct lookup
|
|
24
|
+
WSP: str
|
|
25
|
+
The wind speed variable for power lookup
|
|
26
|
+
rpars: dict, optional
|
|
27
|
+
Parameters for pandas file reading
|
|
28
|
+
|
|
29
|
+
:group: models.turbine_types
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
data_source,
|
|
36
|
+
input_vars,
|
|
37
|
+
varmap={},
|
|
38
|
+
lookup_pars={},
|
|
39
|
+
rho=None,
|
|
40
|
+
p_ct=1.0,
|
|
41
|
+
p_P=1.88,
|
|
42
|
+
var_ws_ct=FV.REWS2,
|
|
43
|
+
var_ws_P=FV.REWS3,
|
|
44
|
+
pd_file_read_pars={},
|
|
45
|
+
interpn_args={},
|
|
46
|
+
**parameters,
|
|
47
|
+
):
|
|
48
|
+
"""
|
|
49
|
+
Constructor.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
data_source: str or pandas.DataFrame
|
|
54
|
+
The file path, static name, or data
|
|
55
|
+
input_vars: list of str
|
|
56
|
+
The foxes input variables
|
|
57
|
+
varmap: dict
|
|
58
|
+
Mapping from foxes variable names
|
|
59
|
+
to column names in the data_source
|
|
60
|
+
lookup_pars: dict
|
|
61
|
+
Additional parameters for the LookupTable model
|
|
62
|
+
rho: float, optional
|
|
63
|
+
The air density for which the data is valid
|
|
64
|
+
or None for no correction
|
|
65
|
+
p_ct: float
|
|
66
|
+
The exponent for yaw dependency of ct
|
|
67
|
+
p_P: float
|
|
68
|
+
The exponent for yaw dependency of P
|
|
69
|
+
var_ws_ct: str
|
|
70
|
+
The wind speed variable for ct lookup
|
|
71
|
+
var_ws_P: str
|
|
72
|
+
The wind speed variable for power lookup
|
|
73
|
+
pd_file_read_pars: dict
|
|
74
|
+
Parameters for pandas file reading
|
|
75
|
+
interpn_args: dict
|
|
76
|
+
Parameters for scipy intern or interp1d
|
|
77
|
+
parameters: dict, optional
|
|
78
|
+
Additional parameters for TurbineType class
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
if not isinstance(data_source, pd.DataFrame):
|
|
82
|
+
pars = parse_Pct_file_name(data_source)
|
|
83
|
+
pars.update(parameters)
|
|
84
|
+
else:
|
|
85
|
+
pars = parameters
|
|
86
|
+
|
|
87
|
+
super().__init__(**pars)
|
|
88
|
+
|
|
89
|
+
self.source = data_source
|
|
90
|
+
self.rho = rho
|
|
91
|
+
self.p_ct = p_ct
|
|
92
|
+
self.p_P = p_P
|
|
93
|
+
self.WSCT = var_ws_ct
|
|
94
|
+
self.WSP = var_ws_P
|
|
95
|
+
self.rpars = pd_file_read_pars
|
|
96
|
+
|
|
97
|
+
if FV.REWS not in input_vars or len(
|
|
98
|
+
set(input_vars).intersection([FV.WS, FV.REWS2, FV.REWS3])
|
|
99
|
+
):
|
|
100
|
+
raise KeyError(
|
|
101
|
+
f"Turbine type '{self.name}': Expecting '{FV.REWS}' as wind speed variable in inputv_vars, got {input_vars}"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
iargs = dict(bounds_error=False, fill_value=0)
|
|
105
|
+
iargs.update(interpn_args)
|
|
106
|
+
self._lookup = LookupTable(
|
|
107
|
+
data_source=data_source,
|
|
108
|
+
input_vars=input_vars,
|
|
109
|
+
output_vars=[FV.P, FV.CT],
|
|
110
|
+
varmap=varmap,
|
|
111
|
+
interpn_args=iargs,
|
|
112
|
+
**lookup_pars,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
def __repr__(self):
|
|
116
|
+
a = f"D={self.D}, H={self.H}, P_nominal={self.P_nominal}, P_unit={self.P_unit}, rho={self.rho}"
|
|
117
|
+
a += f", var_ws_ct={self.WSCT}, var_ws_P={self.WSP}"
|
|
118
|
+
return f"{type(self).__name__}({a})"
|
|
119
|
+
|
|
120
|
+
def needs_rews2(self):
|
|
121
|
+
"""
|
|
122
|
+
Returns flag for requiring REWS2 variable
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
flag: bool
|
|
127
|
+
True if REWS2 is required
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
return self.WSCT == FV.REWS2 or self.WSP == FV.REWS2
|
|
131
|
+
|
|
132
|
+
def needs_rews3(self):
|
|
133
|
+
"""
|
|
134
|
+
Returns flag for requiring REWS3 variable
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
flag: bool
|
|
139
|
+
True if REWS3 is required
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
return self.WSCT == FV.REWS3 or self.WSP == FV.REWS3
|
|
143
|
+
|
|
144
|
+
def sub_models(self):
|
|
145
|
+
"""
|
|
146
|
+
List of all sub-models
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
smdls: list of foxes.core.Model
|
|
151
|
+
All sub models
|
|
152
|
+
|
|
153
|
+
"""
|
|
154
|
+
return [self._lookup]
|
|
155
|
+
|
|
156
|
+
def output_farm_vars(self, algo):
|
|
157
|
+
"""
|
|
158
|
+
The variables which are being modified by the model.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
algo: foxes.core.Algorithm
|
|
163
|
+
The calculation algorithm
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
output_vars: list of str
|
|
168
|
+
The output variable names
|
|
169
|
+
|
|
170
|
+
"""
|
|
171
|
+
return [FV.P, FV.CT]
|
|
172
|
+
|
|
173
|
+
def initialize(self, algo, verbosity=0, force=False):
|
|
174
|
+
"""
|
|
175
|
+
Initializes the model.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
algo: foxes.core.Algorithm
|
|
180
|
+
The calculation algorithm
|
|
181
|
+
verbosity: int
|
|
182
|
+
The verbosity level, 0 = silent
|
|
183
|
+
force: bool
|
|
184
|
+
Overwrite existing data
|
|
185
|
+
|
|
186
|
+
"""
|
|
187
|
+
super().initialize(algo, verbosity, force)
|
|
188
|
+
if self.P_nominal is None:
|
|
189
|
+
col_P = self._lookup.varmap.get(FV.P, FV.P)
|
|
190
|
+
self.P_nominal = np.max(self._lookup._data[col_P].to_numpy())
|
|
191
|
+
|
|
192
|
+
def modify_cutin(
|
|
193
|
+
self,
|
|
194
|
+
modify_ct,
|
|
195
|
+
modify_P,
|
|
196
|
+
steps=20,
|
|
197
|
+
iterations=100,
|
|
198
|
+
a=0.55,
|
|
199
|
+
b=0.55,
|
|
200
|
+
):
|
|
201
|
+
"""
|
|
202
|
+
Modify the data such that a discontinuity
|
|
203
|
+
at cutin wind speed is avoided
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
variable: str
|
|
208
|
+
The target variable
|
|
209
|
+
modify_ct: bool
|
|
210
|
+
Flag for modification of the ct curve
|
|
211
|
+
modify_P: bool
|
|
212
|
+
Flag for modification of the power curve
|
|
213
|
+
steps: int
|
|
214
|
+
The number of wind speed steps between 0 and
|
|
215
|
+
the cutin wind speed
|
|
216
|
+
iterations: int
|
|
217
|
+
The number of iterations
|
|
218
|
+
a: float
|
|
219
|
+
Coefficient for iterative mixing
|
|
220
|
+
b: float
|
|
221
|
+
Coefficient for iterative mixing
|
|
222
|
+
|
|
223
|
+
"""
|
|
224
|
+
if modify_ct or modify_P:
|
|
225
|
+
raise NotImplementedError
|
|
226
|
+
|
|
227
|
+
else:
|
|
228
|
+
super().modify_cutin(modify_ct, modify_P)
|
|
229
|
+
|
|
230
|
+
def calculate(self, algo, mdata, fdata, st_sel):
|
|
231
|
+
"""
|
|
232
|
+
The main model calculation.
|
|
233
|
+
|
|
234
|
+
This function is executed on a single chunk of data,
|
|
235
|
+
all computations should be based on numpy arrays.
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
algo: foxes.core.Algorithm
|
|
240
|
+
The calculation algorithm
|
|
241
|
+
mdata: foxes.core.MData
|
|
242
|
+
The model data
|
|
243
|
+
fdata: foxes.core.FData
|
|
244
|
+
The farm data
|
|
245
|
+
st_sel: numpy.ndarray of bool
|
|
246
|
+
The state-turbine selection,
|
|
247
|
+
shape: (n_states, n_turbines)
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
results: dict
|
|
252
|
+
The resulting data, keys: output variable str.
|
|
253
|
+
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
254
|
+
|
|
255
|
+
"""
|
|
256
|
+
# prepare data for lookup:
|
|
257
|
+
input_vars = self._lookup.input_vars
|
|
258
|
+
fdata_lookup = FData(
|
|
259
|
+
data={v: fdata[v] for v in input_vars},
|
|
260
|
+
dims={v: fdata.dims[v] for v in input_vars},
|
|
261
|
+
loop_dims=fdata.loop_dims,
|
|
262
|
+
)
|
|
263
|
+
for v in self.output_farm_vars(algo):
|
|
264
|
+
fdata_lookup.add(v, fdata[v], fdata.dims[v])
|
|
265
|
+
|
|
266
|
+
rews2 = None
|
|
267
|
+
rews3 = None
|
|
268
|
+
if self.WSP != FV.REWS or self.WSCT != FV.REWS:
|
|
269
|
+
rews2 = fdata[self.WSCT].copy()
|
|
270
|
+
rews3 = fdata[self.WSP].copy()
|
|
271
|
+
|
|
272
|
+
# apply air density correction:
|
|
273
|
+
if self.rho is not None:
|
|
274
|
+
if rews2 is None:
|
|
275
|
+
rews2 = fdata[self.WSCT].copy()
|
|
276
|
+
rews3 = fdata[self.WSP].copy()
|
|
277
|
+
|
|
278
|
+
# correct wind speed by air density, such
|
|
279
|
+
# that in the partial load region the
|
|
280
|
+
# correct value is reconstructed:
|
|
281
|
+
rho = fdata[FV.RHO][st_sel]
|
|
282
|
+
rews3[st_sel] *= (self.rho / rho) ** (1.0 / 3.0)
|
|
283
|
+
del rho
|
|
284
|
+
|
|
285
|
+
# in yawed case, calc yaw corrected wind speed:
|
|
286
|
+
if FV.YAWM in fdata and (self.p_P is not None or self.p_ct is not None):
|
|
287
|
+
if rews2 is None:
|
|
288
|
+
rews2 = fdata[self.WSCT].copy()
|
|
289
|
+
rews3 = fdata[self.WSP].copy()
|
|
290
|
+
|
|
291
|
+
# calculate corrected wind speed wsc,
|
|
292
|
+
# gives ws**3 * cos**p_P in partial load region
|
|
293
|
+
# and smoothly deals with full load region:
|
|
294
|
+
yawm = fdata[FV.YAWM][st_sel]
|
|
295
|
+
if np.any(np.isnan(yawm)):
|
|
296
|
+
raise ValueError(
|
|
297
|
+
f"{self.name}: Found NaN values for variable '{FV.YAWM}'. Maybe change order in turbine_models?"
|
|
298
|
+
)
|
|
299
|
+
cosm = np.cos(yawm / 180 * np.pi)
|
|
300
|
+
if self.p_ct is not None:
|
|
301
|
+
rews2[st_sel] *= (cosm**self.p_ct) ** 0.5
|
|
302
|
+
if self.p_P is not None:
|
|
303
|
+
rews3[st_sel] *= (cosm**self.p_P) ** (1.0 / 3.0)
|
|
304
|
+
del yawm, cosm
|
|
305
|
+
|
|
306
|
+
# run lookup:
|
|
307
|
+
if rews2 is None:
|
|
308
|
+
out = self._lookup.calculate(algo, mdata, fdata_lookup, st_sel)
|
|
309
|
+
else:
|
|
310
|
+
fdata_lookup[FV.REWS] = rews2
|
|
311
|
+
ct = self._lookup.calculate(algo, mdata, fdata_lookup, st_sel)[FV.CT]
|
|
312
|
+
fdata_lookup[FV.REWS] = rews3
|
|
313
|
+
out = self._lookup.calculate(algo, mdata, fdata_lookup, st_sel)
|
|
314
|
+
out[FV.CT] = ct
|
|
315
|
+
|
|
316
|
+
return out
|
|
@@ -9,6 +9,56 @@ class NullType(TurbineType):
|
|
|
9
9
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
*args,
|
|
15
|
+
needs_rews2=False,
|
|
16
|
+
needs_rews3=False,
|
|
17
|
+
**kwargs,
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Constructor.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
args: tuple, optional
|
|
25
|
+
Additional parameters for TurbineType class
|
|
26
|
+
needs_rews2: bool
|
|
27
|
+
Flag for runs that require the REWS2 variable
|
|
28
|
+
needs_rews3: bool
|
|
29
|
+
Flag for runs that require the REWS3 variable
|
|
30
|
+
kwargs: dict, optional
|
|
31
|
+
Additional parameters for TurbineType class
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
super().__init__(*args, **kwargs)
|
|
35
|
+
self._rews2 = needs_rews2
|
|
36
|
+
self._rews3 = needs_rews3
|
|
37
|
+
|
|
38
|
+
def needs_rews2(self):
|
|
39
|
+
"""
|
|
40
|
+
Returns flag for requiring REWS2 variable
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
flag: bool
|
|
45
|
+
True if REWS2 is required
|
|
46
|
+
|
|
47
|
+
"""
|
|
48
|
+
return self._rews2
|
|
49
|
+
|
|
50
|
+
def needs_rews3(self):
|
|
51
|
+
"""
|
|
52
|
+
Returns flag for requiring REWS3 variable
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
flag: bool
|
|
57
|
+
True if REWS3 is required
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
return self._rews3
|
|
61
|
+
|
|
12
62
|
def output_farm_vars(self, algo):
|
|
13
63
|
"""
|
|
14
64
|
The variables which are being modified by the model.
|
|
@@ -27,7 +77,7 @@ class NullType(TurbineType):
|
|
|
27
77
|
return []
|
|
28
78
|
|
|
29
79
|
def calculate(self, algo, mdata, fdata, st_sel):
|
|
30
|
-
"""
|
|
80
|
+
"""
|
|
31
81
|
The main model calculation.
|
|
32
82
|
|
|
33
83
|
This function is executed on a single chunk of data,
|
|
@@ -37,9 +37,9 @@ class WsRho2PCtFromTwo(TurbineType):
|
|
|
37
37
|
rpars_ct: dict, optional
|
|
38
38
|
Parameters for pandas ct file reading
|
|
39
39
|
ipars_P: dict, optional
|
|
40
|
-
Parameters for scipy.interpolate.interpn
|
|
40
|
+
Parameters for scipy.interpolate.interpn
|
|
41
41
|
ipars_ct: dict, optional
|
|
42
|
-
Parameters for scipy.interpolate.interpn
|
|
42
|
+
Parameters for scipy.interpolate.interpn
|
|
43
43
|
|
|
44
44
|
:group: models.turbine_types
|
|
45
45
|
|
|
@@ -81,9 +81,9 @@ class WsRho2PCtFromTwo(TurbineType):
|
|
|
81
81
|
pd_file_read_pars_ct: dict
|
|
82
82
|
Parameters for pandas ct file reading
|
|
83
83
|
interpn_pars_P: dict, optional
|
|
84
|
-
Parameters for scipy.interpolate.interpn
|
|
84
|
+
Parameters for scipy.interpolate.interpn
|
|
85
85
|
interpn_pars_ct: dict, optional
|
|
86
|
-
Parameters for scipy.interpolate.interpn
|
|
86
|
+
Parameters for scipy.interpolate.interpn
|
|
87
87
|
parameters: dict, optional
|
|
88
88
|
Additional parameters for TurbineType class
|
|
89
89
|
|
|
@@ -115,6 +115,30 @@ class WsRho2PCtFromTwo(TurbineType):
|
|
|
115
115
|
self._P = None
|
|
116
116
|
self._ct = None
|
|
117
117
|
|
|
118
|
+
def needs_rews2(self):
|
|
119
|
+
"""
|
|
120
|
+
Returns flag for requiring REWS2 variable
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
flag: bool
|
|
125
|
+
True if REWS2 is required
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
return self.WSCT == FV.REWS2 or self.WSP == FV.REWS2
|
|
129
|
+
|
|
130
|
+
def needs_rews3(self):
|
|
131
|
+
"""
|
|
132
|
+
Returns flag for requiring REWS3 variable
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
flag: bool
|
|
137
|
+
True if REWS3 is required
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
return self.WSCT == FV.REWS3 or self.WSP == FV.REWS3
|
|
141
|
+
|
|
118
142
|
def output_farm_vars(self, algo):
|
|
119
143
|
"""
|
|
120
144
|
The variables which are being modified by the model.
|
|
@@ -205,7 +229,7 @@ class WsRho2PCtFromTwo(TurbineType):
|
|
|
205
229
|
print()
|
|
206
230
|
|
|
207
231
|
def calculate(self, algo, mdata, fdata, st_sel):
|
|
208
|
-
"""
|
|
232
|
+
"""
|
|
209
233
|
The main model calculation.
|
|
210
234
|
|
|
211
235
|
This function is executed on a single chunk of data,
|
|
@@ -37,11 +37,11 @@ class WsTI2PCtFromTwo(TurbineType):
|
|
|
37
37
|
rpars_ct: dict, optional
|
|
38
38
|
Parameters for pandas ct file reading
|
|
39
39
|
ipars_P: dict, optional
|
|
40
|
-
Parameters for scipy.interpolate.interpn
|
|
40
|
+
Parameters for scipy.interpolate.interpn
|
|
41
41
|
ipars_ct: dict, optional
|
|
42
|
-
Parameters for scipy.interpolate.interpn
|
|
42
|
+
Parameters for scipy.interpolate.interpn
|
|
43
43
|
rho: float
|
|
44
|
-
The air
|
|
44
|
+
The air density for which the data is valid
|
|
45
45
|
or None for no correction
|
|
46
46
|
|
|
47
47
|
:group: models.turbine_types
|
|
@@ -73,7 +73,7 @@ class WsTI2PCtFromTwo(TurbineType):
|
|
|
73
73
|
data_source_ct: str or pandas.DataFrame
|
|
74
74
|
The file path for the ct curve, static name, or data
|
|
75
75
|
rho: float, optional
|
|
76
|
-
The air
|
|
76
|
+
The air density for which the data is valid
|
|
77
77
|
or None for no correction
|
|
78
78
|
p_ct: float
|
|
79
79
|
The exponent for yaw dependency of ct
|
|
@@ -88,9 +88,9 @@ class WsTI2PCtFromTwo(TurbineType):
|
|
|
88
88
|
pd_file_read_pars_ct: dict
|
|
89
89
|
Parameters for pandas ct file reading
|
|
90
90
|
interpn_pars_P: dict, optional
|
|
91
|
-
Parameters for scipy.interpolate.interpn
|
|
91
|
+
Parameters for scipy.interpolate.interpn
|
|
92
92
|
interpn_pars_ct: dict, optional
|
|
93
|
-
Parameters for scipy.interpolate.interpn
|
|
93
|
+
Parameters for scipy.interpolate.interpn
|
|
94
94
|
parameters: dict, optional
|
|
95
95
|
Additional parameters for TurbineType class
|
|
96
96
|
|
|
@@ -127,6 +127,30 @@ class WsTI2PCtFromTwo(TurbineType):
|
|
|
127
127
|
a = f"D={self.D}, H={self.H}, P_nominal={self.P_nominal}, P_unit={self.P_unit}, rho={self.rho}"
|
|
128
128
|
return f"{type(self).__name__}({a})"
|
|
129
129
|
|
|
130
|
+
def needs_rews2(self):
|
|
131
|
+
"""
|
|
132
|
+
Returns flag for requiring REWS2 variable
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
flag: bool
|
|
137
|
+
True if REWS2 is required
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
return self.WSCT == FV.REWS2 or self.WSP == FV.REWS2
|
|
141
|
+
|
|
142
|
+
def needs_rews3(self):
|
|
143
|
+
"""
|
|
144
|
+
Returns flag for requiring REWS3 variable
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
flag: bool
|
|
149
|
+
True if REWS3 is required
|
|
150
|
+
|
|
151
|
+
"""
|
|
152
|
+
return self.WSCT == FV.REWS3 or self.WSP == FV.REWS3
|
|
153
|
+
|
|
130
154
|
def output_farm_vars(self, algo):
|
|
131
155
|
"""
|
|
132
156
|
The variables which are being modified by the model.
|
|
@@ -217,7 +241,7 @@ class WsTI2PCtFromTwo(TurbineType):
|
|
|
217
241
|
print()
|
|
218
242
|
|
|
219
243
|
def calculate(self, algo, mdata, fdata, st_sel):
|
|
220
|
-
"""
|
|
244
|
+
"""
|
|
221
245
|
The main model calculation.
|
|
222
246
|
|
|
223
247
|
This function is executed on a single chunk of data,
|