foxes 0.7.2__py3-none-any.whl → 0.7.3.1__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 (60) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +57 -45
  3. foxes/algorithms/downwind/models/farm_wakes_calc.py +17 -6
  4. foxes/algorithms/downwind/models/point_wakes_calc.py +13 -45
  5. foxes/algorithms/iterative/iterative.py +1 -1
  6. foxes/algorithms/iterative/models/farm_wakes_calc.py +18 -4
  7. foxes/constants.py +5 -0
  8. foxes/core/__init__.py +2 -1
  9. foxes/core/ground_model.py +254 -0
  10. foxes/core/model.py +3 -2
  11. foxes/core/partial_wakes_model.py +19 -3
  12. foxes/core/states.py +33 -0
  13. foxes/core/wake_model.py +138 -2
  14. foxes/data/__init__.py +1 -1
  15. foxes/data/states/WRF-Timeseries-3000.nc +0 -0
  16. foxes/data/states/windio_timeseries_5000.nc +0 -0
  17. foxes/data/static_data.py +7 -0
  18. foxes/data/windio/DTU_10MW_turbine.yaml +10 -0
  19. foxes/data/windio/__init__.py +0 -0
  20. foxes/data/windio/windio_5turbines_timeseries.yaml +63 -0
  21. foxes/input/states/__init__.py +1 -0
  22. foxes/input/states/multi_height.py +225 -6
  23. foxes/input/windio/__init__.py +6 -1
  24. foxes/input/windio/get_states.py +115 -0
  25. foxes/input/windio/read_attributes.py +321 -0
  26. foxes/input/windio/read_farm.py +163 -0
  27. foxes/input/windio/read_fields.py +164 -0
  28. foxes/input/windio/runner.py +105 -0
  29. foxes/input/windio/windio.py +136 -254
  30. foxes/models/__init__.py +1 -0
  31. foxes/models/ground_models/__init__.py +2 -0
  32. foxes/models/ground_models/no_ground.py +12 -0
  33. foxes/models/ground_models/wake_mirror.py +161 -0
  34. foxes/models/model_book.py +68 -149
  35. foxes/models/partial_wakes/axiwake.py +27 -4
  36. foxes/models/partial_wakes/top_hat.py +26 -4
  37. foxes/models/turbine_types/PCt_file.py +1 -0
  38. foxes/models/turbine_types/PCt_from_two.py +92 -0
  39. foxes/models/wake_frames/yawed_wakes.py +41 -38
  40. foxes/models/wake_models/__init__.py +0 -1
  41. foxes/models/wake_models/induction/__init__.py +1 -0
  42. foxes/models/wake_models/induction/rankine_half_body.py +1 -1
  43. foxes/models/wake_models/induction/vortex_sheet.py +227 -0
  44. foxes/models/wake_models/ti/crespo_hernandez.py +26 -24
  45. foxes/models/wake_models/ti/iec_ti.py +33 -26
  46. foxes/models/wake_models/wind/bastankhah14.py +11 -32
  47. foxes/models/wake_models/wind/bastankhah16.py +30 -34
  48. foxes/models/wake_models/wind/jensen.py +13 -29
  49. foxes/models/wake_models/wind/turbopark.py +31 -61
  50. foxes/output/grids.py +6 -6
  51. foxes/output/output.py +6 -6
  52. foxes/utils/__init__.py +1 -1
  53. foxes/utils/factory.py +203 -11
  54. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/METADATA +8 -6
  55. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/RECORD +59 -45
  56. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/WHEEL +1 -1
  57. foxes/models/wake_models/wake_mirror.py +0 -196
  58. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/LICENSE +0 -0
  59. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/top_level.txt +0 -0
  60. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/zip-safe +0 -0
@@ -123,6 +123,7 @@ class PCtFromTwo(TurbineType):
123
123
 
124
124
  def __repr__(self):
125
125
  a = f"D={self.D}, H={self.H}, P_nominal={self.P_nominal}, P_unit={self.P_unit}, rho={self.rho}"
126
+ a += f", var_ws_ct={self.WSCT}, var_ws_P={self.WSP}"
126
127
  return f"{type(self).__name__}({a})"
127
128
 
128
129
  def output_farm_vars(self, algo):
@@ -196,6 +197,97 @@ class PCtFromTwo(TurbineType):
196
197
 
197
198
  return super().load_data(algo, verbosity)
198
199
 
200
+ def modify_cutin(
201
+ self,
202
+ modify_ct,
203
+ modify_P,
204
+ steps=20,
205
+ iterations=100,
206
+ a=0.55,
207
+ b=0.55,
208
+ ):
209
+ """
210
+ Modify the data such that a discontinuity
211
+ at cutin wind speed is avoided
212
+
213
+ Parameters
214
+ ----------
215
+ variable: str
216
+ The target variable
217
+ modify_ct: bool
218
+ Flag for modification of the ct curve
219
+ modify_P: bool
220
+ Flag for modification of the power curve
221
+ steps: int
222
+ The number of wind speed steps between 0 and
223
+ the cutin wind speed
224
+ iterations: int
225
+ The number of iterations
226
+ a: float
227
+ Coefficient for iterative mixing
228
+ b: float
229
+ Coefficient for iterative mixing
230
+
231
+ """
232
+ if modify_ct:
233
+
234
+ ws = self._data_ws_ct
235
+ ct = self._data_ct
236
+
237
+ i = 0
238
+ try:
239
+ while i < len(ws) and (not modify_ct or ct[i] < 1e-5):
240
+ i += 1
241
+ except IndexError:
242
+ raise IndexError(
243
+ f"Turbine type '{self.name}': Failed not determine cutin wind speed. ws = {ws}, ct = {ct}"
244
+ )
245
+
246
+ if ws[i] > 0:
247
+ ws = ws[i:]
248
+ ct = ct[i:]
249
+
250
+ new_ws = np.linspace(0.0, ws[0], steps + 1, dtype=ws.dtype)
251
+ new_ct = np.zeros_like(new_ws)
252
+
253
+ new_ct[-1] = ct[0]
254
+ for it in range(iterations):
255
+ new_ct[1:-1] = a * new_ct[:-2] + (1 - a) * new_ct[2:]
256
+
257
+ self._data_ws_ct = np.concatenate([new_ws[:-1], ws], axis=0)
258
+ self._data_ct = np.concatenate([new_ct[:-1], ct], axis=0)
259
+
260
+ if modify_P:
261
+
262
+ ws = self._data_ws_P
263
+ P = self._data_P
264
+
265
+ i = 0
266
+ try:
267
+ while i < len(ws) and (not modify_P or P[i] < 0.1):
268
+ i += 1
269
+ except IndexError:
270
+ raise IndexError(
271
+ f"Turbine type '{self.name}': Failed not determine cutin wind speed. ws = {ws}, P = {P}"
272
+ )
273
+
274
+ if ws[i] > 0:
275
+ ws = ws[i:]
276
+ P = P[i:]
277
+
278
+ new_ws = np.linspace(0.0, ws[0], steps + 1, dtype=ws.dtype)
279
+ new_P = np.zeros_like(new_ws)
280
+
281
+ new_P[-1] = P[0]
282
+ for it in range(iterations):
283
+ new_P[1:-1] = b * new_P[:-2] + (1 - b) * new_P[2:]
284
+
285
+ self._data_ws_P = np.concatenate([new_ws[:-1], ws], axis=0)
286
+ self._data_P = np.concatenate([new_P[:-1], P], axis=0)
287
+
288
+ if not modify_ct and not modify_P:
289
+ super().modify_cutin(modify_ct, modify_P)
290
+
199
291
  def calculate(self, algo, mdata, fdata, st_sel):
200
292
  """ "
201
293
  The main model calculation.
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
 
3
- from foxes.core import WakeFrame
3
+ from foxes.core import WakeFrame, WakeK, TData
4
4
  from foxes.models.wake_models.wind.bastankhah16 import (
5
5
  Bastankhah2016Model,
6
6
  Bastankhah2016,
@@ -28,16 +28,11 @@ class YawedWakes(WakeFrame):
28
28
  The model for computing common data
29
29
  model_pars: dict
30
30
  Model parameters
31
- K: float
32
- The wake growth parameter k. If not given here
33
- it will be searched in the farm data.
34
31
  YAWM: float
35
32
  The yaw misalignment YAWM. If not given here
36
33
  it will be searched in the farm data.
37
34
  base_frame: foxes.core.WakeFrame
38
35
  The wake frame from which to start
39
- k_var: str
40
- The variable name for k
41
36
 
42
37
  :group: models.wake_frames
43
38
 
@@ -45,45 +40,46 @@ class YawedWakes(WakeFrame):
45
40
 
46
41
  def __init__(
47
42
  self,
48
- k=None,
49
43
  base_frame=RotorWD(),
50
- k_var=FV.K,
51
- **kwargs,
44
+ alpha=0.58,
45
+ beta=0.07,
46
+ induction="Madsen",
47
+ **wake_k,
52
48
  ):
53
49
  """
54
50
  Constructor.
55
51
 
56
52
  Parameters
57
53
  ----------
58
- k: float, optional
59
- The wake growth parameter k. If not given here
60
- it will be searched in the farm data, by default None
61
54
  base_frame: foxes.core.WakeFrame
62
55
  The wake frame from which to start
63
- k_var: str
64
- The variable name for k
65
- kwargs: dict, optional
66
- Additional parameters for the Bastankhah2016Model,
56
+ alpha: float
57
+ model parameter used to determine onset of far wake region,
58
+ if not found in wake model
59
+ beta: float
60
+ model parameter used to determine onset of far wake region,
67
61
  if not found in wake model
62
+ induction: foxes.core.AxialInductionModel or str
63
+ The induction model, if not found in wake model
64
+ wake_k: dict, optional
65
+ Parameters for the WakeK class, if not found in wake model
68
66
 
69
67
  """
70
68
  super().__init__()
71
69
 
72
70
  self.base_frame = base_frame
73
71
  self.model = None
74
- self.model_pars = kwargs
75
- self.k_var = k_var
72
+ self.alpha = alpha
73
+ self.beta = beta
74
+ self.induction = induction
75
+ self.wake_k = None
76
+ self._wake_k_pars = wake_k
76
77
 
77
- setattr(self, k_var, k)
78
78
  setattr(self, FV.YAWM, 0.0)
79
79
 
80
80
  def __repr__(self):
81
- k = getattr(self, self.k_var)
82
81
  s = f"{type(self).__name__}("
83
- if k is None:
84
- s += f"k_var={self.k_var}"
85
- else:
86
- s += f"{self.k_var}={k}"
82
+ s += self.wake_k.repr() if self.wake_k is not None else ""
87
83
  s += ")"
88
84
  return s
89
85
 
@@ -97,7 +93,7 @@ class YawedWakes(WakeFrame):
97
93
  Names of all sub models
98
94
 
99
95
  """
100
- return [self.base_frame, self.model]
96
+ return [self.wake_k, self.base_frame, self.model]
101
97
 
102
98
  def initialize(self, algo, verbosity=0, force=False):
103
99
  """
@@ -114,20 +110,26 @@ class YawedWakes(WakeFrame):
114
110
 
115
111
  """
116
112
  if not self.initialized:
117
- for w in algo.wake_models:
113
+ for w in algo.wake_models.values():
118
114
  if isinstance(w, Bastankhah2016):
119
115
  if not w.initialized:
120
116
  w.initialize(algo, verbosity, force)
121
117
  self.model = w.model
122
- if w.k_var == self.k_var:
123
- setattr(self, self.k_var, getattr(w, self.k_var))
118
+ self.wake_k = w.wake_k
119
+ break
124
120
  if self.model is None:
125
- self.model = Bastankhah2016Model(**self.model_pars)
126
- if self.k is None:
127
- for w in algo.wake_models:
128
- if hasattr(w, "k_var") and w.k_var == self.k_var:
129
- setattr(self, self.k_var, getattr(w, self.k_var))
130
- break
121
+ self.model = Bastankhah2016Model(
122
+ alpha=self.alpha, beta=self.beta, induction=self.induction
123
+ )
124
+ if self.wake_k is None:
125
+ wake_k = WakeK(**self._wake_k_pars)
126
+ if not wake_k.all_none:
127
+ self.wake_k = wake_k
128
+ else:
129
+ for w in algo.wake_models.values():
130
+ if hasattr(w, "wake_k"):
131
+ self.wake_k = w.wake_k
132
+ break
131
133
 
132
134
  super().initialize(algo, verbosity, force)
133
135
 
@@ -175,10 +177,10 @@ class YawedWakes(WakeFrame):
175
177
  gamma *= np.pi / 180
176
178
 
177
179
  # get k:
178
- k = self.get_data(
179
- self.k_var,
180
+ k = self.wake_k(
180
181
  FC.STATE_TARGET,
181
- lookup="sf",
182
+ lookup_ti="f",
183
+ lookup_k="sf",
182
184
  algo=algo,
183
185
  fdata=fdata,
184
186
  tdata=tdata,
@@ -299,6 +301,7 @@ class YawedWakes(WakeFrame):
299
301
  points = self.base_frame.get_centreline_points(
300
302
  algo, mdata, fdata, downwind_index, x
301
303
  )
304
+ tdata = TData.from_points(points)
302
305
 
303
306
  nx = np.zeros_like(points)
304
307
  nx[:, 0] = points[:, 1] - points[:, 0]
@@ -314,7 +317,7 @@ class YawedWakes(WakeFrame):
314
317
  del nx, nz
315
318
 
316
319
  y = np.zeros_like(x)
317
- self._update_y(algo, mdata, fdata, None, downwind_index, x, y)
320
+ self._update_y(algo, mdata, fdata, tdata, downwind_index, x, y)
318
321
 
319
322
  points += y[:, :, None] * ny
320
323
 
@@ -6,7 +6,6 @@ from .dist_sliced import DistSlicedWakeModel
6
6
  from .axisymmetric import AxisymmetricWakeModel
7
7
  from .top_hat import TopHatWakeModel
8
8
  from .gaussian import GaussianWakeModel
9
- from .wake_mirror import WakeMirror, GroundMirror
10
9
 
11
10
  from . import wind
12
11
  from . import ti
@@ -6,3 +6,4 @@ from .rankine_half_body import RankineHalfBody
6
6
  from .rathmann import Rathmann
7
7
  from .self_similar import SelfSimilar
8
8
  from .self_similar2020 import SelfSimilar2020
9
+ from .vortex_sheet import VortexSheet
@@ -195,7 +195,7 @@ class RankineHalfBody(TurbineInductionModel):
195
195
  )
196
196
 
197
197
  # stagnation point condition
198
- xs = -np.sqrt(m / (4 * ws))
198
+ xs = -np.sqrt(m / (4 * ws + 1e-15))
199
199
 
200
200
  # set values out of body shape
201
201
  st_sel = (ct > 0) & ((RHB_shape < -1) | (x < xs))
@@ -0,0 +1,227 @@
1
+ import numpy as np
2
+
3
+ from foxes.core import TurbineInductionModel
4
+ from foxes.utils import uv2wd, wd2uv
5
+ import foxes.variables as FV
6
+ import foxes.constants as FC
7
+
8
+
9
+ class VortexSheet(TurbineInductionModel):
10
+ """
11
+ The Vortex Sheet model implemented with a radial dependency
12
+
13
+ Ref: Medici, D., et al. "The upstream flow of a wind turbine: blockage effect." Wind Energy 14.5 (2011): 691-697.
14
+ https://doi.org/10.1002/we.451
15
+
16
+ Attributes
17
+ ----------
18
+ pre_rotor_only: bool
19
+ Calculate only the pre-rotor region
20
+ induction: foxes.core.AxialInductionModel or str
21
+ The induction model
22
+
23
+ :group: models.wake_models.induction
24
+
25
+ """
26
+
27
+ def __init__(self, pre_rotor_only=False, induction="Madsen"):
28
+ """
29
+ Constructor.
30
+
31
+ Parameters
32
+ ----------
33
+ pre_rotor_only: bool
34
+ Calculate only the pre-rotor region
35
+ induction: foxes.core.AxialInductionModel or str
36
+ The induction model
37
+
38
+ :group: models.wake_models.induction
39
+
40
+ """
41
+ super().__init__()
42
+ self.induction = induction
43
+ self.pre_rotor_only = pre_rotor_only
44
+
45
+ def __repr__(self):
46
+ iname = (
47
+ self.induction if isinstance(self.induction, str) else self.induction.name
48
+ )
49
+ return f"{type(self).__name__}, induction={iname})"
50
+
51
+ def sub_models(self):
52
+ """
53
+ List of all sub-models
54
+
55
+ Returns
56
+ -------
57
+ smdls: list of foxes.core.Model
58
+ All sub models
59
+
60
+ """
61
+ return [self.induction]
62
+
63
+ def initialize(self, algo, verbosity=0, force=False):
64
+ """
65
+ Initializes the model.
66
+
67
+ Parameters
68
+ ----------
69
+ algo: foxes.core.Algorithm
70
+ The calculation algorithm
71
+ verbosity: int
72
+ The verbosity level, 0 = silent
73
+ force: bool
74
+ Overwrite existing data
75
+
76
+ """
77
+ if isinstance(self.induction, str):
78
+ self.induction = algo.mbook.axial_induction[self.induction]
79
+ super().initialize(algo, verbosity, force)
80
+
81
+ def new_wake_deltas(self, algo, mdata, fdata, tdata):
82
+ """
83
+ Initialize wake delta storage.
84
+
85
+ They are added on the fly to the wake_deltas dict.
86
+
87
+ Parameters
88
+ ----------
89
+ algo: foxes.core.Algorithm
90
+ The calculation algorithm
91
+ mdata: foxes.core.Data
92
+ The model data
93
+ fdata: foxes.core.Data
94
+ The farm data
95
+ pdata: foxes.core.Data
96
+ The evaluation point data
97
+ wake_deltas: dict
98
+ The wake deltas storage, add wake deltas
99
+ on the fly. Keys: Variable name str, for which the
100
+ wake delta applies, values: numpy.ndarray with
101
+ shape (n_states, n_points, ...)
102
+
103
+ """
104
+ return {FV.WS: np.zeros_like(tdata[FC.TARGETS][..., 0])}
105
+
106
+ def contribute(
107
+ self,
108
+ algo,
109
+ mdata,
110
+ fdata,
111
+ tdata,
112
+ downwind_index,
113
+ wake_coos,
114
+ wake_deltas,
115
+ ):
116
+ """
117
+ Modifies wake deltas at target points by
118
+ contributions from the specified wake source turbines.
119
+
120
+ Parameters
121
+ ----------
122
+ algo: foxes.core.Algorithm
123
+ The calculation algorithm
124
+ mdata: foxes.core.Data
125
+ The model data
126
+ fdata: foxes.core.Data
127
+ The farm data
128
+ tdata: foxes.core.Data
129
+ The target point data
130
+ downwind_index: int
131
+ The index of the wake causing turbine
132
+ in the downwnd order
133
+ wake_coos: numpy.ndarray
134
+ The wake frame coordinates of the evaluation
135
+ points, shape: (n_states, n_targets, n_tpoints, 3)
136
+ wake_deltas: dict
137
+ The wake deltas. Key: variable name,
138
+ value: numpy.ndarray with shape
139
+ (n_states, n_targets, n_tpoints, ...)
140
+
141
+ """
142
+
143
+ # get x, y and z. Rounding for safe x < 0 condition
144
+ x = np.round(wake_coos[..., 0], 12)
145
+ y = wake_coos[..., 1]
146
+ z = wake_coos[..., 2]
147
+ r = np.sqrt(y**2 + z**2)
148
+ r_sph = np.sqrt(r**2 + x**2)
149
+
150
+ # get ct
151
+ ct = self.get_data(
152
+ FV.CT,
153
+ FC.STATE_TARGET_TPOINT,
154
+ lookup="w",
155
+ algo=algo,
156
+ fdata=fdata,
157
+ tdata=tdata,
158
+ upcast=True,
159
+ downwind_index=downwind_index,
160
+ )
161
+
162
+ # get ws
163
+ ws = self.get_data(
164
+ FV.REWS,
165
+ FC.STATE_TARGET_TPOINT,
166
+ lookup="w",
167
+ algo=algo,
168
+ fdata=fdata,
169
+ tdata=tdata,
170
+ upcast=True,
171
+ downwind_index=downwind_index,
172
+ )
173
+
174
+ # get D
175
+ D = self.get_data(
176
+ FV.D,
177
+ FC.STATE_TARGET_TPOINT,
178
+ lookup="w",
179
+ algo=algo,
180
+ fdata=fdata,
181
+ tdata=tdata,
182
+ upcast=True,
183
+ downwind_index=downwind_index,
184
+ )
185
+
186
+ sp_sel = (ct > 0) & (x <= 0)
187
+ ws_sel = ws[sp_sel]
188
+ ct_sel = ct[sp_sel]
189
+ r_sph_sel = r_sph[sp_sel]
190
+ D_sel = D[sp_sel]
191
+
192
+ if np.any(sp_sel):
193
+ blockage = (
194
+ ws_sel
195
+ * (
196
+ 1
197
+ - self.induction.ct2a(ct_sel)
198
+ * ((1 + 2 * r_sph_sel / D_sel) * (1 + (2 * r_sph_sel / D_sel) ** 2))
199
+ ** (-0.5)
200
+ )
201
+ ) - ws_sel
202
+ wake_deltas[FV.WS][sp_sel] += blockage
203
+
204
+ if not self.pre_rotor_only:
205
+ sp_sel = (
206
+ (ct > 0) & (x > 0) & (r > D / 2)
207
+ ) # mirror in rotor plane and inverse blockage, but not directly behind rotor
208
+ ws_sel = ws[sp_sel]
209
+ ct_sel = ct[sp_sel]
210
+ r_sph_sel = r_sph[sp_sel]
211
+ D_sel = D[sp_sel]
212
+ if np.any(sp_sel):
213
+ blockage = (
214
+ ws_sel
215
+ * (
216
+ 1
217
+ - self.induction.ct2a(ct_sel)
218
+ * (
219
+ (1 + 2 * r_sph_sel / D_sel)
220
+ * (1 + (2 * r_sph_sel / D_sel) ** 2)
221
+ )
222
+ ** (-0.5)
223
+ )
224
+ ) - ws_sel
225
+ wake_deltas[FV.WS][sp_sel] += -blockage
226
+
227
+ return wake_deltas
@@ -1,5 +1,6 @@
1
1
  import numpy as np
2
2
 
3
+ from foxes.core import WakeK
3
4
  from foxes.models.wake_models.top_hat import TopHatWakeModel
4
5
  import foxes.variables as FV
5
6
  import foxes.constants as FC
@@ -21,9 +22,6 @@ class CrespoHernandezTIWake(TopHatWakeModel):
21
22
 
22
23
  Attributes
23
24
  ----------
24
- k: float
25
- The wake growth parameter k. If not given here
26
- it will be searched in the farm data.
27
25
  a_near: float
28
26
  Model parameter
29
27
  a_far: float
@@ -42,8 +40,8 @@ class CrespoHernandezTIWake(TopHatWakeModel):
42
40
  near_wake_D: float
43
41
  The near wake distance in units of D,
44
42
  calculated from TI and ct if None
45
- k_var: str
46
- The variable name for k
43
+ wake_k: foxes.core.WakeK
44
+ Handler for the wake growth parameter k
47
45
 
48
46
  :group: models.wake_models.ti
49
47
 
@@ -52,7 +50,6 @@ class CrespoHernandezTIWake(TopHatWakeModel):
52
50
  def __init__(
53
51
  self,
54
52
  superposition,
55
- k=None,
56
53
  use_ambti=False,
57
54
  sbeta_factor=0.25,
58
55
  near_wake_D=None,
@@ -61,8 +58,8 @@ class CrespoHernandezTIWake(TopHatWakeModel):
61
58
  e1=0.83,
62
59
  e2=-0.0325,
63
60
  e3=-0.32,
64
- k_var=FV.K,
65
- **kwargs,
61
+ induction="Betz",
62
+ **wake_k,
66
63
  ):
67
64
  """
68
65
  Constructor.
@@ -94,11 +91,13 @@ class CrespoHernandezTIWake(TopHatWakeModel):
94
91
  Model parameter
95
92
  k_var: str
96
93
  The variable name for k
97
- kwargs: dict, optional
98
- Additional parameters for the base class
94
+ induction: foxes.core.AxialInductionModel or str
95
+ The induction model
96
+ wake_k: dict, optional
97
+ Parameters for the WakeK class
99
98
 
100
99
  """
101
- super().__init__(superpositions={FV.TI: superposition}, **kwargs)
100
+ super().__init__(superpositions={FV.TI: superposition}, induction=induction)
102
101
 
103
102
  self.a_near = a_near
104
103
  self.a_far = a_far
@@ -108,24 +107,29 @@ class CrespoHernandezTIWake(TopHatWakeModel):
108
107
  self.use_ambti = use_ambti
109
108
  self.sbeta_factor = sbeta_factor
110
109
  self.near_wake_D = near_wake_D
111
- self.k_var = k_var
112
-
113
- setattr(self, k_var, k)
110
+ self.wake_k = WakeK(**wake_k)
114
111
 
115
112
  def __repr__(self):
116
- k = getattr(self, self.k_var)
117
113
  iname = (
118
114
  self.induction if isinstance(self.induction, str) else self.induction.name
119
115
  )
120
116
  s = f"{type(self).__name__}"
121
- s += f"({self.superpositions[FV.TI]}, induction={iname}"
122
- if k is None:
123
- s += f", k_var={self.k_var}"
124
- else:
125
- s += f", {self.k_var}={k}"
126
- s += ")"
117
+ s += f"({self.superpositions[FV.TI]}, induction={iname}, "
118
+ s += self.wake_k.repr() + ")"
127
119
  return s
128
120
 
121
+ def sub_models(self):
122
+ """
123
+ List of all sub-models
124
+
125
+ Returns
126
+ -------
127
+ smdls: list of foxes.core.Model
128
+ All sub models
129
+
130
+ """
131
+ return [self.wake_k]
132
+
129
133
  def new_wake_deltas(self, algo, mdata, fdata, tdata):
130
134
  """
131
135
  Creates new empty wake delta arrays.
@@ -200,10 +204,8 @@ class CrespoHernandezTIWake(TopHatWakeModel):
200
204
  )
201
205
 
202
206
  # get k:
203
- k = self.get_data(
204
- self.k_var,
207
+ k = self.wake_k(
205
208
  FC.STATE_TARGET,
206
- lookup="sw",
207
209
  algo=algo,
208
210
  fdata=fdata,
209
211
  tdata=tdata,