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
@@ -23,54 +23,33 @@ class PartialWakesModel(Model):
23
23
 
24
24
  """
25
25
 
26
- def __init__(self, wake_models=None, wake_frame=None):
26
+ @abstractmethod
27
+ def get_wake_points(self, algo, mdata, fdata):
27
28
  """
28
- Constructor.
29
+ Get the wake calculation points, and their
30
+ weights.
29
31
 
30
32
  Parameters
31
33
  ----------
32
- wake_models: list of foxes.core.WakeModel
33
- The wake model selection, None for all
34
- from algorithm.
35
- wake_frame: foxes.core.WakeFrame, optional
36
- The wake frame, None takes from algorithm
37
-
38
- """
39
- super().__init__()
40
-
41
- self._wmodels = wake_models
42
- self._wframe = wake_frame
43
-
44
- def sub_models(self):
45
- """
46
- List of all sub-models
34
+ algo: foxes.core.Algorithm
35
+ The calculation algorithm
36
+ mdata: foxes.core.Data
37
+ The model data
38
+ fdata: foxes.core.Data
39
+ The farm data
47
40
 
48
41
  Returns
49
42
  -------
50
- smdls: list of foxes.core.Model
51
- Names of all sub models
52
-
53
- """
54
- return self.wake_models + [self.wake_frame]
55
-
56
- def initialize(self, algo, verbosity=0):
57
- """
58
- Initializes the model.
59
-
60
- Parameters
61
- ----------
62
- algo: foxes.core.Algorithm
63
- The calculation algorithm
64
- verbosity: int
65
- The verbosity level, 0 = silent
43
+ rpoints: numpy.ndarray
44
+ The wake calculation points, shape:
45
+ (n_states, n_turbines, n_tpoints, 3)
46
+ rweights: numpy.ndarray
47
+ The target point weights, shape: (n_tpoints,)
66
48
 
67
49
  """
68
- self.wake_models = algo.wake_models if self._wmodels is None else self._wmodels
69
- self.wake_frame = algo.wake_frame if self._wframe is None else self._wframe
70
- super().initialize(algo, verbosity)
50
+ pass
71
51
 
72
- @abstractmethod
73
- def new_wake_deltas(self, algo, mdata, fdata):
52
+ def new_wake_deltas(self, algo, mdata, fdata, tdata, wmodel):
74
53
  """
75
54
  Creates new initial wake deltas, filled
76
55
  with zeros.
@@ -83,88 +62,112 @@ class PartialWakesModel(Model):
83
62
  The model data
84
63
  fdata: foxes.core.Data
85
64
  The farm data
65
+ tdata: foxes.core.Data
66
+ The target point data
67
+ wmodel: foxes.core.WakeModel
68
+ The wake model
69
+ wpoints: numpy.ndarray
70
+ The wake evaluation points,
71
+ shape: (n_states, n_turbines, n_tpoints, 3)
86
72
 
87
73
  Returns
88
74
  -------
89
75
  wake_deltas: dict
90
- Keys: Variable name str, values: any
91
- pdata: foxes.core.Data
92
- The evaluation point data
76
+ Key: variable name, value: The zero filled
77
+ wake deltas, shape: (n_states, n_turbines, n_tpoints, ...)
93
78
 
94
79
  """
95
- pass
80
+ return wmodel.new_wake_deltas(algo, mdata, fdata, tdata)
96
81
 
97
- @abstractmethod
98
- def contribute_to_wake_deltas(
82
+ def contribute(
99
83
  self,
100
84
  algo,
101
85
  mdata,
102
86
  fdata,
103
- pdata,
104
- states_source_turbine,
87
+ tdata,
88
+ downwind_index,
105
89
  wake_deltas,
90
+ wmodel,
106
91
  ):
107
92
  """
108
- Modifies wake deltas by contributions from the
109
- specified wake source turbines.
93
+ Modifies wake deltas at target points by
94
+ contributions from the specified wake source turbines.
110
95
 
111
96
  Parameters
112
97
  ----------
113
98
  algo: foxes.core.Algorithm
114
99
  The calculation algorithm
115
- mdata: foxes.core.Data
100
+ mdata: foxes.core.MData
116
101
  The model data
117
- fdata: foxes.core.Data
102
+ fdata: foxes.core.FData
118
103
  The farm data
119
- pdata: foxes.core.Data
120
- The evaluation point data
121
- states_source_turbine: numpy.ndarray of int
122
- For each state, one turbine index corresponding
123
- to the wake causing turbine. Shape: (n_states,)
124
- wake_deltas: Any
125
- The wake deltas object created by the
126
- `new_wake_deltas` function
104
+ tdata: foxes.core.TData
105
+ The target point data
106
+ downwind_index: int
107
+ The index of the wake causing turbine
108
+ in the downwnd order
109
+ wake_deltas: dict
110
+ The wake deltas. Key: variable name,
111
+ value: numpy.ndarray with shape
112
+ (n_states, n_targets, n_tpoints, ...)
113
+ wmodel: foxes.core.WakeModel
114
+ The wake model
127
115
 
128
116
  """
129
- pass
117
+ wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
118
+ wmodel.contribute(algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas)
130
119
 
131
120
  @abstractmethod
132
- def evaluate_results(
121
+ def finalize_wakes(
133
122
  self,
134
123
  algo,
135
124
  mdata,
136
125
  fdata,
137
- pdata,
126
+ tdata,
127
+ amb_res,
128
+ rpoint_weights,
138
129
  wake_deltas,
139
- states_turbine,
140
- amb_res=None,
130
+ wmodel,
131
+ downwind_index,
141
132
  ):
142
133
  """
143
- Updates the farm data according to the wake
144
- deltas.
134
+ Updates the wake_deltas at the selected target
135
+ downwind index.
136
+
137
+ Modifies wake_deltas on the fly.
145
138
 
146
139
  Parameters
147
140
  ----------
148
141
  algo: foxes.core.Algorithm
149
142
  The calculation algorithm
150
- mdata: foxes.core.Data
143
+ mdata: foxes.core.MData
151
144
  The model data
152
- fdata: foxes.core.Data
145
+ fdata: foxes.core.FData
153
146
  The farm data
154
- Modified in-place by this function
155
- pdata: foxes.core.Data
156
- The evaluation point data
157
- wake_deltas: Any
158
- The wake deltas object, created by the
159
- `new_wake_deltas` function and filled
160
- by `contribute_to_wake_deltas`
161
- states_turbine: numpy.ndarray of int
162
- For each state, the index of one turbine
163
- for which to evaluate the wake deltas.
164
- Shape: (n_states,)
165
- amb_res: dict, optional
166
- Ambient states results. Keys: var str, values:
167
- numpy.ndarray of shape (n_states, n_points)
147
+ tdata: foxes.core.Data
148
+ The target point data
149
+ amb_res: dict
150
+ The ambient results at the target points
151
+ of all rotors. Key: variable name, value
152
+ np.ndarray of shape:
153
+ (n_states, n_turbines, n_rotor_points)
154
+ rpoint_weights: numpy.ndarray
155
+ The rotor point weights, shape: (n_rotor_points,)
156
+ wake_deltas: dict
157
+ The wake deltas. Key: variable name,
158
+ value: np.ndarray of shape
159
+ (n_states, n_turbines, n_tpoints)
160
+ wmodel: foxes.core.WakeModel
161
+ The wake model
162
+ downwind_index: int
163
+ The index in the downwind order
164
+
165
+ Returns
166
+ -------
167
+ final_wake_deltas: dict
168
+ The final wake deltas at the selected downwind
169
+ turbines. Key: variable name, value: np.ndarray
170
+ of shape (n_states, n_rotor_points)
168
171
 
169
172
  """
170
173
  pass
@@ -1,3 +1,4 @@
1
+ import numpy as np
1
2
  from abc import abstractmethod
2
3
 
3
4
  from .data_calc_model import DataCalcModel
@@ -26,8 +27,33 @@ class PointDataModel(DataCalcModel):
26
27
  """
27
28
  return []
28
29
 
30
+ def ensure_variables(self, algo, mdata, fdata, tdata):
31
+ """
32
+ Add variables to tdata, initialized with NaN
33
+
34
+ Parameters
35
+ ----------
36
+ algo: foxes.core.Algorithm
37
+ The calculation algorithm
38
+ mdata: foxes.core.Data
39
+ The model data
40
+ fdata: foxes.core.Data
41
+ The farm data
42
+ tdata: foxes.core.Data
43
+ The target point data
44
+
45
+ """
46
+ for v in self.output_point_vars(algo):
47
+ if v not in tdata:
48
+ tdata[v] = np.full(
49
+ (tdata.n_states, tdata.n_targets, tdata.n_tpoints),
50
+ np.nan,
51
+ dtype=FC.DTYPE,
52
+ )
53
+ tdata.dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
54
+
29
55
  @abstractmethod
30
- def calculate(self, algo, mdata, fdata, pdata):
56
+ def calculate(self, algo, mdata, fdata, tdata):
31
57
  """ "
32
58
  The main model calculation.
33
59
 
@@ -38,18 +64,19 @@ class PointDataModel(DataCalcModel):
38
64
  ----------
39
65
  algo: foxes.core.Algorithm
40
66
  The calculation algorithm
41
- mdata: foxes.core.Data
67
+ mdata: foxes.core.MData
42
68
  The model data
43
- fdata: foxes.core.Data
69
+ fdata: foxes.core.FData
44
70
  The farm data
45
- pdata: foxes.core.Data
46
- The point data
71
+ tdata: foxes.core.TData
72
+ The target point data
47
73
 
48
74
  Returns
49
75
  -------
50
76
  results: dict
51
77
  The resulting data, keys: output variable str.
52
- Values: numpy.ndarray with shape (n_states, n_points)
78
+ Values: numpy.ndarray with shape
79
+ (n_states, n_targets, n_tpoints)
53
80
 
54
81
  """
55
82
  pass
@@ -78,14 +105,19 @@ class PointDataModel(DataCalcModel):
78
105
  The calculation results
79
106
 
80
107
  """
81
- return super().run_calculation(
108
+ results = super().run_calculation(
82
109
  algo,
83
110
  *data,
84
111
  out_vars=out_vars,
85
- loop_dims=[FC.STATE, FC.POINT],
86
- out_core_vars=[FC.VARS],
112
+ loop_dims=[FC.STATE, FC.TARGET],
113
+ out_core_vars=[FC.TPOINT, FC.VARS],
87
114
  **calc_pars,
88
115
  )
116
+ if results.sizes[FC.TPOINT] != 1:
117
+ raise ValueError(
118
+ f"PointDataModel '{self.name}': Expecting dimension '{FC.TPOINT}' of size 1, found {results.sizes[FC.TPOINT]}"
119
+ )
120
+ return results.sel({FC.TPOINT: 0}).rename({FC.TARGET: FC.POINT})
89
121
 
90
122
  def __add__(self, m):
91
123
  if isinstance(m, list):
@@ -170,7 +202,7 @@ class PointDataModelList(PointDataModel):
170
202
  ovars += m.output_point_vars(algo)
171
203
  return list(dict.fromkeys(ovars))
172
204
 
173
- def calculate(self, algo, mdata, fdata, pdata, parameters=None):
205
+ def calculate(self, algo, mdata, fdata, tdata, parameters=None):
174
206
  """ "
175
207
  The main model calculation.
176
208
 
@@ -181,12 +213,12 @@ class PointDataModelList(PointDataModel):
181
213
  ----------
182
214
  algo: foxes.core.Algorithm
183
215
  The calculation algorithm
184
- mdata: foxes.core.Data
216
+ mdata: foxes.core.MData
185
217
  The model data
186
- fdata: foxes.core.Data
218
+ fdata: foxes.core.FData
187
219
  The farm data
188
- pdata: foxes.core.Data
189
- The point data
220
+ tdata: foxes.core.TData
221
+ The target point data
190
222
  parameters: list of dict, optional
191
223
  A list of parameter dicts, one for each model
192
224
 
@@ -194,7 +226,8 @@ class PointDataModelList(PointDataModel):
194
226
  -------
195
227
  results: dict
196
228
  The resulting data, keys: output variable str.
197
- Values: numpy.ndarray with shape (n_states, n_points)
229
+ Values: numpy.ndarray with shape
230
+ (n_states, n_targets, n_tpoints)
198
231
 
199
232
  """
200
233
  if parameters is None:
@@ -209,7 +242,7 @@ class PointDataModelList(PointDataModel):
209
242
  )
210
243
 
211
244
  for mi, m in enumerate(self.models):
212
- res = m.calculate(algo, mdata, fdata, pdata, **parameters[mi])
213
- pdata.update(res)
245
+ res = m.calculate(algo, mdata, fdata, tdata, **parameters[mi])
246
+ tdata.update(res)
214
247
 
215
- return {v: pdata[v] for v in self.output_point_vars(algo)}
248
+ return {v: tdata[v] for v in self.output_point_vars(algo)}
foxes/core/rotor_model.py CHANGED
@@ -6,7 +6,7 @@ import foxes.constants as FC
6
6
  from .farm_data_model import FarmDataModel
7
7
  from foxes.utils import wd2uv, uv2wd, all_subclasses
8
8
 
9
- from .data import Data
9
+ from .data import TData
10
10
 
11
11
 
12
12
  class RotorModel(FarmDataModel):
@@ -41,6 +41,10 @@ class RotorModel(FarmDataModel):
41
41
  super().__init__()
42
42
  self.calc_vars = calc_vars
43
43
 
44
+ self.RPOINTS = self.var("rpoints")
45
+ self.RWEIGHTS = self.var("rweights")
46
+ self.AMBRES = self.var("amb_res")
47
+
44
48
  def output_farm_vars(self, algo):
45
49
  """
46
50
  The variables which are being modified by the model.
@@ -118,9 +122,9 @@ class RotorModel(FarmDataModel):
118
122
  ----------
119
123
  algo: foxes.core.Algorithm
120
124
  The calculation algorithm
121
- mdata: foxes.core.Data
125
+ mdata: foxes.core.MData
122
126
  The model data
123
- fdata: foxes.core.Data
127
+ fdata: foxes.core.FData
124
128
  The farm data
125
129
 
126
130
  Returns
@@ -152,17 +156,17 @@ class RotorModel(FarmDataModel):
152
156
 
153
157
  return points
154
158
 
155
- def _set_res(self, fdata, v, res, stsel):
159
+ def _set_res(self, fdata, v, res, downwind_index):
156
160
  """
157
161
  Helper function for results setting
158
162
  """
159
- if stsel is None:
163
+ if downwind_index is None:
160
164
  fdata[v] = res.copy()
161
165
  elif res.shape[1] == 1:
162
- fdata[v][stsel] = res[:, 0]
166
+ fdata[v][:, downwind_index] = res[:, 0]
163
167
  else:
164
168
  raise ValueError(
165
- f"Rotor model '{self.name}': states_turbine is not None, but results shape for '{v}' has more than one turbine, {res.shape}"
169
+ f"Rotor model '{self.name}': downwind_index is not None, but results shape for '{v}' has more than one turbine, {res.shape}"
166
170
  )
167
171
 
168
172
  def eval_rpoint_results(
@@ -170,9 +174,9 @@ class RotorModel(FarmDataModel):
170
174
  algo,
171
175
  mdata,
172
176
  fdata,
173
- rpoint_results,
177
+ tdata,
174
178
  weights,
175
- states_turbine=None,
179
+ downwind_index=None,
176
180
  copy_to_ambient=False,
177
181
  ):
178
182
  """
@@ -188,32 +192,21 @@ class RotorModel(FarmDataModel):
188
192
  ----------
189
193
  algo: foxes.core.Algorithm
190
194
  The calculation algorithm
191
- mdata: foxes.core.Data
195
+ mdata: foxes.core.MData
192
196
  The model data
193
- fdata: foxes.core.Data
197
+ fdata: foxes.core.FData
194
198
  The farm data
195
- rpoint_results: dict
196
- The results at rotor points. Keys: variable str.
197
- Values: numpy.ndarray, shape if `states_turbine`
198
- is None: (n_states, n_turbines, n_rpoints).
199
- Else: (n_states, 1, n_rpoints)
199
+ tdata: foxes.core.TData
200
+ The target point data
200
201
  weights: numpy.ndarray
201
202
  The rotor point weights, shape: (n_rpoints,)
202
- states_turbine: numpy.ndarray of int, optional
203
- The turbine indices, one per state. Shape: (n_states,)
204
- copy_to_ambient: bool, optional
203
+ downwind_index: int, optional
204
+ The index in the downwind order
205
+ copy_to_ambient: bool
205
206
  If `True`, the fdata results are copied to ambient
206
207
  variables after calculation
207
208
 
208
209
  """
209
-
210
- n_states = mdata.n_states
211
- n_turbines = algo.n_turbines
212
- if states_turbine is not None:
213
- stsel = (np.arange(n_states), states_turbine)
214
- else:
215
- stsel = None
216
-
217
210
  uvp = None
218
211
  uv = None
219
212
  if (
@@ -224,8 +217,8 @@ class RotorModel(FarmDataModel):
224
217
  or FV.REWS2 in self.calc_vars
225
218
  or FV.REWS3 in self.calc_vars
226
219
  ):
227
- wd = rpoint_results[FV.WD]
228
- ws = rpoint_results[FV.WS]
220
+ wd = tdata[FV.WD]
221
+ ws = tdata[FV.WS]
229
222
  uvp = wd2uv(wd, ws, axis=-1)
230
223
  uv = np.einsum("stpd,p->std", uvp, weights)
231
224
 
@@ -235,12 +228,12 @@ class RotorModel(FarmDataModel):
235
228
  if v == FV.WD or v == FV.YAW:
236
229
  if wd is None:
237
230
  wd = uv2wd(uv, axis=-1)
238
- self._set_res(fdata, v, wd, stsel)
231
+ self._set_res(fdata, v, wd, downwind_index)
239
232
  vdone.append(v)
240
233
 
241
234
  elif v == FV.WS:
242
235
  ws = np.linalg.norm(uv, axis=-1)
243
- self._set_res(fdata, v, ws, stsel)
236
+ self._set_res(fdata, v, ws, downwind_index)
244
237
  del ws
245
238
  vdone.append(v)
246
239
  del uv, wd
@@ -250,17 +243,17 @@ class RotorModel(FarmDataModel):
250
243
  or FV.REWS2 in self.calc_vars
251
244
  or FV.REWS3 in self.calc_vars
252
245
  ):
253
- if stsel is None:
246
+ if downwind_index is None:
254
247
  yaw = fdata[FV.YAW].copy()
255
248
  else:
256
- yaw = fdata[FV.YAW][stsel][:, None]
249
+ yaw = fdata[FV.YAW][:, downwind_index, None]
257
250
  nax = wd2uv(yaw, axis=-1)
258
251
  wsp = np.einsum("stpd,std->stp", uvp, nax)
259
252
 
260
253
  for v in self.calc_vars:
261
254
  if v == FV.REWS:
262
255
  rews = np.maximum(np.einsum("stp,p->st", wsp, weights), 0.0)
263
- self._set_res(fdata, v, rews, stsel)
256
+ self._set_res(fdata, v, rews, downwind_index)
264
257
  del rews
265
258
  vdone.append(v)
266
259
 
@@ -278,7 +271,7 @@ class RotorModel(FarmDataModel):
278
271
  )
279
272
  else:
280
273
  rews2 = np.sqrt(np.einsum("stp,p->st", wsp**2, weights))
281
- self._set_res(fdata, v, rews2, stsel)
274
+ self._set_res(fdata, v, rews2, downwind_index)
282
275
  del rews2
283
276
  vdone.append(v)
284
277
 
@@ -293,7 +286,7 @@ class RotorModel(FarmDataModel):
293
286
  ) ** (1.0 / 3.0)
294
287
  else:
295
288
  rews3 = (np.einsum("stp,p->st", wsp**3, weights)) ** (1.0 / 3.0)
296
- self._set_res(fdata, v, rews3, stsel)
289
+ self._set_res(fdata, v, rews3, downwind_index)
297
290
  del rews3
298
291
  vdone.append(v)
299
292
 
@@ -302,8 +295,8 @@ class RotorModel(FarmDataModel):
302
295
 
303
296
  for v in self.calc_vars:
304
297
  if v not in vdone:
305
- res = np.einsum("stp,p->st", rpoint_results[v], weights)
306
- self._set_res(fdata, v, res, stsel)
298
+ res = np.einsum("stp,p->st", tdata[v], weights)
299
+ self._set_res(fdata, v, res, downwind_index)
307
300
  if copy_to_ambient and v in FV.var2amb:
308
301
  fdata[FV.var2amb[v]] = fdata[v].copy()
309
302
 
@@ -317,7 +310,7 @@ class RotorModel(FarmDataModel):
317
310
  store_rpoints=False,
318
311
  store_rweights=False,
319
312
  store_amb_res=False,
320
- states_turbine=None,
313
+ downwind_index=None,
321
314
  ):
322
315
  """
323
316
  Calculate ambient rotor effective results.
@@ -326,9 +319,9 @@ class RotorModel(FarmDataModel):
326
319
  ----------
327
320
  algo: foxes.core.Algorithm
328
321
  The calculation algorithm
329
- mdata: foxes.core.Data
322
+ mdata: foxes.core.MData
330
323
  The model data
331
- fdata: foxes.core.Data
324
+ fdata: foxes.core.FData
332
325
  The farm data
333
326
  rpoints: numpy.ndarray, optional
334
327
  The rotor points, or None for automatic for
@@ -343,8 +336,8 @@ class RotorModel(FarmDataModel):
343
336
  store_amb_res: bool, optional
344
337
  Switch for storing ambient rotor point reults as they
345
338
  come from the states to mdata
346
- states_turbine: numpy.ndarray of int, optional
347
- The turbine indices, one per state. Shape: (n_states,)
339
+ downwind_index: int, optional
340
+ Only compute for index in the downwind order
348
341
 
349
342
  Returns
350
343
  -------
@@ -355,56 +348,45 @@ class RotorModel(FarmDataModel):
355
348
  """
356
349
 
357
350
  if rpoints is None:
358
- rpoints = mdata.get(FC.RPOINTS, self.get_rotor_points(algo, mdata, fdata))
351
+ rpoints = mdata.get(self.RPOINTS, self.get_rotor_points(algo, mdata, fdata))
359
352
  if store_rpoints:
360
- mdata[FC.RPOINTS] = rpoints
361
- mdata.dims[FC.RPOINTS] = (FC.STATE, FC.TURBINE, FC.RPOINT, FC.XYH)
362
- self.data_to_store(FC.RPOINTS, algo, mdata)
353
+ mdata[self.RPOINTS] = rpoints
354
+ mdata.dims[self.RPOINTS] = (FC.STATE, FC.TURBINE, FC.TPOINT, FC.XYH)
355
+ self.data_to_store(self.RPOINTS, algo, mdata)
363
356
 
364
- if states_turbine is not None:
365
- n_states = mdata.n_states
366
- stsel = (np.arange(n_states), states_turbine)
367
- rpoints = rpoints[stsel][:, None]
368
- n_states, n_turbines, n_rpoints, __ = rpoints.shape
369
- n_points = n_turbines * n_rpoints
357
+ if downwind_index is not None:
358
+ rpoints = rpoints[:, downwind_index, None]
370
359
 
371
360
  if weights is None:
372
- weights = mdata.get(FC.RWEIGHTS, self.rotor_point_weights())
361
+ weights = mdata.get(FC.TWEIGHTS, self.rotor_point_weights())
373
362
  if store_rweights:
374
- mdata[FC.RWEIGHTS] = weights
375
- mdata.dims[FC.RWEIGHTS] = (FC.RPOINT,)
376
- self.data_to_store(FC.RWEIGHTS, algo, mdata)
363
+ mdata[self.RWEIGHTS] = weights
364
+ mdata.dims[self.RWEIGHTS] = (FC.TPOINT,)
365
+ self.data_to_store(self.RWEIGHTS, algo, mdata)
377
366
 
367
+ tdata = TData.from_tpoints(rpoints, weights)
378
368
  svars = algo.states.output_point_vars(algo)
379
- points = rpoints.reshape(n_states, n_points, 3)
380
- pdata = {FC.POINTS: points}
381
- pdims = {FC.POINTS: (FC.STATE, FC.POINT, FC.XYH)}
382
- pdata.update(
383
- {v: np.full((n_states, n_points), np.nan, dtype=FC.DTYPE) for v in svars}
384
- )
385
- pdims.update({v: (FC.STATE, FC.POINT) for v in svars})
386
- pdata = Data(pdata, pdims, loop_dims=[FC.STATE, FC.POINT])
387
- del pdims, points
388
-
389
- sres = algo.states.calculate(algo, mdata, fdata, pdata)
390
- pdata.update(sres)
391
- del sres
392
-
393
- rpoint_results = {}
394
369
  for v in svars:
395
- rpoint_results[v] = pdata[v].reshape(n_states, n_turbines, n_rpoints)
370
+ tdata.add(
371
+ v,
372
+ data=np.full_like(rpoints[..., 0], np.nan),
373
+ dims=(FC.STATE, FC.TARGET, FC.TPOINT),
374
+ )
375
+
376
+ sres = algo.states.calculate(algo, mdata, fdata, tdata)
377
+ tdata.update(sres)
396
378
 
397
379
  if store_amb_res:
398
- mdata[FC.AMB_RPOINT_RESULTS] = rpoint_results
399
- self.data_to_store(FC.AMB_RPOINT_RESULTS, algo, mdata)
380
+ mdata[self.AMBRES] = sres.copy()
381
+ self.data_to_store(self.AMBRES, algo, mdata)
400
382
 
401
383
  self.eval_rpoint_results(
402
384
  algo,
403
385
  mdata,
404
386
  fdata,
405
- rpoint_results,
387
+ tdata,
406
388
  weights,
407
- states_turbine,
389
+ downwind_index,
408
390
  copy_to_ambient=True,
409
391
  )
410
392
 
foxes/core/states.py CHANGED
@@ -245,7 +245,7 @@ class ExtendedStates(States):
245
245
  """
246
246
  return self.states.output_point_vars(algo)
247
247
 
248
- def calculate(self, algo, mdata, fdata, pdata):
248
+ def calculate(self, algo, mdata, fdata, tdata):
249
249
  """ "
250
250
  The main model calculation.
251
251
 
@@ -256,12 +256,12 @@ class ExtendedStates(States):
256
256
  ----------
257
257
  algo: foxes.core.Algorithm
258
258
  The calculation algorithm
259
- mdata: foxes.core.Data
259
+ mdata: foxes.core.MData
260
260
  The model data
261
- fdata: foxes.core.Data
261
+ fdata: foxes.core.FData
262
262
  The farm data
263
- pdata: foxes.core.Data
264
- The point data
263
+ tdata: foxes.core.TData
264
+ The target point data
265
265
 
266
266
  Returns
267
267
  -------
@@ -270,7 +270,7 @@ class ExtendedStates(States):
270
270
  Values: numpy.ndarray with shape (n_states, n_points)
271
271
 
272
272
  """
273
- return self.pmodels.calculate(algo, mdata, fdata, pdata)
273
+ return self.pmodels.calculate(algo, mdata, fdata, tdata)
274
274
 
275
275
  def __add__(self, m):
276
276
  models = self.pmodels.models[1:]