foxes 0.8.2__py3-none-any.whl → 1.0__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_RHB/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 +183 -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 +232 -101
- foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -6
- foxes/algorithms/downwind/models/init_farm_data.py +1 -1
- foxes/algorithms/downwind/models/point_wakes_calc.py +5 -6
- foxes/algorithms/downwind/models/reorder_farm_output.py +0 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +4 -2
- foxes/algorithms/iterative/iterative.py +73 -33
- foxes/algorithms/iterative/models/farm_wakes_calc.py +11 -6
- foxes/algorithms/sequential/models/plugin.py +1 -1
- foxes/algorithms/sequential/sequential.py +126 -255
- foxes/constants.py +17 -2
- foxes/core/__init__.py +1 -0
- foxes/core/algorithm.py +631 -146
- foxes/core/data.py +252 -20
- foxes/core/data_calc_model.py +13 -289
- foxes/core/engine.py +630 -0
- foxes/core/farm_controller.py +37 -9
- foxes/core/farm_data_model.py +15 -0
- foxes/core/model.py +133 -80
- foxes/core/point_data_model.py +15 -0
- foxes/core/rotor_model.py +27 -21
- foxes/core/states.py +16 -0
- foxes/core/turbine_type.py +28 -0
- foxes/core/wake_frame.py +22 -4
- foxes/core/wake_model.py +2 -3
- foxes/data/windio/windio_5turbines_timeseries.yaml +23 -1
- foxes/engines/__init__.py +16 -0
- foxes/engines/dask.py +975 -0
- foxes/engines/default.py +75 -0
- foxes/engines/futures.py +72 -0
- foxes/engines/mpi.py +38 -0
- foxes/engines/multiprocess.py +74 -0
- foxes/engines/numpy.py +185 -0
- foxes/engines/pool.py +263 -0
- foxes/engines/single.py +139 -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 +1 -1
- 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 +6 -0
- foxes/input/states/create/random_abl_states.py +1 -1
- foxes/input/states/field_data_nc.py +157 -32
- foxes/input/states/multi_height.py +127 -13
- foxes/input/states/one_point_flow.py +577 -0
- foxes/input/states/scan_ws.py +73 -2
- foxes/input/states/states_table.py +204 -35
- foxes/input/windio/__init__.py +1 -1
- foxes/input/windio/get_states.py +44 -23
- foxes/input/windio/read_attributes.py +41 -16
- foxes/input/windio/read_farm.py +116 -102
- foxes/input/windio/read_fields.py +13 -6
- foxes/input/windio/read_outputs.py +63 -22
- foxes/input/windio/runner.py +31 -17
- foxes/input/windio/windio.py +36 -22
- foxes/models/ground_models/wake_mirror.py +8 -4
- foxes/models/model_book.py +29 -18
- foxes/models/partial_wakes/rotor_points.py +3 -3
- foxes/models/rotor_models/centre.py +4 -0
- foxes/models/rotor_models/grid.py +22 -23
- foxes/models/rotor_models/levels.py +4 -5
- foxes/models/turbine_models/calculator.py +0 -2
- foxes/models/turbine_models/lookup_table.py +27 -2
- 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 +24 -0
- foxes/models/turbine_types/PCt_from_two.py +24 -0
- foxes/models/turbine_types/__init__.py +1 -0
- foxes/models/turbine_types/lookup.py +316 -0
- foxes/models/turbine_types/null_type.py +50 -0
- foxes/models/turbine_types/wsrho2PCt_from_two.py +24 -0
- foxes/models/turbine_types/wsti2PCt_from_two.py +24 -0
- 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 +23 -3
- foxes/models/wake_frames/rotor_wd.py +4 -2
- foxes/models/wake_frames/seq_dynamic_wakes.py +56 -63
- foxes/models/wake_frames/streamlines.py +19 -20
- foxes/models/wake_frames/timelines.py +328 -127
- foxes/models/wake_frames/yawed_wakes.py +4 -1
- foxes/models/wake_models/dist_sliced.py +1 -3
- foxes/models/wake_models/induction/rankine_half_body.py +4 -4
- foxes/models/wake_models/induction/rathmann.py +2 -2
- foxes/models/wake_models/induction/self_similar.py +2 -2
- foxes/models/wake_models/induction/vortex_sheet.py +2 -2
- foxes/models/wake_models/ti/iec_ti.py +34 -17
- foxes/models/wake_models/top_hat.py +1 -1
- foxes/models/wake_models/wind/bastankhah14.py +2 -2
- foxes/models/wake_models/wind/bastankhah16.py +8 -7
- foxes/models/wake_models/wind/jensen.py +1 -1
- foxes/models/wake_models/wind/turbopark.py +2 -2
- foxes/output/__init__.py +4 -1
- foxes/output/farm_layout.py +2 -2
- foxes/output/flow_plots_2d/__init__.py +0 -1
- foxes/output/flow_plots_2d/flow_plots.py +70 -30
- foxes/output/grids.py +91 -21
- foxes/output/seq_plugins/__init__.py +2 -0
- foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +62 -20
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
- foxes/output/slice_data.py +131 -111
- foxes/output/state_turbine_map.py +18 -13
- foxes/output/state_turbine_table.py +19 -19
- foxes/utils/__init__.py +1 -1
- foxes/utils/dev_utils.py +42 -0
- foxes/utils/dict.py +1 -1
- foxes/utils/factory.py +147 -52
- foxes/utils/pandas_helpers.py +4 -3
- foxes/utils/wind_dir.py +0 -2
- foxes/utils/xarray_utils.py +23 -13
- foxes/variables.py +37 -0
- {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/METADATA +71 -33
- foxes-1.0.dist-info/RECORD +307 -0
- {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/WHEEL +1 -1
- foxes-1.0.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/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.0.dist-info}/LICENSE +0 -0
foxes/engines/single.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from xarray import Dataset
|
|
2
|
+
|
|
3
|
+
import foxes.constants as FC
|
|
4
|
+
from foxes.core import Engine
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class SingleChunkEngine(Engine):
|
|
8
|
+
"""
|
|
9
|
+
Runs computations in a single chunk.
|
|
10
|
+
|
|
11
|
+
:group: engines
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, *args, **kwargs):
|
|
16
|
+
"""
|
|
17
|
+
Constructor.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
args: tuple, optional
|
|
22
|
+
Additional parameters for the base class
|
|
23
|
+
kwargs: dict, optional
|
|
24
|
+
Additional parameters for the base class
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
ignr = ["chunk_size_states", "chunk_size_points", "n_procs"]
|
|
28
|
+
for k in ignr:
|
|
29
|
+
if kwargs.pop(k, None) is not None and kwargs.get("verbosity", 1) > 1:
|
|
30
|
+
print(f"{type(self).__name__}: Ignoring {k}")
|
|
31
|
+
super().__init__(
|
|
32
|
+
*args,
|
|
33
|
+
chunk_size_states=None,
|
|
34
|
+
chunk_size_points=None,
|
|
35
|
+
n_procs=1,
|
|
36
|
+
**kwargs,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def __repr__(self):
|
|
40
|
+
return f"{type(self).__name__}()"
|
|
41
|
+
|
|
42
|
+
def run_calculation(
|
|
43
|
+
self,
|
|
44
|
+
algo,
|
|
45
|
+
model,
|
|
46
|
+
model_data=None,
|
|
47
|
+
farm_data=None,
|
|
48
|
+
point_data=None,
|
|
49
|
+
out_vars=[],
|
|
50
|
+
chunk_store={},
|
|
51
|
+
sel=None,
|
|
52
|
+
isel=None,
|
|
53
|
+
iterative=False,
|
|
54
|
+
**calc_pars,
|
|
55
|
+
):
|
|
56
|
+
"""
|
|
57
|
+
Runs the model calculation
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
algo: foxes.core.Algorithm
|
|
62
|
+
The algorithm object
|
|
63
|
+
model: foxes.core.DataCalcModel
|
|
64
|
+
The model that whose calculate function
|
|
65
|
+
should be run
|
|
66
|
+
model_data: xarray.Dataset
|
|
67
|
+
The initial model data
|
|
68
|
+
farm_data: xarray.Dataset
|
|
69
|
+
The initial farm data
|
|
70
|
+
point_data: xarray.Dataset
|
|
71
|
+
The initial point data
|
|
72
|
+
out_vars: list of str, optional
|
|
73
|
+
Names of the output variables
|
|
74
|
+
chunk_store: foxes.utils.Dict
|
|
75
|
+
The chunk store
|
|
76
|
+
sel: dict, optional
|
|
77
|
+
Selection of coordinate subsets
|
|
78
|
+
isel: dict, optional
|
|
79
|
+
Selection of coordinate subsets index values
|
|
80
|
+
iterative: bool
|
|
81
|
+
Flag for use within the iterative algorithm
|
|
82
|
+
calc_pars: dict, optional
|
|
83
|
+
Additional parameters for the model.calculate()
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
results: xarray.Dataset
|
|
88
|
+
The model results
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
# subset selection:
|
|
92
|
+
model_data, farm_data, point_data = self.select_subsets(
|
|
93
|
+
model_data, farm_data, point_data, sel=sel, isel=isel
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# basic checks:
|
|
97
|
+
super().run_calculation(algo, model, model_data, farm_data, point_data)
|
|
98
|
+
|
|
99
|
+
# prepare:
|
|
100
|
+
n_states = model_data.sizes[FC.STATE]
|
|
101
|
+
n_targets = point_data.sizes[FC.TARGET] if point_data is not None else 0
|
|
102
|
+
out_coords = model.output_coords()
|
|
103
|
+
coords = {}
|
|
104
|
+
if FC.STATE in out_coords and FC.STATE in model_data.coords:
|
|
105
|
+
coords[FC.STATE] = model_data[FC.STATE].to_numpy()
|
|
106
|
+
if farm_data is None:
|
|
107
|
+
farm_data = Dataset()
|
|
108
|
+
goal_data = farm_data if point_data is None else point_data
|
|
109
|
+
algo.reset_chunk_store(chunk_store)
|
|
110
|
+
|
|
111
|
+
# calculate:
|
|
112
|
+
|
|
113
|
+
if n_states > 1:
|
|
114
|
+
self.print(f"Running single chunk calculation for {n_states} states")
|
|
115
|
+
|
|
116
|
+
data = self.get_chunk_input_data(
|
|
117
|
+
algo=algo,
|
|
118
|
+
model_data=model_data,
|
|
119
|
+
farm_data=farm_data,
|
|
120
|
+
point_data=point_data,
|
|
121
|
+
states_i0_i1=(0, n_states),
|
|
122
|
+
targets_i0_i1=(0, n_targets),
|
|
123
|
+
out_vars=out_vars,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
results = {}
|
|
127
|
+
results[(0, 0)] = (model.calculate(algo, *data, **calc_pars), algo.chunk_store)
|
|
128
|
+
|
|
129
|
+
return self.combine_results(
|
|
130
|
+
algo=algo,
|
|
131
|
+
results=results,
|
|
132
|
+
model_data=model_data,
|
|
133
|
+
out_vars=out_vars,
|
|
134
|
+
out_coords=out_coords,
|
|
135
|
+
n_chunks_states=1,
|
|
136
|
+
n_chunks_targets=1,
|
|
137
|
+
goal_data=goal_data,
|
|
138
|
+
iterative=iterative,
|
|
139
|
+
)
|
|
@@ -14,6 +14,7 @@ def add_from_csv(
|
|
|
14
14
|
col_D=None,
|
|
15
15
|
col_id=None,
|
|
16
16
|
cols_models_pre=None,
|
|
17
|
+
col_turbine_type=None,
|
|
17
18
|
cols_models_post=None,
|
|
18
19
|
turbine_base_name="T",
|
|
19
20
|
turbine_ids=None,
|
|
@@ -47,6 +48,8 @@ def add_from_csv(
|
|
|
47
48
|
cols_models_pre: list of str, optional
|
|
48
49
|
The turbine model columns, entered before
|
|
49
50
|
turbine_models
|
|
51
|
+
col_turbine_type: str, optional
|
|
52
|
+
The turbine type name
|
|
50
53
|
cols_models_post: list of str, optional
|
|
51
54
|
The turbine model columns, entered after
|
|
52
55
|
turbine_models
|
|
@@ -95,6 +98,7 @@ def add_from_csv(
|
|
|
95
98
|
hmodels = (
|
|
96
99
|
[] if cols_models_pre is None else data.loc[i, cols_models_pre].tolist()
|
|
97
100
|
)
|
|
101
|
+
hmodels += [] if col_turbine_type is None else [data.loc[i, col_turbine_type]]
|
|
98
102
|
hmodels += tmodels
|
|
99
103
|
hmodels += (
|
|
100
104
|
[] if cols_models_post is None else data.loc[i, cols_models_post].tolist()
|
foxes/input/farm_layout/grid.py
CHANGED
|
@@ -12,7 +12,7 @@ def add_grid(
|
|
|
12
12
|
indices=None,
|
|
13
13
|
names=None,
|
|
14
14
|
verbosity=1,
|
|
15
|
-
**turbine_parameters
|
|
15
|
+
**turbine_parameters,
|
|
16
16
|
):
|
|
17
17
|
"""
|
|
18
18
|
Add a regular grid of turbines.
|
|
@@ -54,7 +54,7 @@ def add_grid(
|
|
|
54
54
|
xy=xy_base + xi * step_vectors[0] + yi * step_vectors[1],
|
|
55
55
|
index=None if indices is None else indices[i],
|
|
56
56
|
name=None if names is None else names[i],
|
|
57
|
-
**turbine_parameters
|
|
57
|
+
**turbine_parameters,
|
|
58
58
|
),
|
|
59
59
|
verbosity=verbosity,
|
|
60
60
|
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from foxes.core import Turbine
|
|
4
|
+
from foxes.utils import wd2wdvec
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def add_ring(
|
|
8
|
+
farm,
|
|
9
|
+
xy_base,
|
|
10
|
+
dist,
|
|
11
|
+
n_turbines,
|
|
12
|
+
offset_deg=0,
|
|
13
|
+
indices=None,
|
|
14
|
+
names=None,
|
|
15
|
+
verbosity=1,
|
|
16
|
+
**turbine_parameters,
|
|
17
|
+
):
|
|
18
|
+
"""
|
|
19
|
+
Add a ring of turbines.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
farm: foxes.WindFarm
|
|
24
|
+
The wind farm
|
|
25
|
+
xy_base: numpy.ndarray
|
|
26
|
+
The base point, shape: (2,)
|
|
27
|
+
dist: float
|
|
28
|
+
The distance between turbines
|
|
29
|
+
n_turbines: int
|
|
30
|
+
The number of turbines
|
|
31
|
+
offset_deg: float
|
|
32
|
+
The offset from north in degrees,
|
|
33
|
+
following wind direction conventions
|
|
34
|
+
indices: list of int, optional
|
|
35
|
+
The turbine indices
|
|
36
|
+
names: list of str, optional
|
|
37
|
+
The turbine names
|
|
38
|
+
verbosity: int
|
|
39
|
+
The verbosity level, 0 = silent
|
|
40
|
+
turbine_parameters: dict, optional
|
|
41
|
+
Parameters forwarded to `foxes.core.Turbine`
|
|
42
|
+
|
|
43
|
+
:group: input.farm_layout
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
p0 = np.array(xy_base)
|
|
47
|
+
R = n_turbines * dist / (2 * np.pi)
|
|
48
|
+
a = np.atleast_1d(offset_deg)
|
|
49
|
+
da = 360 / n_turbines
|
|
50
|
+
|
|
51
|
+
for i in range(n_turbines):
|
|
52
|
+
|
|
53
|
+
n = wd2wdvec(a)[0]
|
|
54
|
+
|
|
55
|
+
farm.add_turbine(
|
|
56
|
+
Turbine(
|
|
57
|
+
xy=p0 + R * n,
|
|
58
|
+
index=None if indices is None else indices[i],
|
|
59
|
+
name=None if names is None else names[i],
|
|
60
|
+
**turbine_parameters,
|
|
61
|
+
),
|
|
62
|
+
verbosity=verbosity,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
a[0] += da
|
foxes/input/farm_layout/row.py
CHANGED
|
@@ -11,7 +11,7 @@ def add_row(
|
|
|
11
11
|
indices=None,
|
|
12
12
|
names=None,
|
|
13
13
|
verbosity=1,
|
|
14
|
-
**turbine_parameters
|
|
14
|
+
**turbine_parameters,
|
|
15
15
|
):
|
|
16
16
|
"""
|
|
17
17
|
Add a single row of turbines.
|
|
@@ -47,7 +47,7 @@ def add_row(
|
|
|
47
47
|
xy=p0 + i * delta,
|
|
48
48
|
index=None if indices is None else indices[i],
|
|
49
49
|
name=None if names is None else names[i],
|
|
50
|
-
**turbine_parameters
|
|
50
|
+
**turbine_parameters,
|
|
51
51
|
),
|
|
52
52
|
verbosity=verbosity,
|
|
53
53
|
)
|
foxes/input/states/__init__.py
CHANGED
|
@@ -8,5 +8,11 @@ from .states_table import StatesTable, Timeseries, TabStates
|
|
|
8
8
|
from .field_data_nc import FieldDataNC
|
|
9
9
|
from .multi_height import MultiHeightStates, MultiHeightTimeseries
|
|
10
10
|
from .multi_height import MultiHeightNCStates, MultiHeightNCTimeseries
|
|
11
|
+
from .one_point_flow import (
|
|
12
|
+
OnePointFlowStates,
|
|
13
|
+
OnePointFlowTimeseries,
|
|
14
|
+
OnePointFlowMultiHeightTimeseries,
|
|
15
|
+
OnePointFlowMultiHeightNCTimeseries,
|
|
16
|
+
)
|
|
11
17
|
|
|
12
18
|
from . import create
|
|
@@ -2,9 +2,10 @@ import numpy as np
|
|
|
2
2
|
import pandas as pd
|
|
3
3
|
import xarray as xr
|
|
4
4
|
from scipy.interpolate import interpn
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from foxes.core import States
|
|
7
|
-
from foxes.utils import wd2uv, uv2wd
|
|
8
|
+
from foxes.utils import wd2uv, uv2wd, import_module
|
|
8
9
|
from foxes.data import STATES, StaticData
|
|
9
10
|
import foxes.variables as FV
|
|
10
11
|
import foxes.constants as FC
|
|
@@ -120,7 +121,6 @@ class FieldDataNC(States):
|
|
|
120
121
|
"""
|
|
121
122
|
super().__init__()
|
|
122
123
|
|
|
123
|
-
self.data_source = data_source
|
|
124
124
|
self.states_coord = states_coord
|
|
125
125
|
self.ovars = output_vars
|
|
126
126
|
self.fixed_vars = fixed_vars
|
|
@@ -139,16 +139,18 @@ class FieldDataNC(States):
|
|
|
139
139
|
v: var2ncvar.get(v, v) for v in output_vars if v not in fixed_vars
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
self._inds = None
|
|
143
142
|
self._N = None
|
|
144
|
-
self._weights = None
|
|
145
143
|
|
|
146
|
-
|
|
144
|
+
self.__data_source = data_source
|
|
145
|
+
self.__weights = None
|
|
146
|
+
self.__inds = None
|
|
147
|
+
|
|
148
|
+
# pre-load file reading:
|
|
147
149
|
if not isinstance(self.data_source, xr.Dataset):
|
|
148
150
|
if "*" in str(self.data_source):
|
|
149
151
|
pass
|
|
150
152
|
else:
|
|
151
|
-
self.
|
|
153
|
+
self.__data_source = StaticData().get_file_path(
|
|
152
154
|
STATES, self.data_source, check_raw=True
|
|
153
155
|
)
|
|
154
156
|
if verbosity:
|
|
@@ -161,26 +163,54 @@ class FieldDataNC(States):
|
|
|
161
163
|
f"States '{self.name}': Reading index from '{self.data_source}'"
|
|
162
164
|
)
|
|
163
165
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
166
|
+
def _read_ds():
|
|
167
|
+
if Path(self.data_source).is_file():
|
|
168
|
+
return xr.open_dataset(self.data_source)
|
|
169
|
+
else:
|
|
170
|
+
# try to read multiple files, needs dask:
|
|
171
|
+
try:
|
|
172
|
+
return xr.open_mfdataset(
|
|
173
|
+
str(self.data_source),
|
|
174
|
+
parallel=False,
|
|
175
|
+
concat_dim=self.states_coord,
|
|
176
|
+
combine="nested",
|
|
177
|
+
data_vars="minimal",
|
|
178
|
+
coords="minimal",
|
|
179
|
+
compat="override",
|
|
180
|
+
)
|
|
181
|
+
except ValueError as e:
|
|
182
|
+
import_module("dask", hint="pip install dask")
|
|
183
|
+
raise e
|
|
184
|
+
|
|
185
|
+
with _read_ds() as ds:
|
|
186
|
+
self.__data_source = ds
|
|
174
187
|
|
|
175
188
|
if sel is not None:
|
|
176
|
-
self.
|
|
189
|
+
self.__data_source = self.data_source.sel(self.sel)
|
|
177
190
|
if isel is not None:
|
|
178
|
-
self.
|
|
191
|
+
self.__data_source = self.data_source.isel(self.isel)
|
|
179
192
|
if pre_load:
|
|
180
|
-
self.
|
|
193
|
+
self.__data_source.load()
|
|
181
194
|
|
|
182
195
|
self._get_inds(self.data_source)
|
|
183
196
|
|
|
197
|
+
@property
|
|
198
|
+
def data_source(self):
|
|
199
|
+
"""
|
|
200
|
+
The data source
|
|
201
|
+
|
|
202
|
+
Returns
|
|
203
|
+
-------
|
|
204
|
+
s: object
|
|
205
|
+
The data source
|
|
206
|
+
|
|
207
|
+
"""
|
|
208
|
+
if self.pre_load and self.running:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
f"States '{self.name}': Cannot acces data_source while running"
|
|
211
|
+
)
|
|
212
|
+
return self.__data_source
|
|
213
|
+
|
|
184
214
|
def _get_inds(self, ds):
|
|
185
215
|
"""
|
|
186
216
|
Helper function for index and weights
|
|
@@ -192,13 +222,15 @@ class FieldDataNC(States):
|
|
|
192
222
|
f"States '{self.name}': Missing coordinate '{c}' in data"
|
|
193
223
|
)
|
|
194
224
|
|
|
195
|
-
self.
|
|
225
|
+
self.__inds = ds[self.states_coord].to_numpy()
|
|
196
226
|
if self.time_format is not None:
|
|
197
|
-
self.
|
|
198
|
-
|
|
227
|
+
self.__inds = pd.to_datetime(
|
|
228
|
+
self.__inds, format=self.time_format
|
|
229
|
+
).to_numpy()
|
|
230
|
+
self._N = len(self.__inds)
|
|
199
231
|
|
|
200
232
|
if self.weight_ncvar is not None:
|
|
201
|
-
self.
|
|
233
|
+
self.__weights = ds[self.weight_ncvar].to_numpy()
|
|
202
234
|
|
|
203
235
|
for v in self.ovars:
|
|
204
236
|
if v in self.var2ncvar:
|
|
@@ -331,8 +363,8 @@ class FieldDataNC(States):
|
|
|
331
363
|
self._dkys[v] = len(self._dkys)
|
|
332
364
|
self._n_dvars = len(self._dkys)
|
|
333
365
|
|
|
334
|
-
if self.
|
|
335
|
-
self.
|
|
366
|
+
if self.__weights is None:
|
|
367
|
+
self.__weights = np.full(
|
|
336
368
|
(self._N, algo.n_turbines), 1.0 / self._N, dtype=FC.DTYPE
|
|
337
369
|
)
|
|
338
370
|
|
|
@@ -363,6 +395,84 @@ class FieldDataNC(States):
|
|
|
363
395
|
|
|
364
396
|
return idata
|
|
365
397
|
|
|
398
|
+
def set_running(
|
|
399
|
+
self,
|
|
400
|
+
algo,
|
|
401
|
+
data_stash,
|
|
402
|
+
sel=None,
|
|
403
|
+
isel=None,
|
|
404
|
+
verbosity=0,
|
|
405
|
+
):
|
|
406
|
+
"""
|
|
407
|
+
Sets this model status to running, and moves
|
|
408
|
+
all large data to stash.
|
|
409
|
+
|
|
410
|
+
The stashed data will be returned by the
|
|
411
|
+
unset_running() function after running calculations.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
algo: foxes.core.Algorithm
|
|
416
|
+
The calculation algorithm
|
|
417
|
+
data_stash: dict
|
|
418
|
+
Large data stash, this function adds data here.
|
|
419
|
+
Key: model name. Value: dict, large model data
|
|
420
|
+
sel: dict, optional
|
|
421
|
+
The subset selection dictionary
|
|
422
|
+
isel: dict, optional
|
|
423
|
+
The index subset selection dictionary
|
|
424
|
+
verbosity: int
|
|
425
|
+
The verbosity level, 0 = silent
|
|
426
|
+
|
|
427
|
+
"""
|
|
428
|
+
super().set_running(algo, data_stash, sel, isel, verbosity)
|
|
429
|
+
|
|
430
|
+
data_stash[self.name] = dict(
|
|
431
|
+
weights=self.__weights,
|
|
432
|
+
inds=self.__inds,
|
|
433
|
+
)
|
|
434
|
+
del self.__weights, self.__inds
|
|
435
|
+
|
|
436
|
+
if self.pre_load:
|
|
437
|
+
data_stash[self.name]["data_source"] = self.__data_source
|
|
438
|
+
del self.__data_source
|
|
439
|
+
|
|
440
|
+
def unset_running(
|
|
441
|
+
self,
|
|
442
|
+
algo,
|
|
443
|
+
data_stash,
|
|
444
|
+
sel=None,
|
|
445
|
+
isel=None,
|
|
446
|
+
verbosity=0,
|
|
447
|
+
):
|
|
448
|
+
"""
|
|
449
|
+
Sets this model status to not running, recovering large data
|
|
450
|
+
from stash
|
|
451
|
+
|
|
452
|
+
Parameters
|
|
453
|
+
----------
|
|
454
|
+
algo: foxes.core.Algorithm
|
|
455
|
+
The calculation algorithm
|
|
456
|
+
data_stash: dict
|
|
457
|
+
Large data stash, this function adds data here.
|
|
458
|
+
Key: model name. Value: dict, large model data
|
|
459
|
+
sel: dict, optional
|
|
460
|
+
The subset selection dictionary
|
|
461
|
+
isel: dict, optional
|
|
462
|
+
The index subset selection dictionary
|
|
463
|
+
verbosity: int
|
|
464
|
+
The verbosity level, 0 = silent
|
|
465
|
+
|
|
466
|
+
"""
|
|
467
|
+
super().unset_running(algo, data_stash, sel, isel, verbosity)
|
|
468
|
+
|
|
469
|
+
data = data_stash[self.name]
|
|
470
|
+
self.__weights = data.pop("weights")
|
|
471
|
+
self.__inds = data.pop("inds")
|
|
472
|
+
|
|
473
|
+
if self.pre_load:
|
|
474
|
+
self.__data_source = data.pop("data_source")
|
|
475
|
+
|
|
366
476
|
def size(self):
|
|
367
477
|
"""
|
|
368
478
|
The total number of states.
|
|
@@ -385,7 +495,9 @@ class FieldDataNC(States):
|
|
|
385
495
|
The index labels of states, or None for default integers
|
|
386
496
|
|
|
387
497
|
"""
|
|
388
|
-
|
|
498
|
+
if self.running:
|
|
499
|
+
raise ValueError(f"States '{self.name}': Cannot acces index while running")
|
|
500
|
+
return self.__inds
|
|
389
501
|
|
|
390
502
|
def output_point_vars(self, algo):
|
|
391
503
|
"""
|
|
@@ -419,7 +531,11 @@ class FieldDataNC(States):
|
|
|
419
531
|
The weights, shape: (n_states, n_turbines)
|
|
420
532
|
|
|
421
533
|
"""
|
|
422
|
-
|
|
534
|
+
if self.running:
|
|
535
|
+
raise ValueError(
|
|
536
|
+
f"States '{self.name}': Cannot acces weights while running"
|
|
537
|
+
)
|
|
538
|
+
return self.__weights
|
|
423
539
|
|
|
424
540
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
425
541
|
""" "
|
|
@@ -464,7 +580,7 @@ class FieldDataNC(States):
|
|
|
464
580
|
|
|
465
581
|
# read data for this chunk:
|
|
466
582
|
else:
|
|
467
|
-
i0 =
|
|
583
|
+
i0 = mdata.states_i0(counter=True)
|
|
468
584
|
s = slice(i0, i0 + n_states)
|
|
469
585
|
ds = self.data_source.isel({self.states_coord: s}).load()
|
|
470
586
|
|
|
@@ -520,17 +636,26 @@ class FieldDataNC(States):
|
|
|
520
636
|
|
|
521
637
|
# interpolate:
|
|
522
638
|
try:
|
|
523
|
-
|
|
639
|
+
ipars = dict(bounds_error=True, fill_value=None)
|
|
640
|
+
ipars.update(self.interpn_pars)
|
|
641
|
+
data = interpn(gvars, data, pts, **ipars).reshape(
|
|
524
642
|
n_states, n_pts, self._n_dvars
|
|
525
643
|
)
|
|
526
644
|
except ValueError as e:
|
|
527
|
-
print(f"\
|
|
645
|
+
print(f"\nStates '{self.name}': Interpolation error")
|
|
528
646
|
print("INPUT VARS: (state, heights, y, x)")
|
|
529
647
|
print(
|
|
530
|
-
"DATA BOUNDS:",
|
|
648
|
+
"DATA BOUNDS:",
|
|
649
|
+
[float(np.min(d)) for d in gvars],
|
|
650
|
+
[float(np.max(d)) for d in gvars],
|
|
651
|
+
)
|
|
652
|
+
print(
|
|
653
|
+
"EVAL BOUNDS:",
|
|
654
|
+
[float(np.min(p)) for p in pts.T],
|
|
655
|
+
[float(np.max(p)) for p in pts.T],
|
|
531
656
|
)
|
|
532
657
|
print(
|
|
533
|
-
"
|
|
658
|
+
"\nMaybe you want to try the option 'bounds_error=False'? This will extrapolate the data.\n"
|
|
534
659
|
)
|
|
535
660
|
raise e
|
|
536
661
|
del pts, x, y, h, gvars
|