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
@@ -95,7 +95,7 @@ class PartialAxiwake(PartialCentre):
95
95
  The target point data
96
96
  downwind_index: int
97
97
  The index of the wake causing turbine
98
- in the downwnd order
98
+ in the downwind order
99
99
  wake_deltas: dict
100
100
  The wake deltas. Key: variable name,
101
101
  value: numpy.ndarray with shape
@@ -127,7 +127,7 @@ class PartialAxiwake(PartialCentre):
127
127
  wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
128
128
 
129
129
  # prepare x and r coordinates:
130
- x = np.round(wcoos[..., 0, 0], 12)
130
+ x = wcoos[..., 0, 0]
131
131
  n = wcoos[..., 0, 1:3]
132
132
  R = np.linalg.norm(n, axis=-1)
133
133
  r = np.zeros((n_states, n_targets, self.n), dtype=FC.DTYPE)
@@ -145,7 +145,7 @@ class PartialAxiwake(PartialCentre):
145
145
  n[:, :, 0][~sel] = 1
146
146
 
147
147
  # case wake centre outside rotor disk:
148
- sel = (x > 0) & (R > D / 2)
148
+ sel = (x > 1e-8) & (R > D / 2)
149
149
  if np.any(sel):
150
150
  n_sel = np.sum(sel)
151
151
  Rsel = np.zeros((n_sel, self.n + 1), dtype=FC.DTYPE)
@@ -1,4 +1,5 @@
1
1
  from foxes.core import PartialWakesModel
2
+ import foxes.constants as FC
2
3
 
3
4
 
4
5
  class RotorPoints(PartialWakesModel):
@@ -33,10 +34,9 @@ class RotorPoints(PartialWakesModel):
33
34
  The target point weights, shape: (n_tpoints,)
34
35
 
35
36
  """
36
- rotor = algo.rotor_model
37
37
  return (
38
- rotor.from_data_or_store(rotor.RPOINTS, algo, mdata),
39
- rotor.from_data_or_store(rotor.RWEIGHTS, algo, mdata),
38
+ algo.get_from_chunk_store(FC.ROTOR_POINTS, mdata=mdata),
39
+ algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata),
40
40
  )
41
41
 
42
42
  def finalize_wakes(
@@ -121,7 +121,7 @@ class PartialTopHat(PartialCentre):
121
121
  The target point data
122
122
  downwind_index: int
123
123
  The index of the wake causing turbine
124
- in the downwnd order
124
+ in the downwind order
125
125
  wake_deltas: dict
126
126
  The wake deltas. Key: variable name,
127
127
  value: numpy.ndarray with shape
@@ -148,7 +148,7 @@ class PartialTopHat(PartialCentre):
148
148
  upcast=True,
149
149
  )
150
150
 
151
- sel0 = (ct > 0) & (x > 0)
151
+ sel0 = (ct > 1e-8) & (x > 1e-8)
152
152
  if np.any(sel0):
153
153
  R = np.linalg.norm(yz, axis=-1)
154
154
  del yz
@@ -119,7 +119,7 @@ class SetUniformData(PointDataModel):
119
119
  return self.ovars
120
120
 
121
121
  def calculate(self, algo, mdata, fdata, pdata):
122
- """ "
122
+ """
123
123
  The main model calculation.
124
124
 
125
125
  This function is executed on a single chunk of data,
@@ -30,7 +30,7 @@ class TKE2TI(PointDataModel):
30
30
  return [FV.TI]
31
31
 
32
32
  def calculate(self, algo, mdata, fdata, pdata):
33
- """ "
33
+ """
34
34
  The main model calculation.
35
35
 
36
36
  This function is executed on a single chunk of data,
@@ -52,7 +52,7 @@ class WakeDeltas(PointDataModel):
52
52
  return [f"DELTA_{v}" for v in self.vars]
53
53
 
54
54
  def calculate(self, algo, mdata, fdata, pdata):
55
- """ "
55
+ """
56
56
  The main model calculation.
57
57
 
58
58
  This function is executed on a single chunk of data,
@@ -132,6 +132,10 @@ class CentreRotor(RotorModel):
132
132
  n_states = mdata.n_states
133
133
  n_turbines = algo.n_turbines
134
134
 
135
+ for v in [FV.REWS2, FV.REWS3]:
136
+ if v in fdata and v not in self.calc_vars:
137
+ self.calc_vars.append(v)
138
+
135
139
  uvp = None
136
140
  uv = None
137
141
  if (
@@ -16,8 +16,8 @@ class GridRotor(RotorModel):
16
16
  maximal number of points is N = n * n
17
17
  reduce: bool
18
18
  Flag for reduction to points actually representing
19
- an area with overlap with the circe, recalculating
20
- the self.weights accordingly
19
+ an area with overlap with the circle, recalculating
20
+ the self.__weights accordingly
21
21
  nint: int
22
22
  Integration steps per element
23
23
 
@@ -25,7 +25,7 @@ class GridRotor(RotorModel):
25
25
 
26
26
  """
27
27
 
28
- def __init__(self, n, calc_vars, reduce=True, nint=200):
28
+ def __init__(self, n, reduce=True, nint=200, **kwargs):
29
29
  """
30
30
  Constructor.
31
31
 
@@ -34,20 +34,19 @@ class GridRotor(RotorModel):
34
34
  n: int
35
35
  The number of points along one direction,
36
36
  maximal number of points is N = n * n
37
- calc_vars: list of str
38
- The variables that are calculated by the model
39
- (Their ambients are added automatically)
40
37
  reduce: bool
41
38
  Flag for reduction to points actually representing
42
- an area with overlap with the circe, recalculating
43
- the self.weights accordingly
39
+ an area with overlap with the circle, recalculating
40
+ the self.__weights accordingly
44
41
  nint: int
45
42
  Integration steps per element
46
43
  name: str, optional
47
44
  The model name
45
+ kwargs: dict, optional
46
+ Addition parameters for the base model
48
47
 
49
48
  """
50
- super().__init__(calc_vars)
49
+ super().__init__(**kwargs)
51
50
 
52
51
  self.n = n
53
52
  self.reduce = reduce
@@ -76,12 +75,12 @@ class GridRotor(RotorModel):
76
75
  x = [-1.0 + (i + 0.5) * delta for i in range(self.n)]
77
76
  x, y = np.meshgrid(x, x, indexing="ij")
78
77
 
79
- self.dpoints = np.zeros([N, 3], dtype=FC.DTYPE)
80
- self.dpoints[:, 1] = x.reshape(N)
81
- self.dpoints[:, 2] = y.reshape(N)
78
+ self.__dpoints = np.zeros([N, 3], dtype=FC.DTYPE)
79
+ self.__dpoints[:, 1] = x.reshape(N)
80
+ self.__dpoints[:, 2] = y.reshape(N)
82
81
 
83
82
  if self.reduce:
84
- self.weights = np.zeros((self.n, self.n), dtype=FC.DTYPE)
83
+ self.__weights = np.zeros((self.n, self.n), dtype=FC.DTYPE)
85
84
  for i in range(0, self.n):
86
85
  for j in range(0, self.n):
87
86
  d = delta / self.nint
@@ -95,18 +94,18 @@ class GridRotor(RotorModel):
95
94
  pts[:, :, 0], pts[:, :, 1] = np.meshgrid(hx, hy, indexing="ij")
96
95
 
97
96
  d = np.linalg.norm(pts, axis=2)
98
- self.weights[i, j] = np.sum(d <= 1.0) / self.nint**2
97
+ self.__weights[i, j] = np.sum(d <= 1.0) / self.nint**2
99
98
 
100
- self.weights = self.weights.reshape(N)
101
- sel = self.weights > 0.0
102
- self.dpoints = self.dpoints[sel]
103
- self.weights = self.weights[sel]
104
- self.weights /= np.sum(self.weights)
99
+ self.__weights = self.__weights.reshape(N)
100
+ sel = self.__weights > 0.0
101
+ self.__dpoints = self.__dpoints[sel]
102
+ self.__weights = self.__weights[sel]
103
+ self.__weights /= np.sum(self.__weights)
105
104
 
106
105
  else:
107
- self.dpoints[:, 1] = x.reshape(N)
108
- self.dpoints[:, 2] = y.reshape(N)
109
- self.weights = np.ones(N, dtype=FC.DTYPE) / N
106
+ self.__dpoints[:, 1] = x.reshape(N)
107
+ self.__dpoints[:, 2] = y.reshape(N)
108
+ self.__weights = np.ones(N, dtype=FC.DTYPE) / N
110
109
 
111
110
  def n_rotor_points(self):
112
111
  """
@@ -118,7 +117,7 @@ class GridRotor(RotorModel):
118
117
  The number of rotor points
119
118
 
120
119
  """
121
- return len(self.weights)
120
+ return len(self.__weights)
122
121
 
123
122
  def design_points(self):
124
123
  """
@@ -137,7 +136,7 @@ class GridRotor(RotorModel):
137
136
  The design points, shape: (n_points, 3)
138
137
 
139
138
  """
140
- return self.dpoints
139
+ return self.__dpoints
141
140
 
142
141
  def rotor_point_weights(self):
143
142
  """
@@ -150,4 +149,4 @@ class GridRotor(RotorModel):
150
149
  add to one, shape: (n_rpoints,)
151
150
 
152
151
  """
153
- return self.weights
152
+ return self.__weights
@@ -24,7 +24,7 @@ class LevelRotor(RotorModel):
24
24
 
25
25
  """
26
26
 
27
- def __init__(self, n, calc_vars, reduce=True, nint=200):
27
+ def __init__(self, n, reduce=True, nint=200, **kwargs):
28
28
  """
29
29
  Constructor.
30
30
 
@@ -32,9 +32,6 @@ class LevelRotor(RotorModel):
32
32
  ----------
33
33
  n: int
34
34
  The number of points along the vertical direction
35
- calc_vars: list of str
36
- The variables that are calculated by the model
37
- (Their ambients are added automatically)
38
35
  reduce: bool
39
36
  Flag for calculating the weight of every element according
40
37
  to the rotor diameter at the respective height level
@@ -42,9 +39,11 @@ class LevelRotor(RotorModel):
42
39
  Integration steps per element
43
40
  name: str, optional
44
41
  The model name
42
+ kwargs: dict, optional
43
+ Addition parameters for the base model
45
44
 
46
45
  """
47
- super().__init__(calc_vars)
46
+ super().__init__(**kwargs)
48
47
 
49
48
  self.n = n
50
49
  self.reduce = reduce
@@ -1,5 +1,3 @@
1
- import numpy as np
2
-
3
1
  from foxes.core import TurbineModel
4
2
 
5
3
 
@@ -10,11 +8,11 @@ class Calculator(TurbineModel):
10
8
  Attributes
11
9
  ----------
12
10
  in_vars: list of str
13
- The input farm vairables
11
+ The input farm variables
14
12
  out_vars: list of str
15
13
  The output variables
16
14
  func: Function
17
- The function: f(in0, in1, ..., stsel) -> (out0, ou1, ...)
15
+ The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
18
16
  where inX and outY are numpy.ndarrays and
19
17
  st_sel is the state-turbine selection slice or array.
20
18
  All arrays have shape (n_states, n_turbines).
@@ -30,11 +28,11 @@ class Calculator(TurbineModel):
30
28
  Parameters
31
29
  ----------
32
30
  in_vars: list of str
33
- The input farm vairables
31
+ The input farm variables
34
32
  out_vars: list of str
35
33
  The output variables
36
34
  func: Function
37
- The function: f(in0, in1, ..., stsel) -> (out0, ou1, ...)
35
+ The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
38
36
  where inX and outY are numpy.ndarrays and
39
37
  st_sel is the state-turbine selection slice or array.
40
38
  All arrays have shape (n_states, n_turbines).
@@ -101,15 +101,31 @@ class kTI(TurbineModel):
101
101
  Values: numpy.ndarray with shape (n_states, n_turbines)
102
102
 
103
103
  """
104
+
104
105
  kti = self.get_data(
105
- FV.KTI, FC.STATE_TURBINE, lookup="sf", fdata=fdata, upcast=True
106
- )[st_sel]
106
+ FV.KTI,
107
+ FC.STATE_TURBINE,
108
+ lookup="sf",
109
+ fdata=fdata,
110
+ upcast=False,
111
+ selection=st_sel,
112
+ )
107
113
  kb = self.get_data(
108
- FV.KB, FC.STATE_TURBINE, lookup="sf", fdata=fdata, upcast=True
109
- )[st_sel]
114
+ FV.KB,
115
+ FC.STATE_TURBINE,
116
+ lookup="sf",
117
+ fdata=fdata,
118
+ upcast=False,
119
+ selection=st_sel,
120
+ )
110
121
  ti = self.get_data(
111
- self.ti_var, FC.STATE_TURBINE, lookup="sf", fdata=fdata, upcast=True
112
- )[st_sel]
122
+ self.ti_var,
123
+ FC.STATE_TURBINE,
124
+ lookup="f",
125
+ fdata=fdata,
126
+ upcast=False,
127
+ selection=st_sel,
128
+ )
113
129
 
114
130
  k = fdata.get(
115
131
  self.k_var, np.zeros((fdata.n_states, fdata.n_turbines), dtype=FC.DTYPE)
@@ -36,6 +36,7 @@ class LookupTable(TurbineModel):
36
36
  varmap={},
37
37
  pd_file_read_pars={},
38
38
  xr_interp_args={},
39
+ interpn_args={},
39
40
  **kwargs,
40
41
  ):
41
42
  """
@@ -56,6 +57,8 @@ class LookupTable(TurbineModel):
56
57
  Parameters for pandas file reading
57
58
  xr_interp_args: dict
58
59
  Parameters for xarray interpolation method
60
+ interpn_args: dict
61
+ Parameters for scipy intern or interp1d
59
62
  kwargs: dict, optional
60
63
  Additional parameters, added as default
61
64
  values if not in data
@@ -70,6 +73,7 @@ class LookupTable(TurbineModel):
70
73
 
71
74
  self._rpars = pd_file_read_pars
72
75
  self._xargs = xr_interp_args
76
+ self._iargs = interpn_args
73
77
  self._data = None
74
78
 
75
79
  for v, d in kwargs.items():
@@ -184,14 +188,16 @@ class LookupTable(TurbineModel):
184
188
  """
185
189
  data = {
186
190
  v: self.get_data(
187
- self.input_vars[0],
191
+ v,
188
192
  FC.STATE_TURBINE,
189
193
  lookup="fs",
190
194
  fdata=fdata,
191
- upcast=True,
192
- )[st_sel]
195
+ upcast=False,
196
+ selection=st_sel,
197
+ )
193
198
  for v in self.input_vars
194
199
  }
200
+
195
201
  dims = {
196
202
  v: ("_z") if len(data[v].shape) == 1 else ("_z", "_u")
197
203
  for v in self.input_vars
@@ -205,7 +211,27 @@ class LookupTable(TurbineModel):
205
211
  }
206
212
  del data, dims
207
213
 
208
- odata = self._data.interp(**indata, **self._xargs)
214
+ iargs = dict(bounds_error=True)
215
+ iargs.update(self._iargs)
216
+ try:
217
+ odata = self._data.interp(**indata, kwargs=iargs, **self._xargs)
218
+ except ValueError as e:
219
+ print("\nBOUNDS ERROR", self.name)
220
+ print("Variables:", list(indata.keys()))
221
+ print(
222
+ "DATA min/max:",
223
+ [float(np.min(self._data[v].to_numpy())) for v in indata.keys()],
224
+ [float(np.max(self._data[v].to_numpy())) for v in indata.keys()],
225
+ )
226
+ print(
227
+ "EVAL min/max:",
228
+ [float(np.min(d.to_numpy())) for d in indata.values()],
229
+ [float(np.max(d.to_numpy())) for d in indata.values()],
230
+ )
231
+ print(
232
+ "\nMaybe you want to try the options 'bounds_error=False, fill_value=None'? This will extrapolate the data.\n"
233
+ )
234
+ raise e
209
235
 
210
236
  out = {}
211
237
  for v in self.output_vars:
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
 
3
- from foxes.core import TurbineModel, Data
3
+ from foxes.core import TurbineModel, TData
4
4
  import foxes.variables as FV
5
5
  import foxes.constants as FC
6
6
 
@@ -108,7 +108,7 @@ class RotorCentreCalc(TurbineModel):
108
108
 
109
109
  """
110
110
  # prepare target point data:
111
- tdata = Data.from_points(
111
+ tdata = TData.from_points(
112
112
  fdata[FV.TXYH],
113
113
  data={
114
114
  v: np.zeros_like(fdata[FV.X][:, :, None])
@@ -131,6 +131,7 @@ class RotorCentreCalc(TurbineModel):
131
131
  # extract results:
132
132
  out = {v: fdata[v] for v in self.calc_vars.keys()}
133
133
  for v in out.keys():
134
- out[v][st_sel] = res[self.calc_vars[v]][st_sel]
134
+ w = self.calc_vars[v]
135
+ out[v][st_sel] = res[w][st_sel][..., 0]
135
136
 
136
137
  return out
@@ -44,15 +44,23 @@ class SetFarmVars(TurbineModel):
44
44
  The data, shape: (n_states, n_turbines)
45
45
 
46
46
  """
47
+ if self.initialized:
48
+ raise ValueError(
49
+ f"Model '{self.name}': Cannot add_var after initialization"
50
+ )
51
+ if self.running:
52
+ raise ValueError(f"Model '{self.name}': Cannot add_var while running")
47
53
  self.vars.append(var)
48
- self._vdata.append(np.asarray(data, dtype=FC.DTYPE))
54
+ self.__vdata.append(np.asarray(data, dtype=FC.DTYPE))
49
55
 
50
56
  def reset(self):
51
57
  """
52
58
  Remove all variables.
53
59
  """
60
+ if self.running:
61
+ raise ValueError(f"Model '{self.name}': Cannot reset while running")
54
62
  self.vars = []
55
- self._vdata = []
63
+ self.__vdata = []
56
64
 
57
65
  def output_farm_vars(self, algo):
58
66
  """
@@ -98,7 +106,7 @@ class SetFarmVars(TurbineModel):
98
106
 
99
107
  for i, v in enumerate(self.vars):
100
108
  data = np.full((algo.n_states, algo.n_turbines), np.nan, dtype=FC.DTYPE)
101
- vdata = self._vdata[i]
109
+ vdata = self.__vdata[i]
102
110
 
103
111
  # handle special case of call during vectorized optimization:
104
112
  if (
@@ -110,14 +118,105 @@ class SetFarmVars(TurbineModel):
110
118
  n_ost = algo.states.states.size()
111
119
  n_trb = algo.n_turbines
112
120
  vdata = np.zeros((n_pop, n_ost, n_trb), dtype=FC.DTYPE)
113
- vdata[:] = self._vdata[i][None, :]
121
+ vdata[:] = self.__vdata[i][None, :]
114
122
  vdata = vdata.reshape(n_pop * n_ost, n_trb)
115
123
 
116
124
  data[:] = vdata
117
125
  idata["data_vars"][self.var(v)] = ((FC.STATE, FC.TURBINE), data)
118
126
 
127
+ # special case of turbine positions:
128
+ if v in [FV.X, FV.Y]:
129
+ i = [FV.X, FV.Y].index(v)
130
+ for ti in range(algo.n_turbines):
131
+ t = algo.farm.turbines[ti]
132
+ if len(t.xy.shape) == 1:
133
+ xy = np.zeros((algo.n_states, 2), dtype=FC.DTYPE)
134
+ xy[:] = t.xy[None, :]
135
+ t.xy = xy
136
+ t.xy[:, i] = np.where(
137
+ np.isnan(data[:, ti]), t.xy[:, i], data[:, ti]
138
+ )
139
+
140
+ # special case of rotor diameter and hub height:
141
+ if v in [FV.D, FV.H]:
142
+ for ti in range(algo.n_turbines):
143
+ t = algo.farm.turbines[ti]
144
+ x = np.zeros(algo.n_states, dtype=FC.DTYPE)
145
+ if v == FV.D:
146
+ x[:] = t.D
147
+ t.D = x
148
+ else:
149
+ x[:] = t.H
150
+ t.H = x
151
+ x[:] = np.where(np.isnan(data[:, ti]), x, data[:, ti])
152
+
119
153
  return idata
120
154
 
155
+ def set_running(
156
+ self,
157
+ algo,
158
+ data_stash,
159
+ sel=None,
160
+ isel=None,
161
+ verbosity=0,
162
+ ):
163
+ """
164
+ Sets this model status to running, and moves
165
+ all large data to stash.
166
+
167
+ The stashed data will be returned by the
168
+ unset_running() function after running calculations.
169
+
170
+ Parameters
171
+ ----------
172
+ algo: foxes.core.Algorithm
173
+ The calculation algorithm
174
+ data_stash: dict
175
+ Large data stash, this function adds data here.
176
+ Key: model name. Value: dict, large model data
177
+ sel: dict, optional
178
+ The subset selection dictionary
179
+ isel: dict, optional
180
+ The index subset selection dictionary
181
+ verbosity: int
182
+ The verbosity level, 0 = silent
183
+
184
+ """
185
+ super().set_running(algo, data_stash, sel, isel, verbosity)
186
+
187
+ data_stash[self.name]["vdata"] = self.__vdata
188
+ del self.__vdata
189
+
190
+ def unset_running(
191
+ self,
192
+ algo,
193
+ data_stash,
194
+ sel=None,
195
+ isel=None,
196
+ verbosity=0,
197
+ ):
198
+ """
199
+ Sets this model status to not running, recovering large data
200
+ from stash
201
+
202
+ Parameters
203
+ ----------
204
+ algo: foxes.core.Algorithm
205
+ The calculation algorithm
206
+ data_stash: dict
207
+ Large data stash, this function adds data here.
208
+ Key: model name. Value: dict, large model data
209
+ sel: dict, optional
210
+ The subset selection dictionary
211
+ isel: dict, optional
212
+ The index subset selection dictionary
213
+ verbosity: int
214
+ The verbosity level, 0 = silent
215
+
216
+ """
217
+ super().unset_running(algo, data_stash, sel, isel, verbosity)
218
+ self.__vdata = data_stash[self.name].pop("vdata")
219
+
121
220
  def calculate(self, algo, mdata, fdata, st_sel):
122
221
  """
123
222
  The main model calculation.
@@ -159,36 +258,6 @@ class SetFarmVars(TurbineModel):
159
258
  hsel = ~np.isnan(data)
160
259
  tsel = bsel & hsel
161
260
 
162
- # special case of turbine positions:
163
- if v in [FV.X, FV.Y]:
164
- i = [FV.X, FV.Y].index(v)
165
- for ti in np.where(tsel)[1]:
166
- t = algo.farm.turbines[ti]
167
- if len(t.xy.shape) == 1:
168
- xy = np.zeros((algo.n_states, 2), dtype=FC.DTYPE)
169
- xy[:] = t.xy[None, :]
170
- t.xy = xy
171
- i0 = fdata.states_i0()
172
- hsel = tsel[:, ti]
173
- ssel = i0 + np.where(hsel)[0]
174
- t.xy[ssel, i] = data[hsel, ti]
175
-
176
- # special case of rotor diameter and hub height:
177
- if v in [FV.D, FV.H]:
178
- for ti in np.where(tsel)[1]:
179
- t = algo.farm.turbines[ti]
180
- x = np.zeros(algo.n_states, dtype=FC.DTYPE)
181
- if v == FV.D:
182
- x[:] = t.D
183
- t.D = x
184
- else:
185
- x[:] = t.H
186
- t.H = x
187
- i0 = fdata.states_i0()
188
- hsel = tsel[:, ti]
189
- ssel = i0 + np.where(hsel)[0]
190
- x[ssel] = data[hsel, ti]
191
-
192
261
  fdata[v][tsel] = data[tsel]
193
262
 
194
263
  return {v: fdata[v] for v in self.vars}
@@ -25,7 +25,7 @@ class PCtFile(TurbineType):
25
25
  col_ct: str
26
26
  The ct column
27
27
  rho: float
28
- The air densitiy for which the data is valid
28
+ The air density for which the data is valid
29
29
  or None for no correction
30
30
  WSCT: str
31
31
  The wind speed variable for ct lookup
@@ -66,7 +66,7 @@ class PCtFile(TurbineType):
66
66
  col_ct: str
67
67
  The ct column
68
68
  rho: float, optional
69
- The air densitiy for which the data is valid
69
+ The air density for which the data is valid
70
70
  or None for no correction
71
71
  p_ct: float
72
72
  The exponent for yaw dependency of ct
@@ -106,6 +106,30 @@ class PCtFile(TurbineType):
106
106
  a += f", var_ws_ct={self.WSCT}, var_ws_P={self.WSP}"
107
107
  return f"{type(self).__name__}({a})"
108
108
 
109
+ def needs_rews2(self):
110
+ """
111
+ Returns flag for requiring REWS2 variable
112
+
113
+ Returns
114
+ -------
115
+ flag: bool
116
+ True if REWS2 is required
117
+
118
+ """
119
+ return self.WSCT == FV.REWS2 or self.WSP == FV.REWS2
120
+
121
+ def needs_rews3(self):
122
+ """
123
+ Returns flag for requiring REWS3 variable
124
+
125
+ Returns
126
+ -------
127
+ flag: bool
128
+ True if REWS3 is required
129
+
130
+ """
131
+ return self.WSCT == FV.REWS3 or self.WSP == FV.REWS3
132
+
109
133
  def output_farm_vars(self, algo):
110
134
  """
111
135
  The variables which are being modified by the model.
@@ -252,7 +276,7 @@ class PCtFile(TurbineType):
252
276
  super().modify_cutin(modify_ct, modify_P)
253
277
 
254
278
  def calculate(self, algo, mdata, fdata, st_sel):
255
- """ "
279
+ """
256
280
  The main model calculation.
257
281
 
258
282
  This function is executed on a single chunk of data,