foxes 1.0__py3-none-any.whl → 1.1.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 (128) hide show
  1. docs/source/conf.py +0 -1
  2. examples/states_lookup_table/run.py +1 -1
  3. examples/timeseries/run.py +11 -4
  4. foxes/algorithms/downwind/downwind.py +18 -13
  5. foxes/algorithms/downwind/models/farm_wakes_calc.py +1 -1
  6. foxes/algorithms/downwind/models/init_farm_data.py +1 -1
  7. foxes/algorithms/downwind/models/point_wakes_calc.py +1 -1
  8. foxes/algorithms/downwind/models/reorder_farm_output.py +1 -1
  9. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  10. foxes/algorithms/downwind/models/set_amb_point_results.py +1 -1
  11. foxes/algorithms/iterative/iterative.py +1 -1
  12. foxes/algorithms/iterative/models/farm_wakes_calc.py +1 -1
  13. foxes/algorithms/iterative/models/urelax.py +3 -3
  14. foxes/algorithms/sequential/models/plugin.py +4 -4
  15. foxes/algorithms/sequential/models/seq_state.py +1 -1
  16. foxes/constants.py +5 -5
  17. foxes/core/algorithm.py +2 -2
  18. foxes/core/data_calc_model.py +2 -2
  19. foxes/core/engine.py +20 -10
  20. foxes/core/farm_controller.py +3 -3
  21. foxes/core/farm_data_model.py +1 -1
  22. foxes/core/ground_model.py +2 -2
  23. foxes/core/model.py +122 -108
  24. foxes/core/partial_wakes_model.py +1 -1
  25. foxes/core/point_data_model.py +2 -2
  26. foxes/core/states.py +1 -1
  27. foxes/core/turbine_type.py +2 -2
  28. foxes/core/wake_frame.py +8 -30
  29. foxes/core/wake_model.py +3 -2
  30. foxes/core/wake_superposition.py +1 -1
  31. foxes/data/windio/windio_5turbines_timeseries.yaml +9 -15
  32. foxes/engines/__init__.py +1 -0
  33. foxes/engines/dask.py +13 -6
  34. foxes/engines/multiprocess.py +5 -8
  35. foxes/engines/numpy.py +8 -26
  36. foxes/engines/pool.py +10 -24
  37. foxes/engines/ray.py +79 -0
  38. foxes/engines/single.py +3 -1
  39. foxes/input/farm_layout/from_json.py +1 -1
  40. foxes/input/states/__init__.py +1 -0
  41. foxes/input/states/field_data_nc.py +4 -4
  42. foxes/input/states/multi_height.py +4 -4
  43. foxes/input/states/scan_ws.py +1 -1
  44. foxes/input/states/single.py +1 -1
  45. foxes/input/states/slice_data_nc.py +681 -0
  46. foxes/input/states/states_table.py +3 -3
  47. foxes/input/windio/__init__.py +1 -1
  48. foxes/input/windio/read_attributes.py +8 -2
  49. foxes/input/windio/read_fields.py +3 -0
  50. foxes/input/windio/read_outputs.py +8 -2
  51. foxes/input/windio/windio.py +6 -2
  52. foxes/models/farm_models/turbine2farm.py +1 -1
  53. foxes/models/ground_models/wake_mirror.py +2 -2
  54. foxes/models/model_book.py +29 -2
  55. foxes/models/partial_wakes/axiwake.py +3 -3
  56. foxes/models/partial_wakes/top_hat.py +2 -2
  57. foxes/models/point_models/set_uniform_data.py +1 -1
  58. foxes/models/point_models/tke2ti.py +1 -1
  59. foxes/models/point_models/wake_deltas.py +1 -1
  60. foxes/models/rotor_models/grid.py +2 -2
  61. foxes/models/turbine_models/calculator.py +4 -4
  62. foxes/models/turbine_models/kTI_model.py +22 -6
  63. foxes/models/turbine_models/lookup_table.py +3 -2
  64. foxes/models/turbine_types/PCt_file.py +5 -5
  65. foxes/models/turbine_types/PCt_from_two.py +5 -5
  66. foxes/models/turbine_types/TBL_file.py +80 -0
  67. foxes/models/turbine_types/__init__.py +1 -0
  68. foxes/models/turbine_types/lookup.py +5 -5
  69. foxes/models/turbine_types/null_type.py +3 -3
  70. foxes/models/turbine_types/wsrho2PCt_from_two.py +7 -7
  71. foxes/models/turbine_types/wsti2PCt_from_two.py +9 -9
  72. foxes/models/vertical_profiles/__init__.py +1 -1
  73. foxes/models/wake_frames/dynamic_wakes.py +2 -2
  74. foxes/models/wake_frames/farm_order.py +2 -2
  75. foxes/models/wake_frames/rotor_wd.py +2 -2
  76. foxes/models/wake_frames/seq_dynamic_wakes.py +5 -11
  77. foxes/models/wake_frames/streamlines.py +2 -2
  78. foxes/models/wake_frames/timelines.py +2 -2
  79. foxes/models/wake_frames/yawed_wakes.py +3 -3
  80. foxes/models/wake_models/dist_sliced.py +1 -1
  81. foxes/models/wake_models/induction/rankine_half_body.py +1 -1
  82. foxes/models/wake_models/induction/rathmann.py +76 -22
  83. foxes/models/wake_models/induction/self_similar.py +76 -26
  84. foxes/models/wake_models/induction/vortex_sheet.py +84 -46
  85. foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
  86. foxes/models/wake_models/ti/iec_ti.py +7 -5
  87. foxes/models/wake_models/wind/bastankhah14.py +6 -4
  88. foxes/models/wake_models/wind/bastankhah16.py +9 -9
  89. foxes/models/wake_models/wind/jensen.py +3 -2
  90. foxes/models/wake_models/wind/turbopark.py +14 -11
  91. foxes/models/wake_superpositions/ti_linear.py +1 -1
  92. foxes/models/wake_superpositions/ti_max.py +1 -1
  93. foxes/models/wake_superpositions/ti_pow.py +1 -1
  94. foxes/models/wake_superpositions/ti_quadratic.py +1 -1
  95. foxes/models/wake_superpositions/ws_linear.py +8 -7
  96. foxes/models/wake_superpositions/ws_max.py +8 -7
  97. foxes/models/wake_superpositions/ws_pow.py +8 -7
  98. foxes/models/wake_superpositions/ws_product.py +5 -5
  99. foxes/models/wake_superpositions/ws_quadratic.py +8 -7
  100. foxes/output/farm_layout.py +14 -10
  101. foxes/output/farm_results_eval.py +1 -1
  102. foxes/output/grids.py +1 -1
  103. foxes/output/results_writer.py +2 -2
  104. foxes/output/rose_plot.py +3 -3
  105. foxes/output/seq_plugins/seq_flow_ani_plugin.py +2 -2
  106. foxes/output/seq_plugins/seq_wake_debug_plugin.py +2 -2
  107. foxes/output/state_turbine_map.py +1 -1
  108. foxes/utils/abl/neutral.py +2 -2
  109. foxes/utils/abl/stable.py +2 -2
  110. foxes/utils/abl/unstable.py +2 -2
  111. foxes/utils/data_book.py +1 -1
  112. foxes/utils/dict.py +23 -0
  113. foxes/utils/exec_python.py +1 -1
  114. foxes/utils/factory.py +29 -1
  115. foxes/utils/geom2d/circle.py +1 -1
  116. foxes/utils/geom2d/polygon.py +1 -1
  117. foxes/utils/geopandas_utils.py +2 -2
  118. foxes/utils/load.py +2 -2
  119. foxes/utils/pandas_helpers.py +1 -1
  120. foxes/utils/xarray_utils.py +1 -1
  121. foxes/variables.py +3 -3
  122. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/METADATA +8 -6
  123. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/RECORD +127 -125
  124. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/WHEEL +1 -1
  125. foxes/utils/geopandas_helpers.py +0 -294
  126. /examples/{induction_RHB → induction}/run.py +0 -0
  127. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/LICENSE +0 -0
  128. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/top_level.txt +0 -0
@@ -24,6 +24,7 @@ def _read_wind_deficit(
24
24
  {
25
25
  "Linear": "ws_linear",
26
26
  "Quadratic": "ws_quadratic",
27
+ "Product": "ws_product",
27
28
  },
28
29
  name="ws_sup_dict",
29
30
  )
@@ -31,6 +32,7 @@ def _read_wind_deficit(
31
32
  {
32
33
  "Linear": "ws_linear_amb",
33
34
  "Quadratic": "ws_quadratic_amb",
35
+ "Product": "ws_product",
34
36
  },
35
37
  name="ws_sup_dict",
36
38
  )
@@ -311,7 +313,7 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
311
313
  print("deflection_model not found, using default settings")
312
314
 
313
315
 
314
- def read_attributes(wio, algo_dict, verbosity):
316
+ def read_attributes(wio, algo_dict, verbosity=1, **output_pars):
315
317
  """
316
318
  Reads the attributes part of windio
317
319
 
@@ -323,6 +325,8 @@ def read_attributes(wio, algo_dict, verbosity):
323
325
  The algorithm dictionary
324
326
  verbosity: int
325
327
  The verbosity level, 0=silent
328
+ **output_pars: dict, optional
329
+ Additional parameters for output reading
326
330
 
327
331
  Returns
328
332
  -------
@@ -358,6 +362,8 @@ def read_attributes(wio, algo_dict, verbosity):
358
362
  out_dicts = []
359
363
  if "outputs" in wio_attrs:
360
364
  outputs = Dict(wio_attrs["outputs"], name="outputs")
361
- out_dicts, odir = read_outputs(outputs, algo_dict, verbosity)
365
+ out_dicts, odir = read_outputs(
366
+ outputs, algo_dict, verbosity=verbosity, **output_pars
367
+ )
362
368
 
363
369
  return out_dicts, odir
@@ -143,6 +143,9 @@ def read_wind_resource_field(
143
143
  "lapse_rate",
144
144
  "capping_inversion_thickness",
145
145
  "capping_inversion_strength",
146
+ "tau_x",
147
+ "tau_y",
148
+ "fc",
146
149
  ]:
147
150
  if verbosity > 2:
148
151
  print(f" Ignoring variable '{name}'")
@@ -126,7 +126,7 @@ def _read_flow_field(wio_outs, odir, out_dicts, verbosity):
126
126
  )
127
127
 
128
128
 
129
- def read_outputs(wio_outs, algo_dict, verbosity):
129
+ def read_outputs(wio_outs, algo_dict, output_dir=None, verbosity=1):
130
130
  """
131
131
  Reads the windio outputs
132
132
 
@@ -136,6 +136,8 @@ def read_outputs(wio_outs, algo_dict, verbosity):
136
136
  The windio output data
137
137
  algo_dict: dict
138
138
  The algorithm dictionary
139
+ output_dir: pathlib.Path, optional
140
+ Path to the output folder
139
141
  verbosity: int
140
142
  The verbosity level, 0=silent
141
143
 
@@ -150,7 +152,11 @@ def read_outputs(wio_outs, algo_dict, verbosity):
150
152
 
151
153
  """
152
154
  out_dicts = []
153
- odir = Path(wio_outs.pop("output_folder", "results"))
155
+ odir = (
156
+ Path(output_dir)
157
+ if output_dir is not None
158
+ else Path(wio_outs.pop("output_folder", "results"))
159
+ )
154
160
  odir.mkdir(exist_ok=True, parents=True)
155
161
  if verbosity > 2:
156
162
  print(" Reading outputs")
@@ -95,6 +95,7 @@ def read_windio(
95
95
  windio_yaml,
96
96
  verbosity=1,
97
97
  algo_pars=None,
98
+ output_dir=None,
98
99
  **runner_pars,
99
100
  ):
100
101
  """
@@ -111,6 +112,8 @@ def read_windio(
111
112
  The verbosity level, 0 = silent
112
113
  algo_pars: dict, optional
113
114
  Additional algorithm parameters
115
+ output_dir: str, optional
116
+ Path to the output folder
114
117
  runner_pars: dict, optional
115
118
  Additional parameters for the WindioRunner
116
119
 
@@ -130,7 +133,7 @@ def read_windio(
130
133
  if verbosity > 0:
131
134
  print(f"Reading windio file {wio_file}")
132
135
 
133
- yml_utils = import_module("windIO.utils.yml_utils", hint="pip install windio")
136
+ yml_utils = import_module("windIO.utils.yml_utils", hint="pip install git+https://github.com/kilojoules/windIO@master#egg=windIO")
134
137
  wio = yml_utils.load_yaml(wio_file)
135
138
 
136
139
  if verbosity > 1:
@@ -155,7 +158,8 @@ def read_windio(
155
158
  out_dicts, odir = read_attributes(
156
159
  wio,
157
160
  algo_dict,
158
- verbosity,
161
+ output_dir=output_dir,
162
+ verbosity=verbosity,
159
163
  )
160
164
 
161
165
  if verbosity > 1:
@@ -65,7 +65,7 @@ class Turbine2FarmModel(FarmModel):
65
65
  return self.turbine_model.output_farm_vars(algo)
66
66
 
67
67
  def calculate(self, algo, mdata, fdata, **parameters):
68
- """ "
68
+ """
69
69
  The main model calculation.
70
70
 
71
71
  This function is executed on a single chunk of data,
@@ -56,7 +56,7 @@ class WakeMirror(GroundModel):
56
56
  The target point data
57
57
  downwind_index: int
58
58
  The index of the wake causing turbine
59
- in the downwnd order
59
+ in the downwind order
60
60
  wake_deltas: dict
61
61
  The wake deltas. Key: variable name,
62
62
  value: numpy.ndarray with shape
@@ -117,7 +117,7 @@ class WakeMirror(GroundModel):
117
117
  The target point data
118
118
  downwind_index: int
119
119
  The index of the wake causing turbine
120
- in the downwnd order
120
+ in the downwind order
121
121
  wake_deltas: dict
122
122
  The wake deltas. Key: variable name,
123
123
  value: numpy.ndarray with shape
@@ -460,12 +460,39 @@ class ModelBook:
460
460
  )
461
461
 
462
462
  self.wake_models[f"RHB"] = fm.wake_models.induction.RankineHalfBody()
463
+
464
+ self.wake_models[f"VortexSheet"] = fm.wake_models.induction.VortexSheet()
465
+ self.wake_models.add_factory(
466
+ fm.wake_models.induction.VortexSheet,
467
+ "VortexSheet_<superposition>",
468
+ superposition=lambda s: f"ws_{s}",
469
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
470
+ )
471
+
463
472
  self.wake_models[f"Rathmann"] = fm.wake_models.induction.Rathmann()
473
+ self.wake_models.add_factory(
474
+ fm.wake_models.induction.Rathmann,
475
+ "Rathmann_<superposition>",
476
+ superposition=lambda s: f"ws_{s}",
477
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
478
+ )
479
+
464
480
  self.wake_models[f"SelfSimilar"] = fm.wake_models.induction.SelfSimilar()
465
481
  self.wake_models[f"SelfSimilar2020"] = (
466
482
  fm.wake_models.induction.SelfSimilar2020()
467
483
  )
468
- self.wake_models[f"VortexSheet"] = fm.wake_models.induction.VortexSheet()
484
+ self.wake_models.add_factory(
485
+ fm.wake_models.induction.SelfSimilar,
486
+ "SelfSimilar_<superposition>",
487
+ superposition=lambda s: f"ws_{s}",
488
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
489
+ )
490
+ self.wake_models.add_factory(
491
+ fm.wake_models.induction.SelfSimilar2020,
492
+ "SelfSimilar2020_<superposition>",
493
+ superposition=lambda s: f"ws_{s}",
494
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
495
+ )
469
496
 
470
497
  self.ground_models = FDict(name="ground_models")
471
498
  self.ground_models["no_ground"] = fm.ground_models.NoGround()
@@ -515,7 +542,7 @@ class ModelBook:
515
542
  m.name = k
516
543
 
517
544
  def __getitem__(self, key):
518
- return self.sources.__getitem__(key)
545
+ return self.sources.get_item(key)
519
546
 
520
547
  def print_toc(self, subset=None, search=None):
521
548
  """
@@ -95,7 +95,7 @@ class PartialAxiwake(PartialCentre):
95
95
  The target point data
96
96
  downwind_index: int
97
97
  The index of the wake causing turbine
98
- in the downwnd order
98
+ in the downwind order
99
99
  wake_deltas: dict
100
100
  The wake deltas. Key: variable name,
101
101
  value: numpy.ndarray with shape
@@ -127,7 +127,7 @@ class PartialAxiwake(PartialCentre):
127
127
  wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
128
128
 
129
129
  # prepare x and r coordinates:
130
- x = np.round(wcoos[..., 0, 0], 12)
130
+ x = wcoos[..., 0, 0]
131
131
  n = wcoos[..., 0, 1:3]
132
132
  R = np.linalg.norm(n, axis=-1)
133
133
  r = np.zeros((n_states, n_targets, self.n), dtype=FC.DTYPE)
@@ -145,7 +145,7 @@ class PartialAxiwake(PartialCentre):
145
145
  n[:, :, 0][~sel] = 1
146
146
 
147
147
  # case wake centre outside rotor disk:
148
- sel = (x > 0) & (R > D / 2)
148
+ sel = (x > 1e-8) & (R > D / 2)
149
149
  if np.any(sel):
150
150
  n_sel = np.sum(sel)
151
151
  Rsel = np.zeros((n_sel, self.n + 1), dtype=FC.DTYPE)
@@ -121,7 +121,7 @@ class PartialTopHat(PartialCentre):
121
121
  The target point data
122
122
  downwind_index: int
123
123
  The index of the wake causing turbine
124
- in the downwnd order
124
+ in the downwind order
125
125
  wake_deltas: dict
126
126
  The wake deltas. Key: variable name,
127
127
  value: numpy.ndarray with shape
@@ -148,7 +148,7 @@ class PartialTopHat(PartialCentre):
148
148
  upcast=True,
149
149
  )
150
150
 
151
- sel0 = (ct > 0) & (x > 0)
151
+ sel0 = (ct > 1e-8) & (x > 1e-8)
152
152
  if np.any(sel0):
153
153
  R = np.linalg.norm(yz, axis=-1)
154
154
  del yz
@@ -119,7 +119,7 @@ class SetUniformData(PointDataModel):
119
119
  return self.ovars
120
120
 
121
121
  def calculate(self, algo, mdata, fdata, pdata):
122
- """ "
122
+ """
123
123
  The main model calculation.
124
124
 
125
125
  This function is executed on a single chunk of data,
@@ -30,7 +30,7 @@ class TKE2TI(PointDataModel):
30
30
  return [FV.TI]
31
31
 
32
32
  def calculate(self, algo, mdata, fdata, pdata):
33
- """ "
33
+ """
34
34
  The main model calculation.
35
35
 
36
36
  This function is executed on a single chunk of data,
@@ -52,7 +52,7 @@ class WakeDeltas(PointDataModel):
52
52
  return [f"DELTA_{v}" for v in self.vars]
53
53
 
54
54
  def calculate(self, algo, mdata, fdata, pdata):
55
- """ "
55
+ """
56
56
  The main model calculation.
57
57
 
58
58
  This function is executed on a single chunk of data,
@@ -16,7 +16,7 @@ class GridRotor(RotorModel):
16
16
  maximal number of points is N = n * n
17
17
  reduce: bool
18
18
  Flag for reduction to points actually representing
19
- an area with overlap with the circe, recalculating
19
+ an area with overlap with the circle, recalculating
20
20
  the self.__weights accordingly
21
21
  nint: int
22
22
  Integration steps per element
@@ -36,7 +36,7 @@ class GridRotor(RotorModel):
36
36
  maximal number of points is N = n * n
37
37
  reduce: bool
38
38
  Flag for reduction to points actually representing
39
- an area with overlap with the circe, recalculating
39
+ an area with overlap with the circle, recalculating
40
40
  the self.__weights accordingly
41
41
  nint: int
42
42
  Integration steps per element
@@ -8,11 +8,11 @@ class Calculator(TurbineModel):
8
8
  Attributes
9
9
  ----------
10
10
  in_vars: list of str
11
- The input farm vairables
11
+ The input farm variables
12
12
  out_vars: list of str
13
13
  The output variables
14
14
  func: Function
15
- The function: f(in0, in1, ..., stsel) -> (out0, ou1, ...)
15
+ The function: f(in0, in1, ..., stsel) -> (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).
@@ -28,11 +28,11 @@ class Calculator(TurbineModel):
28
28
  Parameters
29
29
  ----------
30
30
  in_vars: list of str
31
- The input farm vairables
31
+ The input farm variables
32
32
  out_vars: list of str
33
33
  The output variables
34
34
  func: Function
35
- The function: f(in0, in1, ..., stsel) -> (out0, ou1, ...)
35
+ The function: f(in0, in1, ..., stsel) -> (out0, out1, ...)
36
36
  where inX and outY are numpy.ndarrays and
37
37
  st_sel is the state-turbine selection slice or array.
38
38
  All arrays have shape (n_states, n_turbines).
@@ -101,15 +101,31 @@ class kTI(TurbineModel):
101
101
  Values: numpy.ndarray with shape (n_states, n_turbines)
102
102
 
103
103
  """
104
+
104
105
  kti = self.get_data(
105
- FV.KTI, FC.STATE_TURBINE, lookup="sf", fdata=fdata, upcast=True
106
- )[st_sel]
106
+ FV.KTI,
107
+ FC.STATE_TURBINE,
108
+ lookup="sf",
109
+ fdata=fdata,
110
+ upcast=False,
111
+ selection=st_sel,
112
+ )
107
113
  kb = self.get_data(
108
- FV.KB, FC.STATE_TURBINE, lookup="sf", fdata=fdata, upcast=True
109
- )[st_sel]
114
+ FV.KB,
115
+ FC.STATE_TURBINE,
116
+ lookup="sf",
117
+ fdata=fdata,
118
+ upcast=False,
119
+ selection=st_sel,
120
+ )
110
121
  ti = self.get_data(
111
- self.ti_var, FC.STATE_TURBINE, lookup="sf", fdata=fdata, upcast=True
112
- )[st_sel]
122
+ self.ti_var,
123
+ FC.STATE_TURBINE,
124
+ lookup="f",
125
+ fdata=fdata,
126
+ upcast=False,
127
+ selection=st_sel,
128
+ )
113
129
 
114
130
  k = fdata.get(
115
131
  self.k_var, np.zeros((fdata.n_states, fdata.n_turbines), dtype=FC.DTYPE)
@@ -192,8 +192,9 @@ class LookupTable(TurbineModel):
192
192
  FC.STATE_TURBINE,
193
193
  lookup="fs",
194
194
  fdata=fdata,
195
- upcast=True,
196
- )[st_sel]
195
+ upcast=False,
196
+ selection=st_sel,
197
+ )
197
198
  for v in self.input_vars
198
199
  }
199
200
 
@@ -25,7 +25,7 @@ class PCtFile(TurbineType):
25
25
  col_ct: str
26
26
  The ct column
27
27
  rho: float
28
- The air densitiy for which the data is valid
28
+ The air density for which the data is valid
29
29
  or None for no correction
30
30
  WSCT: str
31
31
  The wind speed variable for ct lookup
@@ -66,7 +66,7 @@ class PCtFile(TurbineType):
66
66
  col_ct: str
67
67
  The ct column
68
68
  rho: float, optional
69
- The air densitiy for which the data is valid
69
+ The air density for which the data is valid
70
70
  or None for no correction
71
71
  p_ct: float
72
72
  The exponent for yaw dependency of ct
@@ -108,7 +108,7 @@ class PCtFile(TurbineType):
108
108
 
109
109
  def needs_rews2(self):
110
110
  """
111
- Returns flag for requirering REWS2 variable
111
+ Returns flag for requiring REWS2 variable
112
112
 
113
113
  Returns
114
114
  -------
@@ -120,7 +120,7 @@ class PCtFile(TurbineType):
120
120
 
121
121
  def needs_rews3(self):
122
122
  """
123
- Returns flag for requirering REWS3 variable
123
+ Returns flag for requiring REWS3 variable
124
124
 
125
125
  Returns
126
126
  -------
@@ -276,7 +276,7 @@ class PCtFile(TurbineType):
276
276
  super().modify_cutin(modify_ct, modify_P)
277
277
 
278
278
  def calculate(self, algo, mdata, fdata, st_sel):
279
- """ "
279
+ """
280
280
  The main model calculation.
281
281
 
282
282
  This function is executed on a single chunk of data,
@@ -26,7 +26,7 @@ class PCtFromTwo(TurbineType):
26
26
  col_ct: str
27
27
  The ct column
28
28
  rho: float
29
- The air densitiy for which the data is valid
29
+ The air density for which the data is valid
30
30
  or None for no correction
31
31
  WSCT: str
32
32
  The wind speed variable for ct lookup
@@ -76,7 +76,7 @@ class PCtFromTwo(TurbineType):
76
76
  col_ct: str
77
77
  The ct column
78
78
  rho: float, optional
79
- The air densitiy for which the data is valid
79
+ The air density for which the data is valid
80
80
  or None for no correction
81
81
  p_ct: float
82
82
  The exponent for yaw dependency of ct
@@ -128,7 +128,7 @@ class PCtFromTwo(TurbineType):
128
128
 
129
129
  def needs_rews2(self):
130
130
  """
131
- Returns flag for requirering REWS2 variable
131
+ Returns flag for requiring REWS2 variable
132
132
 
133
133
  Returns
134
134
  -------
@@ -140,7 +140,7 @@ class PCtFromTwo(TurbineType):
140
140
 
141
141
  def needs_rews3(self):
142
142
  """
143
- Returns flag for requirering REWS3 variable
143
+ Returns flag for requiring REWS3 variable
144
144
 
145
145
  Returns
146
146
  -------
@@ -313,7 +313,7 @@ class PCtFromTwo(TurbineType):
313
313
  super().modify_cutin(modify_ct, modify_P)
314
314
 
315
315
  def calculate(self, algo, mdata, fdata, st_sel):
316
- """ "
316
+ """
317
317
  The main model calculation.
318
318
 
319
319
  This function is executed on a single chunk of data,
@@ -0,0 +1,80 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from pathlib import Path
4
+
5
+ from .PCt_file import PCtFile
6
+ from foxes.data import parse_Pct_file_name
7
+ import foxes.constants as FC
8
+
9
+
10
+ class TBLFile(PCtFile):
11
+ """
12
+ Reads turbine data from a TBL file.
13
+
14
+ Examples
15
+ --------
16
+ A TBL file is a csv file with space as separator
17
+ and two header lines. The followind lines denote
18
+ wind speed, ct, P.
19
+
20
+ - first row will be ignored
21
+ - second row: H D ct-stand-still rated-power-in-MW
22
+ - further rows: ws ct P-in-kW
23
+
24
+ For example:
25
+
26
+ 45
27
+ 175.0 290.0 0.03 22.0
28
+ 3.0 0.820 102.9
29
+ 3.5 0.800 444.0
30
+ 4.0 0.810 874.7
31
+ 4.5 0.820 1418.7
32
+ 5.0 0.820 2100.9
33
+ 5.5 0.830 3021.2
34
+ 6.0 0.830 3904.7
35
+ 6.5 0.830 5061.7
36
+ 7.0 0.810 6379.0
37
+
38
+ :group: models.turbine_types
39
+
40
+ """
41
+
42
+ def __init__(
43
+ self,
44
+ tbl_file,
45
+ rho=1.225,
46
+ **parameters,
47
+ ):
48
+ """
49
+ Constructor.
50
+
51
+ Parameters
52
+ ----------
53
+ tbl_file: str
54
+ Path to the tbl file
55
+ rho: float
56
+ The air density for the curves
57
+ paramerers: dict, optional
58
+ Additional parameters for PCtFile class
59
+
60
+ """
61
+ fpath = Path(tbl_file)
62
+ assert fpath.suffix == ".tbl", f"Expecting *.tbl file, got '{tbl_file}'"
63
+
64
+ meta = np.genfromtxt(fpath, skip_header=1, max_rows=1)
65
+ sdata = pd.read_csv(
66
+ fpath, sep=" ", skiprows=2, header=None, names=["ws", "ct", "P"]
67
+ )
68
+
69
+ super().__init__(
70
+ sdata,
71
+ col_ws="ws",
72
+ col_P="P",
73
+ col_ct="ct",
74
+ H=meta[0],
75
+ D=meta[1],
76
+ P_nominal=meta[3] * 1e3,
77
+ P_unit="kW",
78
+ rho=rho,
79
+ **parameters,
80
+ )
@@ -10,3 +10,4 @@ from .null_type import NullType
10
10
  from .wsrho2PCt_from_two import WsRho2PCtFromTwo
11
11
  from .wsti2PCt_from_two import WsTI2PCtFromTwo
12
12
  from .lookup import FromLookupTable
13
+ from .TBL_file import TBLFile
@@ -17,7 +17,7 @@ class FromLookupTable(TurbineType):
17
17
  source: str or pandas.DataFrame
18
18
  The file path, static name, or data
19
19
  rho: float
20
- The air densitiy for which the data is valid
20
+ The air density for which the data is valid
21
21
  or None for no correction
22
22
  WSCT: str
23
23
  The wind speed variable for ct lookup
@@ -60,7 +60,7 @@ class FromLookupTable(TurbineType):
60
60
  lookup_pars: dict
61
61
  Additional parameters for the LookupTable model
62
62
  rho: float, optional
63
- The air densitiy for which the data is valid
63
+ The air density for which the data is valid
64
64
  or None for no correction
65
65
  p_ct: float
66
66
  The exponent for yaw dependency of ct
@@ -119,7 +119,7 @@ class FromLookupTable(TurbineType):
119
119
 
120
120
  def needs_rews2(self):
121
121
  """
122
- Returns flag for requirering REWS2 variable
122
+ Returns flag for requiring REWS2 variable
123
123
 
124
124
  Returns
125
125
  -------
@@ -131,7 +131,7 @@ class FromLookupTable(TurbineType):
131
131
 
132
132
  def needs_rews3(self):
133
133
  """
134
- Returns flag for requirering REWS3 variable
134
+ Returns flag for requiring REWS3 variable
135
135
 
136
136
  Returns
137
137
  -------
@@ -228,7 +228,7 @@ class FromLookupTable(TurbineType):
228
228
  super().modify_cutin(modify_ct, modify_P)
229
229
 
230
230
  def calculate(self, algo, mdata, fdata, st_sel):
231
- """ "
231
+ """
232
232
  The main model calculation.
233
233
 
234
234
  This function is executed on a single chunk of data,
@@ -37,7 +37,7 @@ class NullType(TurbineType):
37
37
 
38
38
  def needs_rews2(self):
39
39
  """
40
- Returns flag for requirering REWS2 variable
40
+ Returns flag for requiring REWS2 variable
41
41
 
42
42
  Returns
43
43
  -------
@@ -49,7 +49,7 @@ class NullType(TurbineType):
49
49
 
50
50
  def needs_rews3(self):
51
51
  """
52
- Returns flag for requirering REWS3 variable
52
+ Returns flag for requiring REWS3 variable
53
53
 
54
54
  Returns
55
55
  -------
@@ -77,7 +77,7 @@ class NullType(TurbineType):
77
77
  return []
78
78
 
79
79
  def calculate(self, algo, mdata, fdata, st_sel):
80
- """ "
80
+ """
81
81
  The main model calculation.
82
82
 
83
83
  This function is executed on a single chunk of data,
@@ -37,9 +37,9 @@ class WsRho2PCtFromTwo(TurbineType):
37
37
  rpars_ct: dict, optional
38
38
  Parameters for pandas ct file reading
39
39
  ipars_P: dict, optional
40
- Parameters for scipy.interpolate.interpn()
40
+ Parameters for scipy.interpolate.interpn
41
41
  ipars_ct: dict, optional
42
- Parameters for scipy.interpolate.interpn()
42
+ Parameters for scipy.interpolate.interpn
43
43
 
44
44
  :group: models.turbine_types
45
45
 
@@ -81,9 +81,9 @@ class WsRho2PCtFromTwo(TurbineType):
81
81
  pd_file_read_pars_ct: dict
82
82
  Parameters for pandas ct file reading
83
83
  interpn_pars_P: dict, optional
84
- Parameters for scipy.interpolate.interpn()
84
+ Parameters for scipy.interpolate.interpn
85
85
  interpn_pars_ct: dict, optional
86
- Parameters for scipy.interpolate.interpn()
86
+ Parameters for scipy.interpolate.interpn
87
87
  parameters: dict, optional
88
88
  Additional parameters for TurbineType class
89
89
 
@@ -117,7 +117,7 @@ class WsRho2PCtFromTwo(TurbineType):
117
117
 
118
118
  def needs_rews2(self):
119
119
  """
120
- Returns flag for requirering REWS2 variable
120
+ Returns flag for requiring REWS2 variable
121
121
 
122
122
  Returns
123
123
  -------
@@ -129,7 +129,7 @@ class WsRho2PCtFromTwo(TurbineType):
129
129
 
130
130
  def needs_rews3(self):
131
131
  """
132
- Returns flag for requirering REWS3 variable
132
+ Returns flag for requiring REWS3 variable
133
133
 
134
134
  Returns
135
135
  -------
@@ -229,7 +229,7 @@ class WsRho2PCtFromTwo(TurbineType):
229
229
  print()
230
230
 
231
231
  def calculate(self, algo, mdata, fdata, st_sel):
232
- """ "
232
+ """
233
233
  The main model calculation.
234
234
 
235
235
  This function is executed on a single chunk of data,