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.

Files changed (215) hide show
  1. docs/source/conf.py +353 -0
  2. examples/abl_states/run.py +160 -0
  3. examples/compare_rotors_pwakes/run.py +217 -0
  4. examples/compare_wakes/run.py +241 -0
  5. examples/dyn_wakes/run.py +311 -0
  6. examples/field_data_nc/run.py +121 -0
  7. examples/induction/run.py +201 -0
  8. examples/multi_height/run.py +113 -0
  9. examples/power_mask/run.py +249 -0
  10. examples/random_timeseries/run.py +210 -0
  11. examples/scan_row/run.py +193 -0
  12. examples/sector_management/run.py +162 -0
  13. examples/sequential/run.py +209 -0
  14. examples/single_state/run.py +201 -0
  15. examples/states_lookup_table/run.py +137 -0
  16. examples/streamline_wakes/run.py +138 -0
  17. examples/tab_file/run.py +142 -0
  18. examples/timelines/run.py +267 -0
  19. examples/timeseries/run.py +190 -0
  20. examples/timeseries_slurm/run.py +185 -0
  21. examples/wind_rose/run.py +141 -0
  22. examples/windio/run.py +29 -0
  23. examples/yawed_wake/run.py +196 -0
  24. foxes/__init__.py +4 -8
  25. foxes/algorithms/__init__.py +1 -1
  26. foxes/algorithms/downwind/downwind.py +247 -111
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
  28. foxes/algorithms/downwind/models/init_farm_data.py +2 -2
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
  33. foxes/algorithms/iterative/iterative.py +74 -34
  34. foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
  35. foxes/algorithms/iterative/models/urelax.py +3 -3
  36. foxes/algorithms/sequential/models/plugin.py +5 -5
  37. foxes/algorithms/sequential/models/seq_state.py +1 -1
  38. foxes/algorithms/sequential/sequential.py +126 -255
  39. foxes/constants.py +22 -7
  40. foxes/core/__init__.py +1 -0
  41. foxes/core/algorithm.py +632 -147
  42. foxes/core/data.py +252 -20
  43. foxes/core/data_calc_model.py +15 -291
  44. foxes/core/engine.py +640 -0
  45. foxes/core/farm_controller.py +38 -10
  46. foxes/core/farm_data_model.py +16 -1
  47. foxes/core/ground_model.py +2 -2
  48. foxes/core/model.py +249 -182
  49. foxes/core/partial_wakes_model.py +1 -1
  50. foxes/core/point_data_model.py +17 -2
  51. foxes/core/rotor_model.py +27 -21
  52. foxes/core/states.py +17 -1
  53. foxes/core/turbine_type.py +28 -0
  54. foxes/core/wake_frame.py +30 -34
  55. foxes/core/wake_model.py +5 -5
  56. foxes/core/wake_superposition.py +1 -1
  57. foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
  58. foxes/engines/__init__.py +17 -0
  59. foxes/engines/dask.py +982 -0
  60. foxes/engines/default.py +75 -0
  61. foxes/engines/futures.py +72 -0
  62. foxes/engines/mpi.py +38 -0
  63. foxes/engines/multiprocess.py +71 -0
  64. foxes/engines/numpy.py +167 -0
  65. foxes/engines/pool.py +249 -0
  66. foxes/engines/ray.py +79 -0
  67. foxes/engines/single.py +141 -0
  68. foxes/input/farm_layout/__init__.py +1 -0
  69. foxes/input/farm_layout/from_csv.py +4 -0
  70. foxes/input/farm_layout/from_json.py +2 -2
  71. foxes/input/farm_layout/grid.py +2 -2
  72. foxes/input/farm_layout/ring.py +65 -0
  73. foxes/input/farm_layout/row.py +2 -2
  74. foxes/input/states/__init__.py +7 -0
  75. foxes/input/states/create/random_abl_states.py +1 -1
  76. foxes/input/states/field_data_nc.py +158 -33
  77. foxes/input/states/multi_height.py +128 -14
  78. foxes/input/states/one_point_flow.py +577 -0
  79. foxes/input/states/scan_ws.py +74 -3
  80. foxes/input/states/single.py +1 -1
  81. foxes/input/states/slice_data_nc.py +681 -0
  82. foxes/input/states/states_table.py +204 -35
  83. foxes/input/windio/__init__.py +2 -2
  84. foxes/input/windio/get_states.py +44 -23
  85. foxes/input/windio/read_attributes.py +48 -17
  86. foxes/input/windio/read_farm.py +116 -102
  87. foxes/input/windio/read_fields.py +16 -6
  88. foxes/input/windio/read_outputs.py +71 -24
  89. foxes/input/windio/runner.py +31 -17
  90. foxes/input/windio/windio.py +41 -23
  91. foxes/models/farm_models/turbine2farm.py +1 -1
  92. foxes/models/ground_models/wake_mirror.py +10 -6
  93. foxes/models/model_book.py +58 -20
  94. foxes/models/partial_wakes/axiwake.py +3 -3
  95. foxes/models/partial_wakes/rotor_points.py +3 -3
  96. foxes/models/partial_wakes/top_hat.py +2 -2
  97. foxes/models/point_models/set_uniform_data.py +1 -1
  98. foxes/models/point_models/tke2ti.py +1 -1
  99. foxes/models/point_models/wake_deltas.py +1 -1
  100. foxes/models/rotor_models/centre.py +4 -0
  101. foxes/models/rotor_models/grid.py +24 -25
  102. foxes/models/rotor_models/levels.py +4 -5
  103. foxes/models/turbine_models/calculator.py +4 -6
  104. foxes/models/turbine_models/kTI_model.py +22 -6
  105. foxes/models/turbine_models/lookup_table.py +30 -4
  106. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  107. foxes/models/turbine_models/set_farm_vars.py +103 -34
  108. foxes/models/turbine_types/PCt_file.py +27 -3
  109. foxes/models/turbine_types/PCt_from_two.py +27 -3
  110. foxes/models/turbine_types/TBL_file.py +80 -0
  111. foxes/models/turbine_types/__init__.py +2 -0
  112. foxes/models/turbine_types/lookup.py +316 -0
  113. foxes/models/turbine_types/null_type.py +51 -1
  114. foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
  115. foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
  116. foxes/models/vertical_profiles/__init__.py +1 -1
  117. foxes/models/vertical_profiles/data_profile.py +1 -1
  118. foxes/models/wake_frames/__init__.py +1 -0
  119. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  120. foxes/models/wake_frames/farm_order.py +25 -5
  121. foxes/models/wake_frames/rotor_wd.py +6 -4
  122. foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
  123. foxes/models/wake_frames/streamlines.py +21 -22
  124. foxes/models/wake_frames/timelines.py +330 -129
  125. foxes/models/wake_frames/yawed_wakes.py +7 -4
  126. foxes/models/wake_models/dist_sliced.py +2 -4
  127. foxes/models/wake_models/induction/rankine_half_body.py +5 -5
  128. foxes/models/wake_models/induction/rathmann.py +78 -24
  129. foxes/models/wake_models/induction/self_similar.py +78 -28
  130. foxes/models/wake_models/induction/vortex_sheet.py +86 -48
  131. foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
  132. foxes/models/wake_models/ti/iec_ti.py +40 -21
  133. foxes/models/wake_models/top_hat.py +1 -1
  134. foxes/models/wake_models/wind/bastankhah14.py +8 -6
  135. foxes/models/wake_models/wind/bastankhah16.py +17 -16
  136. foxes/models/wake_models/wind/jensen.py +4 -3
  137. foxes/models/wake_models/wind/turbopark.py +16 -13
  138. foxes/models/wake_superpositions/ti_linear.py +1 -1
  139. foxes/models/wake_superpositions/ti_max.py +1 -1
  140. foxes/models/wake_superpositions/ti_pow.py +1 -1
  141. foxes/models/wake_superpositions/ti_quadratic.py +1 -1
  142. foxes/models/wake_superpositions/ws_linear.py +8 -7
  143. foxes/models/wake_superpositions/ws_max.py +8 -7
  144. foxes/models/wake_superpositions/ws_pow.py +8 -7
  145. foxes/models/wake_superpositions/ws_product.py +5 -5
  146. foxes/models/wake_superpositions/ws_quadratic.py +8 -7
  147. foxes/output/__init__.py +4 -1
  148. foxes/output/farm_layout.py +16 -12
  149. foxes/output/farm_results_eval.py +1 -1
  150. foxes/output/flow_plots_2d/__init__.py +0 -1
  151. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  152. foxes/output/grids.py +92 -22
  153. foxes/output/results_writer.py +2 -2
  154. foxes/output/rose_plot.py +3 -3
  155. foxes/output/seq_plugins/__init__.py +2 -0
  156. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
  157. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  158. foxes/output/slice_data.py +131 -111
  159. foxes/output/state_turbine_map.py +19 -14
  160. foxes/output/state_turbine_table.py +19 -19
  161. foxes/utils/__init__.py +1 -1
  162. foxes/utils/abl/neutral.py +2 -2
  163. foxes/utils/abl/stable.py +2 -2
  164. foxes/utils/abl/unstable.py +2 -2
  165. foxes/utils/data_book.py +1 -1
  166. foxes/utils/dev_utils.py +42 -0
  167. foxes/utils/dict.py +24 -1
  168. foxes/utils/exec_python.py +1 -1
  169. foxes/utils/factory.py +176 -53
  170. foxes/utils/geom2d/circle.py +1 -1
  171. foxes/utils/geom2d/polygon.py +1 -1
  172. foxes/utils/geopandas_utils.py +2 -2
  173. foxes/utils/load.py +2 -2
  174. foxes/utils/pandas_helpers.py +3 -2
  175. foxes/utils/wind_dir.py +0 -2
  176. foxes/utils/xarray_utils.py +24 -14
  177. foxes/variables.py +39 -2
  178. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
  179. foxes-1.1.0.2.dist-info/RECORD +309 -0
  180. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
  181. foxes-1.1.0.2.dist-info/top_level.txt +4 -0
  182. tests/0_consistency/iterative/test_iterative.py +92 -0
  183. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  184. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  185. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  186. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  187. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  188. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  189. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  190. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  191. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  192. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  193. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  194. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  195. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  196. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  197. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  198. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  199. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  200. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  201. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  202. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  203. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  204. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  205. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  206. tests/3_examples/test_examples.py +34 -0
  207. foxes/VERSION +0 -1
  208. foxes/output/flow_plots_2d.py +0 -0
  209. foxes/utils/geopandas_helpers.py +0 -294
  210. foxes/utils/runners/__init__.py +0 -1
  211. foxes/utils/runners/runners.py +0 -280
  212. foxes-0.8.2.dist-info/RECORD +0 -247
  213. foxes-0.8.2.dist-info/top_level.txt +0 -1
  214. foxes-0.8.2.dist-info/zip-safe +0 -1
  215. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/LICENSE +0 -0
@@ -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
@@ -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,71 @@
1
+ from foxes.utils import import_module
2
+
3
+ from .pool import PoolEngine
4
+
5
+ Pool = None
6
+
7
+
8
+ def load_multiprocess():
9
+ """On-demand loading of the multiprocess package"""
10
+ global Pool
11
+ if Pool is None:
12
+ Pool = import_module("multiprocess", hint="pip install multiprocess").Pool
13
+
14
+
15
+ class MultiprocessEngine(PoolEngine):
16
+ """
17
+ The multiprocessing engine for foxes calculations.
18
+
19
+ :group: engines
20
+
21
+ """
22
+
23
+ def _create_pool(self):
24
+ """Creates the pool"""
25
+ load_multiprocess()
26
+ self._pool = Pool(processes=self.n_procs)
27
+
28
+ def _submit(self, f, *args, **kwargs):
29
+ """
30
+ Submits to the pool
31
+
32
+ Parameters
33
+ ----------
34
+ f: Callable
35
+ The function f(*args, **kwargs) to be
36
+ submitted
37
+ args: tuple, optional
38
+ Arguments for the function
39
+ kwargs: dict, optional
40
+ Arguments for the function
41
+
42
+ Returns
43
+ -------
44
+ future: object
45
+ The future object
46
+
47
+ """
48
+ return self._pool.apply_async(f, args=args, kwds=kwargs)
49
+
50
+ def _result(self, future):
51
+ """
52
+ Waits for result from a future
53
+
54
+ Parameters
55
+ ----------
56
+ future: object
57
+ The future
58
+
59
+ Returns
60
+ -------
61
+ result: object
62
+ The calculation result
63
+
64
+ """
65
+ return future.get()
66
+
67
+ def _shutdown_pool(self):
68
+ """Shuts down the pool"""
69
+ self._pool.close()
70
+ self._pool.terminate()
71
+ self._pool.join()
foxes/engines/numpy.py ADDED
@@ -0,0 +1,167 @@
1
+ from tqdm import tqdm
2
+ from xarray import Dataset
3
+ from tqdm import tqdm
4
+
5
+ from foxes.core import Engine
6
+ import foxes.constants as FC
7
+
8
+ from .pool import _run
9
+
10
+
11
+ class NumpyEngine(Engine):
12
+ """
13
+ The numpy engine for foxes calculations.
14
+
15
+ :group: engines
16
+
17
+ """
18
+
19
+ def run_calculation(
20
+ self,
21
+ algo,
22
+ model,
23
+ model_data=None,
24
+ farm_data=None,
25
+ point_data=None,
26
+ out_vars=[],
27
+ chunk_store={},
28
+ sel=None,
29
+ isel=None,
30
+ iterative=False,
31
+ **calc_pars,
32
+ ):
33
+ """
34
+ Runs the model calculation
35
+
36
+ Parameters
37
+ ----------
38
+ algo: foxes.core.Algorithm
39
+ The algorithm object
40
+ model: foxes.core.DataCalcModel
41
+ The model that whose calculate function
42
+ should be run
43
+ model_data: xarray.Dataset
44
+ The initial model data
45
+ farm_data: xarray.Dataset
46
+ The initial farm data
47
+ point_data: xarray.Dataset
48
+ The initial point data
49
+ out_vars: list of str, optional
50
+ Names of the output variables
51
+ chunk_store: foxes.utils.Dict
52
+ The chunk store
53
+ sel: dict, optional
54
+ Selection of coordinate subsets
55
+ isel: dict, optional
56
+ Selection of coordinate subsets index values
57
+ iterative: bool
58
+ Flag for use within the iterative algorithm
59
+ calc_pars: dict, optional
60
+ Additional parameters for the model.calculate()
61
+
62
+ Returns
63
+ -------
64
+ results: xarray.Dataset
65
+ The model results
66
+
67
+ """
68
+ # subset selection:
69
+ model_data, farm_data, point_data = self.select_subsets(
70
+ model_data, farm_data, point_data, sel=sel, isel=isel
71
+ )
72
+
73
+ # basic checks:
74
+ super().run_calculation(algo, model, model_data, farm_data, point_data)
75
+
76
+ # prepare:
77
+ n_states = model_data.sizes[FC.STATE]
78
+ out_coords = model.output_coords()
79
+ coords = {}
80
+ if FC.STATE in out_coords and FC.STATE in model_data.coords:
81
+ coords[FC.STATE] = model_data[FC.STATE].to_numpy()
82
+ if farm_data is None:
83
+ farm_data = Dataset()
84
+ goal_data = farm_data if point_data is None else point_data
85
+
86
+ # DEBUG objec mem sizes:
87
+ # from foxes.utils import print_mem
88
+ # for m in [algo] + model.models:
89
+ # print_mem(m, pre_str="MULTIP CHECKING LARGE DATA", min_csize=9999)
90
+
91
+ # calculate chunk sizes:
92
+ n_targets = point_data.sizes[FC.TARGET] if point_data is not None else 0
93
+ chunk_sizes_states, chunk_sizes_targets = self.calc_chunk_sizes(
94
+ n_states, n_targets
95
+ )
96
+ n_chunks_states = len(chunk_sizes_states)
97
+ n_chunks_targets = len(chunk_sizes_targets)
98
+ self.print(
99
+ f"{type(self).__name__}: Selecting n_chunks_states = {n_chunks_states}, n_chunks_targets = {n_chunks_targets}",
100
+ level=2,
101
+ )
102
+
103
+ # prepare and submit chunks:
104
+ n_chunks_all = n_chunks_states * n_chunks_targets
105
+ self.print(f"{type(self).__name__}: Looping over {n_chunks_all} chunks")
106
+ pbar = (
107
+ tqdm(total=n_chunks_all)
108
+ if self.verbosity > 0 and n_chunks_all > 1
109
+ else None
110
+ )
111
+ results = {}
112
+ i0_states = 0
113
+ for chunki_states in range(n_chunks_states):
114
+ i1_states = i0_states + chunk_sizes_states[chunki_states]
115
+ i0_targets = 0
116
+ for chunki_points in range(n_chunks_targets):
117
+ i1_targets = i0_targets + chunk_sizes_targets[chunki_points]
118
+
119
+ i = chunki_states * n_chunks_targets + chunki_points
120
+
121
+ # get this chunk's data:
122
+ data = self.get_chunk_input_data(
123
+ algo=algo,
124
+ model_data=model_data,
125
+ farm_data=farm_data,
126
+ point_data=point_data,
127
+ states_i0_i1=(i0_states, i1_states),
128
+ targets_i0_i1=(i0_targets, i1_targets),
129
+ out_vars=out_vars,
130
+ )
131
+
132
+ # submit model calculation:
133
+ key = (chunki_states, chunki_points)
134
+ results[key] = _run(
135
+ algo,
136
+ model,
137
+ data,
138
+ iterative,
139
+ chunk_store,
140
+ (i0_states, i0_targets),
141
+ **calc_pars,
142
+ )
143
+ chunk_store.update(results[key][1])
144
+ del data
145
+
146
+ i0_targets = i1_targets
147
+
148
+ if pbar is not None:
149
+ pbar.update()
150
+
151
+ i0_states = i1_states
152
+
153
+ del calc_pars, farm_data, point_data
154
+ if pbar is not None:
155
+ pbar.close()
156
+
157
+ return self.combine_results(
158
+ algo=algo,
159
+ results=results,
160
+ model_data=model_data,
161
+ out_vars=out_vars,
162
+ out_coords=out_coords,
163
+ n_chunks_states=n_chunks_states,
164
+ n_chunks_targets=n_chunks_targets,
165
+ goal_data=goal_data,
166
+ iterative=iterative,
167
+ )
foxes/engines/pool.py ADDED
@@ -0,0 +1,249 @@
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 __enter__(self):
78
+ self._create_pool()
79
+ return super().__enter__()
80
+
81
+ def __exit__(self, *exit_args):
82
+ self._shutdown_pool()
83
+ super().__exit__(*exit_args)
84
+
85
+ def run_calculation(
86
+ self,
87
+ algo,
88
+ model,
89
+ model_data=None,
90
+ farm_data=None,
91
+ point_data=None,
92
+ out_vars=[],
93
+ chunk_store={},
94
+ sel=None,
95
+ isel=None,
96
+ iterative=False,
97
+ **calc_pars,
98
+ ):
99
+ """
100
+ Runs the model calculation
101
+
102
+ Parameters
103
+ ----------
104
+ algo: foxes.core.Algorithm
105
+ The algorithm object
106
+ model: foxes.core.DataCalcModel
107
+ The model that whose calculate function
108
+ should be run
109
+ model_data: xarray.Dataset
110
+ The initial model data
111
+ farm_data: xarray.Dataset
112
+ The initial farm data
113
+ point_data: xarray.Dataset
114
+ The initial point data
115
+ out_vars: list of str, optional
116
+ Names of the output variables
117
+ chunk_store: foxes.utils.Dict
118
+ The chunk store
119
+ sel: dict, optional
120
+ Selection of coordinate subsets
121
+ isel: dict, optional
122
+ Selection of coordinate subsets index values
123
+ iterative: bool
124
+ Flag for use within the iterative algorithm
125
+ calc_pars: dict, optional
126
+ Additional parameters for the model.calculate()
127
+
128
+ Returns
129
+ -------
130
+ results: xarray.Dataset
131
+ The model results
132
+
133
+ """
134
+ # subset selection:
135
+ model_data, farm_data, point_data = self.select_subsets(
136
+ model_data, farm_data, point_data, sel=sel, isel=isel
137
+ )
138
+
139
+ # basic checks:
140
+ super().run_calculation(algo, model, model_data, farm_data, point_data)
141
+
142
+ # prepare:
143
+ n_states = model_data.sizes[FC.STATE]
144
+ out_coords = model.output_coords()
145
+ coords = {}
146
+ if FC.STATE in out_coords and FC.STATE in model_data.coords:
147
+ coords[FC.STATE] = model_data[FC.STATE].to_numpy()
148
+ if farm_data is None:
149
+ farm_data = xr.Dataset()
150
+ goal_data = farm_data if point_data is None else point_data
151
+
152
+ # DEBUG objec mem sizes:
153
+ # from foxes.utils import print_mem
154
+ # for m in [algo] + model.models:
155
+ # print_mem(m, pre_str="MULTIP CHECKING LARGE DATA", min_csize=9999)
156
+
157
+ # calculate chunk sizes:
158
+ n_targets = point_data.sizes[FC.TARGET] if point_data is not None else 0
159
+ chunk_sizes_states, chunk_sizes_targets = self.calc_chunk_sizes(
160
+ n_states, n_targets
161
+ )
162
+ n_chunks_states = len(chunk_sizes_states)
163
+ n_chunks_targets = len(chunk_sizes_targets)
164
+ self.print(
165
+ f"{type(self).__name__}: Selecting n_chunks_states = {n_chunks_states}, n_chunks_targets = {n_chunks_targets}",
166
+ level=2,
167
+ )
168
+
169
+ # prepare and submit chunks:
170
+ n_chunks_all = n_chunks_states * n_chunks_targets
171
+ self.print(
172
+ f"{type(self).__name__}: Submitting {n_chunks_all} chunks to {self.n_procs} processes",
173
+ level=2,
174
+ )
175
+ pbar = tqdm(total=n_chunks_all) if self.verbosity > 1 else None
176
+ jobs = {}
177
+ i0_states = 0
178
+ for chunki_states in range(n_chunks_states):
179
+ i1_states = i0_states + chunk_sizes_states[chunki_states]
180
+ i0_targets = 0
181
+ for chunki_points in range(n_chunks_targets):
182
+ i1_targets = i0_targets + chunk_sizes_targets[chunki_points]
183
+
184
+ # get this chunk's data:
185
+ data = self.get_chunk_input_data(
186
+ algo=algo,
187
+ model_data=model_data,
188
+ farm_data=farm_data,
189
+ point_data=point_data,
190
+ states_i0_i1=(i0_states, i1_states),
191
+ targets_i0_i1=(i0_targets, i1_targets),
192
+ out_vars=out_vars,
193
+ )
194
+
195
+ # submit model calculation:
196
+ jobs[(chunki_states, chunki_points)] = self._submit(
197
+ _run,
198
+ algo,
199
+ model,
200
+ data,
201
+ iterative,
202
+ chunk_store,
203
+ (i0_states, i0_targets),
204
+ **calc_pars,
205
+ )
206
+ del data
207
+
208
+ i0_targets = i1_targets
209
+
210
+ if pbar is not None:
211
+ pbar.update()
212
+
213
+ i0_states = i1_states
214
+
215
+ del calc_pars, farm_data, point_data
216
+ if pbar is not None:
217
+ pbar.close()
218
+
219
+ # wait for results:
220
+ if n_chunks_all > 1 or self.verbosity > 1:
221
+ self.print(
222
+ f"{type(self).__name__}: Computing {n_chunks_all} chunks using {self.n_procs} processes"
223
+ )
224
+ pbar = (
225
+ tqdm(total=n_chunks_all)
226
+ if n_chunks_all > 1 and self.verbosity > 0
227
+ else None
228
+ )
229
+ results = {}
230
+ for chunki_states in range(n_chunks_states):
231
+ for chunki_points in range(n_chunks_targets):
232
+ key = (chunki_states, chunki_points)
233
+ results[key] = self._result(jobs.pop((chunki_states, chunki_points)))
234
+ if pbar is not None:
235
+ pbar.update()
236
+ if pbar is not None:
237
+ pbar.close()
238
+
239
+ return self.combine_results(
240
+ algo=algo,
241
+ results=results,
242
+ model_data=model_data,
243
+ out_vars=out_vars,
244
+ out_coords=out_coords,
245
+ n_chunks_states=n_chunks_states,
246
+ n_chunks_targets=n_chunks_targets,
247
+ goal_data=goal_data,
248
+ iterative=iterative,
249
+ )