foxes 0.8.1__py3-none-any.whl → 1.0__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 (175) hide show
  1. docs/source/conf.py +353 -0
  2. examples/abl_states/run.py +160 -0
  3. examples/compare_rotors_pwakes/run.py +217 -0
  4. examples/compare_wakes/run.py +241 -0
  5. examples/dyn_wakes/run.py +311 -0
  6. examples/field_data_nc/run.py +121 -0
  7. examples/induction_RHB/run.py +201 -0
  8. examples/multi_height/run.py +113 -0
  9. examples/power_mask/run.py +249 -0
  10. examples/random_timeseries/run.py +210 -0
  11. examples/scan_row/run.py +193 -0
  12. examples/sector_management/run.py +162 -0
  13. examples/sequential/run.py +209 -0
  14. examples/single_state/run.py +201 -0
  15. examples/states_lookup_table/run.py +137 -0
  16. examples/streamline_wakes/run.py +138 -0
  17. examples/tab_file/run.py +142 -0
  18. examples/timelines/run.py +267 -0
  19. examples/timeseries/run.py +183 -0
  20. examples/timeseries_slurm/run.py +185 -0
  21. examples/wind_rose/run.py +141 -0
  22. examples/windio/run.py +29 -0
  23. examples/yawed_wake/run.py +196 -0
  24. foxes/__init__.py +4 -8
  25. foxes/algorithms/__init__.py +1 -1
  26. foxes/algorithms/downwind/downwind.py +232 -101
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -6
  28. foxes/algorithms/downwind/models/init_farm_data.py +1 -1
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +5 -6
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +0 -1
  31. foxes/algorithms/downwind/models/set_amb_point_results.py +4 -2
  32. foxes/algorithms/iterative/iterative.py +73 -33
  33. foxes/algorithms/iterative/models/farm_wakes_calc.py +11 -6
  34. foxes/algorithms/sequential/models/plugin.py +1 -1
  35. foxes/algorithms/sequential/sequential.py +126 -255
  36. foxes/constants.py +17 -2
  37. foxes/core/__init__.py +1 -0
  38. foxes/core/algorithm.py +631 -146
  39. foxes/core/data.py +252 -20
  40. foxes/core/data_calc_model.py +13 -289
  41. foxes/core/engine.py +630 -0
  42. foxes/core/farm_controller.py +37 -9
  43. foxes/core/farm_data_model.py +15 -0
  44. foxes/core/model.py +133 -80
  45. foxes/core/point_data_model.py +15 -0
  46. foxes/core/rotor_model.py +27 -21
  47. foxes/core/states.py +16 -0
  48. foxes/core/turbine_type.py +28 -0
  49. foxes/core/wake_frame.py +22 -4
  50. foxes/core/wake_model.py +2 -3
  51. foxes/data/windio/windio_5turbines_timeseries.yaml +23 -1
  52. foxes/engines/__init__.py +16 -0
  53. foxes/engines/dask.py +975 -0
  54. foxes/engines/default.py +75 -0
  55. foxes/engines/futures.py +72 -0
  56. foxes/engines/mpi.py +38 -0
  57. foxes/engines/multiprocess.py +74 -0
  58. foxes/engines/numpy.py +185 -0
  59. foxes/engines/pool.py +263 -0
  60. foxes/engines/single.py +139 -0
  61. foxes/input/farm_layout/__init__.py +1 -0
  62. foxes/input/farm_layout/from_csv.py +4 -0
  63. foxes/input/farm_layout/from_json.py +1 -1
  64. foxes/input/farm_layout/grid.py +2 -2
  65. foxes/input/farm_layout/ring.py +65 -0
  66. foxes/input/farm_layout/row.py +2 -2
  67. foxes/input/states/__init__.py +6 -0
  68. foxes/input/states/create/random_abl_states.py +1 -1
  69. foxes/input/states/field_data_nc.py +157 -32
  70. foxes/input/states/multi_height.py +127 -13
  71. foxes/input/states/one_point_flow.py +577 -0
  72. foxes/input/states/scan_ws.py +73 -2
  73. foxes/input/states/states_table.py +204 -35
  74. foxes/input/windio/__init__.py +1 -1
  75. foxes/input/windio/get_states.py +44 -23
  76. foxes/input/windio/read_attributes.py +41 -16
  77. foxes/input/windio/read_farm.py +116 -102
  78. foxes/input/windio/read_fields.py +13 -6
  79. foxes/input/windio/read_outputs.py +63 -22
  80. foxes/input/windio/runner.py +31 -17
  81. foxes/input/windio/windio.py +36 -22
  82. foxes/models/ground_models/wake_mirror.py +8 -4
  83. foxes/models/model_book.py +29 -18
  84. foxes/models/partial_wakes/rotor_points.py +3 -3
  85. foxes/models/rotor_models/centre.py +4 -0
  86. foxes/models/rotor_models/grid.py +22 -23
  87. foxes/models/rotor_models/levels.py +4 -5
  88. foxes/models/turbine_models/calculator.py +0 -2
  89. foxes/models/turbine_models/lookup_table.py +27 -2
  90. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  91. foxes/models/turbine_models/set_farm_vars.py +103 -34
  92. foxes/models/turbine_types/PCt_file.py +24 -0
  93. foxes/models/turbine_types/PCt_from_two.py +24 -0
  94. foxes/models/turbine_types/__init__.py +1 -0
  95. foxes/models/turbine_types/lookup.py +316 -0
  96. foxes/models/turbine_types/null_type.py +50 -0
  97. foxes/models/turbine_types/wsrho2PCt_from_two.py +24 -0
  98. foxes/models/turbine_types/wsti2PCt_from_two.py +24 -0
  99. foxes/models/vertical_profiles/data_profile.py +1 -1
  100. foxes/models/wake_frames/__init__.py +1 -0
  101. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  102. foxes/models/wake_frames/farm_order.py +23 -3
  103. foxes/models/wake_frames/rotor_wd.py +4 -2
  104. foxes/models/wake_frames/seq_dynamic_wakes.py +56 -63
  105. foxes/models/wake_frames/streamlines.py +19 -20
  106. foxes/models/wake_frames/timelines.py +328 -127
  107. foxes/models/wake_frames/yawed_wakes.py +4 -1
  108. foxes/models/wake_models/dist_sliced.py +1 -3
  109. foxes/models/wake_models/induction/rankine_half_body.py +4 -4
  110. foxes/models/wake_models/induction/rathmann.py +2 -2
  111. foxes/models/wake_models/induction/self_similar.py +2 -2
  112. foxes/models/wake_models/induction/vortex_sheet.py +2 -2
  113. foxes/models/wake_models/ti/iec_ti.py +34 -17
  114. foxes/models/wake_models/top_hat.py +1 -1
  115. foxes/models/wake_models/wind/bastankhah14.py +2 -2
  116. foxes/models/wake_models/wind/bastankhah16.py +8 -7
  117. foxes/models/wake_models/wind/jensen.py +1 -1
  118. foxes/models/wake_models/wind/turbopark.py +2 -2
  119. foxes/output/__init__.py +4 -1
  120. foxes/output/farm_layout.py +2 -2
  121. foxes/output/flow_plots_2d/__init__.py +0 -1
  122. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  123. foxes/output/grids.py +91 -21
  124. foxes/output/seq_plugins/__init__.py +2 -0
  125. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +62 -20
  126. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  127. foxes/output/slice_data.py +131 -111
  128. foxes/output/state_turbine_map.py +18 -13
  129. foxes/output/state_turbine_table.py +19 -19
  130. foxes/utils/__init__.py +1 -1
  131. foxes/utils/dev_utils.py +42 -0
  132. foxes/utils/dict.py +1 -1
  133. foxes/utils/factory.py +147 -52
  134. foxes/utils/pandas_helpers.py +4 -3
  135. foxes/utils/wind_dir.py +0 -2
  136. foxes/utils/xarray_utils.py +25 -13
  137. foxes/variables.py +37 -0
  138. {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/METADATA +72 -34
  139. foxes-1.0.dist-info/RECORD +307 -0
  140. {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/WHEEL +1 -1
  141. foxes-1.0.dist-info/top_level.txt +4 -0
  142. tests/0_consistency/iterative/test_iterative.py +92 -0
  143. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  144. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  145. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  146. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  147. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  148. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  149. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  150. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  151. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  152. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  153. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  154. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  155. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  156. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  157. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  158. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  159. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  160. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  161. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  162. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  163. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  164. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  165. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  166. tests/3_examples/test_examples.py +34 -0
  167. foxes/VERSION +0 -1
  168. foxes/output/flow_plots_2d.py +0 -0
  169. foxes/utils/plotly_helpers.py +0 -19
  170. foxes/utils/runners/__init__.py +0 -1
  171. foxes/utils/runners/runners.py +0 -280
  172. foxes-0.8.1.dist-info/RECORD +0 -248
  173. foxes-0.8.1.dist-info/top_level.txt +0 -1
  174. foxes-0.8.1.dist-info/zip-safe +0 -1
  175. {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/LICENSE +0 -0
@@ -1,5 +1,3 @@
1
- import numpy as np
2
- import pandas as pd
3
1
  from pathlib import Path
4
2
 
5
3
  from foxes.core import WindFarm
@@ -9,7 +7,7 @@ from foxes.data import StaticData, WINDIO
9
7
 
10
8
  from .read_fields import read_wind_resource_field
11
9
  from .get_states import get_states
12
- from .read_farm import read_layout, read_turbine_type
10
+ from .read_farm import read_layout, read_turbine_types
13
11
  from .read_attributes import read_attributes
14
12
  from .runner import WindioRunner
15
13
 
@@ -78,19 +76,27 @@ def _read_farm(wio, algo_dict, verbosity):
78
76
  ws_exp_ct = 1
79
77
 
80
78
  # read turbine type:
81
- turbines = Dict(wio_farm["turbines"], name="turbines")
82
- ttype = read_turbine_type(turbines, algo_dict, ws_exp_P, ws_exp_ct, verbosity)
79
+ ttypes = read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity)
83
80
 
84
81
  # read layouts:
85
- layouts = Dict(wio_farm["layouts"], name="layouts")
82
+ wfarm = wio_farm["layouts"]
83
+ if isinstance(wfarm, dict):
84
+ layouts = Dict(wfarm, name="layouts")
85
+ else:
86
+ layouts = Dict({i: l for i, l in enumerate(wfarm)}, name="layouts")
86
87
  if verbosity > 2:
87
88
  print(" Reading layouts")
88
89
  print(" Contents:", [k for k in layouts.keys()])
89
90
  for lname, ldict in layouts.items():
90
- read_layout(lname, ldict, algo_dict, ttype, verbosity)
91
+ read_layout(lname, ldict, algo_dict, ttypes, verbosity)
91
92
 
92
93
 
93
- def read_windio(windio_yaml, verbosity=1):
94
+ def read_windio(
95
+ windio_yaml,
96
+ verbosity=1,
97
+ algo_pars=None,
98
+ **runner_pars,
99
+ ):
94
100
  """
95
101
  Reads a complete WindIO case.
96
102
 
@@ -103,6 +109,10 @@ def read_windio(windio_yaml, verbosity=1):
103
109
  Path to the windio yaml file
104
110
  verbosity: int
105
111
  The verbosity level, 0 = silent
112
+ algo_pars: dict, optional
113
+ Additional algorithm parameters
114
+ runner_pars: dict, optional
115
+ Additional parameters for the WindioRunner
106
116
 
107
117
  Returns
108
118
  -------
@@ -113,7 +123,6 @@ def read_windio(windio_yaml, verbosity=1):
113
123
  :group: input.windio
114
124
 
115
125
  """
116
-
117
126
  wio_file = Path(windio_yaml)
118
127
  if not wio_file.is_file():
119
128
  wio_file = StaticData().get_file_path(WINDIO, wio_file, check_raw=False)
@@ -128,17 +137,21 @@ def read_windio(windio_yaml, verbosity=1):
128
137
  print(" Name:", wio.pop("name", None))
129
138
  print(" Contents:", [k for k in wio.keys()])
130
139
 
131
- algo_dict = Dict(
132
- algo_type="Downwind",
133
- mbook=ModelBook(),
134
- farm=WindFarm(),
135
- wake_models=[],
136
- verbosity=verbosity-3,
140
+ algo_dict = Dict(algo_type="Downwind", name="algo_dict")
141
+ if algo_pars is not None:
142
+ algo_dict.update(algo_pars)
143
+ algo_dict.update(
144
+ dict(
145
+ mbook=ModelBook(),
146
+ farm=WindFarm(),
147
+ wake_models=[],
148
+ verbosity=verbosity - 3,
149
+ )
137
150
  )
138
151
 
139
152
  _read_site(wio, algo_dict, verbosity)
140
153
  _read_farm(wio, algo_dict, verbosity)
141
-
154
+
142
155
  out_dicts, odir = read_attributes(
143
156
  wio,
144
157
  algo_dict,
@@ -148,12 +161,13 @@ def read_windio(windio_yaml, verbosity=1):
148
161
  if verbosity > 1:
149
162
  print("Creating windio runner")
150
163
  runner = WindioRunner(
151
- algo_dict,
152
- output_dir=odir,
153
- output_dicts=out_dicts,
154
- wio_input_data=wio,
155
- verbosity=verbosity
156
- )
164
+ algo_dict,
165
+ output_dir=odir,
166
+ output_dicts=out_dicts,
167
+ wio_input_data=wio,
168
+ verbosity=verbosity,
169
+ **runner_pars,
170
+ )
157
171
 
158
172
  return runner
159
173
 
@@ -70,6 +70,10 @@ class WakeMirror(GroundModel):
70
70
  # prepare:
71
71
  hh = fdata[FV.H][:, downwind_index].copy()
72
72
 
73
+ # DEBUG CHECK:
74
+ # import numpy as np
75
+ # assert(np.all(fdata[FV.H]==fdata[FV.TXYH[..., 2]]))
76
+
73
77
  # contribution from main wake:
74
78
  wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
75
79
  wmodel.contribute(algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas)
@@ -78,14 +82,14 @@ class WakeMirror(GroundModel):
78
82
  tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
79
83
  for h in self.heights:
80
84
 
81
- fdata[FV.H][:, downwind_index] = hh + 2 * (h - hh)
85
+ fdata[FV.TXYH][:, downwind_index, 2] = hh + 2 * (h - hh)
82
86
 
83
87
  pwake.contribute(
84
88
  algo, mdata, fdata, tdata, downwind_index, wake_deltas, wmodel
85
89
  )
86
90
 
87
91
  # reset heights:
88
- fdata[FV.H][:, downwind_index] = hh
92
+ fdata[FV.TXYH][:, downwind_index, 2] = hh
89
93
 
90
94
  def contribute_to_point_wakes(
91
95
  self,
@@ -133,7 +137,7 @@ class WakeMirror(GroundModel):
133
137
  tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
134
138
  for h in self.heights:
135
139
 
136
- fdata[FV.H][:, downwind_index] = hh + 2 * (h - hh)
140
+ fdata[FV.TXYH][:, downwind_index, 2] = hh + 2 * (h - hh)
137
141
 
138
142
  wcoos = algo.wake_frame.get_wake_coos(
139
143
  algo, mdata, fdata, tdata, downwind_index
@@ -143,7 +147,7 @@ class WakeMirror(GroundModel):
143
147
  )
144
148
 
145
149
  # reset heights:
146
- fdata[FV.H][:, downwind_index] = hh
150
+ fdata[FV.TXYH][:, downwind_index, 2] = hh
147
151
 
148
152
 
149
153
  class GroundMirror(WakeMirror):
@@ -85,8 +85,7 @@ class ModelBook:
85
85
  self.point_models["tke2ti"] = fm.point_models.TKE2TI()
86
86
 
87
87
  self.rotor_models = FDict(name="rotor_models")
88
- rvars = [FV.REWS, FV.REWS2, FV.REWS3, FV.TI, FV.RHO]
89
- self.rotor_models["centre"] = fm.rotor_models.CentreRotor(calc_vars=rvars)
88
+ self.rotor_models["centre"] = fm.rotor_models.CentreRotor()
90
89
 
91
90
  def _n2n(n2):
92
91
  n2 = float(n2)
@@ -100,7 +99,7 @@ class ModelBook:
100
99
  self.rotor_models.add_factory(
101
100
  fm.rotor_models.GridRotor,
102
101
  "grid<n2>",
103
- kwargs=dict(calc_vars=rvars, reduce=True),
102
+ kwargs=dict(reduce=True),
104
103
  var2arg={"n2": "n"},
105
104
  n2=_n2n,
106
105
  hints={"n2": "(Number of points in square grid)"},
@@ -108,7 +107,7 @@ class ModelBook:
108
107
  self.rotor_models.add_factory(
109
108
  fm.rotor_models.GridRotor,
110
109
  "grid<n2>_raw",
111
- kwargs=dict(calc_vars=rvars, reduce=False),
110
+ kwargs=dict(reduce=False),
112
111
  var2arg={"n2": "n"},
113
112
  n2=_n2n,
114
113
  hints={"n2": "(Number of points in square grid)"},
@@ -116,14 +115,14 @@ class ModelBook:
116
115
  self.rotor_models.add_factory(
117
116
  fm.rotor_models.LevelRotor,
118
117
  "level<n>",
119
- kwargs=dict(calc_vars=rvars, reduce=True),
118
+ kwargs=dict(reduce=True),
120
119
  n=lambda x: int(x),
121
120
  hints={"n": "(Number of vertical levels)"},
122
121
  )
123
122
  self.rotor_models.add_factory(
124
123
  fm.rotor_models.LevelRotor,
125
124
  "level<n>_raw",
126
- kwargs=dict(calc_vars=rvars, reduce=False),
125
+ kwargs=dict(reduce=False),
127
126
  n=lambda x: int(x),
128
127
  hints={"n": "(Number of vertical levels)"},
129
128
  )
@@ -158,14 +157,14 @@ class ModelBook:
158
157
  fm.turbine_models.kTI,
159
158
  "kTI_<kTI>",
160
159
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
161
- hints={"kTI": "(Value, e.g. 004 for 0.04)"},
160
+ hints={"kTI": "(Value, e.g. 02 for 0.2)"},
162
161
  )
163
162
  self.turbine_models.add_factory(
164
163
  fm.turbine_models.kTI,
165
164
  "kTI_amb_<kTI>",
166
165
  kwargs=dict(ti_var=FV.AMB_TI),
167
166
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
168
- hints={"kTI": "(Value, e.g. 004 for 0.04)"},
167
+ hints={"kTI": "(Value, e.g. 04 for 0.4)"},
169
168
  )
170
169
  self.turbine_models.add_factory(
171
170
  fm.turbine_models.kTI,
@@ -173,7 +172,7 @@ class ModelBook:
173
172
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
174
173
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
175
174
  hints={
176
- "kTI": "(Value, e.g. 004 for 0.04)",
175
+ "kTI": "(Value, e.g. 04 for 0.4)",
177
176
  "kb": "(Value, e.g. 004 for 0.04)",
178
177
  },
179
178
  )
@@ -184,7 +183,7 @@ class ModelBook:
184
183
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
185
184
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
186
185
  hints={
187
- "kTI": "(Value, e.g. 004 for 0.04)",
186
+ "kTI": "(Value, e.g. 04 for 0.4)",
188
187
  "kb": "(Value, e.g. 004 for 0.04)",
189
188
  },
190
189
  )
@@ -254,12 +253,24 @@ class ModelBook:
254
253
  )
255
254
 
256
255
  self.wake_frames["timelines"] = fm.wake_frames.Timelines()
256
+ self.wake_frames["dyn_wakes"] = fm.wake_frames.DynamicWakes()
257
+ self.wake_frames["seq_dyn_wakes"] = fm.wake_frames.SeqDynamicWakes()
257
258
 
258
259
  def _todt(x):
259
260
  if x[-1] == "s":
260
261
  return float(x[:-1]) / 60
261
262
  elif x[-3:] == "min":
262
263
  return float(x[:-3])
264
+ else:
265
+ raise NotImplementedError(f"Cannot translate '{x}' into minutes")
266
+
267
+ def _tokm(x):
268
+ if x[-2:] == "km":
269
+ return float(x[:-2])
270
+ elif x[-1] == "m":
271
+ return float(x[:-1]) / 1e3
272
+ else:
273
+ raise NotImplementedError(f"Cannot translate '{x}' into km")
263
274
 
264
275
  self.wake_frames.add_factory(
265
276
  fm.wake_frames.Timelines,
@@ -268,6 +279,13 @@ class ModelBook:
268
279
  var2arg={"dt": "dt_min"},
269
280
  hints={"dt": "(Time step, e.g '10s', '1min' etc.)"},
270
281
  )
282
+ self.wake_frames.add_factory(
283
+ fm.wake_frames.DynamicWakes,
284
+ "dyn_wakes_<length>",
285
+ length=_tokm,
286
+ var2arg={"length": "max_length_km"},
287
+ hints={"length": "(Maximal wake length, e.g. '5km' or '5000m')"},
288
+ )
271
289
  self.wake_frames.add_factory(
272
290
  fm.wake_frames.SeqDynamicWakes,
273
291
  "seq_dyn_wakes_<dt>",
@@ -411,14 +429,6 @@ class ModelBook:
411
429
  hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
412
430
  )
413
431
 
414
- self.wake_models.add_factory(
415
- fm.wake_models.ti.IECTIWake,
416
- "IECTI2005_<superposition>",
417
- kwargs=dict(iec_type="2005"),
418
- superposition=lambda s: f"ti_{s}",
419
- hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
420
- )
421
-
422
432
  self.wake_models.add_factory(
423
433
  fm.wake_models.ti.IECTIWake,
424
434
  "IECTI2019_<superposition>",
@@ -466,6 +476,7 @@ class ModelBook:
466
476
  var2arg={"height": "heights"},
467
477
  height=lambda h: [0.0, float(h)],
468
478
  hints={"height": "(Boundary layer wake reflection height)"},
479
+ example_vars={"height": 500},
469
480
  )
470
481
 
471
482
  self.sources = FDict(
@@ -1,4 +1,5 @@
1
1
  from foxes.core import PartialWakesModel
2
+ import foxes.constants as FC
2
3
 
3
4
 
4
5
  class RotorPoints(PartialWakesModel):
@@ -33,10 +34,9 @@ class RotorPoints(PartialWakesModel):
33
34
  The target point weights, shape: (n_tpoints,)
34
35
 
35
36
  """
36
- rotor = algo.rotor_model
37
37
  return (
38
- rotor.from_data_or_store(rotor.RPOINTS, algo, mdata),
39
- rotor.from_data_or_store(rotor.RWEIGHTS, algo, mdata),
38
+ algo.get_from_chunk_store(FC.ROTOR_POINTS, mdata=mdata),
39
+ algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata),
40
40
  )
41
41
 
42
42
  def finalize_wakes(
@@ -132,6 +132,10 @@ class CentreRotor(RotorModel):
132
132
  n_states = mdata.n_states
133
133
  n_turbines = algo.n_turbines
134
134
 
135
+ for v in [FV.REWS2, FV.REWS3]:
136
+ if v in fdata and v not in self.calc_vars:
137
+ self.calc_vars.append(v)
138
+
135
139
  uvp = None
136
140
  uv = None
137
141
  if (
@@ -17,7 +17,7 @@ class GridRotor(RotorModel):
17
17
  reduce: bool
18
18
  Flag for reduction to points actually representing
19
19
  an area with overlap with the circe, recalculating
20
- the self.weights accordingly
20
+ the self.__weights accordingly
21
21
  nint: int
22
22
  Integration steps per element
23
23
 
@@ -25,7 +25,7 @@ class GridRotor(RotorModel):
25
25
 
26
26
  """
27
27
 
28
- def __init__(self, n, calc_vars, reduce=True, nint=200):
28
+ def __init__(self, n, reduce=True, nint=200, **kwargs):
29
29
  """
30
30
  Constructor.
31
31
 
@@ -34,20 +34,19 @@ class GridRotor(RotorModel):
34
34
  n: int
35
35
  The number of points along one direction,
36
36
  maximal number of points is N = n * n
37
- calc_vars: list of str
38
- The variables that are calculated by the model
39
- (Their ambients are added automatically)
40
37
  reduce: bool
41
38
  Flag for reduction to points actually representing
42
39
  an area with overlap with the circe, recalculating
43
- the self.weights accordingly
40
+ the self.__weights accordingly
44
41
  nint: int
45
42
  Integration steps per element
46
43
  name: str, optional
47
44
  The model name
45
+ kwargs: dict, optional
46
+ Addition parameters for the base model
48
47
 
49
48
  """
50
- super().__init__(calc_vars)
49
+ super().__init__(**kwargs)
51
50
 
52
51
  self.n = n
53
52
  self.reduce = reduce
@@ -76,12 +75,12 @@ class GridRotor(RotorModel):
76
75
  x = [-1.0 + (i + 0.5) * delta for i in range(self.n)]
77
76
  x, y = np.meshgrid(x, x, indexing="ij")
78
77
 
79
- self.dpoints = np.zeros([N, 3], dtype=FC.DTYPE)
80
- self.dpoints[:, 1] = x.reshape(N)
81
- self.dpoints[:, 2] = y.reshape(N)
78
+ self.__dpoints = np.zeros([N, 3], dtype=FC.DTYPE)
79
+ self.__dpoints[:, 1] = x.reshape(N)
80
+ self.__dpoints[:, 2] = y.reshape(N)
82
81
 
83
82
  if self.reduce:
84
- self.weights = np.zeros((self.n, self.n), dtype=FC.DTYPE)
83
+ self.__weights = np.zeros((self.n, self.n), dtype=FC.DTYPE)
85
84
  for i in range(0, self.n):
86
85
  for j in range(0, self.n):
87
86
  d = delta / self.nint
@@ -95,18 +94,18 @@ class GridRotor(RotorModel):
95
94
  pts[:, :, 0], pts[:, :, 1] = np.meshgrid(hx, hy, indexing="ij")
96
95
 
97
96
  d = np.linalg.norm(pts, axis=2)
98
- self.weights[i, j] = np.sum(d <= 1.0) / self.nint**2
97
+ self.__weights[i, j] = np.sum(d <= 1.0) / self.nint**2
99
98
 
100
- self.weights = self.weights.reshape(N)
101
- sel = self.weights > 0.0
102
- self.dpoints = self.dpoints[sel]
103
- self.weights = self.weights[sel]
104
- self.weights /= np.sum(self.weights)
99
+ self.__weights = self.__weights.reshape(N)
100
+ sel = self.__weights > 0.0
101
+ self.__dpoints = self.__dpoints[sel]
102
+ self.__weights = self.__weights[sel]
103
+ self.__weights /= np.sum(self.__weights)
105
104
 
106
105
  else:
107
- self.dpoints[:, 1] = x.reshape(N)
108
- self.dpoints[:, 2] = y.reshape(N)
109
- self.weights = np.ones(N, dtype=FC.DTYPE) / N
106
+ self.__dpoints[:, 1] = x.reshape(N)
107
+ self.__dpoints[:, 2] = y.reshape(N)
108
+ self.__weights = np.ones(N, dtype=FC.DTYPE) / N
110
109
 
111
110
  def n_rotor_points(self):
112
111
  """
@@ -118,7 +117,7 @@ class GridRotor(RotorModel):
118
117
  The number of rotor points
119
118
 
120
119
  """
121
- return len(self.weights)
120
+ return len(self.__weights)
122
121
 
123
122
  def design_points(self):
124
123
  """
@@ -137,7 +136,7 @@ class GridRotor(RotorModel):
137
136
  The design points, shape: (n_points, 3)
138
137
 
139
138
  """
140
- return self.dpoints
139
+ return self.__dpoints
141
140
 
142
141
  def rotor_point_weights(self):
143
142
  """
@@ -150,4 +149,4 @@ class GridRotor(RotorModel):
150
149
  add to one, shape: (n_rpoints,)
151
150
 
152
151
  """
153
- return self.weights
152
+ return self.__weights
@@ -24,7 +24,7 @@ class LevelRotor(RotorModel):
24
24
 
25
25
  """
26
26
 
27
- def __init__(self, n, calc_vars, reduce=True, nint=200):
27
+ def __init__(self, n, reduce=True, nint=200, **kwargs):
28
28
  """
29
29
  Constructor.
30
30
 
@@ -32,9 +32,6 @@ class LevelRotor(RotorModel):
32
32
  ----------
33
33
  n: int
34
34
  The number of points along the vertical direction
35
- calc_vars: list of str
36
- The variables that are calculated by the model
37
- (Their ambients are added automatically)
38
35
  reduce: bool
39
36
  Flag for calculating the weight of every element according
40
37
  to the rotor diameter at the respective height level
@@ -42,9 +39,11 @@ class LevelRotor(RotorModel):
42
39
  Integration steps per element
43
40
  name: str, optional
44
41
  The model name
42
+ kwargs: dict, optional
43
+ Addition parameters for the base model
45
44
 
46
45
  """
47
- super().__init__(calc_vars)
46
+ super().__init__(**kwargs)
48
47
 
49
48
  self.n = n
50
49
  self.reduce = reduce
@@ -1,5 +1,3 @@
1
- import numpy as np
2
-
3
1
  from foxes.core import TurbineModel
4
2
 
5
3
 
@@ -36,6 +36,7 @@ class LookupTable(TurbineModel):
36
36
  varmap={},
37
37
  pd_file_read_pars={},
38
38
  xr_interp_args={},
39
+ interpn_args={},
39
40
  **kwargs,
40
41
  ):
41
42
  """
@@ -56,6 +57,8 @@ class LookupTable(TurbineModel):
56
57
  Parameters for pandas file reading
57
58
  xr_interp_args: dict
58
59
  Parameters for xarray interpolation method
60
+ interpn_args: dict
61
+ Parameters for scipy intern or interp1d
59
62
  kwargs: dict, optional
60
63
  Additional parameters, added as default
61
64
  values if not in data
@@ -70,6 +73,7 @@ class LookupTable(TurbineModel):
70
73
 
71
74
  self._rpars = pd_file_read_pars
72
75
  self._xargs = xr_interp_args
76
+ self._iargs = interpn_args
73
77
  self._data = None
74
78
 
75
79
  for v, d in kwargs.items():
@@ -184,7 +188,7 @@ class LookupTable(TurbineModel):
184
188
  """
185
189
  data = {
186
190
  v: self.get_data(
187
- self.input_vars[0],
191
+ v,
188
192
  FC.STATE_TURBINE,
189
193
  lookup="fs",
190
194
  fdata=fdata,
@@ -192,6 +196,7 @@ class LookupTable(TurbineModel):
192
196
  )[st_sel]
193
197
  for v in self.input_vars
194
198
  }
199
+
195
200
  dims = {
196
201
  v: ("_z") if len(data[v].shape) == 1 else ("_z", "_u")
197
202
  for v in self.input_vars
@@ -205,7 +210,27 @@ class LookupTable(TurbineModel):
205
210
  }
206
211
  del data, dims
207
212
 
208
- odata = self._data.interp(**indata, **self._xargs)
213
+ iargs = dict(bounds_error=True)
214
+ iargs.update(self._iargs)
215
+ try:
216
+ odata = self._data.interp(**indata, kwargs=iargs, **self._xargs)
217
+ except ValueError as e:
218
+ print("\nBOUNDS ERROR", self.name)
219
+ print("Variables:", list(indata.keys()))
220
+ print(
221
+ "DATA min/max:",
222
+ [float(np.min(self._data[v].to_numpy())) for v in indata.keys()],
223
+ [float(np.max(self._data[v].to_numpy())) for v in indata.keys()],
224
+ )
225
+ print(
226
+ "EVAL min/max:",
227
+ [float(np.min(d.to_numpy())) for d in indata.values()],
228
+ [float(np.max(d.to_numpy())) for d in indata.values()],
229
+ )
230
+ print(
231
+ "\nMaybe you want to try the options 'bounds_error=False, fill_value=None'? This will extrapolate the data.\n"
232
+ )
233
+ raise e
209
234
 
210
235
  out = {}
211
236
  for v in self.output_vars:
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
 
3
- from foxes.core import TurbineModel, Data
3
+ from foxes.core import TurbineModel, TData
4
4
  import foxes.variables as FV
5
5
  import foxes.constants as FC
6
6
 
@@ -108,7 +108,7 @@ class RotorCentreCalc(TurbineModel):
108
108
 
109
109
  """
110
110
  # prepare target point data:
111
- tdata = Data.from_points(
111
+ tdata = TData.from_points(
112
112
  fdata[FV.TXYH],
113
113
  data={
114
114
  v: np.zeros_like(fdata[FV.X][:, :, None])
@@ -131,6 +131,7 @@ class RotorCentreCalc(TurbineModel):
131
131
  # extract results:
132
132
  out = {v: fdata[v] for v in self.calc_vars.keys()}
133
133
  for v in out.keys():
134
- out[v][st_sel] = res[self.calc_vars[v]][st_sel]
134
+ w = self.calc_vars[v]
135
+ out[v][st_sel] = res[w][st_sel][..., 0]
135
136
 
136
137
  return out