foxes 0.8.1__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 +25 -13
- foxes/variables.py +37 -0
- {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/METADATA +72 -34
- foxes-1.0.dist-info/RECORD +307 -0
- {foxes-0.8.1.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/plotly_helpers.py +0 -19
- foxes/utils/runners/__init__.py +0 -1
- foxes/utils/runners/runners.py +0 -280
- foxes-0.8.1.dist-info/RECORD +0 -248
- foxes-0.8.1.dist-info/top_level.txt +0 -1
- foxes-0.8.1.dist-info/zip-safe +0 -1
- {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/LICENSE +0 -0
foxes/engines/default.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from foxes.core import Engine
|
|
4
|
+
import foxes.constants as FC
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DefaultEngine(Engine):
|
|
8
|
+
"""
|
|
9
|
+
The case size dependent default engine.
|
|
10
|
+
|
|
11
|
+
:group: engines
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def run_calculation(
|
|
16
|
+
self,
|
|
17
|
+
algo,
|
|
18
|
+
model,
|
|
19
|
+
model_data=None,
|
|
20
|
+
farm_data=None,
|
|
21
|
+
point_data=None,
|
|
22
|
+
**kwargs,
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
Runs the model calculation
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
algo: foxes.core.Algorithm
|
|
30
|
+
The algorithm object
|
|
31
|
+
model: foxes.core.DataCalcModel
|
|
32
|
+
The model that whose calculate function
|
|
33
|
+
should be run
|
|
34
|
+
model_data: xarray.Dataset, optional
|
|
35
|
+
The initial model data
|
|
36
|
+
farm_data: xarray.Dataset, optional
|
|
37
|
+
The initial farm data
|
|
38
|
+
point_data: xarray.Dataset, optional
|
|
39
|
+
The initial point data
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
results: xarray.Dataset
|
|
44
|
+
The model results
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
max_n = np.sqrt(self.n_procs) * (500 / algo.n_turbines) ** 1.5
|
|
48
|
+
|
|
49
|
+
if (algo.n_states >= max_n) or (
|
|
50
|
+
point_data is not None
|
|
51
|
+
and self.chunk_size_points is not None
|
|
52
|
+
and point_data.sizes[FC.TARGET] > self.chunk_size_points
|
|
53
|
+
):
|
|
54
|
+
ename = "process"
|
|
55
|
+
else:
|
|
56
|
+
ename = "single"
|
|
57
|
+
|
|
58
|
+
self.print(f"{type(self).__name__}: Selecting engine '{ename}'", level=1)
|
|
59
|
+
|
|
60
|
+
self.finalize()
|
|
61
|
+
|
|
62
|
+
with Engine.new(
|
|
63
|
+
ename,
|
|
64
|
+
n_procs=self.n_procs,
|
|
65
|
+
chunk_size_states=self.chunk_size_states,
|
|
66
|
+
chunk_size_points=self.chunk_size_points,
|
|
67
|
+
verbosity=self.verbosity,
|
|
68
|
+
) as e:
|
|
69
|
+
results = e.run_calculation(
|
|
70
|
+
algo, model, model_data, farm_data, point_data=point_data, **kwargs
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
self.initialize()
|
|
74
|
+
|
|
75
|
+
return results
|
foxes/engines/futures.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
|
|
2
|
+
|
|
3
|
+
from .pool import PoolEngine
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ThreadsEngine(PoolEngine):
|
|
7
|
+
"""
|
|
8
|
+
The threads engine for foxes calculations.
|
|
9
|
+
|
|
10
|
+
:group: engines
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def _create_pool(self):
|
|
15
|
+
"""Creates the pool"""
|
|
16
|
+
self._pool = ThreadPoolExecutor(max_workers=self.n_procs)
|
|
17
|
+
|
|
18
|
+
def _submit(self, f, *args, **kwargs):
|
|
19
|
+
"""
|
|
20
|
+
Submits to the pool
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
f: Callable
|
|
25
|
+
The function f(*args, **kwargs) to be
|
|
26
|
+
submitted
|
|
27
|
+
args: tuple, optional
|
|
28
|
+
Arguments for the function
|
|
29
|
+
kwargs: dict, optional
|
|
30
|
+
Arguments for the function
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
future: object
|
|
35
|
+
The future object
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
return self._pool.submit(f, *args, **kwargs)
|
|
39
|
+
|
|
40
|
+
def _result(self, future):
|
|
41
|
+
"""
|
|
42
|
+
Waits for result from a future
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
future: object
|
|
47
|
+
The future
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
result: object
|
|
52
|
+
The calculation result
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
return future.result()
|
|
56
|
+
|
|
57
|
+
def _shutdown_pool(self):
|
|
58
|
+
"""Shuts down the pool"""
|
|
59
|
+
self._pool.shutdown()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ProcessEngine(ThreadsEngine):
|
|
63
|
+
"""
|
|
64
|
+
The processes engine for foxes calculations.
|
|
65
|
+
|
|
66
|
+
:group: engines
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def _create_pool(self):
|
|
71
|
+
"""Creates the pool"""
|
|
72
|
+
self._pool = ProcessPoolExecutor(max_workers=self.n_procs)
|
foxes/engines/mpi.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from foxes.utils import import_module
|
|
2
|
+
|
|
3
|
+
from .pool import PoolEngine
|
|
4
|
+
from .futures import ProcessEngine
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def load_mpi():
|
|
8
|
+
"""On-demand loading of the mpi4py package"""
|
|
9
|
+
global MPIPoolExecutor
|
|
10
|
+
MPIPoolExecutor = import_module(
|
|
11
|
+
"mpi4py.futures", hint="pip install mpi4py"
|
|
12
|
+
).MPIPoolExecutor
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MPIEngine(ProcessEngine):
|
|
16
|
+
"""
|
|
17
|
+
The MPI engine for foxes calculations.
|
|
18
|
+
|
|
19
|
+
Examples
|
|
20
|
+
--------
|
|
21
|
+
Run command, e.g. for 12 processors and a script run.py:
|
|
22
|
+
|
|
23
|
+
>>> mpiexec -n 12 -m mpi4py.futures run.py
|
|
24
|
+
|
|
25
|
+
:group: engines
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def initialize(self):
|
|
30
|
+
"""
|
|
31
|
+
Initializes the engine.
|
|
32
|
+
"""
|
|
33
|
+
load_mpi()
|
|
34
|
+
PoolEngine.initialize(self)
|
|
35
|
+
|
|
36
|
+
def _create_pool(self):
|
|
37
|
+
"""Creates the pool"""
|
|
38
|
+
self._pool = MPIPoolExecutor(max_workers=self.n_procs)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from foxes.utils import import_module
|
|
2
|
+
|
|
3
|
+
from .pool import PoolEngine
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load_multiprocess():
|
|
7
|
+
"""On-demand loading of the multiprocess package"""
|
|
8
|
+
global Pool
|
|
9
|
+
Pool = import_module("multiprocess", hint="pip install multiprocess").Pool
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MultiprocessEngine(PoolEngine):
|
|
13
|
+
"""
|
|
14
|
+
The multiprocessing engine for foxes calculations.
|
|
15
|
+
|
|
16
|
+
:group: engines
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def initialize(self):
|
|
21
|
+
"""
|
|
22
|
+
Initializes the engine.
|
|
23
|
+
"""
|
|
24
|
+
load_multiprocess()
|
|
25
|
+
super().initialize()
|
|
26
|
+
|
|
27
|
+
def _create_pool(self):
|
|
28
|
+
"""Creates the pool"""
|
|
29
|
+
self._pool = Pool(processes=self.n_procs)
|
|
30
|
+
|
|
31
|
+
def _submit(self, f, *args, **kwargs):
|
|
32
|
+
"""
|
|
33
|
+
Submits to the pool
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
f: Callable
|
|
38
|
+
The function f(*args, **kwargs) to be
|
|
39
|
+
submitted
|
|
40
|
+
args: tuple, optional
|
|
41
|
+
Arguments for the function
|
|
42
|
+
kwargs: dict, optional
|
|
43
|
+
Arguments for the function
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
future: object
|
|
48
|
+
The future object
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
return self._pool.apply_async(f, args=args, kwds=kwargs)
|
|
52
|
+
|
|
53
|
+
def _result(self, future):
|
|
54
|
+
"""
|
|
55
|
+
Waits for result from a future
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
future: object
|
|
60
|
+
The future
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
result: object
|
|
65
|
+
The calculation result
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
return future.get()
|
|
69
|
+
|
|
70
|
+
def _shutdown_pool(self):
|
|
71
|
+
"""Shuts down the pool"""
|
|
72
|
+
self._pool.close()
|
|
73
|
+
self._pool.terminate()
|
|
74
|
+
self._pool.join()
|
foxes/engines/numpy.py
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
from tqdm import tqdm
|
|
2
|
+
from xarray import Dataset
|
|
3
|
+
|
|
4
|
+
from foxes.core import Engine
|
|
5
|
+
import foxes.constants as FC
|
|
6
|
+
|
|
7
|
+
from .pool import _run
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class NumpyEngine(Engine):
|
|
11
|
+
"""
|
|
12
|
+
The numpy engine for foxes calculations.
|
|
13
|
+
|
|
14
|
+
:group: engines
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, *args, **kwargs):
|
|
19
|
+
"""
|
|
20
|
+
Constructor.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
args: tuple, optional
|
|
25
|
+
Additional parameters for the base class
|
|
26
|
+
kwargs: dict, optional
|
|
27
|
+
Additional parameters for the base class
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
ignr = ["n_procs"]
|
|
31
|
+
for k in ignr:
|
|
32
|
+
if kwargs.pop(k, None) is not None:
|
|
33
|
+
print(f"{type(self).__name__}: Ignoring {k}")
|
|
34
|
+
super().__init__(
|
|
35
|
+
*args,
|
|
36
|
+
n_procs=1,
|
|
37
|
+
**kwargs,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def run_calculation(
|
|
41
|
+
self,
|
|
42
|
+
algo,
|
|
43
|
+
model,
|
|
44
|
+
model_data=None,
|
|
45
|
+
farm_data=None,
|
|
46
|
+
point_data=None,
|
|
47
|
+
out_vars=[],
|
|
48
|
+
chunk_store={},
|
|
49
|
+
sel=None,
|
|
50
|
+
isel=None,
|
|
51
|
+
iterative=False,
|
|
52
|
+
**calc_pars,
|
|
53
|
+
):
|
|
54
|
+
"""
|
|
55
|
+
Runs the model calculation
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
algo: foxes.core.Algorithm
|
|
60
|
+
The algorithm object
|
|
61
|
+
model: foxes.core.DataCalcModel
|
|
62
|
+
The model that whose calculate function
|
|
63
|
+
should be run
|
|
64
|
+
model_data: xarray.Dataset
|
|
65
|
+
The initial model data
|
|
66
|
+
farm_data: xarray.Dataset
|
|
67
|
+
The initial farm data
|
|
68
|
+
point_data: xarray.Dataset
|
|
69
|
+
The initial point data
|
|
70
|
+
out_vars: list of str, optional
|
|
71
|
+
Names of the output variables
|
|
72
|
+
chunk_store: foxes.utils.Dict
|
|
73
|
+
The chunk store
|
|
74
|
+
sel: dict, optional
|
|
75
|
+
Selection of coordinate subsets
|
|
76
|
+
isel: dict, optional
|
|
77
|
+
Selection of coordinate subsets index values
|
|
78
|
+
iterative: bool
|
|
79
|
+
Flag for use within the iterative algorithm
|
|
80
|
+
calc_pars: dict, optional
|
|
81
|
+
Additional parameters for the model.calculate()
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
results: xarray.Dataset
|
|
86
|
+
The model results
|
|
87
|
+
|
|
88
|
+
"""
|
|
89
|
+
# subset selection:
|
|
90
|
+
model_data, farm_data, point_data = self.select_subsets(
|
|
91
|
+
model_data, farm_data, point_data, sel=sel, isel=isel
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# basic checks:
|
|
95
|
+
super().run_calculation(algo, model, model_data, farm_data, point_data)
|
|
96
|
+
|
|
97
|
+
# prepare:
|
|
98
|
+
n_states = model_data.sizes[FC.STATE]
|
|
99
|
+
out_coords = model.output_coords()
|
|
100
|
+
coords = {}
|
|
101
|
+
if FC.STATE in out_coords and FC.STATE in model_data.coords:
|
|
102
|
+
coords[FC.STATE] = model_data[FC.STATE].to_numpy()
|
|
103
|
+
if farm_data is None:
|
|
104
|
+
farm_data = Dataset()
|
|
105
|
+
goal_data = farm_data if point_data is None else point_data
|
|
106
|
+
|
|
107
|
+
# DEBUG objec mem sizes:
|
|
108
|
+
# from foxes.utils import print_mem
|
|
109
|
+
# for m in [algo] + model.models:
|
|
110
|
+
# print_mem(m, pre_str="MULTIP CHECKING LARGE DATA", min_csize=9999)
|
|
111
|
+
|
|
112
|
+
# calculate chunk sizes:
|
|
113
|
+
n_targets = point_data.sizes[FC.TARGET] if point_data is not None else 0
|
|
114
|
+
chunk_sizes_states, chunk_sizes_targets = self.calc_chunk_sizes(
|
|
115
|
+
n_states, n_targets
|
|
116
|
+
)
|
|
117
|
+
n_chunks_states = len(chunk_sizes_states)
|
|
118
|
+
n_chunks_targets = len(chunk_sizes_targets)
|
|
119
|
+
self.print(
|
|
120
|
+
f"Selecting n_chunks_states = {n_chunks_states}, n_chunks_targets = {n_chunks_targets}",
|
|
121
|
+
level=2,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# prepare and submit chunks:
|
|
125
|
+
n_chunks_all = n_chunks_states * n_chunks_targets
|
|
126
|
+
self.print(f"Looping over {n_chunks_all} chunks")
|
|
127
|
+
pbar = tqdm(total=n_chunks_all) if self.verbosity > 1 else None
|
|
128
|
+
results = {}
|
|
129
|
+
i0_states = 0
|
|
130
|
+
for chunki_states in range(n_chunks_states):
|
|
131
|
+
i1_states = i0_states + chunk_sizes_states[chunki_states]
|
|
132
|
+
i0_targets = 0
|
|
133
|
+
for chunki_points in range(n_chunks_targets):
|
|
134
|
+
i1_targets = i0_targets + chunk_sizes_targets[chunki_points]
|
|
135
|
+
|
|
136
|
+
i = chunki_states * n_chunks_targets + chunki_points
|
|
137
|
+
self.print(f"Computing chunk {i}/{n_chunks_all}")
|
|
138
|
+
|
|
139
|
+
# get this chunk's data:
|
|
140
|
+
data = self.get_chunk_input_data(
|
|
141
|
+
algo=algo,
|
|
142
|
+
model_data=model_data,
|
|
143
|
+
farm_data=farm_data,
|
|
144
|
+
point_data=point_data,
|
|
145
|
+
states_i0_i1=(i0_states, i1_states),
|
|
146
|
+
targets_i0_i1=(i0_targets, i1_targets),
|
|
147
|
+
out_vars=out_vars,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# submit model calculation:
|
|
151
|
+
key = (chunki_states, chunki_points)
|
|
152
|
+
results[key] = _run(
|
|
153
|
+
algo,
|
|
154
|
+
model,
|
|
155
|
+
data,
|
|
156
|
+
iterative,
|
|
157
|
+
chunk_store,
|
|
158
|
+
(i0_states, i0_targets),
|
|
159
|
+
**calc_pars,
|
|
160
|
+
)
|
|
161
|
+
chunk_store.update(results[key][1])
|
|
162
|
+
del data
|
|
163
|
+
|
|
164
|
+
i0_targets = i1_targets
|
|
165
|
+
|
|
166
|
+
if pbar is not None:
|
|
167
|
+
pbar.update()
|
|
168
|
+
|
|
169
|
+
i0_states = i1_states
|
|
170
|
+
|
|
171
|
+
del calc_pars, farm_data, point_data
|
|
172
|
+
if pbar is not None:
|
|
173
|
+
pbar.close()
|
|
174
|
+
|
|
175
|
+
return self.combine_results(
|
|
176
|
+
algo=algo,
|
|
177
|
+
results=results,
|
|
178
|
+
model_data=model_data,
|
|
179
|
+
out_vars=out_vars,
|
|
180
|
+
out_coords=out_coords,
|
|
181
|
+
n_chunks_states=n_chunks_states,
|
|
182
|
+
n_chunks_targets=n_chunks_targets,
|
|
183
|
+
goal_data=goal_data,
|
|
184
|
+
iterative=iterative,
|
|
185
|
+
)
|
foxes/engines/pool.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import xarray as xr
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from tqdm import tqdm
|
|
4
|
+
|
|
5
|
+
from foxes.core import Engine
|
|
6
|
+
import foxes.constants as FC
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _run(algo, model, data, iterative, chunk_store, i0_t0, **cpars):
|
|
10
|
+
"""Helper function for running in a single process"""
|
|
11
|
+
algo.reset_chunk_store(chunk_store)
|
|
12
|
+
results = model.calculate(algo, *data, **cpars)
|
|
13
|
+
chunk_store = algo.reset_chunk_store() if iterative else {}
|
|
14
|
+
cstore = {i0_t0: chunk_store[i0_t0]} if i0_t0 in chunk_store else {}
|
|
15
|
+
return results, cstore
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PoolEngine(Engine):
|
|
19
|
+
"""
|
|
20
|
+
Abstract engine for pool type parallelizations.
|
|
21
|
+
|
|
22
|
+
:group: engines
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def _create_pool(self):
|
|
28
|
+
"""Creates the pool"""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def _submit(self, f, *args, **kwargs):
|
|
33
|
+
"""
|
|
34
|
+
Submits to the pool
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
f: Callable
|
|
39
|
+
The function f(*args, **kwargs) to be
|
|
40
|
+
submitted
|
|
41
|
+
args: tuple, optional
|
|
42
|
+
Arguments for the function
|
|
43
|
+
kwargs: dict, optional
|
|
44
|
+
Arguments for the function
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
future: object
|
|
49
|
+
The future object
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def _result(self, future):
|
|
56
|
+
"""
|
|
57
|
+
Waits for result from a future
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
future: object
|
|
62
|
+
The future
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
result: object
|
|
67
|
+
The calculation result
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def _shutdown_pool(self):
|
|
74
|
+
"""Shuts down the pool"""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def initialize(self):
|
|
78
|
+
"""
|
|
79
|
+
Initializes the engine.
|
|
80
|
+
"""
|
|
81
|
+
super().initialize()
|
|
82
|
+
self._create_pool()
|
|
83
|
+
|
|
84
|
+
def run_calculation(
|
|
85
|
+
self,
|
|
86
|
+
algo,
|
|
87
|
+
model,
|
|
88
|
+
model_data=None,
|
|
89
|
+
farm_data=None,
|
|
90
|
+
point_data=None,
|
|
91
|
+
out_vars=[],
|
|
92
|
+
chunk_store={},
|
|
93
|
+
sel=None,
|
|
94
|
+
isel=None,
|
|
95
|
+
iterative=False,
|
|
96
|
+
**calc_pars,
|
|
97
|
+
):
|
|
98
|
+
"""
|
|
99
|
+
Runs the model calculation
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
algo: foxes.core.Algorithm
|
|
104
|
+
The algorithm object
|
|
105
|
+
model: foxes.core.DataCalcModel
|
|
106
|
+
The model that whose calculate function
|
|
107
|
+
should be run
|
|
108
|
+
model_data: xarray.Dataset
|
|
109
|
+
The initial model data
|
|
110
|
+
farm_data: xarray.Dataset
|
|
111
|
+
The initial farm data
|
|
112
|
+
point_data: xarray.Dataset
|
|
113
|
+
The initial point data
|
|
114
|
+
out_vars: list of str, optional
|
|
115
|
+
Names of the output variables
|
|
116
|
+
chunk_store: foxes.utils.Dict
|
|
117
|
+
The chunk store
|
|
118
|
+
sel: dict, optional
|
|
119
|
+
Selection of coordinate subsets
|
|
120
|
+
isel: dict, optional
|
|
121
|
+
Selection of coordinate subsets index values
|
|
122
|
+
iterative: bool
|
|
123
|
+
Flag for use within the iterative algorithm
|
|
124
|
+
calc_pars: dict, optional
|
|
125
|
+
Additional parameters for the model.calculate()
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
results: xarray.Dataset
|
|
130
|
+
The model results
|
|
131
|
+
|
|
132
|
+
"""
|
|
133
|
+
# subset selection:
|
|
134
|
+
model_data, farm_data, point_data = self.select_subsets(
|
|
135
|
+
model_data, farm_data, point_data, sel=sel, isel=isel
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# basic checks:
|
|
139
|
+
super().run_calculation(algo, model, model_data, farm_data, point_data)
|
|
140
|
+
|
|
141
|
+
# prepare:
|
|
142
|
+
n_states = model_data.sizes[FC.STATE]
|
|
143
|
+
out_coords = model.output_coords()
|
|
144
|
+
coords = {}
|
|
145
|
+
if FC.STATE in out_coords and FC.STATE in model_data.coords:
|
|
146
|
+
coords[FC.STATE] = model_data[FC.STATE].to_numpy()
|
|
147
|
+
if farm_data is None:
|
|
148
|
+
farm_data = xr.Dataset()
|
|
149
|
+
goal_data = farm_data if point_data is None else point_data
|
|
150
|
+
|
|
151
|
+
# DEBUG objec mem sizes:
|
|
152
|
+
# from foxes.utils import print_mem
|
|
153
|
+
# for m in [algo] + model.models:
|
|
154
|
+
# print_mem(m, pre_str="MULTIP CHECKING LARGE DATA", min_csize=9999)
|
|
155
|
+
|
|
156
|
+
# calculate chunk sizes:
|
|
157
|
+
n_targets = point_data.sizes[FC.TARGET] if point_data is not None else 0
|
|
158
|
+
chunk_sizes_states, chunk_sizes_targets = self.calc_chunk_sizes(
|
|
159
|
+
n_states, n_targets
|
|
160
|
+
)
|
|
161
|
+
n_chunks_states = len(chunk_sizes_states)
|
|
162
|
+
n_chunks_targets = len(chunk_sizes_targets)
|
|
163
|
+
self.print(
|
|
164
|
+
f"Selecting n_chunks_states = {n_chunks_states}, n_chunks_targets = {n_chunks_targets}",
|
|
165
|
+
level=2,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# prepare and submit chunks:
|
|
169
|
+
n_chunks_all = n_chunks_states * n_chunks_targets
|
|
170
|
+
self.print(
|
|
171
|
+
f"Submitting {n_chunks_all} chunks to {self.n_procs} processes", level=2
|
|
172
|
+
)
|
|
173
|
+
pbar = tqdm(total=n_chunks_all) if self.verbosity > 1 else None
|
|
174
|
+
jobs = {}
|
|
175
|
+
i0_states = 0
|
|
176
|
+
for chunki_states in range(n_chunks_states):
|
|
177
|
+
i1_states = i0_states + chunk_sizes_states[chunki_states]
|
|
178
|
+
i0_targets = 0
|
|
179
|
+
for chunki_points in range(n_chunks_targets):
|
|
180
|
+
i1_targets = i0_targets + chunk_sizes_targets[chunki_points]
|
|
181
|
+
|
|
182
|
+
# get this chunk's data:
|
|
183
|
+
data = self.get_chunk_input_data(
|
|
184
|
+
algo=algo,
|
|
185
|
+
model_data=model_data,
|
|
186
|
+
farm_data=farm_data,
|
|
187
|
+
point_data=point_data,
|
|
188
|
+
states_i0_i1=(i0_states, i1_states),
|
|
189
|
+
targets_i0_i1=(i0_targets, i1_targets),
|
|
190
|
+
out_vars=out_vars,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# submit model calculation:
|
|
194
|
+
jobs[(chunki_states, chunki_points)] = self._submit(
|
|
195
|
+
_run,
|
|
196
|
+
algo,
|
|
197
|
+
model,
|
|
198
|
+
data,
|
|
199
|
+
iterative,
|
|
200
|
+
chunk_store,
|
|
201
|
+
(i0_states, i0_targets),
|
|
202
|
+
**calc_pars,
|
|
203
|
+
)
|
|
204
|
+
del data
|
|
205
|
+
|
|
206
|
+
i0_targets = i1_targets
|
|
207
|
+
|
|
208
|
+
if pbar is not None:
|
|
209
|
+
pbar.update()
|
|
210
|
+
|
|
211
|
+
i0_states = i1_states
|
|
212
|
+
|
|
213
|
+
del calc_pars, farm_data, point_data
|
|
214
|
+
if pbar is not None:
|
|
215
|
+
pbar.close()
|
|
216
|
+
|
|
217
|
+
# wait for results:
|
|
218
|
+
if n_chunks_all > 1 or self.verbosity > 1:
|
|
219
|
+
self.print(
|
|
220
|
+
f"Computing {n_chunks_all} chunks using {self.n_procs} processes"
|
|
221
|
+
)
|
|
222
|
+
pbar = (
|
|
223
|
+
tqdm(total=n_chunks_all)
|
|
224
|
+
if n_chunks_all > 1 and self.verbosity > 0
|
|
225
|
+
else None
|
|
226
|
+
)
|
|
227
|
+
results = {}
|
|
228
|
+
for chunki_states in range(n_chunks_states):
|
|
229
|
+
for chunki_points in range(n_chunks_targets):
|
|
230
|
+
key = (chunki_states, chunki_points)
|
|
231
|
+
results[key] = self._result(jobs.pop((chunki_states, chunki_points)))
|
|
232
|
+
if pbar is not None:
|
|
233
|
+
pbar.update()
|
|
234
|
+
if pbar is not None:
|
|
235
|
+
pbar.close()
|
|
236
|
+
|
|
237
|
+
return self.combine_results(
|
|
238
|
+
algo=algo,
|
|
239
|
+
results=results,
|
|
240
|
+
model_data=model_data,
|
|
241
|
+
out_vars=out_vars,
|
|
242
|
+
out_coords=out_coords,
|
|
243
|
+
n_chunks_states=n_chunks_states,
|
|
244
|
+
n_chunks_targets=n_chunks_targets,
|
|
245
|
+
goal_data=goal_data,
|
|
246
|
+
iterative=iterative,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def finalize(self, *exit_args, **exit_kwargs):
|
|
250
|
+
"""
|
|
251
|
+
Finalizes the engine.
|
|
252
|
+
|
|
253
|
+
Parameters
|
|
254
|
+
----------
|
|
255
|
+
exit_args: tuple, optional
|
|
256
|
+
Arguments from the exit function
|
|
257
|
+
exit_kwargs: dict, optional
|
|
258
|
+
Arguments from the exit function
|
|
259
|
+
|
|
260
|
+
"""
|
|
261
|
+
if self.initialized:
|
|
262
|
+
self._shutdown_pool()
|
|
263
|
+
super().finalize(*exit_args, **exit_kwargs)
|