foxes 1.4__py3-none-any.whl → 1.5__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 (85) hide show
  1. docs/source/conf.py +1 -1
  2. examples/field_data_nc/run.py +1 -1
  3. examples/streamline_wakes/run.py +2 -2
  4. examples/yawed_wake/run.py +3 -1
  5. foxes/algorithms/downwind/downwind.py +5 -5
  6. foxes/algorithms/downwind/models/init_farm_data.py +58 -28
  7. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  8. foxes/core/algorithm.py +5 -5
  9. foxes/core/data.py +75 -4
  10. foxes/core/data_calc_model.py +4 -2
  11. foxes/core/engine.py +33 -40
  12. foxes/core/farm_data_model.py +16 -13
  13. foxes/core/model.py +19 -1
  14. foxes/core/point_data_model.py +19 -14
  15. foxes/core/rotor_model.py +1 -0
  16. foxes/core/wake_deflection.py +3 -3
  17. foxes/data/states/point_cloud_100.nc +0 -0
  18. foxes/data/states/weibull_cloud_4.nc +0 -0
  19. foxes/data/states/weibull_grid.nc +0 -0
  20. foxes/engines/dask.py +3 -6
  21. foxes/engines/default.py +2 -2
  22. foxes/engines/numpy.py +11 -10
  23. foxes/engines/pool.py +20 -11
  24. foxes/engines/single.py +8 -6
  25. foxes/input/farm_layout/__init__.py +1 -0
  26. foxes/input/farm_layout/from_arrays.py +68 -0
  27. foxes/input/states/__init__.py +7 -1
  28. foxes/input/states/dataset_states.py +710 -0
  29. foxes/input/states/field_data.py +531 -0
  30. foxes/input/states/multi_height.py +2 -0
  31. foxes/input/states/one_point_flow.py +1 -0
  32. foxes/input/states/point_cloud_data.py +618 -0
  33. foxes/input/states/scan.py +2 -0
  34. foxes/input/states/single.py +2 -0
  35. foxes/input/states/states_table.py +13 -23
  36. foxes/input/states/weibull_sectors.py +182 -77
  37. foxes/input/states/wrg_states.py +1 -1
  38. foxes/input/yaml/dict.py +25 -24
  39. foxes/input/yaml/windio/read_attributes.py +40 -27
  40. foxes/input/yaml/windio/read_farm.py +12 -10
  41. foxes/input/yaml/windio/read_outputs.py +25 -15
  42. foxes/input/yaml/windio/read_site.py +121 -12
  43. foxes/input/yaml/windio/windio.py +22 -10
  44. foxes/input/yaml/yaml.py +1 -0
  45. foxes/models/model_book.py +16 -15
  46. foxes/models/rotor_models/__init__.py +1 -0
  47. foxes/models/rotor_models/centre.py +1 -1
  48. foxes/models/rotor_models/direct_infusion.py +241 -0
  49. foxes/models/turbine_models/calculator.py +16 -3
  50. foxes/models/turbine_models/kTI_model.py +1 -0
  51. foxes/models/turbine_models/lookup_table.py +2 -0
  52. foxes/models/turbine_models/power_mask.py +1 -0
  53. foxes/models/turbine_models/rotor_centre_calc.py +2 -0
  54. foxes/models/turbine_models/sector_management.py +1 -0
  55. foxes/models/turbine_models/set_farm_vars.py +3 -8
  56. foxes/models/turbine_models/table_factors.py +2 -0
  57. foxes/models/turbine_models/thrust2ct.py +1 -0
  58. foxes/models/turbine_models/yaw2yawm.py +2 -0
  59. foxes/models/turbine_models/yawm2yaw.py +2 -0
  60. foxes/models/turbine_types/PCt_file.py +2 -4
  61. foxes/models/turbine_types/PCt_from_two.py +1 -0
  62. foxes/models/turbine_types/__init__.py +1 -0
  63. foxes/models/turbine_types/calculator_type.py +123 -0
  64. foxes/models/turbine_types/null_type.py +1 -0
  65. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
  66. foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
  67. foxes/output/farm_layout.py +2 -0
  68. foxes/output/farm_results_eval.py +4 -1
  69. foxes/output/flow_plots_2d/flow_plots.py +18 -0
  70. foxes/output/flow_plots_2d/get_fig.py +1 -0
  71. foxes/output/output.py +6 -1
  72. foxes/output/results_writer.py +1 -1
  73. foxes/output/rose_plot.py +10 -0
  74. foxes/output/rotor_point_plots.py +3 -0
  75. foxes/output/state_turbine_map.py +3 -0
  76. foxes/output/turbine_type_curves.py +3 -0
  77. foxes/utils/dict.py +46 -34
  78. foxes/utils/factory.py +2 -2
  79. {foxes-1.4.dist-info → foxes-1.5.dist-info}/METADATA +32 -52
  80. {foxes-1.4.dist-info → foxes-1.5.dist-info}/RECORD +84 -76
  81. foxes/input/states/field_data_nc.py +0 -833
  82. {foxes-1.4.dist-info → foxes-1.5.dist-info}/WHEEL +0 -0
  83. {foxes-1.4.dist-info → foxes-1.5.dist-info}/entry_points.txt +0 -0
  84. {foxes-1.4.dist-info → foxes-1.5.dist-info}/licenses/LICENSE +0 -0
  85. {foxes-1.4.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
@@ -85,12 +85,13 @@ class ModelBook:
85
85
  Path to power/ct curve file, for creation
86
86
  of default turbine type model
87
87
  """
88
- self.point_models = FDict(name="point_models")
88
+ self.point_models = FDict(_name="point_models")
89
89
  self.point_models["tke2ti"] = fm.point_models.TKE2TI()
90
90
  self.point_models["ustar2ti"] = fm.point_models.Ustar2TI()
91
91
 
92
- self.rotor_models = FDict(name="rotor_models")
92
+ self.rotor_models = FDict(_name="rotor_models")
93
93
  self.rotor_models["centre"] = fm.rotor_models.CentreRotor()
94
+ self.rotor_models["direct_mdata"] = fm.rotor_models.DirectMDataInfusion()
94
95
 
95
96
  def _n2n(n2):
96
97
  n2 = float(n2)
@@ -132,7 +133,7 @@ class ModelBook:
132
133
  hints={"n": "(Number of vertical levels)"},
133
134
  )
134
135
 
135
- self.turbine_types = FDict(name="turbine_types")
136
+ self.turbine_types = FDict(_name="turbine_types")
136
137
  self.turbine_types["null_type"] = fm.turbine_types.NullType()
137
138
  self.turbine_types["NREL5MW"] = fm.turbine_types.PCtFile(
138
139
  "NREL-5MW-D126-H90.csv", rho=1.225
@@ -150,7 +151,7 @@ class ModelBook:
150
151
  self.turbine_types["Pct"] = fm.turbine_types.PCtFile(Pct_file)
151
152
 
152
153
  self.turbine_models = FDict(
153
- name="turbine_models",
154
+ _name="turbine_models",
154
155
  kTI=fm.turbine_models.kTI(),
155
156
  kTI_amb=fm.turbine_models.kTI(ti_var=FV.AMB_TI),
156
157
  thrust2ct=fm.turbine_models.Thrust2Ct(),
@@ -203,7 +204,7 @@ class ModelBook:
203
204
  )
204
205
 
205
206
  self.farm_models = FDict(
206
- name="farm_models",
207
+ _name="farm_models",
207
208
  **{
208
209
  f"farm_{mname}": fm.farm_models.Turbine2FarmModel(m)
209
210
  for mname, m in self.turbine_models.items()
@@ -211,12 +212,12 @@ class ModelBook:
211
212
  )
212
213
 
213
214
  self.farm_controllers = FDict(
214
- name="farm_controllers",
215
+ _name="farm_controllers",
215
216
  basic_ctrl=fm.farm_controllers.BasicFarmController(),
216
217
  )
217
218
 
218
219
  self.partial_wakes = FDict(
219
- name="partial_wakes",
220
+ _name="partial_wakes",
220
221
  rotor_points=fm.partial_wakes.RotorPoints(),
221
222
  top_hat=fm.partial_wakes.PartialTopHat(),
222
223
  centre=fm.partial_wakes.PartialCentre(),
@@ -236,7 +237,7 @@ class ModelBook:
236
237
  )
237
238
 
238
239
  self.wake_deflections = FDict(
239
- name="wake_deflections",
240
+ _name="wake_deflections",
240
241
  no_deflection=fm.wake_deflections.NoDeflection(),
241
242
  Bastankhah2016=fm.wake_deflections.Bastankhah2016Deflection(),
242
243
  Jimenez=fm.wake_deflections.JimenezDeflection(rotate=True),
@@ -303,7 +304,7 @@ class ModelBook:
303
304
  )
304
305
 
305
306
  self.wake_frames = FDict(
306
- name="wake_frames",
307
+ _name="wake_frames",
307
308
  rotor_wd=fm.wake_frames.RotorWD(),
308
309
  rotor_wd_farmo=fm.wake_frames.FarmOrder(),
309
310
  )
@@ -363,7 +364,7 @@ class ModelBook:
363
364
  )
364
365
 
365
366
  self.wake_superpositions = FDict(
366
- name="wake_superpositions",
367
+ _name="wake_superpositions",
367
368
  ws_linear=fm.wake_superpositions.WSLinear(scale_amb=False),
368
369
  ws_linear_lim=fm.wake_superpositions.WSLinear(
369
370
  scale_amb=False, lim_low=1e-4
@@ -407,11 +408,11 @@ class ModelBook:
407
408
  vector_amb=fm.wake_superpositions.WindVectorLinear(scale_amb=True),
408
409
  )
409
410
 
410
- self.axial_induction = FDict(name="induction_models")
411
+ self.axial_induction = FDict(_name="induction_models")
411
412
  self.axial_induction["Betz"] = fm.axial_induction.BetzAxialInduction()
412
413
  self.axial_induction["Madsen"] = fm.axial_induction.MadsenAxialInduction()
413
414
 
414
- self.wake_models = FDict(name="wake_models")
415
+ self.wake_models = FDict(_name="wake_models")
415
416
 
416
417
  self.wake_models.add_k_factory(
417
418
  fm.wake_models.wind.JensenWake,
@@ -616,7 +617,7 @@ class ModelBook:
616
617
  },
617
618
  )
618
619
 
619
- self.ground_models = FDict(name="ground_models")
620
+ self.ground_models = FDict(_name="ground_models")
620
621
  self.ground_models["no_ground"] = fm.ground_models.NoGround()
621
622
  self.ground_models["ground_mirror"] = fm.ground_models.GroundMirror()
622
623
  self.ground_models.add_factory(
@@ -629,7 +630,7 @@ class ModelBook:
629
630
  )
630
631
 
631
632
  self.sources = FDict(
632
- name="sources",
633
+ _name="sources",
633
634
  point_models=self.point_models,
634
635
  rotor_models=self.rotor_models,
635
636
  turbine_types=self.turbine_types,
@@ -645,7 +646,7 @@ class ModelBook:
645
646
  ground_models=self.ground_models,
646
647
  )
647
648
  self.base_classes = FDict(
648
- name="base_classes",
649
+ _name="base_classes",
649
650
  point_models=PointDataModel,
650
651
  rotor_models=RotorModel,
651
652
  turbine_types=TurbineType,
@@ -5,3 +5,4 @@ Rotor models.
5
5
  from .centre import CentreRotor as CentreRotor
6
6
  from .grid import GridRotor as GridRotor
7
7
  from .levels import LevelRotor as LevelRotor
8
+ from .direct_infusion import DirectMDataInfusion as DirectMDataInfusion
@@ -199,4 +199,4 @@ class CentreRotor(RotorModel):
199
199
  self._set_res(fdata, v, res, downwind_index)
200
200
  del res
201
201
  if copy_to_ambient and v in FV.var2amb:
202
- fdata[FV.var2amb[v]] = fdata[v].copy()
202
+ fdata.add(FV.var2amb[v], fdata[v].copy(), fdata.dims[v])
@@ -0,0 +1,241 @@
1
+ import numpy as np
2
+
3
+ from foxes.core import TData
4
+ import foxes.variables as FV
5
+ import foxes.constants as FC
6
+
7
+ from .centre import CentreRotor
8
+
9
+
10
+ class DirectMDataInfusion(CentreRotor):
11
+ """
12
+ Direct data infusion of data stored under mdata.
13
+
14
+ Attributes
15
+ ----------
16
+ svars2mdvars: dict
17
+ A mapping of state variables to mdata variables.
18
+ mdata_vars: list of str
19
+ The mdata variables to be used for infusion. By default,
20
+ all mdata variables are searched.
21
+ turbine_coord: str, optional
22
+ The mdata coordinate that represents turbine names. By default,
23
+ the second coordinate is used as a candidate if the mdata variable
24
+ has three dimensions.
25
+
26
+ :group: models.turbine_types
27
+
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ svars2mdvars=None,
33
+ mdata_vars=None,
34
+ turbine_coord=None,
35
+ **kwargs,
36
+ ):
37
+ """
38
+ Constructor.
39
+
40
+ Parameters
41
+ ----------
42
+ svars2mdvars: dict, optional
43
+ A mapping of state variables to mdata variables.
44
+ mdata_vars: list of str, optional
45
+ The mdata variables to be used for infusion. By default,
46
+ all mdata variables are searched.
47
+ turbine_coord: str, optional
48
+ The mdata coordinate that represents turbine names. By default,
49
+ the second coordinate is used as a candidate if the mdata variable
50
+ has three dimensions.
51
+ kwargs: dict, optional
52
+ Additional parameters for RotorModel class
53
+
54
+ """
55
+ super().__init__(**kwargs)
56
+ self.svars2mdvars = svars2mdvars
57
+ self.mdata_vars = mdata_vars
58
+ self.turbine_coord = turbine_coord
59
+
60
+ def output_farm_vars(self, algo):
61
+ """
62
+ The variables which are being modified by the model.
63
+
64
+ Parameters
65
+ ----------
66
+ algo: foxes.core.Algorithm
67
+ The calculation algorithm
68
+
69
+ Returns
70
+ -------
71
+ output_vars: list of str
72
+ The output variable names
73
+
74
+ """
75
+ if self.svars2mdvars is None:
76
+ self.svars2mdvars = {v: v for v in algo.states.output_point_vars(algo)}
77
+
78
+ if self.calc_vars is None:
79
+ vrs = list(self.svars2mdvars.keys())
80
+ assert FV.WEIGHT not in vrs, (
81
+ f"Rotor '{self.name}': svars2mdvars keys {vrs} contain '{FV.WEIGHT}', please remove"
82
+ )
83
+
84
+ if FV.WS in vrs:
85
+ self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
86
+ else:
87
+ self.calc_vars = vrs
88
+
89
+ if algo.farm_controller.needs_rews2() and FV.REWS2 not in self.calc_vars:
90
+ self.calc_vars.append(FV.REWS2)
91
+ if algo.farm_controller.needs_rews3() and FV.REWS3 not in self.calc_vars:
92
+ self.calc_vars.append(FV.REWS3)
93
+
94
+ self.calc_vars = sorted(self.calc_vars)
95
+
96
+ if FV.WEIGHT not in self.calc_vars:
97
+ self.calc_vars.append(FV.WEIGHT)
98
+ if FV.WEIGHT not in self.svars2mdvars:
99
+ self.svars2mdvars[FV.WEIGHT] = FV.WEIGHT
100
+
101
+ return self.calc_vars
102
+
103
+ def calculate(
104
+ self,
105
+ algo,
106
+ mdata,
107
+ fdata,
108
+ rpoints=None,
109
+ rpoint_weights=None,
110
+ store=False,
111
+ downwind_index=None,
112
+ ):
113
+ """
114
+ Calculate ambient rotor effective results.
115
+
116
+ Parameters
117
+ ----------
118
+ algo: foxes.core.Algorithm
119
+ The calculation algorithm
120
+ mdata: foxes.core.MData
121
+ The model data
122
+ fdata: foxes.core.FData
123
+ The farm data
124
+ rpoints: numpy.ndarray, optional
125
+ The rotor points, or None for automatic for
126
+ this rotor. Shape: (n_states, n_turbines, n_rpoints, 3)
127
+ rpoint_weights: numpy.ndarray, optional
128
+ The rotor point weights, or None for automatic
129
+ for this rotor. Shape: (n_rpoints,)
130
+ store: bool, optional
131
+ Flag for storing ambient rotor point results
132
+ downwind_index: int, optional
133
+ Only compute for index in the downwind order
134
+
135
+ Returns
136
+ -------
137
+ results: dict
138
+ results dict. Keys: Variable name str. Values:
139
+ numpy.ndarray with results, shape: (n_states, n_turbines)
140
+
141
+ """
142
+ self.ensure_output_vars(algo, fdata)
143
+
144
+ if rpoints is None:
145
+ rpoints = mdata.get(
146
+ FC.ROTOR_POINTS, self.get_rotor_points(algo, mdata, fdata)
147
+ )
148
+ if downwind_index is not None:
149
+ rpoints = rpoints[:, downwind_index, None]
150
+ if rpoint_weights is None:
151
+ rpoint_weights = mdata.get_item(FC.TWEIGHTS, self.rotor_point_weights())
152
+
153
+ tdata = TData.from_tpoints(rpoints, rpoint_weights)
154
+ sres = {}
155
+ mdvs = self.mdata_vars if self.mdata_vars is not None else list(mdata.keys())
156
+ for v, w in self.svars2mdvars.items():
157
+ tdata.add(
158
+ v,
159
+ data=np.full_like(rpoints[..., 0], np.nan),
160
+ dims=(FC.STATE, FC.TARGET, FC.TPOINT),
161
+ )
162
+
163
+ # check fixed variables
164
+ if hasattr(algo.states, "fixed_vars") and v in algo.states.fixed_vars:
165
+ tdata[v][:] = algo.states.fixed_vars[v]
166
+ sres[v] = tdata[v]
167
+ continue
168
+
169
+ # search in mdata variables
170
+ tcoord = self.turbine_coord
171
+ for mdv in mdvs:
172
+ assert mdv in mdata and mdv in mdata.dims, (
173
+ f"Rotor '{self.name}': mdata variable '{mdv}' not found in mdata {list(mdata.keys())} with dims {list(mdata.dims.keys())}"
174
+ )
175
+ mdat = mdata[mdv]
176
+ dims = mdata.dims[mdv]
177
+
178
+ # skip coordinates in the search:
179
+ if dims == (mdv,):
180
+ continue
181
+
182
+ # find variable index in last data array dimension
183
+ vc = dims[-1]
184
+ assert vc in mdata and vc in mdata.dims and mdata.dims[vc] == (vc,), (
185
+ f"Rotor '{self.name}': mdata coordinate '{vc}' not in mdata or wrong dimensions {mdata.dims}, expected '{(vc,)}'"
186
+ )
187
+ vrs = list(mdata[vc])
188
+ if w in vrs:
189
+ i = vrs.index(w)
190
+ mdat = mdat[..., i]
191
+ dims = dims[:-1]
192
+
193
+ # pure state dependent variable
194
+ if dims == (FC.STATE,):
195
+ tdata[v][:] = mdat[:, None, None]
196
+
197
+ # state and turbine dependent variable
198
+ elif len(dims) == 2 and dims[0] == FC.STATE:
199
+ assert mdat.shape[1] == mdata.n_turbines, (
200
+ f"Rotor '{self.name}': mdata variable '{mdv}' has dimensions {dims} and unexpected shape {mdat.shape} for variable '{w}', expected ({mdata.n_states}, {mdata.n_turbines}) for this wind farm with {mdata.n_turbines} turbines"
201
+ )
202
+ if tcoord is None:
203
+ tcoord = dims[1]
204
+ assert dims[1] == tcoord, (
205
+ f"Rotor '{self.name}': mdata variable '{mdv}' has unexpected dimensions {dims} for variable '{w}', expected ({FC.STATE}, {tcoord})"
206
+ )
207
+
208
+ tdata[v][:] = mdat[:, :, None]
209
+
210
+ else:
211
+ if tcoord is None:
212
+ tcoord = "<turbine>"
213
+ raise ValueError(
214
+ f"Rotor '{self.name}': mdata variable '{mdv}' has unexpected dimensions {dims} for variable '{w}' at position {i}, expected ({FC.STATE},) or ({FC.STATE}, {tcoord})"
215
+ )
216
+
217
+ sres[v] = tdata[v]
218
+ break
219
+
220
+ if v not in sres:
221
+ raise ValueError(
222
+ f"Rotor '{self.name}': mdata variable '{w}' not found in any of the mdata variables {mdvs}"
223
+ )
224
+
225
+ if store:
226
+ algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
227
+ algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, rpoint_weights, mdata=mdata)
228
+ algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres, mdata=mdata)
229
+ algo.add_to_chunk_store(FC.WEIGHT_RES, tdata[FV.WEIGHT], mdata=mdata)
230
+
231
+ self.eval_rpoint_results(
232
+ algo,
233
+ mdata,
234
+ fdata,
235
+ tdata,
236
+ rpoint_weights,
237
+ downwind_index,
238
+ copy_to_ambient=True,
239
+ )
240
+
241
+ return {v: fdata[v] for v in self.output_farm_vars(algo)}
@@ -12,11 +12,17 @@ class Calculator(TurbineModel):
12
12
  out_vars: list of str
13
13
  The output variables
14
14
  func: Function
15
- The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
15
+ The function: f(in0, in1, ..., algo, mdata, fdata, st_sel) -> (out0, out1, ...)
16
16
  where inX and outY are numpy.ndarrays and
17
17
  st_sel is the state-turbine selection slice or array.
18
18
  All arrays have shape (n_states, n_turbines).
19
19
 
20
+ Beware that the turbine ordering in fdata is in downwind order,
21
+ hence external data X of shape (n_states, n_turbines) in farm order
22
+ needs to be reordered by X[ssel, order] with
23
+ ssel = fdata[FV.ORDER_SSEL], order = fdata[FV.ORDER]
24
+ before using it in combination with fdata variables.
25
+
20
26
  :group: models.turbine_models
21
27
 
22
28
  """
@@ -32,10 +38,16 @@ class Calculator(TurbineModel):
32
38
  out_vars: list of str
33
39
  The output variables
34
40
  func: Function
35
- The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
41
+ The function: f(in0, in1, ..., algo, mdata, fdata, st_sel) -> (out0, out1, ...)
36
42
  where inX and outY are numpy.ndarrays and
37
43
  st_sel is the state-turbine selection slice or array.
38
44
  All arrays have shape (n_states, n_turbines).
45
+
46
+ Beware that the turbine ordering in fdata is in downwind order,
47
+ hence external data X of shape (n_states, n_turbines) in farm order
48
+ needs to be reordered by X[ssel, order] with
49
+ ssel = fdata[FV.ORDER_SSEL], order = fdata[FV.ORDER]
50
+ before using it in combination with fdata variables.
39
51
  kwargs: dict, optional
40
52
  Additional arguments for TurbineModel
41
53
 
@@ -92,7 +104,8 @@ class Calculator(TurbineModel):
92
104
  Values: numpy.ndarray with shape (n_states, n_turbines)
93
105
 
94
106
  """
107
+ self.ensure_output_vars(algo, fdata)
95
108
  ins = [fdata[v] if v in fdata else mdata[v] for v in self.in_vars]
96
- outs = self.func(*ins, st_sel=st_sel)
109
+ outs = self.func(*ins, algo=algo, mdata=mdata, fdata=fdata, st_sel=st_sel)
97
110
 
98
111
  return {v: outs[vi] for vi, v in enumerate(self.out_vars)}
@@ -102,6 +102,7 @@ class kTI(TurbineModel):
102
102
  Values: numpy.ndarray with shape (n_states, n_turbines)
103
103
 
104
104
  """
105
+ self.ensure_output_vars(algo, fdata)
105
106
 
106
107
  kti = self.get_data(
107
108
  FV.KTI,
@@ -189,6 +189,8 @@ class LookupTable(TurbineModel):
189
189
  Values: numpy.ndarray with shape (n_states, n_turbines)
190
190
 
191
191
  """
192
+ self.ensure_output_vars(algo, fdata)
193
+
192
194
  data = {
193
195
  v: self.get_data(
194
196
  v,
@@ -151,6 +151,7 @@ class PowerMask(TurbineModel):
151
151
 
152
152
  """
153
153
  # prepare:
154
+ self.ensure_output_vars(algo, fdata)
154
155
  P = fdata[FV.P]
155
156
  max_P = fdata[FV.MAX_P]
156
157
  P_rated = self._P_rated[None, :]
@@ -107,6 +107,8 @@ class RotorCentreCalc(TurbineModel):
107
107
  Values: numpy.ndarray with shape (n_states, n_turbines)
108
108
 
109
109
  """
110
+ self.ensure_output_vars(algo, fdata)
111
+
110
112
  # prepare target point data:
111
113
  tdata = TData.from_points(
112
114
  fdata[FV.TXYH],
@@ -190,6 +190,7 @@ class SectorManagement(TurbineModel):
190
190
 
191
191
  """
192
192
  # prepare:
193
+ self.ensure_output_vars(algo, fdata)
193
194
  n_trbs = len(self._trbs)
194
195
  if n_trbs == fdata.n_turbines and np.all(
195
196
  self._trbs == np.arange(fdata.n_turbines)
@@ -268,20 +268,15 @@ class SetFarmVars(TurbineModel):
268
268
  Values: numpy.ndarray with shape (n_states, n_turbines)
269
269
 
270
270
  """
271
+ self.ensure_output_vars(algo, fdata)
272
+
271
273
  i0 = mdata.states_i0(counter=True)
272
274
  if not self.once or i0 not in self.__once_done:
273
- if self.pre_rotor:
274
- order = np.s_[:]
275
- ssel = np.s_[:]
276
- else:
277
- order = fdata[FV.ORDER]
278
- ssel = fdata[FV.ORDER_SSEL]
279
-
280
275
  bsel = np.zeros((fdata.n_states, fdata.n_turbines), dtype=bool)
281
276
  bsel[st_sel] = True
282
277
 
283
278
  for v in self.vars:
284
- data = mdata[self.var(v)][ssel, order]
279
+ data = mdata[self.var(v)]
285
280
  hsel = ~np.isnan(data)
286
281
  tsel = bsel & hsel
287
282
 
@@ -143,6 +143,8 @@ class TableFactors(TurbineModel):
143
143
  Values: numpy.ndarray with shape (n_states, n_turbines)
144
144
 
145
145
  """
146
+ self.ensure_output_vars(algo, fdata)
147
+
146
148
  n_sel = np.sum(st_sel)
147
149
  qts = np.zeros((n_sel, 2), dtype=config.dtype_double)
148
150
  qts[:, 0] = fdata[self.row_var][st_sel]
@@ -82,6 +82,7 @@ class Thrust2Ct(TurbineModel):
82
82
  Values: numpy.ndarray with shape (n_states, n_turbines)
83
83
 
84
84
  """
85
+ self.ensure_output_vars(algo, fdata)
85
86
  ct = fdata[FV.CT]
86
87
 
87
88
  T = fdata[self.thrust_var][st_sel]
@@ -55,6 +55,8 @@ class YAW2YAWM(TurbineModel):
55
55
  Values: numpy.ndarray with shape (n_states, n_turbines)
56
56
 
57
57
  """
58
+ self.ensure_output_vars(algo, fdata)
59
+
58
60
  yaw = fdata[FV.YAW][st_sel]
59
61
  wd = fdata[FV.WD][st_sel]
60
62
 
@@ -56,6 +56,8 @@ class YAWM2YAW(TurbineModel):
56
56
  Values: numpy.ndarray with shape (n_states, n_turbines)
57
57
 
58
58
  """
59
+ self.ensure_output_vars(algo, fdata)
60
+
59
61
  yawm = fdata[FV.YAWM][st_sel]
60
62
  wd = fdata[FV.WD][st_sel]
61
63
 
@@ -300,6 +300,7 @@ class PCtFile(TurbineType):
300
300
  Values: numpy.ndarray with shape (n_states, n_turbines)
301
301
 
302
302
  """
303
+ self.ensure_output_vars(algo, fdata)
303
304
  rews2 = fdata[self.WSCT][st_sel]
304
305
  rews3 = fdata[self.WSP][st_sel]
305
306
 
@@ -330,10 +331,7 @@ class PCtFile(TurbineType):
330
331
  rews3 *= (cosm**self.p_P) ** (1.0 / 3.0)
331
332
  del yawm, cosm
332
333
 
333
- out = {
334
- FV.P: fdata[FV.P],
335
- FV.CT: fdata[FV.CT],
336
- }
334
+ out = {FV.P: fdata[FV.P], FV.CT: fdata[FV.CT]}
337
335
 
338
336
  out[FV.P][st_sel] = np.interp(
339
337
  rews3, self.data_ws, self.data_P, left=0.0, right=0.0
@@ -345,6 +345,7 @@ class PCtFromTwo(TurbineType):
345
345
  Values: numpy.ndarray with shape (n_states, n_turbines)
346
346
 
347
347
  """
348
+ self.ensure_output_vars(algo, fdata)
348
349
  rews2 = fdata[self.WSCT][st_sel]
349
350
  rews3 = fdata[self.WSP][st_sel]
350
351
 
@@ -11,3 +11,4 @@ from .wsrho2PCt_from_two import WsRho2PCtFromTwo as WsRho2PCtFromTwo
11
11
  from .wsti2PCt_from_two import WsTI2PCtFromTwo as WsTI2PCtFromTwo
12
12
  from .lookup import FromLookupTable as FromLookupTable
13
13
  from .TBL_file import TBLFile as TBLFile
14
+ from .calculator_type import CalculatorType as CalculatorType