foxes 0.6.1__py3-none-any.whl → 0.7__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 (129) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +131 -65
  3. foxes/algorithms/downwind/models/__init__.py +2 -1
  4. foxes/algorithms/downwind/models/farm_wakes_calc.py +87 -55
  5. foxes/algorithms/downwind/models/init_farm_data.py +134 -0
  6. foxes/algorithms/downwind/models/point_wakes_calc.py +54 -65
  7. foxes/algorithms/downwind/models/{calc_order.py → reorder_farm_output.py} +28 -26
  8. foxes/algorithms/iterative/iterative.py +100 -51
  9. foxes/algorithms/iterative/models/convergence.py +3 -3
  10. foxes/algorithms/iterative/models/farm_wakes_calc.py +55 -48
  11. foxes/algorithms/sequential/models/seq_state.py +7 -6
  12. foxes/algorithms/sequential/sequential.py +81 -44
  13. foxes/constants.py +33 -18
  14. foxes/core/__init__.py +2 -2
  15. foxes/core/algorithm.py +31 -12
  16. foxes/core/data.py +335 -41
  17. foxes/core/data_calc_model.py +27 -23
  18. foxes/core/farm_controller.py +27 -28
  19. foxes/core/farm_data_model.py +26 -4
  20. foxes/core/model.py +186 -129
  21. foxes/core/partial_wakes_model.py +84 -81
  22. foxes/core/point_data_model.py +51 -18
  23. foxes/core/rotor_model.py +59 -77
  24. foxes/core/states.py +6 -6
  25. foxes/core/turbine_model.py +4 -4
  26. foxes/core/turbine_type.py +24 -0
  27. foxes/core/vertical_profile.py +3 -3
  28. foxes/core/wake_frame.py +91 -50
  29. foxes/core/wake_model.py +74 -43
  30. foxes/core/wake_superposition.py +29 -26
  31. foxes/input/farm_layout/__init__.py +1 -0
  32. foxes/input/farm_layout/from_random.py +49 -0
  33. foxes/input/states/__init__.py +1 -1
  34. foxes/input/states/create/__init__.py +1 -0
  35. foxes/input/states/create/random_abl_states.py +6 -2
  36. foxes/input/states/create/random_timeseries.py +56 -0
  37. foxes/input/states/field_data_nc.py +12 -8
  38. foxes/input/states/multi_height.py +24 -14
  39. foxes/input/states/scan_ws.py +13 -17
  40. foxes/input/states/single.py +28 -20
  41. foxes/input/states/states_table.py +22 -18
  42. foxes/models/axial_induction_models/betz.py +1 -1
  43. foxes/models/farm_models/turbine2farm.py +2 -2
  44. foxes/models/model_book.py +40 -14
  45. foxes/models/partial_wakes/__init__.py +2 -2
  46. foxes/models/partial_wakes/axiwake.py +73 -200
  47. foxes/models/partial_wakes/centre.py +40 -0
  48. foxes/models/partial_wakes/grid.py +7 -63
  49. foxes/models/partial_wakes/rotor_points.py +53 -147
  50. foxes/models/partial_wakes/segregated.py +158 -0
  51. foxes/models/partial_wakes/top_hat.py +88 -196
  52. foxes/models/point_models/set_uniform_data.py +4 -4
  53. foxes/models/point_models/tke2ti.py +4 -4
  54. foxes/models/point_models/wake_deltas.py +4 -4
  55. foxes/models/rotor_models/centre.py +15 -19
  56. foxes/models/rotor_models/grid.py +2 -1
  57. foxes/models/rotor_models/levels.py +2 -1
  58. foxes/models/turbine_models/__init__.py +0 -1
  59. foxes/models/turbine_models/calculator.py +11 -7
  60. foxes/models/turbine_models/kTI_model.py +13 -11
  61. foxes/models/turbine_models/lookup_table.py +22 -9
  62. foxes/models/turbine_models/power_mask.py +81 -51
  63. foxes/models/turbine_models/rotor_centre_calc.py +17 -20
  64. foxes/models/turbine_models/sector_management.py +5 -6
  65. foxes/models/turbine_models/set_farm_vars.py +49 -20
  66. foxes/models/turbine_models/table_factors.py +5 -5
  67. foxes/models/turbine_models/thrust2ct.py +9 -5
  68. foxes/models/turbine_models/yaw2yawm.py +7 -13
  69. foxes/models/turbine_models/yawm2yaw.py +7 -11
  70. foxes/models/turbine_types/PCt_file.py +84 -3
  71. foxes/models/turbine_types/PCt_from_two.py +7 -3
  72. foxes/models/turbine_types/null_type.py +2 -2
  73. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -2
  74. foxes/models/turbine_types/wsti2PCt_from_two.py +6 -2
  75. foxes/models/wake_frames/farm_order.py +26 -22
  76. foxes/models/wake_frames/rotor_wd.py +32 -31
  77. foxes/models/wake_frames/seq_dynamic_wakes.py +112 -64
  78. foxes/models/wake_frames/streamlines.py +51 -47
  79. foxes/models/wake_frames/timelines.py +59 -47
  80. foxes/models/wake_frames/yawed_wakes.py +63 -40
  81. foxes/models/wake_models/axisymmetric.py +31 -35
  82. foxes/models/wake_models/dist_sliced.py +50 -56
  83. foxes/models/wake_models/gaussian.py +33 -35
  84. foxes/models/wake_models/induction/rankine_half_body.py +79 -87
  85. foxes/models/wake_models/induction/rathmann.py +56 -63
  86. foxes/models/wake_models/induction/self_similar.py +59 -62
  87. foxes/models/wake_models/ti/crespo_hernandez.py +83 -74
  88. foxes/models/wake_models/ti/iec_ti.py +65 -75
  89. foxes/models/wake_models/top_hat.py +60 -69
  90. foxes/models/wake_models/wake_mirror.py +49 -54
  91. foxes/models/wake_models/wind/bastankhah14.py +44 -66
  92. foxes/models/wake_models/wind/bastankhah16.py +84 -111
  93. foxes/models/wake_models/wind/jensen.py +67 -89
  94. foxes/models/wake_models/wind/turbopark.py +93 -133
  95. foxes/models/wake_superpositions/ti_linear.py +33 -27
  96. foxes/models/wake_superpositions/ti_max.py +33 -27
  97. foxes/models/wake_superpositions/ti_pow.py +35 -27
  98. foxes/models/wake_superpositions/ti_quadratic.py +33 -27
  99. foxes/models/wake_superpositions/ws_linear.py +39 -32
  100. foxes/models/wake_superpositions/ws_max.py +40 -33
  101. foxes/models/wake_superpositions/ws_pow.py +39 -32
  102. foxes/models/wake_superpositions/ws_product.py +35 -28
  103. foxes/models/wake_superpositions/ws_quadratic.py +39 -32
  104. foxes/opt/constraints/min_dist.py +1 -1
  105. foxes/opt/objectives/farm_vars.py +1 -1
  106. foxes/opt/problems/layout/farm_layout.py +38 -97
  107. foxes/output/__init__.py +1 -0
  108. foxes/output/farm_results_eval.py +1 -1
  109. foxes/output/flow_plots_2d/flow_plots.py +2 -0
  110. foxes/output/flow_plots_2d/get_fig.py +2 -0
  111. foxes/output/grids.py +1 -1
  112. foxes/output/rose_plot.py +3 -3
  113. foxes/output/rotor_point_plots.py +117 -0
  114. foxes/output/turbine_type_curves.py +2 -2
  115. foxes/utils/__init__.py +2 -1
  116. foxes/utils/load.py +29 -0
  117. foxes/utils/random_xy.py +56 -0
  118. foxes/utils/runners/runners.py +13 -1
  119. foxes/utils/windrose_plot.py +1 -1
  120. foxes/variables.py +10 -0
  121. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/METADATA +13 -7
  122. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/RECORD +126 -122
  123. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/WHEEL +1 -1
  124. foxes/models/partial_wakes/distsliced.py +0 -322
  125. foxes/models/partial_wakes/mapped.py +0 -252
  126. foxes/models/turbine_models/set_XYHD.py +0 -130
  127. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/LICENSE +0 -0
  128. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/top_level.txt +0 -0
  129. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/zip-safe +0 -0
@@ -1,4 +1,5 @@
1
1
  from abc import abstractmethod
2
+ import numpy as np
2
3
 
3
4
  from foxes.core import WakeModel
4
5
 
@@ -73,13 +74,13 @@ class DistSlicedWakeModel(WakeModel):
73
74
  super().initialize(algo, verbosity, force)
74
75
 
75
76
  @abstractmethod
76
- def calc_wakes_spsel_x_yz(
77
+ def calc_wakes_x_yz(
77
78
  self,
78
79
  algo,
79
80
  mdata,
80
81
  fdata,
81
- pdata,
82
- states_source_turbine,
82
+ tdata,
83
+ downwind_index,
83
84
  x,
84
85
  yz,
85
86
  ):
@@ -90,77 +91,74 @@ class DistSlicedWakeModel(WakeModel):
90
91
  ----------
91
92
  algo: foxes.core.Algorithm
92
93
  The calculation algorithm
93
- mdata: foxes.core.Data
94
+ mdata: foxes.core.MData
94
95
  The model data
95
- fdata: foxes.core.Data
96
+ fdata: foxes.core.FData
96
97
  The farm data
97
- pdata: foxes.core.Data
98
- The evaluation point data
99
- states_source_turbine: numpy.ndarray
100
- For each state, one turbine index for the
101
- wake causing turbine. Shape: (n_states,)
98
+ tdata: foxes.core.TData
99
+ The target point data
100
+ downwind_index: int
101
+ The index in the downwind order
102
102
  x: numpy.ndarray
103
- The x values, shape: (n_states, n_points)
103
+ The x values, shape: (n_states, n_targets)
104
104
  yz: numpy.ndarray
105
105
  The yz values for each x value, shape:
106
- (n_states, n_points, n_yz_per_x, 2)
106
+ (n_states, n_targets, n_yz_per_target, 2)
107
107
 
108
108
  Returns
109
109
  -------
110
110
  wdeltas: dict
111
111
  The wake deltas. Key: variable name str,
112
- value: numpy.ndarray, shape: (n_sp_sel, n_yz_per_x)
113
- sp_sel: numpy.ndarray of bool
114
- The state-point selection, for which the wake
115
- is non-zero, shape: (n_states, n_points)
112
+ value: numpy.ndarray, shape: (n_st_sel, n_yz_per_target)
113
+ st_sel: numpy.ndarray of bool
114
+ The state-target selection, for which the wake
115
+ is non-zero, shape: (n_states, n_targets)
116
116
 
117
117
  """
118
118
  pass
119
119
 
120
- def contribute_to_wake_deltas(
120
+ def contribute(
121
121
  self,
122
122
  algo,
123
123
  mdata,
124
124
  fdata,
125
- pdata,
126
- states_source_turbine,
125
+ tdata,
126
+ downwind_index,
127
127
  wake_coos,
128
128
  wake_deltas,
129
129
  ):
130
130
  """
131
- Calculate the contribution to the wake deltas
132
- by this wake model.
133
-
134
- Modifies wake_deltas on the fly.
131
+ Modifies wake deltas at target points by
132
+ contributions from the specified wake source turbines.
135
133
 
136
134
  Parameters
137
135
  ----------
138
136
  algo: foxes.core.Algorithm
139
137
  The calculation algorithm
140
- mdata: foxes.core.Data
138
+ mdata: foxes.core.MData
141
139
  The model data
142
- fdata: foxes.core.Data
140
+ fdata: foxes.core.FData
143
141
  The farm data
144
- pdata: foxes.core.Data
145
- The evaluation point data
146
- states_source_turbine: numpy.ndarray
147
- For each state, one turbine index for the
148
- wake causing turbine. Shape: (n_states,)
142
+ tdata: foxes.core.TData
143
+ The target point data
144
+ downwind_index: int
145
+ The index of the wake causing turbine
146
+ in the downwnd order
149
147
  wake_coos: numpy.ndarray
150
148
  The wake frame coordinates of the evaluation
151
- points, shape: (n_states, n_points, 3)
149
+ points, shape: (n_states, n_targets, n_tpoints, 3)
152
150
  wake_deltas: dict
153
- The wake deltas, are being modified ob the fly.
154
- Key: Variable name str, for which the
155
- wake delta applies, values: numpy.ndarray with
156
- shape (n_states, n_points, ...)
151
+ The wake deltas. Key: variable name,
152
+ value: numpy.ndarray with shape
153
+ (n_states, n_targets, n_tpoints, ...)
157
154
 
158
155
  """
159
- x = wake_coos[:, :, 0]
160
- yz = wake_coos[:, :, None, 1:3]
156
+ # rounding for safe x > 0 conditions
157
+ x = np.round(wake_coos[:, :, 0, 0], 12)
158
+ yz = wake_coos[..., 1:3]
161
159
 
162
- wdeltas, sp_sel = self.calc_wakes_spsel_x_yz(
163
- algo, mdata, fdata, pdata, states_source_turbine, x, yz
160
+ wdeltas, st_sel = self.calc_wakes_x_yz(
161
+ algo, mdata, fdata, tdata, downwind_index, x, yz
164
162
  )
165
163
 
166
164
  for v, hdel in wdeltas.items():
@@ -171,16 +169,16 @@ class DistSlicedWakeModel(WakeModel):
171
169
  f"Model '{self.name}': Missing wake superposition entry for variable '{v}', found {sorted(list(self.superp.keys()))}"
172
170
  )
173
171
 
174
- wake_deltas[v] = superp.calc_wakes_plus_wake(
172
+ wake_deltas[v] = superp.add_wake(
175
173
  algo,
176
174
  mdata,
177
175
  fdata,
178
- pdata,
179
- states_source_turbine,
180
- sp_sel,
176
+ tdata,
177
+ downwind_index,
178
+ st_sel,
181
179
  v,
182
180
  wake_deltas[v],
183
- hdel[:, 0],
181
+ hdel,
184
182
  )
185
183
 
186
184
  def finalize_wake_deltas(
@@ -188,7 +186,6 @@ class DistSlicedWakeModel(WakeModel):
188
186
  algo,
189
187
  mdata,
190
188
  fdata,
191
- pdata,
192
189
  amb_results,
193
190
  wake_deltas,
194
191
  ):
@@ -201,24 +198,21 @@ class DistSlicedWakeModel(WakeModel):
201
198
  ----------
202
199
  algo: foxes.core.Algorithm
203
200
  The calculation algorithm
204
- mdata: foxes.core.Data
201
+ mdata: foxes.core.MData
205
202
  The model data
206
- fdata: foxes.core.Data
203
+ fdata: foxes.core.FData
207
204
  The farm data
208
- pdata: foxes.core.Data
209
- The evaluation point data
210
205
  amb_results: dict
211
206
  The ambient results, key: variable name str,
212
- values: numpy.ndarray with shape (n_states, n_points)
207
+ values: numpy.ndarray with shape
208
+ (n_states, n_targets, n_tpoints)
213
209
  wake_deltas: dict
214
- The wake deltas, are being modified ob the fly.
215
- Key: Variable name str, for which the wake delta
216
- applies, values: numpy.ndarray with shape
217
- (n_states, n_points, ...) before evaluation,
218
- numpy.ndarray with shape (n_states, n_points) afterwards
210
+ The wake deltas object at the selected target
211
+ turbines. Key: variable str, value: numpy.ndarray
212
+ with shape (n_states, n_targets, n_tpoints)
219
213
 
220
214
  """
221
215
  for v, s in self.superp.items():
222
216
  wake_deltas[v] = s.calc_final_wake_delta(
223
- algo, mdata, fdata, pdata, v, amb_results[v], wake_deltas[v]
217
+ algo, mdata, fdata, v, amb_results[v], wake_deltas[v]
224
218
  )
@@ -13,13 +13,13 @@ class GaussianWakeModel(AxisymmetricWakeModel):
13
13
  """
14
14
 
15
15
  @abstractmethod
16
- def calc_amplitude_sigma_spsel(
16
+ def calc_amplitude_sigma(
17
17
  self,
18
18
  algo,
19
19
  mdata,
20
20
  fdata,
21
- pdata,
22
- states_source_turbine,
21
+ tdata,
22
+ downwind_index,
23
23
  x,
24
24
  ):
25
25
  """
@@ -30,37 +30,36 @@ class GaussianWakeModel(AxisymmetricWakeModel):
30
30
  ----------
31
31
  algo: foxes.core.Algorithm
32
32
  The calculation algorithm
33
- mdata: foxes.core.Data
33
+ mdata: foxes.core.MData
34
34
  The model data
35
- fdata: foxes.core.Data
35
+ fdata: foxes.core.FData
36
36
  The farm data
37
- pdata: foxes.core.Data
38
- The evaluation point data
39
- states_source_turbine: numpy.ndarray
40
- For each state, one turbine index for the
41
- wake causing turbine. Shape: (n_states,)
37
+ tdata: foxes.core.TData
38
+ The target point data
39
+ downwind_index: int
40
+ The index in the downwind order
42
41
  x: numpy.ndarray
43
- The x values, shape: (n_states, n_points)
42
+ The x values, shape: (n_states, n_targets)
44
43
 
45
44
  Returns
46
45
  -------
47
46
  amsi: tuple
48
47
  The amplitude and sigma, both numpy.ndarray
49
- with shape (n_sp_sel,)
50
- sp_sel: numpy.ndarray of bool
51
- The state-point selection, for which the wake
52
- is non-zero, shape: (n_states, n_points)
48
+ with shape (n_st_sel,)
49
+ st_sel: numpy.ndarray of bool
50
+ The state-target selection, for which the wake
51
+ is non-zero, shape: (n_states, n_targets)
53
52
 
54
53
  """
55
54
  pass
56
55
 
57
- def calc_wakes_spsel_x_r(
56
+ def calc_wakes_x_r(
58
57
  self,
59
58
  algo,
60
59
  mdata,
61
60
  fdata,
62
- pdata,
63
- states_source_turbine,
61
+ tdata,
62
+ downwind_index,
64
63
  x,
65
64
  r,
66
65
  ):
@@ -71,38 +70,37 @@ class GaussianWakeModel(AxisymmetricWakeModel):
71
70
  ----------
72
71
  algo: foxes.core.Algorithm
73
72
  The calculation algorithm
74
- mdata: foxes.core.Data
73
+ mdata: foxes.core.MData
75
74
  The model data
76
- fdata: foxes.core.Data
75
+ fdata: foxes.core.FData
77
76
  The farm data
78
- pdata: foxes.core.Data
79
- The evaluation point data
80
- states_source_turbine: numpy.ndarray
81
- For each state, one turbine index for the
82
- wake causing turbine. Shape: (n_states,)
77
+ tdata: foxes.core.TData
78
+ The target point data
79
+ downwind_index: int
80
+ The index in the downwind order
83
81
  x: numpy.ndarray
84
- The x values, shape: (n_states, n_points)
82
+ The x values, shape: (n_states, n_targets)
85
83
  r: numpy.ndarray
86
84
  The radial values for each x value, shape:
87
- (n_states, n_points, n_r_per_x, 2)
85
+ (n_states, n_targets, n_yz_per_target)
88
86
 
89
87
  Returns
90
88
  -------
91
89
  wdeltas: dict
92
90
  The wake deltas. Key: variable name str,
93
- value: numpy.ndarray, shape: (n_sp_sel, n_r_per_x)
94
- sp_sel: numpy.ndarray of bool
95
- The state-point selection, for which the wake
96
- is non-zero, shape: (n_states, n_points)
91
+ value: numpy.ndarray, shape: (n_st_sel, n_r_per_x)
92
+ st_sel: numpy.ndarray of bool
93
+ The state-target selection, for which the wake
94
+ is non-zero, shape: (n_states, n_targets)
97
95
 
98
96
  """
99
- amsi, sp_sel = self.calc_amplitude_sigma_spsel(
100
- algo, mdata, fdata, pdata, states_source_turbine, x
97
+ amsi, st_sel = self.calc_amplitude_sigma(
98
+ algo, mdata, fdata, tdata, downwind_index, x
101
99
  )
102
100
  wdeltas = {}
103
- rsel = r[sp_sel]
101
+ rsel = r[st_sel]
104
102
  for v in amsi.keys():
105
103
  ampld, sigma = amsi[v]
106
104
  wdeltas[v] = ampld[:, None] * np.exp(-0.5 * (rsel / sigma[:, None]) ** 2)
107
105
 
108
- return wdeltas, sp_sel
106
+ return wdeltas, st_sel
@@ -1,12 +1,12 @@
1
1
  import numpy as np
2
2
 
3
- from foxes.core import WakeModel
3
+ from foxes.core import TurbineInductionModel
4
4
  from foxes.utils import uv2wd, wd2uv
5
5
  import foxes.variables as FV
6
6
  import foxes.constants as FC
7
7
 
8
8
 
9
- class RankineHalfBody(WakeModel):
9
+ class RankineHalfBody(TurbineInductionModel):
10
10
  """
11
11
  The Rankine half body induction wake model
12
12
 
@@ -43,6 +43,12 @@ class RankineHalfBody(WakeModel):
43
43
  super().__init__()
44
44
  self.induction = induction
45
45
 
46
+ def __repr__(self):
47
+ iname = (
48
+ self.induction if isinstance(self.induction, str) else self.induction.name
49
+ )
50
+ return f"{type(self).__name__}(induction={iname})"
51
+
46
52
  def sub_models(self):
47
53
  """
48
54
  List of all sub-models
@@ -73,122 +79,113 @@ class RankineHalfBody(WakeModel):
73
79
  self.induction = algo.mbook.axial_induction[self.induction]
74
80
  super().initialize(algo, verbosity, force)
75
81
 
76
- def init_wake_deltas(self, algo, mdata, fdata, pdata, wake_deltas):
82
+ def new_wake_deltas(self, algo, mdata, fdata, tdata):
77
83
  """
78
- Initialize wake delta storage.
79
-
80
- They are added on the fly to the wake_deltas dict.
84
+ Creates new empty wake delta arrays.
81
85
 
82
86
  Parameters
83
87
  ----------
84
88
  algo: foxes.core.Algorithm
85
89
  The calculation algorithm
86
- mdata: foxes.core.Data
90
+ mdata: foxes.core.MData
87
91
  The model data
88
- fdata: foxes.core.Data
92
+ fdata: foxes.core.FData
89
93
  The farm data
90
- pdata: foxes.core.Data
91
- The evaluation point data
94
+ tdata: foxes.core.TData
95
+ The target point data
96
+
97
+ Returns
98
+ -------
92
99
  wake_deltas: dict
93
- The wake deltas storage, add wake deltas
94
- on the fly. Keys: Variable name str, for which the
95
- wake delta applies, values: numpy.ndarray with
96
- shape (n_states, n_points, ...)
100
+ Key: variable name, value: The zero filled
101
+ wake deltas, shape: (n_states, n_turbines, n_rpoints, ...)
97
102
 
98
103
  """
99
- n_states = mdata.n_states
100
- n_points = pdata.n_points
101
- wake_deltas["U"] = np.zeros((n_states, n_points), dtype=FC.DTYPE)
102
- wake_deltas["V"] = np.zeros((n_states, n_points), dtype=FC.DTYPE)
103
- wake_deltas[FV.WS] = np.zeros((n_states, n_points), dtype=FC.DTYPE)
104
- wake_deltas[FV.WD] = np.zeros((n_states, n_points), dtype=FC.DTYPE)
105
-
106
- def contribute_to_wake_deltas(
104
+ return {
105
+ FV.WS: np.zeros_like(tdata[FC.TARGETS][..., 0]),
106
+ FV.WD: np.zeros_like(tdata[FC.TARGETS][..., 0]),
107
+ "U": np.zeros_like(tdata[FC.TARGETS][..., 0]),
108
+ "V": np.zeros_like(tdata[FC.TARGETS][..., 0]),
109
+ }
110
+
111
+ def contribute(
107
112
  self,
108
113
  algo,
109
114
  mdata,
110
115
  fdata,
111
- pdata,
112
- states_source_turbine,
116
+ tdata,
117
+ downwind_index,
113
118
  wake_coos,
114
119
  wake_deltas,
115
120
  ):
116
121
  """
117
- Calculate the contribution to the wake deltas
118
- by this wake model.
119
-
120
- Modifies wake_deltas on the fly.
122
+ Modifies wake deltas at target points by
123
+ contributions from the specified wake source turbines.
121
124
 
122
125
  Parameters
123
126
  ----------
124
127
  algo: foxes.core.Algorithm
125
128
  The calculation algorithm
126
- mdata: foxes.core.Data
129
+ mdata: foxes.core.MData
127
130
  The model data
128
- fdata: foxes.core.Data
131
+ fdata: foxes.core.FData
129
132
  The farm data
130
- pdata: foxes.core.Data
131
- The evaluation point data
132
- states_source_turbine: numpy.ndarray
133
- For each state, one turbine index for the
134
- wake causing turbine. Shape: (n_states,)
133
+ tdata: foxes.core.TData
134
+ The target point data
135
+ downwind_index: int
136
+ The index of the wake causing turbine
137
+ in the downwnd order
135
138
  wake_coos: numpy.ndarray
136
139
  The wake frame coordinates of the evaluation
137
- points, shape: (n_states, n_points, 3)
140
+ points, shape: (n_states, n_targets, n_tpoints, 3)
138
141
  wake_deltas: dict
139
- The wake deltas, are being modified ob the fly.
140
- Key: Variable name str, for which the
141
- wake delta applies, values: numpy.ndarray with
142
- shape (n_states, n_points, ...)
142
+ The wake deltas. Key: variable name,
143
+ value: numpy.ndarray with shape
144
+ (n_states, n_targets, n_tpoints, ...)
143
145
 
144
146
  """
145
-
146
- # get x, y and z
147
- x = wake_coos[:, :, 0]
148
- y = wake_coos[:, :, 1]
149
- z = wake_coos[:, :, 2]
150
-
151
147
  # get ct:
152
148
  ct = self.get_data(
153
149
  FV.CT,
154
- FC.STATE_POINT,
150
+ FC.STATE_TARGET_TPOINT,
155
151
  lookup="w",
156
152
  algo=algo,
157
153
  fdata=fdata,
158
- pdata=pdata,
159
- upcast=True,
160
- states_source_turbine=states_source_turbine,
154
+ tdata=tdata,
155
+ downwind_index=downwind_index,
156
+ upcast=False,
161
157
  )
162
158
 
163
159
  # get ws:
164
160
  ws = self.get_data(
165
161
  FV.REWS,
166
- FC.STATE_POINT,
162
+ FC.STATE_TARGET_TPOINT,
167
163
  lookup="w",
168
164
  algo=algo,
169
165
  fdata=fdata,
170
- pdata=pdata,
171
- upcast=True,
172
- states_source_turbine=states_source_turbine,
166
+ tdata=tdata,
167
+ downwind_index=downwind_index,
168
+ upcast=False,
173
169
  )
174
170
 
175
171
  # get D
176
172
  D = self.get_data(
177
173
  FV.D,
178
- FC.STATE_POINT,
174
+ FC.STATE_TARGET_TPOINT,
179
175
  lookup="w",
180
176
  algo=algo,
181
177
  fdata=fdata,
182
- pdata=pdata,
178
+ tdata=tdata,
179
+ downwind_index=downwind_index,
183
180
  upcast=True,
184
- states_source_turbine=states_source_turbine,
185
181
  )
186
182
 
187
183
  # calc m (page 7, skipping pi everywhere)
188
184
  m = 2 * ws * self.induction.ct2a(ct) * (D / 2) ** 2
189
185
 
190
186
  # get r and theta
191
- r = np.sqrt(y**2 + z**2)
187
+ x = np.round(wake_coos[..., 0], 12)
188
+ r = np.linalg.norm(wake_coos[..., 1:], axis=-1)
192
189
  r_sph = np.sqrt(r**2 + x**2)
193
190
  theta = np.arctan2(r, x)
194
191
 
@@ -201,35 +198,32 @@ class RankineHalfBody(WakeModel):
201
198
  xs = -np.sqrt(m / (4 * ws))
202
199
 
203
200
  # set values out of body shape
204
- sp_sel = (ct > 0) & ((RHB_shape < -1) | (x < xs))
205
- if np.any(sp_sel):
201
+ st_sel = (ct > 0) & ((RHB_shape < -1) | (x < xs))
202
+ if np.any(st_sel):
206
203
  # apply selection
207
- xyz = wake_coos[sp_sel]
204
+ xyz = wake_coos[st_sel]
208
205
 
209
206
  # calc velocity components
210
- vel_factor = m[sp_sel] / (4 * np.linalg.norm(xyz, axis=-1) ** 3)
211
- wake_deltas["U"][sp_sel] += vel_factor * xyz[:, 0]
212
- wake_deltas["V"][sp_sel] += vel_factor * xyz[:, 1]
207
+ vel_factor = m[st_sel] / (4 * np.linalg.norm(xyz, axis=-1) ** 3)
208
+ wake_deltas["U"][st_sel] += vel_factor * xyz[:, 0]
209
+ wake_deltas["V"][st_sel] += vel_factor * xyz[:, 1]
213
210
 
214
211
  # set values inside body shape
215
- sp_sel = (ct > 0) & (RHB_shape >= -1) & (x >= xs) & (x < 0)
216
- if np.any(sp_sel):
212
+ st_sel = (ct > 0) & (RHB_shape >= -1) & (x >= xs) & (x <= 0)
213
+ if np.any(st_sel):
217
214
  # apply selection
218
- xyz = np.zeros_like(wake_coos[sp_sel])
219
- xyz[:, 0] = xs[sp_sel]
215
+ xyz = np.zeros_like(wake_coos[st_sel])
216
+ xyz[:, 0] = xs[st_sel]
220
217
 
221
218
  # calc velocity components
222
- vel_factor = m[sp_sel] / (4 * np.linalg.norm(xyz, axis=-1) ** 3)
223
- wake_deltas["U"][sp_sel] += vel_factor * xyz[:, 0]
224
-
225
- return wake_deltas
219
+ vel_factor = m[st_sel] / (4 * np.linalg.norm(xyz, axis=-1) ** 3)
220
+ wake_deltas["U"][st_sel] += vel_factor * xyz[:, 0]
226
221
 
227
222
  def finalize_wake_deltas(
228
223
  self,
229
224
  algo,
230
225
  mdata,
231
226
  fdata,
232
- pdata,
233
227
  amb_results,
234
228
  wake_deltas,
235
229
  ):
@@ -242,32 +236,30 @@ class RankineHalfBody(WakeModel):
242
236
  ----------
243
237
  algo: foxes.core.Algorithm
244
238
  The calculation algorithm
245
- mdata: foxes.core.Data
239
+ mdata: foxes.core.MData
246
240
  The model data
247
- fdata: foxes.core.Data
241
+ fdata: foxes.core.FData
248
242
  The farm data
249
- pdata: foxes.core.Data
250
- The evaluation point data
251
243
  amb_results: dict
252
244
  The ambient results, key: variable name str,
253
- values: numpy.ndarray with shape (n_states, n_points)
245
+ values: numpy.ndarray with shape
246
+ (n_states, n_targets, n_tpoints)
254
247
  wake_deltas: dict
255
- The wake deltas, are being modified ob the fly.
256
- Key: Variable name str, for which the wake delta
257
- applies, values: numpy.ndarray with shape
258
- (n_states, n_points, ...) before evaluation,
259
- numpy.ndarray with shape (n_states, n_points) afterwards
248
+ The wake deltas object at the selected target
249
+ turbines. Key: variable str, value: numpy.ndarray
250
+ with shape (n_states, n_targets, n_tpoints)
260
251
 
261
252
  """
262
-
263
253
  # calc ambient wind vector:
264
254
  ws0 = amb_results[FV.WS]
265
255
  nx = wd2uv(amb_results[FV.WD])
266
- wind_vec = nx * ws0[:, :, None]
256
+ wind_vec = nx * ws0[:, :, :, None]
267
257
 
268
258
  # wake deltas are in wake frame, rotate back to global frame:
269
- ny = np.stack((-nx[:, :, 1], nx[:, :, 0]), axis=2)
270
- delta_uv = wake_deltas["U"][:, :, None] * nx + wake_deltas["V"][:, :, None] * ny
259
+ ny = np.stack((-nx[..., 1], nx[..., 0]), axis=-1)
260
+ delta_uv = (
261
+ wake_deltas["U"][:, :, :, None] * nx + wake_deltas["V"][:, :, :, None] * ny
262
+ )
271
263
  del ws0, nx, ny
272
264
 
273
265
  # add ambient result to wake deltas: