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
@@ -0,0 +1,12 @@
1
+ from foxes.core import GroundModel
2
+
3
+
4
+ class NoGround(GroundModel):
5
+ """
6
+ No ground effects
7
+
8
+ :group: models.ground_models
9
+
10
+ """
11
+
12
+ pass
@@ -0,0 +1,161 @@
1
+ from foxes.core import GroundModel
2
+ import foxes.variables as FV
3
+ import foxes.constants as FC
4
+
5
+
6
+ class WakeMirror(GroundModel):
7
+ """
8
+ Wake reflection from ground and/or other horizontal planes.
9
+
10
+ Attributes
11
+ ----------
12
+ heights: list of float
13
+ The reflection heights
14
+
15
+ :group: models.ground_models
16
+
17
+ """
18
+
19
+ def __init__(self, heights):
20
+ """
21
+ Constructor.
22
+
23
+ Parameters
24
+ ----------
25
+ heights: list of float
26
+ The reflection heights
27
+
28
+ """
29
+ super().__init__()
30
+ self.heights = heights
31
+
32
+ def contribute_to_farm_wakes(
33
+ self,
34
+ algo,
35
+ mdata,
36
+ fdata,
37
+ tdata,
38
+ downwind_index,
39
+ wake_deltas,
40
+ wmodel,
41
+ pwake,
42
+ ):
43
+ """
44
+ Modifies wake deltas at target points by
45
+ contributions from the specified wake source turbines.
46
+
47
+ Parameters
48
+ ----------
49
+ algo: foxes.core.Algorithm
50
+ The calculation algorithm
51
+ mdata: foxes.core.MData
52
+ The model data
53
+ fdata: foxes.core.FData
54
+ The farm data
55
+ tdata: foxes.core.TData
56
+ The target point data
57
+ downwind_index: int
58
+ The index of the wake causing turbine
59
+ in the downwnd order
60
+ wake_deltas: dict
61
+ The wake deltas. Key: variable name,
62
+ value: numpy.ndarray with shape
63
+ (n_states, n_targets, n_tpoints, ...)
64
+ wmodel: foxes.core.WakeModel
65
+ The wake model
66
+ pwake: foxes.core.PartialWakesModel
67
+ The partial wakes model
68
+
69
+ """
70
+ # prepare:
71
+ hh = fdata[FV.H][:, downwind_index].copy()
72
+
73
+ # contribution from main wake:
74
+ wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
75
+ wmodel.contribute(algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas)
76
+
77
+ # contribution from mirrors:
78
+ tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
79
+ for h in self.heights:
80
+
81
+ fdata[FV.H][:, downwind_index] = hh + 2 * (h - hh)
82
+
83
+ pwake.contribute(
84
+ algo, mdata, fdata, tdata, downwind_index, wake_deltas, wmodel
85
+ )
86
+
87
+ # reset heights:
88
+ fdata[FV.H][:, downwind_index] = hh
89
+
90
+ def contribute_to_point_wakes(
91
+ self,
92
+ algo,
93
+ mdata,
94
+ fdata,
95
+ tdata,
96
+ downwind_index,
97
+ wake_deltas,
98
+ wmodel,
99
+ ):
100
+ """
101
+ Modifies wake deltas at target points by
102
+ contributions from the specified wake source turbines.
103
+
104
+ Parameters
105
+ ----------
106
+ algo: foxes.core.Algorithm
107
+ The calculation algorithm
108
+ mdata: foxes.core.MData
109
+ The model data
110
+ fdata: foxes.core.FData
111
+ The farm data
112
+ tdata: foxes.core.TData
113
+ The target point data
114
+ downwind_index: int
115
+ The index of the wake causing turbine
116
+ in the downwnd order
117
+ wake_deltas: dict
118
+ The wake deltas. Key: variable name,
119
+ value: numpy.ndarray with shape
120
+ (n_states, n_targets, n_tpoints, ...)
121
+ wmodel: foxes.core.WakeModel
122
+ The wake model
123
+
124
+ """
125
+ # prepare:
126
+ hh = fdata[FV.H][:, downwind_index].copy()
127
+
128
+ # contribution from main wake:
129
+ wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
130
+ wmodel.contribute(algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas)
131
+
132
+ # contribution from mirrors:
133
+ tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
134
+ for h in self.heights:
135
+
136
+ fdata[FV.H][:, downwind_index] = hh + 2 * (h - hh)
137
+
138
+ wcoos = algo.wake_frame.get_wake_coos(
139
+ algo, mdata, fdata, tdata, downwind_index
140
+ )
141
+ wmodel.contribute(
142
+ algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas
143
+ )
144
+
145
+ # reset heights:
146
+ fdata[FV.H][:, downwind_index] = hh
147
+
148
+
149
+ class GroundMirror(WakeMirror):
150
+ """
151
+ Wake reflection from the ground.
152
+
153
+ :group: models.ground_models
154
+
155
+ """
156
+
157
+ def __init__(self):
158
+ """
159
+ Constructor.
160
+ """
161
+ super().__init__(heights=[0.0])
@@ -16,6 +16,7 @@ from foxes.core import (
16
16
  WakeModel,
17
17
  AxialInductionModel,
18
18
  TurbineInductionModel,
19
+ GroundModel,
19
20
  )
20
21
 
21
22
 
@@ -58,6 +59,9 @@ class ModelBook:
58
59
  induction_models: foxes.utils.FDict
59
60
  The induction models. Keys: model name str,
60
61
  values: foxes.core.AxialInductionModel
62
+ ground_models: foxes.utils.FDict
63
+ The ground models. Keys: model name str,
64
+ values: foxes.core.GroundModel
61
65
  sources: foxes.utils.FDict
62
66
  All sources dict
63
67
  base_classes: foxes.utils.FDict
@@ -231,13 +235,10 @@ class ModelBook:
231
235
  name="wake_frames",
232
236
  rotor_wd=fm.wake_frames.RotorWD(var_wd=FV.WD),
233
237
  rotor_wd_farmo=fm.wake_frames.FarmOrder(),
234
- yawed=fm.wake_frames.YawedWakes(),
235
238
  )
236
- self.wake_frames.add_factory(
239
+ self.wake_frames.add_k_factory(
237
240
  fm.wake_frames.YawedWakes,
238
- "yawed_k<k>",
239
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
240
- hints={"k": "(Value, e.g. 004 for 0.04)"},
241
+ "yawed_[wake_k]",
241
242
  )
242
243
  self.wake_frames.add_factory(
243
244
  fm.wake_frames.Streamlines2D,
@@ -324,169 +325,76 @@ class ModelBook:
324
325
 
325
326
  self.wake_models = FDict(name="wake_models")
326
327
 
327
- self.wake_models.add_factory(
328
+ self.wake_models.add_k_factory(
328
329
  fm.wake_models.wind.JensenWake,
329
- "Jensen_<superposition>",
330
+ "Jensen_<superposition>_[wake_k]",
331
+ kwargs=dict(induction="Betz"),
330
332
  superposition=lambda s: f"ws_{s}",
331
333
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
332
334
  )
333
- self.wake_models.add_factory(
334
- fm.wake_models.wind.JensenWake,
335
- "Jensen_<superposition>_k<k>",
336
- superposition=lambda s: f"ws_{s}",
337
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
338
- hints={
339
- "superposition": "(Superposition, e.g. linear for ws_linear)",
340
- "k": "(Value, e.g. 004 for 0.04)",
341
- },
342
- )
343
335
 
344
- self.wake_models.add_factory(
336
+ self.wake_models.add_k_factory(
345
337
  fm.wake_models.wind.Bastankhah2014,
346
- "Bastankhah2014_<superposition>",
347
- kwargs=dict(sbeta_factor=0.2),
338
+ "Bastankhah2014_<superposition>_[wake_k]",
339
+ kwargs=dict(sbeta_factor=0.2, induction="Madsen"),
348
340
  superposition=lambda s: f"ws_{s}",
349
341
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
350
342
  )
351
- self.wake_models.add_factory(
343
+ self.wake_models.add_k_factory(
352
344
  fm.wake_models.wind.Bastankhah2014,
353
- "Bastankhah2014_<superposition>_k<k>",
354
- kwargs=dict(sbeta_factor=0.2),
355
- superposition=lambda s: f"ws_{s}",
356
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
357
- hints={
358
- "superposition": "(Superposition, e.g. linear for ws_linear)",
359
- "k": "(Value, e.g. 004 for 0.04)",
360
- },
361
- )
362
- self.wake_models.add_factory(
363
- fm.wake_models.wind.Bastankhah2014,
364
- "Bastankhah2014B_<superposition>",
345
+ "Bastankhah2014B_<superposition>_[wake_k]",
365
346
  kwargs=dict(sbeta_factor=0.2, induction="Betz"),
366
347
  superposition=lambda s: f"ws_{s}",
367
348
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
368
349
  )
369
- self.wake_models.add_factory(
370
- fm.wake_models.wind.Bastankhah2014,
371
- "Bastankhah2014B_<superposition>_k<k>",
372
- kwargs=dict(sbeta_factor=0.2, induction="Betz"),
373
- superposition=lambda s: f"ws_{s}",
374
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
375
- hints={
376
- "superposition": "(Superposition, e.g. linear for ws_linear)",
377
- "k": "(Value, e.g. 004 for 0.04)",
378
- },
379
- )
380
- self.wake_models.add_factory(
350
+ self.wake_models.add_k_factory(
381
351
  fm.wake_models.wind.Bastankhah2014,
382
- "Bastankhah025_<superposition>",
383
- kwargs=dict(sbeta_factor=0.25),
352
+ "Bastankhah025_<superposition>_[wake_k]",
353
+ kwargs=dict(sbeta_factor=0.25, induction="Madsen"),
384
354
  superposition=lambda s: f"ws_{s}",
385
355
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
386
356
  )
387
- self.wake_models.add_factory(
357
+ self.wake_models.add_k_factory(
388
358
  fm.wake_models.wind.Bastankhah2014,
389
- "Bastankhah025_<superposition>_k<k>",
390
- kwargs=dict(sbeta_factor=0.25),
391
- superposition=lambda s: f"ws_{s}",
392
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
393
- hints={
394
- "superposition": "(Superposition, e.g. linear for ws_linear)",
395
- "k": "(Value, e.g. 004 for 0.04)",
396
- },
397
- )
398
- self.wake_models.add_factory(
399
- fm.wake_models.wind.Bastankhah2014,
400
- "Bastankhah025B_<superposition>",
359
+ "Bastankhah025B_<superposition>_[wake_k]",
401
360
  kwargs=dict(sbeta_factor=0.25, induction="Betz"),
402
361
  superposition=lambda s: f"ws_{s}",
403
362
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
404
363
  )
405
- self.wake_models.add_factory(
406
- fm.wake_models.wind.Bastankhah2014,
407
- "Bastankhah025B_<superposition>_k<k>",
408
- kwargs=dict(sbeta_factor=0.25, induction="Betz"),
409
- superposition=lambda s: f"ws_{s}",
410
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
411
- hints={
412
- "superposition": "(Superposition, e.g. linear for ws_linear)",
413
- "k": "(Value, e.g. 004 for 0.04)",
414
- },
415
- )
416
364
 
417
- self.wake_models.add_factory(
365
+ self.wake_models.add_k_factory(
418
366
  fm.wake_models.wind.Bastankhah2016,
419
- "Bastankhah2016_<superposition>",
367
+ "Bastankhah2016_<superposition>_[wake_k]",
368
+ kwargs=dict(induction="Madsen"),
420
369
  superposition=lambda s: f"ws_{s}",
421
370
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
422
371
  )
423
- self.wake_models.add_factory(
424
- fm.wake_models.wind.Bastankhah2016,
425
- "Bastankhah2016_<superposition>_k<k>",
426
- superposition=lambda s: f"ws_{s}",
427
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
428
- hints={
429
- "superposition": "(Superposition, e.g. linear for ws_linear)",
430
- "k": "(Value, e.g. 004 for 0.04)",
431
- },
432
- )
433
- self.wake_models.add_factory(
372
+ self.wake_models.add_k_factory(
434
373
  fm.wake_models.wind.Bastankhah2016,
435
- "Bastankhah2016B_<superposition>",
374
+ "Bastankhah2016B_<superposition>_[wake_k]",
436
375
  kwargs=dict(induction="Betz"),
437
376
  superposition=lambda s: f"ws_{s}",
438
377
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
439
378
  )
440
- self.wake_models.add_factory(
441
- fm.wake_models.wind.Bastankhah2016,
442
- "Bastankhah2016B_<superposition>_k<k>",
443
- kwargs=dict(induction="Betz"),
444
- superposition=lambda s: f"ws_{s}",
445
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
446
- hints={
447
- "superposition": "(Superposition, e.g. linear for ws_linear)",
448
- "k": "(Value, e.g. 004 for 0.04)",
449
- },
450
- )
451
379
 
452
- self.wake_models.add_factory(
380
+ self.wake_models.add_k_factory(
453
381
  fm.wake_models.wind.TurbOParkWake,
454
- "TurbOPark_<superposition>",
382
+ "TurbOPark_<superposition>_[wake_k]",
383
+ kwargs=dict(induction="Madsen"),
455
384
  superposition=lambda s: f"ws_{s}",
456
385
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
457
386
  )
458
- self.wake_models.add_factory(
387
+ self.wake_models.add_k_factory(
459
388
  fm.wake_models.wind.TurbOParkWake,
460
- "TurbOPark_<superposition>_k<k>",
461
- superposition=lambda s: f"ws_{s}",
462
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
463
- hints={
464
- "superposition": "(Superposition, e.g. linear for ws_linear)",
465
- "k": "(Value, e.g. 004 for 0.04)",
466
- },
467
- )
468
- self.wake_models.add_factory(
469
- fm.wake_models.wind.TurbOParkWake,
470
- "TurbOParkB_<superposition>",
389
+ "TurbOParkB_<superposition>_[wake_k]",
471
390
  kwargs=dict(induction="Betz"),
472
391
  superposition=lambda s: f"ws_{s}",
473
392
  hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
474
393
  )
475
- self.wake_models.add_factory(
476
- fm.wake_models.wind.TurbOParkWake,
477
- "TurbOParkB_<superposition>_k<k>",
478
- kwargs=dict(induction="Betz"),
479
- superposition=lambda s: f"ws_{s}",
480
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
481
- hints={
482
- "superposition": "(Superposition, e.g. linear for ws_linear)",
483
- "k": "(Value, e.g. 004 for 0.04)",
484
- },
485
- )
486
394
 
487
- self.wake_models.add_factory(
395
+ self.wake_models.add_k_factory(
488
396
  fm.wake_models.wind.TurbOParkWakeIX,
489
- "TurbOParkIX_<superposition>_dx<dx>",
397
+ "TurbOParkIX_<superposition>_[wake_k]_dx<dx>",
490
398
  superposition=lambda s: f"ws_{s}",
491
399
  dx=lambda x: float(x),
492
400
  hints={
@@ -495,37 +403,35 @@ class ModelBook:
495
403
  },
496
404
  )
497
405
 
498
- self.wake_models.add_factory(
499
- fm.wake_models.wind.TurbOParkWakeIX,
500
- "TurbOParkIX_<superposition>_k<k>_dx<dx>",
501
- superposition=lambda s: f"ws_{s}",
502
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
503
- dx=lambda x: float(x),
504
- hints={
505
- "superposition": "(Superposition, e.g. linear for ws_linear)",
506
- "k": "(Value, e.g. 004 for 0.04)",
507
- "dx": "(Integration step in m)",
508
- },
406
+ self.wake_models.add_k_factory(
407
+ fm.wake_models.ti.CrespoHernandezTIWake,
408
+ "CrespoHernandez_<superposition>_[wake_k]",
409
+ kwargs=dict(use_ambti=False),
410
+ superposition=lambda s: f"ti_{s}",
411
+ hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
509
412
  )
510
413
 
511
414
  self.wake_models.add_factory(
512
- fm.wake_models.ti.CrespoHernandezTIWake,
513
- "CrespoHernandez_<superposition>",
514
- kwargs=dict(use_ambti=False),
415
+ fm.wake_models.ti.IECTIWake,
416
+ "IECTI2005_<superposition>",
417
+ kwargs=dict(iec_type="2005"),
515
418
  superposition=lambda s: f"ti_{s}",
516
419
  hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
517
420
  )
518
421
 
519
422
  self.wake_models.add_factory(
520
- fm.wake_models.ti.CrespoHernandezTIWake,
521
- "CrespoHernandez_<superposition>_k<k>",
522
- kwargs=dict(use_ambti=False),
423
+ fm.wake_models.ti.IECTIWake,
424
+ "IECTI2019_<superposition>",
425
+ kwargs=dict(iec_type="2019"),
523
426
  superposition=lambda s: f"ti_{s}",
524
- k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
525
- hints={
526
- "superposition": "(Superposition, e.g. linear for ti_linear)",
527
- "k": "(Value, e.g. 004 for 0.04)",
528
- },
427
+ hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
428
+ )
429
+ self.wake_models.add_k_factory(
430
+ fm.wake_models.ti.IECTIWake,
431
+ "IECTI2019k_<superposition>_[wake_k]",
432
+ kwargs=dict(iec_type="2019", opening_angle=None),
433
+ superposition=lambda s: f"ti_{s}",
434
+ hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
529
435
  )
530
436
 
531
437
  self.wake_models.add_factory(
@@ -535,11 +441,10 @@ class ModelBook:
535
441
  superposition=lambda s: f"ti_{s}",
536
442
  hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
537
443
  )
538
-
539
- self.wake_models.add_factory(
444
+ self.wake_models.add_k_factory(
540
445
  fm.wake_models.ti.IECTIWake,
541
- "IECTI2019_<superposition>",
542
- kwargs=dict(iec_type="2019"),
446
+ "IECTI2005k_<superposition>_[wake_k]",
447
+ kwargs=dict(iec_type="2005", opening_angle=None),
543
448
  superposition=lambda s: f"ti_{s}",
544
449
  hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
545
450
  )
@@ -550,6 +455,18 @@ class ModelBook:
550
455
  self.wake_models[f"SelfSimilar2020"] = (
551
456
  fm.wake_models.induction.SelfSimilar2020()
552
457
  )
458
+ self.wake_models[f"VortexSheet"] = fm.wake_models.induction.VortexSheet()
459
+
460
+ self.ground_models = FDict(name="ground_models")
461
+ self.ground_models["no_ground"] = fm.ground_models.NoGround()
462
+ self.ground_models["ground_mirror"] = fm.ground_models.GroundMirror()
463
+ self.ground_models.add_factory(
464
+ fm.ground_models.WakeMirror,
465
+ "blh_mirror_h<height>",
466
+ var2arg={"height": "heights"},
467
+ height=lambda h: [0.0, float(h)],
468
+ hints={"height": "(Boundary layer wake reflection height)"},
469
+ )
553
470
 
554
471
  self.sources = FDict(
555
472
  name="sources",
@@ -564,6 +481,7 @@ class ModelBook:
564
481
  wake_superpositions=self.wake_superpositions,
565
482
  wake_models=self.wake_models,
566
483
  axial_induction=self.axial_induction,
484
+ ground_models=self.ground_models,
567
485
  )
568
486
  self.base_classes = FDict(
569
487
  name="base_classes",
@@ -578,6 +496,7 @@ class ModelBook:
578
496
  wake_superpositions=WakeSuperposition,
579
497
  wake_models=WakeModel,
580
498
  axial_induction=AxialInductionModel,
499
+ ground_models=GroundModel,
581
500
  )
582
501
 
583
502
  for s in self.sources.values():
@@ -44,6 +44,31 @@ class PartialAxiwake(PartialCentre):
44
44
  def __repr__(self):
45
45
  return f"{type(self).__name__}(n={self.n})"
46
46
 
47
+ def check_wmodel(self, wmodel, error=True):
48
+ """
49
+ Checks the wake model type
50
+
51
+ Parameters
52
+ ----------
53
+ wmodel: foxes.core.WakeModel
54
+ The wake model to be tested
55
+ error: bool
56
+ Flag for raising TypeError
57
+
58
+ Returns
59
+ -------
60
+ chk: bool
61
+ True if wake model is compatible
62
+
63
+ """
64
+ if not isinstance(wmodel, AxisymmetricWakeModel):
65
+ if error:
66
+ raise TypeError(
67
+ f"Partial wakes '{self.name}': Cannot be applied to wake model '{wmodel.name}', since not an AxisymmetricWakeModel"
68
+ )
69
+ return False
70
+ return True
71
+
47
72
  def contribute(
48
73
  self,
49
74
  algo,
@@ -79,10 +104,8 @@ class PartialAxiwake(PartialCentre):
79
104
  The wake model
80
105
 
81
106
  """
82
- if not isinstance(wmodel, AxisymmetricWakeModel):
83
- raise TypeError(
84
- f"Partial wakes '{self.name}': Cannot be applied to wake model '{wmodel.name}', since not an AxisymmetricWakeModel"
85
- )
107
+ # check:
108
+ self.check_wmodel(wmodel, error=True)
86
109
 
87
110
  # prepare:
88
111
  n_states = mdata.n_states
@@ -24,6 +24,31 @@ class PartialTopHat(PartialCentre):
24
24
 
25
25
  """
26
26
 
27
+ def check_wmodel(self, wmodel, error=True):
28
+ """
29
+ Checks the wake model type
30
+
31
+ Parameters
32
+ ----------
33
+ wmodel: foxes.core.WakeModel
34
+ The wake model to be tested
35
+ error: bool
36
+ Flag for raising TypeError
37
+
38
+ Returns
39
+ -------
40
+ chk: bool
41
+ True if wake model is compatible
42
+
43
+ """
44
+ if not isinstance(wmodel, TopHatWakeModel):
45
+ if error:
46
+ raise TypeError(
47
+ f"Partial wakes '{self.name}': Cannot be applied to wake model '{wmodel.name}', since not a TopHatWakeModel"
48
+ )
49
+ return False
50
+ return True
51
+
27
52
  def __init__(self, rotor_model=None):
28
53
  """
29
54
  Constructor.
@@ -105,10 +130,7 @@ class PartialTopHat(PartialCentre):
105
130
  The wake model
106
131
 
107
132
  """
108
- if not isinstance(wmodel, TopHatWakeModel):
109
- raise TypeError(
110
- f"Partial wakes '{self.name}': Cannot be applied to wake model '{wmodel.name}', since not a TopHatWakeModel"
111
- )
133
+ self.check_wmodel(wmodel, error=True)
112
134
 
113
135
  wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
114
136
  x = wcoos[:, :, 0, 0]
@@ -103,6 +103,7 @@ class PCtFile(TurbineType):
103
103
 
104
104
  def __repr__(self):
105
105
  a = f"D={self.D}, H={self.H}, P_nominal={self.P_nominal}, P_unit={self.P_unit}, rho={self.rho}"
106
+ a += f", var_ws_ct={self.WSCT}, var_ws_P={self.WSP}"
106
107
  return f"{type(self).__name__}({a})"
107
108
 
108
109
  def output_farm_vars(self, algo):