foxes 0.5.1__py3-none-any.whl → 0.5.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of foxes might be problematic. Click here for more details.

Files changed (66) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +41 -46
  3. foxes/algorithms/downwind/models/point_wakes_calc.py +4 -9
  4. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -22
  5. foxes/core/algorithm.py +1 -1
  6. foxes/core/data_calc_model.py +26 -2
  7. foxes/core/partial_wakes_model.py +1 -1
  8. foxes/core/rotor_model.py +36 -2
  9. foxes/core/turbine_model.py +36 -0
  10. foxes/core/turbine_type.py +35 -1
  11. foxes/core/wake_frame.py +39 -3
  12. foxes/core/wake_model.py +36 -0
  13. foxes/models/model_book.py +132 -85
  14. foxes/models/turbine_models/rotor_centre_calc.py +1 -2
  15. foxes/models/turbine_types/CpCt_file.py +13 -3
  16. foxes/models/turbine_types/CpCt_from_two.py +14 -4
  17. foxes/models/vertical_profiles/abl_log_neutral_ws.py +32 -5
  18. foxes/models/vertical_profiles/abl_log_stable_ws.py +32 -4
  19. foxes/models/vertical_profiles/abl_log_unstable_ws.py +32 -4
  20. foxes/models/vertical_profiles/abl_log_ws.py +50 -18
  21. foxes/models/wake_frames/yawed_wakes.py +15 -9
  22. foxes/models/wake_models/induction/__init__.py +1 -1
  23. foxes/models/wake_models/induction/rankine_half_body.py +33 -7
  24. foxes/models/wake_models/ti/crespo_hernandez.py +6 -1
  25. foxes/models/wake_models/ti/iec_ti.py +5 -3
  26. foxes/models/wake_models/wind/__init__.py +2 -2
  27. foxes/models/wake_models/wind/{bastankhah.py → bastankhah14.py} +11 -14
  28. foxes/models/wake_models/wind/{porte_agel.py → bastankhah16.py} +24 -16
  29. foxes/models/wake_models/wind/turbopark.py +11 -22
  30. foxes/models/wake_superpositions/__init__.py +9 -5
  31. foxes/models/wake_superpositions/ti_linear.py +134 -0
  32. foxes/models/wake_superpositions/ti_max.py +134 -0
  33. foxes/models/wake_superpositions/{ti_superp.py → ti_pow.py} +15 -57
  34. foxes/models/wake_superpositions/ti_quadratic.py +134 -0
  35. foxes/models/wake_superpositions/ws_linear.py +170 -0
  36. foxes/models/wake_superpositions/ws_max.py +173 -0
  37. foxes/models/wake_superpositions/ws_pow.py +175 -0
  38. foxes/models/wake_superpositions/{product.py → ws_product.py} +43 -22
  39. foxes/models/wake_superpositions/ws_quadratic.py +170 -0
  40. foxes/output/__init__.py +4 -0
  41. foxes/output/calc_points.py +143 -0
  42. foxes/output/flow_plots_2d/__init__.py +1 -0
  43. foxes/output/flow_plots_2d/common.py +104 -1
  44. foxes/output/flow_plots_2d/flow_plots.py +237 -569
  45. foxes/output/flow_plots_2d/get_fig.py +183 -0
  46. foxes/output/flow_plots_2d/seq_flow_ani_plugin.py +0 -1
  47. foxes/output/grids.py +705 -0
  48. foxes/output/output.py +58 -11
  49. foxes/output/results_writer.py +101 -17
  50. foxes/output/round.py +10 -0
  51. foxes/output/slice_data.py +900 -0
  52. foxes/utils/__init__.py +5 -3
  53. foxes/utils/exec_python.py +56 -0
  54. foxes/utils/geopandas_utils.py +294 -0
  55. foxes/utils/pandas_utils.py +175 -0
  56. foxes/utils/plotly_utils.py +19 -0
  57. foxes/utils/xarray_utils.py +38 -0
  58. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/METADATA +1 -1
  59. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/RECORD +63 -49
  60. foxes/models/wake_superpositions/linear.py +0 -242
  61. foxes/models/wake_superpositions/max.py +0 -258
  62. foxes/models/wake_superpositions/quadratic.py +0 -252
  63. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/LICENSE +0 -0
  64. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/WHEEL +0 -0
  65. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/top_level.txt +0 -0
  66. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/zip-safe +0 -0
@@ -2,6 +2,18 @@ import foxes.models as fm
2
2
  import foxes.variables as FV
3
3
  from foxes.utils import Dict
4
4
 
5
+ from foxes.core import (
6
+ PointDataModel,
7
+ FarmDataModel,
8
+ FarmController,
9
+ RotorModel,
10
+ TurbineType,
11
+ TurbineModel,
12
+ PartialWakesModel,
13
+ WakeFrame,
14
+ WakeSuperposition,
15
+ WakeModel
16
+ )
5
17
 
6
18
  class ModelBook:
7
19
  """
@@ -21,9 +33,6 @@ class ModelBook:
21
33
  turbine_models: foxes.utils.Dict
22
34
  The turbine models. Keys: model name str,
23
35
  values: foxes.core.TurbineModel
24
- turbine_orders: foxes.utils.Dict
25
- The turbine orders. Keys: model name str,
26
- values: foxes.core.TurbineOrder
27
36
  farm_models: foxes.utils.Dict
28
37
  The farm models. Keys: model name str,
29
38
  values: foxes.core.FarmModel
@@ -44,6 +53,8 @@ class ModelBook:
44
53
  values: foxes.core.WakeModel
45
54
  sources: foxes.utils.Dict
46
55
  All sources dict
56
+ base_classes: foxes.utils.Dict
57
+ The base classes for all model types
47
58
 
48
59
  :group: foxes
49
60
 
@@ -186,47 +197,27 @@ class ModelBook:
186
197
 
187
198
  self.wake_superpositions = Dict(
188
199
  name="wake_superpositions",
189
- linear=fm.wake_superpositions.LinearSuperposition(
190
- scalings=f"source_turbine_{FV.REWS}"
191
- ),
192
- linear_lim=fm.wake_superpositions.LinearSuperposition(
193
- scalings=f"source_turbine_{FV.REWS}",
194
- lim_low={FV.WS: 1e-4},
195
- ),
196
- linear_amb=fm.wake_superpositions.LinearSuperposition(
197
- scalings=f"source_turbine_{FV.AMB_REWS}"
198
- ),
199
- quadratic=fm.wake_superpositions.QuadraticSuperposition(
200
- scalings=f"source_turbine_{FV.REWS}"
201
- ),
202
- quadratic_amb=fm.wake_superpositions.QuadraticSuperposition(
203
- scalings=f"source_turbine_{FV.AMB_REWS}"
204
- ),
205
- max=fm.wake_superpositions.MaxSuperposition(
206
- scalings=f"source_turbine_{FV.REWS}"
207
- ),
208
- max_amb=fm.wake_superpositions.MaxSuperposition(
209
- scalings=f"source_turbine_{FV.AMB_REWS}"
210
- ),
211
- product=fm.wake_superpositions.ProductSuperposition(),
212
- product_lim=fm.wake_superpositions.ProductSuperposition(
213
- lim_low={FV.WS: 1e-4},
214
- ),
215
- ti_linear=fm.wake_superpositions.TISuperposition(
216
- ti_superp="linear", superp_to_amb="quadratic"
217
- ),
218
- ti_quadratic=fm.wake_superpositions.TISuperposition(
219
- ti_superp="quadratic", superp_to_amb="quadratic"
220
- ),
221
- ti_cubic=fm.wake_superpositions.TISuperposition(
222
- ti_superp="power_3", superp_to_amb="quadratic"
223
- ),
224
- ti_quartic=fm.wake_superpositions.TISuperposition(
225
- ti_superp="power_4", superp_to_amb="quadratic"
226
- ),
227
- ti_max=fm.wake_superpositions.TISuperposition(
228
- ti_superp="max", superp_to_amb="quadratic"
229
- ),
200
+ ws_linear=fm.wake_superpositions.WSLinear(scale_amb=False),
201
+ ws_linear_lim=fm.wake_superpositions.WSLinear(scale_amb=False, lim_low=1e-4),
202
+ ws_linear_amb=fm.wake_superpositions.WSLinear(scale_amb=True),
203
+ ws_linear_amb_lim=fm.wake_superpositions.WSLinear(scale_amb=True, lim_low=1e-4),
204
+ ws_quadratic=fm.wake_superpositions.WSQuadratic(scale_amb=False),
205
+ ws_quadratic_lim=fm.wake_superpositions.WSQuadratic(scale_amb=False, lim_low=1e-4),
206
+ ws_quadratic_amb=fm.wake_superpositions.WSQuadratic(scale_amb=True),
207
+ ws_quadratic_amb_lim=fm.wake_superpositions.WSQuadratic(scale_amb=True, lim_low=1e-4),
208
+ ws_cubic=fm.wake_superpositions.WSPow(pow=3, scale_amb=False),
209
+ ws_cubic_amb=fm.wake_superpositions.WSPow(pow=3, scale_amb=True),
210
+ ws_quartic=fm.wake_superpositions.WSPow(pow=4, scale_amb=False),
211
+ ws_quartic_amb=fm.wake_superpositions.WSPow(pow=4, scale_amb=True),
212
+ ws_max=fm.wake_superpositions.WSMax(scale_amb=False),
213
+ ws_max_amb=fm.wake_superpositions.WSMax(scale_amb=True),
214
+ ws_product=fm.wake_superpositions.WSProduct(),
215
+ ws_product_lim=fm.wake_superpositions.WSProduct(lim_low=1e-4),
216
+ ti_linear=fm.wake_superpositions.TILinear(superp_to_amb="quadratic"),
217
+ ti_quadratic=fm.wake_superpositions.TIQuadratic(superp_to_amb="quadratic"),
218
+ ti_cubic=fm.wake_superpositions.TIPow(pow=3, superp_to_amb="quadratic"),
219
+ ti_quartic=fm.wake_superpositions.TIPow(pow=4, superp_to_amb="quadratic"),
220
+ ti_max=fm.wake_superpositions.TIMax(superp_to_amb="quadratic"),
230
221
  )
231
222
 
232
223
  self.wake_models = Dict(name="wake_models")
@@ -234,69 +225,80 @@ class ModelBook:
234
225
  "linear",
235
226
  "linear_lim",
236
227
  "linear_amb",
228
+ "linear_amb_lim",
237
229
  "quadratic",
230
+ "wquadratic_lim",
238
231
  "quadratic_amb",
239
- "max",
232
+ "quadratic_amb_lim",
233
+ "cubic",
234
+ "cubic_amb",
235
+ "quartic",
236
+ "quartic_amb",
237
+ "wmax",
240
238
  "max_amb",
241
239
  "product",
242
240
  "product_lim",
243
241
  ]
244
242
  for s in slist:
245
243
  self.wake_models[f"Jensen_{s}"] = fm.wake_models.wind.JensenWake(
246
- superposition=s
244
+ superposition=f"ws_{s}"
247
245
  )
248
246
  self.wake_models[f"Jensen_{s}_k002"] = fm.wake_models.wind.JensenWake(
249
- k=0.02, superposition=s
247
+ k=0.02, superposition=f"ws_{s}"
250
248
  )
251
249
  self.wake_models[f"Jensen_{s}_k004"] = fm.wake_models.wind.JensenWake(
252
- k=0.04, superposition=s
250
+ k=0.04, superposition=f"ws_{s}"
253
251
  )
254
252
  self.wake_models[f"Jensen_{s}_k007"] = fm.wake_models.wind.JensenWake(
255
- k=0.07, superposition=s
253
+ k=0.07, superposition=f"ws_{s}"
256
254
  )
257
255
  self.wake_models[f"Jensen_{s}_k0075"] = fm.wake_models.wind.JensenWake(
258
- k=0.075, superposition=s
256
+ k=0.075, superposition=f"ws_{s}"
259
257
  )
260
258
 
261
- self.wake_models[f"Bastankhah_{s}"] = fm.wake_models.wind.BastankhahWake(
262
- superposition=s
259
+ self.wake_models[f"Bastankhah2014_{s}"] = fm.wake_models.wind.Bastankhah2014(
260
+ superposition=f"ws_{s}", sbeta_factor=0.2
263
261
  )
264
262
  self.wake_models[
265
- f"Bastankhah_{s}_k002"
266
- ] = fm.wake_models.wind.BastankhahWake(k=0.02, superposition=s)
263
+ f"Bastankhah2014_{s}_k002"
264
+ ] = fm.wake_models.wind.Bastankhah2014(
265
+ k=0.02, sbeta_factor=0.2, superposition=f"ws_{s}"
266
+ )
267
267
  self.wake_models[
268
- f"Bastankhah_{s}_k004"
269
- ] = fm.wake_models.wind.BastankhahWake(k=0.04, superposition=s)
268
+ f"Bastankhah2014_{s}_k004"
269
+ ] = fm.wake_models.wind.Bastankhah2014(
270
+ k=0.04, sbeta_factor=0.2, superposition=f"ws_{s}"
271
+ )
270
272
 
271
- self.wake_models[f"Bastankhah0_{s}"] = fm.wake_models.wind.BastankhahWake(
272
- superposition=s, sbeta_factor=0.2
273
+ self.wake_models[f"Bastankhah025_{s}"] = fm.wake_models.wind.Bastankhah2014(
274
+ superposition=f"ws_{s}", sbeta_factor=0.25
273
275
  )
274
276
  self.wake_models[
275
- f"Bastankhah0_{s}_k002"
276
- ] = fm.wake_models.wind.BastankhahWake(
277
- k=0.02, superposition=s, sbeta_factor=0.2
277
+ f"Bastankhah025_{s}_k002"
278
+ ] = fm.wake_models.wind.Bastankhah2014(
279
+ k=0.02, superposition=f"ws_{s}", sbeta_factor=0.25
278
280
  )
279
281
  self.wake_models[
280
- f"Bastankhah0_{s}_k004"
281
- ] = fm.wake_models.wind.BastankhahWake(
282
- k=0.04, superposition=s, sbeta_factor=0.2
282
+ f"Bastankhah025_{s}_k004"
283
+ ] = fm.wake_models.wind.Bastankhah2014(
284
+ k=0.04, superposition=f"ws_{s}", sbeta_factor=0.25
283
285
  )
284
286
 
285
- self.wake_models[f"PorteAgel_{s}"] = fm.wake_models.wind.PorteAgelWake(
286
- superposition=s
287
+ self.wake_models[f"Bastankhah2016_{s}"] = fm.wake_models.wind.Bastankhah2016(
288
+ superposition=f"ws_{s}"
287
289
  )
288
- self.wake_models[f"PorteAgel_{s}_k002"] = fm.wake_models.wind.PorteAgelWake(
289
- superposition=s, k=0.02
290
+ self.wake_models[f"Bastankhah2016_{s}_k002"] = fm.wake_models.wind.Bastankhah2016(
291
+ superposition=f"ws_{s}", k=0.02
290
292
  )
291
- self.wake_models[f"PorteAgel_{s}_k004"] = fm.wake_models.wind.PorteAgelWake(
292
- superposition=s, k=0.04
293
+ self.wake_models[f"Bastankhah2016_{s}_k004"] = fm.wake_models.wind.Bastankhah2016(
294
+ superposition=f"ws_{s}", k=0.04
293
295
  )
294
296
 
295
297
  self.wake_models[f"TurbOPark_{s}_A002"] = fm.wake_models.wind.TurbOParkWake(
296
- A=0.02, superposition=s
298
+ A=0.02, superposition=f"ws_{s}"
297
299
  )
298
300
  self.wake_models[f"TurbOPark_{s}_A004"] = fm.wake_models.wind.TurbOParkWake(
299
- A=0.04, superposition=s
301
+ A=0.04, superposition=f"ws_{s}"
300
302
  )
301
303
 
302
304
  As = [0.02, 0.04]
@@ -307,29 +309,29 @@ class ModelBook:
307
309
  d = str(dx).replace(".", "") if dx < 1 else int(dx)
308
310
  self.wake_models[
309
311
  f"TurbOParkIX_{s}_A{a}_dx{d}"
310
- ] = fm.wake_models.wind.TurbOParkWakeIX(A=A, superposition=s, dx=dx)
312
+ ] = fm.wake_models.wind.TurbOParkWakeIX(A=A, superposition=f"ws_{s}", dx=dx)
311
313
 
312
- slist = ["ti_linear", "ti_quadratic", "ti_cubic", "ti_quartic", "ti_max"]
314
+ slist = ["linear", "quadratic", "cubic", "quartic", "max"]
313
315
  for s in slist:
314
316
  self.wake_models[
315
- f"CrespoHernandez_{s[3:]}"
316
- ] = fm.wake_models.ti.CrespoHernandezTIWake(superposition=s)
317
+ f"CrespoHernandez_{s}"
318
+ ] = fm.wake_models.ti.CrespoHernandezTIWake(superposition=f"ti_{s}")
317
319
  self.wake_models[
318
- f"CrespoHernandez_ambti_{s[3:]}"
319
- ] = fm.wake_models.ti.CrespoHernandezTIWake(superposition=s, use_ambti=True)
320
+ f"CrespoHernandez_ambti_{s}"
321
+ ] = fm.wake_models.ti.CrespoHernandezTIWake(superposition=f"ti_{s}", use_ambti=True)
320
322
  self.wake_models[
321
- f"CrespoHernandez_{s[3:]}_k002"
322
- ] = fm.wake_models.ti.CrespoHernandezTIWake(k=0.02, superposition=s)
323
+ f"CrespoHernandez_{s}_k002"
324
+ ] = fm.wake_models.ti.CrespoHernandezTIWake(k=0.02, superposition=f"ti_{s}")
323
325
 
324
- self.wake_models[f"IECTI2005_{s[3:]}"] = fm.wake_models.ti.IECTIWake(
325
- superposition=s, iec_type="2005"
326
+ self.wake_models[f"IECTI2005_{s}"] = fm.wake_models.ti.IECTIWake(
327
+ superposition=f"ti_{s}", iec_type="2005"
326
328
  )
327
329
 
328
- self.wake_models[f"IECTI2019_{s[3:]}"] = fm.wake_models.ti.IECTIWake(
329
- superposition=s, iec_type="2019"
330
+ self.wake_models[f"IECTI2019_{s}"] = fm.wake_models.ti.IECTIWake(
331
+ superposition=f"ti_{s}", iec_type="2019"
330
332
  )
331
333
 
332
- self.wake_models[f"RHB"] = fm.wake_models.induction.RHB()
334
+ self.wake_models[f"RHB"] = fm.wake_models.induction.RankineHalfBody()
333
335
 
334
336
  self.sources = Dict(
335
337
  name="sources",
@@ -344,6 +346,19 @@ class ModelBook:
344
346
  wake_superpositions=self.wake_superpositions,
345
347
  wake_models=self.wake_models,
346
348
  )
349
+ self.base_classes = Dict(
350
+ name="base_classes",
351
+ point_models=PointDataModel,
352
+ rotor_models=RotorModel,
353
+ turbine_types=TurbineType,
354
+ turbine_models=TurbineModel,
355
+ farm_models=FarmDataModel,
356
+ farm_controllers=FarmController,
357
+ partial_wakes=PartialWakesModel,
358
+ wake_frames=WakeFrame,
359
+ wake_superpositions=WakeSuperposition,
360
+ wake_models=WakeModel,
361
+ )
347
362
 
348
363
  for s in self.sources.values():
349
364
  for k, m in s.items():
@@ -376,6 +391,38 @@ class ModelBook:
376
391
  else:
377
392
  print("(none)")
378
393
  print()
394
+
395
+ def get(self, model_type, name, class_name=None, *args, **kwargs):
396
+ """
397
+ Gets a model object.
398
+
399
+ If not found, dynamically creates it (given the class name)
400
+
401
+ Parameters
402
+ ----------
403
+ model_type: str
404
+ The model type
405
+ name: str
406
+ The model name
407
+ class_name: str, optinal
408
+ Name of the model class
409
+ args: tuple, optional
410
+ Arguments for the model class
411
+ kwargs: dict, optional
412
+ Arguments for the model class
413
+
414
+ Returns
415
+ -------
416
+ model: mclass
417
+ The model object
418
+
419
+ """
420
+ if name not in self.sources[model_type]:
421
+ if class_name is None:
422
+ raise KeyError(f"Model '{name}' of type '{model_type}' not found in model book. Available: {sorted(list(self.sources[model_type].keys()))}")
423
+ bclass = self.base_classes[model_type]
424
+ self.sources[model_type][name] = bclass.new(class_name, *args, **kwargs)
425
+ return self.sources[model_type][name]
379
426
 
380
427
  def finalize(self, algo, verbosity=0):
381
428
  """
@@ -49,8 +49,7 @@ class RotorCentreCalc(TurbineModel):
49
49
  The verbosity level, 0 = silent
50
50
 
51
51
  """
52
- pvars = list(self.calc_vars.values())
53
- self._wcalc = algo.PointWakesCalculation(point_vars=pvars)
52
+ self._wcalc = algo.get_model("PointWakesCalculation")()
54
53
  super().initialize(algo, verbosity)
55
54
 
56
55
  def sub_models(self):
@@ -4,7 +4,7 @@ import pandas as pd
4
4
  from .PCt_file import PCtFile
5
5
  from foxes.data import parse_Pct_file_name
6
6
  from foxes.utils import PandasFileHelper
7
-
7
+ import foxes.constants as FC
8
8
 
9
9
  class CpCtFile(PCtFile):
10
10
  """
@@ -55,6 +55,16 @@ class CpCtFile(PCtFile):
55
55
  A = np.pi * (D / 2) ** 2
56
56
  ws = data[col_ws].to_numpy()
57
57
  cp = data[col_cp].to_numpy()
58
- data["P"] = 0.5 * rho * A * cp * ws**3
58
+ P_unit = pars.pop("P_unit", FC.kW)
59
+
60
+ ws_delta = 0.0001
61
+ ws_min = np.min(ws)
62
+ ws_max = np.max(ws)
63
+ N = int((ws_max - ws_min)/ws_delta)
64
+
65
+ data_P = pd.DataFrame(index=range(N), dtype=FC.DTYPE)
66
+ data_P["ws"] = np.linspace(ws_min, ws_max, N, endpoint=True)
67
+ data_P["cp"] = np.interp(data_P["ws"], ws, cp, left=0, right=0)
68
+ data_P["P"] = 0.5 * rho * A * data_P["cp"] * data_P["ws"]**3 / FC.P_UNITS[P_unit]
59
69
 
60
- super().__init__(data, col_ws=col_ws, col_P="P", rho=rho, **pars)
70
+ super().__init__(data_P, col_ws="ws", col_P="P", rho=rho, P_unit=P_unit, **pars)
@@ -66,14 +66,24 @@ class CpCtFromTwo(PCtFromTwo):
66
66
  A = np.pi * (D / 2) ** 2
67
67
  ws = data_cp[col_ws_cp_file].to_numpy()
68
68
  cp = data_cp[col_cp].to_numpy()
69
- data_cp["P"] = 0.5 * rho * A * cp * ws**3 / FC.P_UNITS[FC.kW]
69
+ P_unit = pars.pop("P_unit", FC.kW)
70
+
71
+ ws_delta = 0.0001
72
+ ws_min = np.min(ws)
73
+ ws_max = np.max(ws)
74
+ N = int((ws_max - ws_min)/ws_delta)
75
+
76
+ data_P = pd.DataFrame(index=range(N), dtype=FC.DTYPE)
77
+ data_P["ws"] = np.linspace(ws_min, ws_max, N, endpoint=True)
78
+ data_P["cp"] = np.interp(data_P["ws"], ws, cp, left=0, right=0)
79
+ data_P["P"] = 0.5 * rho * A * data_P["cp"] * data_P["ws"]**3 / FC.P_UNITS[P_unit]
70
80
 
71
81
  super().__init__(
72
- data_cp,
82
+ data_P,
73
83
  data_ct,
74
- col_ws_P_file=col_ws_cp_file,
84
+ col_ws_P_file="ws",
75
85
  col_P="P",
76
86
  rho=rho,
77
- P_unit=FC.kW,
87
+ P_unit=P_unit,
78
88
  **pars,
79
89
  )
@@ -8,10 +8,32 @@ class ABLLogNeutralWsProfile(VerticalProfile):
8
8
  """
9
9
  The neutral ABL wind speed log profile.
10
10
 
11
+ Attributes
12
+ ----------
13
+ ustar_input: bool
14
+ Flag for using ustar as an input
15
+
11
16
  :group: models.vertical_profiles
12
17
 
13
18
  """
14
19
 
20
+ def __init__(self, *args, ustar_input=False, **kwargs):
21
+ """
22
+ Constructor.
23
+
24
+ Parameters
25
+ ----------
26
+ args: tuple, optional
27
+ Additional arguments for VerticalProfile
28
+ ustar_input: bool
29
+ Flag for using ustar as an input
30
+ kwargs: dict, optional
31
+ Additional arguments for VerticalProfile
32
+
33
+ """
34
+ super().__init__(*args, **kwargs)
35
+ self.ustar_input = ustar_input
36
+
15
37
  def input_vars(self):
16
38
  """
17
39
  The input variables needed for the profile
@@ -23,7 +45,10 @@ class ABLLogNeutralWsProfile(VerticalProfile):
23
45
  The variable names
24
46
 
25
47
  """
26
- return [FV.WS, FV.H, FV.Z0]
48
+ if self.ustar_input:
49
+ return [FV.USTAR, FV.Z0]
50
+ else:
51
+ return [FV.WS, FV.H, FV.Z0]
27
52
 
28
53
  def calculate(self, data, heights):
29
54
  """
@@ -44,9 +69,11 @@ class ABLLogNeutralWsProfile(VerticalProfile):
44
69
 
45
70
  """
46
71
  z0 = data[FV.Z0]
47
- h0 = data[FV.H]
48
- ws = data[FV.WS]
49
-
50
- ustar = neutral.ustar(ws, h0, z0, kappa=FC.KAPPA)
72
+ if self.ustar_input:
73
+ ustar = data[FV.USTAR]
74
+ else:
75
+ h0 = data[FV.H]
76
+ ws = data[FV.WS]
77
+ ustar = neutral.ustar(ws, h0, z0, kappa=FC.KAPPA)
51
78
 
52
79
  return neutral.calc_ws(heights, z0, ustar, kappa=FC.KAPPA)
@@ -8,10 +8,32 @@ class ABLLogStableWsProfile(VerticalProfile):
8
8
  """
9
9
  The stable ABL wind speed log profile.
10
10
 
11
+ Attributes
12
+ ----------
13
+ ustar_input: bool
14
+ Flag for using ustar as an input
15
+
11
16
  :group: models.vertical_profiles
12
17
 
13
18
  """
14
19
 
20
+ def __init__(self, *args, ustar_input=False, **kwargs):
21
+ """
22
+ Constructor.
23
+
24
+ Parameters
25
+ ----------
26
+ args: tuple, optional
27
+ Additional arguments for VerticalProfile
28
+ ustar_input: bool
29
+ Flag for using ustar as an input
30
+ kwargs: dict, optional
31
+ Additional arguments for VerticalProfile
32
+
33
+ """
34
+ super().__init__(*args, **kwargs)
35
+ self.ustar_input = ustar_input
36
+
15
37
  def input_vars(self):
16
38
  """
17
39
  The input variables needed for the profile
@@ -23,7 +45,10 @@ class ABLLogStableWsProfile(VerticalProfile):
23
45
  The variable names
24
46
 
25
47
  """
26
- return [FV.WS, FV.H, FV.Z0, FV.MOL]
48
+ if self.ustar_input:
49
+ return [FV.USTAR, FV.Z0, FV.MOL]
50
+ else:
51
+ return [FV.WS, FV.H, FV.Z0, FV.MOL]
27
52
 
28
53
  def calculate(self, data, heights):
29
54
  """
@@ -43,12 +68,15 @@ class ABLLogStableWsProfile(VerticalProfile):
43
68
  shape as heights
44
69
 
45
70
  """
46
- ws = data[FV.WS]
47
- h0 = data[FV.H]
48
71
  z0 = data[FV.Z0]
49
72
  mol = data[FV.MOL]
50
73
 
51
- ustar = stable.ustar(ws, h0, z0, mol, kappa=FC.KAPPA)
74
+ if self.ustar_input:
75
+ ustar = data[FV.USTAR]
76
+ else:
77
+ ws = data[FV.WS]
78
+ h0 = data[FV.H]
79
+ ustar = stable.ustar(ws, h0, z0, mol, kappa=FC.KAPPA)
52
80
  psi = stable.psi(heights, mol)
53
81
 
54
82
  return stable.calc_ws(heights, z0, ustar, psi, kappa=FC.KAPPA)
@@ -8,10 +8,32 @@ class ABLLogUnstableWsProfile(VerticalProfile):
8
8
  """
9
9
  The unstable ABL wind speed log profile.
10
10
 
11
+ Attributes
12
+ ----------
13
+ ustar_input: bool
14
+ Flag for using ustar as an input
15
+
11
16
  :group: models.vertical_profiles
12
17
 
13
18
  """
14
19
 
20
+ def __init__(self, *args, ustar_input=False, **kwargs):
21
+ """
22
+ Constructor.
23
+
24
+ Parameters
25
+ ----------
26
+ args: tuple, optional
27
+ Additional arguments for VerticalProfile
28
+ ustar_input: bool
29
+ Flag for using ustar as an input
30
+ kwargs: dict, optional
31
+ Additional arguments for VerticalProfile
32
+
33
+ """
34
+ super().__init__(*args, **kwargs)
35
+ self.ustar_input = ustar_input
36
+
15
37
  def input_vars(self):
16
38
  """
17
39
  The input variables needed for the profile
@@ -23,7 +45,10 @@ class ABLLogUnstableWsProfile(VerticalProfile):
23
45
  The variable names
24
46
 
25
47
  """
26
- return [FV.WS, FV.H, FV.Z0, FV.MOL]
48
+ if self.ustar_input:
49
+ return [FV.USTAR, FV.Z0, FV.MOL]
50
+ else:
51
+ return [FV.WS, FV.H, FV.Z0, FV.MOL]
27
52
 
28
53
  def calculate(self, data, heights):
29
54
  """
@@ -43,12 +68,15 @@ class ABLLogUnstableWsProfile(VerticalProfile):
43
68
  shape as heights
44
69
 
45
70
  """
46
- ws = data[FV.WS]
47
- h0 = data[FV.H]
48
71
  z0 = data[FV.Z0]
49
72
  mol = data[FV.MOL]
50
73
 
51
- ustar = unstable.ustar(ws, h0, z0, mol, kappa=FC.KAPPA)
74
+ if self.ustar_input:
75
+ ustar = data[FV.USTAR]
76
+ else:
77
+ ws = data[FV.WS]
78
+ h0 = data[FV.H]
79
+ ustar = unstable.ustar(ws, h0, z0, mol, kappa=FC.KAPPA)
52
80
  psi = unstable.psi(heights, mol)
53
81
 
54
82
  return unstable.calc_ws(heights, z0, ustar, psi, kappa=FC.KAPPA)