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
foxes/utils/dict.py CHANGED
@@ -32,6 +32,6 @@ class Dict(dict):
32
32
  try:
33
33
  return super().__getitem__(key)
34
34
  except KeyError:
35
- k = ", ".join(sorted(list(self.keys())))
35
+ k = ", ".join(sorted([f"{s}" for s in self.keys()]))
36
36
  e = f"{self.name}: Cannot find key '{key}'. Known keys: {k}"
37
37
  raise KeyError(e)
foxes/utils/factory.py CHANGED
@@ -1,3 +1,5 @@
1
+ import numpy as np
2
+
1
3
  from .dict import Dict
2
4
  import foxes.variables as FV
3
5
 
@@ -23,6 +25,8 @@ class Factory:
23
25
  hints: dict
24
26
  Hints for print_toc, only for variables for which the
25
27
  options are functions or missing
28
+ example: str
29
+ An example name
26
30
  options: dict
27
31
  For each variable, e.g. A, B or C, the list or dict
28
32
  or function that maps a str to the actual value
@@ -39,6 +43,7 @@ class Factory:
39
43
  kwargs={},
40
44
  var2arg={},
41
45
  hints={},
46
+ example_vars=None,
42
47
  **options,
43
48
  ):
44
49
  """
@@ -60,6 +65,8 @@ class Factory:
60
65
  hints: dict
61
66
  Hints for print_toc, only for variables for which the
62
67
  options are functions or missing
68
+ example_vars: dict, optional
69
+ Variable values for creating an example
63
70
  options: dict
64
71
  For each variable, e.g. A, B or C, the list or dict
65
72
  or function that maps a str to the actual value
@@ -122,6 +129,30 @@ class Factory:
122
129
  f"Factory '{name_template}': Variable '{v}' has option of type '{type(v).__name__}'. Only list, tuple, dict or function are supported"
123
130
  )
124
131
 
132
+ exvars = dict(
133
+ n=5,
134
+ n2=9,
135
+ superposition="linear",
136
+ kTI=0.2,
137
+ kb=0.001,
138
+ step=100,
139
+ dx=100,
140
+ dt="10s",
141
+ )
142
+ if example_vars is not None:
143
+ exvars.update(example_vars)
144
+ try:
145
+ self.example = ""
146
+ for i, v in enumerate(self._vars):
147
+ self.example += f"{self._pre[i]}{exvars[v]}"
148
+ self.example += self._pre[-1]
149
+ if not self.check_match(self.example, error=False):
150
+ raise ValueError(
151
+ f"Example '{self.example}' does not match template '{self.name_template}'"
152
+ )
153
+ except KeyError:
154
+ self.example = None
155
+
125
156
  @property
126
157
  def name_prefix(self):
127
158
  """
@@ -171,56 +202,77 @@ class Factory:
171
202
  s += f"\n {v} from {list(self.options[v])}"
172
203
  else:
173
204
  s += f"\n {v}={self.hints.get(v, '(value)')}"
205
+ if self.example is not None:
206
+ s += f"\nExample: {self.example}"
174
207
  return s
175
208
 
176
- def check_match(self, name):
209
+ def get_examples(self, **var_values):
177
210
  """
178
- Tests if a name matches the template
211
+ Create example names from given values
179
212
 
180
213
  Parameters
181
214
  ----------
182
- name: str
183
- The name to be checked
215
+ var_values: dict
216
+ Variables values. Key: Variable,
217
+ value: list or value
184
218
 
185
219
  Returns
186
220
  -------
187
- success: bool
188
- True if the template is matched
221
+ examples: list of str
222
+ The examples
189
223
 
190
224
  """
191
- data_str = name
192
- for vi in range(len(self.variables)):
193
- p = self._pre[vi]
194
- i = data_str.find(p)
195
- j = i + len(p)
196
- if i < 0 or len(data_str) <= j:
197
- return False
198
- data_str = data_str[j:]
199
-
200
- q = self._pre[vi + 1]
201
- if q != "":
202
- i = data_str.find(q)
203
- j = i + len(q)
204
- if i < 0 or len(data_str) <= j:
205
- return False
225
+
226
+ def gete(i, vals, vars, values, examples):
227
+ if i >= len(vars):
228
+ e = ""
229
+ for i, v in enumerate(self._vars):
230
+ e += f"{self._pre[i]}{vals[v]}"
231
+ e += self._pre[-1]
232
+ self.check_match(e, error=True)
233
+ examples.append(e)
206
234
  else:
207
- data_str = ""
235
+ v = vars[i]
236
+ if v in self._vars:
237
+ vls = np.atleast_1d(values[i])
238
+ for x in vls:
239
+ vals[v] = x
240
+ gete(i + 1, vals, vars, values, examples)
241
+ else:
242
+ gete(i + 1, vals, vars, values, examples)
243
+
244
+ examples = []
245
+ gete(
246
+ 0,
247
+ {},
248
+ list(var_values.keys()),
249
+ list(var_values.values()),
250
+ examples,
251
+ )
208
252
 
209
- return True
253
+ return examples
210
254
 
211
- def construct(self, name):
255
+ def check_match(self, name, error=False, ret_pars=False):
212
256
  """
213
- Create an object of the base class.
257
+ Tests if a name matches the template and constructs
258
+ parameters
214
259
 
215
260
  Parameters
216
261
  ----------
217
262
  name: str
218
- The name, matching the template
263
+ The name to be checked
264
+ error: bool
265
+ Flag for raising a Value error in case of
266
+ mismatch
267
+ ret_pars: bool
268
+ Flag for returning the parameters
219
269
 
220
270
  Returns
221
271
  -------
222
- obj: object
223
- The instance of the base class
272
+ success: bool
273
+ True if the template is matched
274
+ pars: dict, optional
275
+ The constructed parameters
224
276
 
225
277
  """
226
278
  j = 0
@@ -229,9 +281,14 @@ class Factory:
229
281
  if len(p) > 0:
230
282
  i = name[j:].find(p)
231
283
  if i < 0 or (pi == 0 and i > 0):
232
- raise ValueError(
233
- f"Factory '{self.name_template}': Name '{name}' not matching template"
234
- )
284
+ if error:
285
+ raise ValueError(
286
+ f"Factory '{self.name_template}': Name '{name}' not matching template"
287
+ )
288
+ elif ret_pars:
289
+ return False, {}
290
+ else:
291
+ return False
235
292
  w = name[j : j + i]
236
293
  j += i + len(p)
237
294
  else:
@@ -239,21 +296,41 @@ class Factory:
239
296
  if pi > 0:
240
297
  wlist.append(w)
241
298
 
242
- kwargs = {}
243
- for vi, v in enumerate(self.variables):
244
- w = self.var2arg.get(v, v)
245
- data = wlist[vi]
246
- if v in self.options:
247
- o = self.options[v]
248
- if hasattr(o, "__call__"):
249
- kwargs[w] = o(data)
299
+ if ret_pars:
300
+ kwargs = {}
301
+ for vi, v in enumerate(self.variables):
302
+ w = self.var2arg.get(v, v)
303
+ data = wlist[vi]
304
+ if v in self.options:
305
+ o = self.options[v]
306
+ if hasattr(o, "__call__"):
307
+ kwargs[w] = o(data)
308
+ else:
309
+ kwargs[w] = self.options[v][data]
250
310
  else:
251
- kwargs[w] = self.options[v][data]
252
- else:
253
- kwargs[w] = data
311
+ kwargs[w] = data
254
312
 
255
- kwargs.update(self.kwargs)
313
+ kwargs.update(self.kwargs)
314
+ return True, kwargs
315
+
316
+ return True
317
+
318
+ def construct(self, name):
319
+ """
320
+ Create an object of the base class.
321
+
322
+ Parameters
323
+ ----------
324
+ name: str
325
+ The name, matching the template
256
326
 
327
+ Returns
328
+ -------
329
+ obj: object
330
+ The instance of the base class
331
+
332
+ """
333
+ __, kwargs = self.check_match(name, error=True, ret_pars=True)
257
334
  return self.base(*self.args, **kwargs)
258
335
 
259
336
 
@@ -299,14 +376,20 @@ class WakeKFactory:
299
376
  i0 = name_template.find("_[wake_k]")
300
377
  i1 = i0 + len("_[wake_k]")
301
378
  kw = kwargs.pop("kwargs", {})
379
+ v2a = kwargs.pop("var2arg", {})
302
380
 
303
381
  if i0 < 0:
304
382
  raise ValueError(
305
383
  f"String '_[wake_k]' not found in name template '{name_template}'"
306
384
  )
307
385
 
386
+ exvars = dict(k=0.04, ka=0.2, ambka=0.4, kb=0.001)
387
+ if "example_vars" in kwargs:
388
+ exvars.update(kwargs.pop("example_vars"))
389
+
308
390
  # add case ka, kb:
309
- t = name_template[:i0] + "_ka<ka>_kb<kb>"
391
+ t0 = name_template[:i0]
392
+ t = t0 + "_ka<ka>_kb<kb>"
310
393
  if len(name_template) > i1:
311
394
  t += name_template[i1:]
312
395
  h = hints.copy()
@@ -323,17 +406,20 @@ class WakeKFactory:
323
406
  **kwargs,
324
407
  ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
325
408
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
409
+ example_vars=exvars,
326
410
  )
327
411
  )
328
412
 
329
- # add case ambient ka, kb:
330
- t = name_template[:i0] + "_ambka<ka>_kb<kb>"
413
+ # add case ambient ambka, kb:
414
+ t = name_template[:i0] + "_ambka<ambka>_kb<kb>"
331
415
  if len(name_template) > i1:
332
416
  t += name_template[i1:]
333
417
  h = hints.copy()
334
- h["ka"] = "(Value, e.g. 04 for 0.4)"
418
+ h["ambka"] = "(Value, e.g. 04 for 0.4)"
335
419
  h["kb"] = "(Value, e.g. 001 for 0.01)"
336
420
  kw["ti_var"] = FV.AMB_TI
421
+ hv2a = v2a.copy()
422
+ hv2a["ambka"] = "ka"
337
423
  self.factories.append(
338
424
  Factory(
339
425
  base,
@@ -341,9 +427,11 @@ class WakeKFactory:
341
427
  *args,
342
428
  hints=h,
343
429
  kwargs=kw.copy(),
430
+ var2arg=hv2a,
344
431
  **kwargs,
345
- ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
432
+ ambka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
346
433
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
434
+ example_vars=exvars,
347
435
  )
348
436
  )
349
437
 
@@ -363,16 +451,19 @@ class WakeKFactory:
363
451
  kwargs=kw.copy(),
364
452
  **kwargs,
365
453
  ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
454
+ example_vars=exvars,
366
455
  )
367
456
  )
368
457
 
369
- # add case ka:
370
- t = name_template[:i0] + "_ambka<ka>"
458
+ # add case ambka:
459
+ t = name_template[:i0] + "_ambka<ambka>"
371
460
  if len(name_template) > i1:
372
461
  t += name_template[i1:]
373
462
  h = hints.copy()
374
- h["ka"] = "(Value, e.g. 04 for 0.4)"
463
+ h["ambka"] = "(Value, e.g. 04 for 0.4)"
375
464
  kw["ti_var"] = FV.AMB_TI
465
+ hv2a = v2a.copy()
466
+ hv2a["ambka"] = "ka"
376
467
  self.factories.append(
377
468
  Factory(
378
469
  base,
@@ -380,8 +471,10 @@ class WakeKFactory:
380
471
  *args,
381
472
  hints=h,
382
473
  kwargs=kw.copy(),
474
+ var2arg=hv2a,
383
475
  **kwargs,
384
- ka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
476
+ ambka=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
477
+ example_vars=exvars,
385
478
  )
386
479
  )
387
480
 
@@ -401,6 +494,7 @@ class WakeKFactory:
401
494
  kwargs=kw.copy(),
402
495
  **kwargs,
403
496
  k=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
497
+ example_vars=exvars,
404
498
  )
405
499
  )
406
500
 
@@ -417,6 +511,7 @@ class WakeKFactory:
417
511
  hints=hints,
418
512
  kwargs=kw.copy(),
419
513
  **kwargs,
514
+ example_vars=exvars,
420
515
  )
421
516
  )
422
517
 
@@ -41,7 +41,7 @@ class PandasFileHelper:
41
41
  "csv.gz": {},
42
42
  "csv.bz2": {},
43
43
  "csv.zip": {},
44
- "h5": {"key": "flappy", "mode": "w"},
44
+ "h5": {"key": "foxes", "mode": "w"},
45
45
  "nc": {},
46
46
  }
47
47
 
@@ -133,12 +133,13 @@ class PandasFileHelper:
133
133
  format_dict: dict
134
134
  Dictionary with format entries for
135
135
  columns, e.g. '{:.4f}'
136
- **kwargs: dict, optional
136
+ kwargs: dict, optional
137
137
  Parameters forwarded to the pandas writing method.
138
138
 
139
139
  """
140
140
 
141
- fdict = deepcopy(cls.DEFAULT_FORMAT_DICT)
141
+ digits = {c: FV.get_default_digits(c) for c in data.columns}
142
+ fdict = {c: "{:." + str(d) + "f}" for c, d in digits.items() if d is not None}
142
143
  fdict.update(format_dict)
143
144
 
144
145
  out = pd.DataFrame(index=data.index)
foxes/utils/wind_dir.py CHANGED
@@ -24,7 +24,6 @@ def wd2wdvec(wd, ws=1.0, axis=-1):
24
24
  :group: utils
25
25
 
26
26
  """
27
-
28
27
  wdr = wd * np.pi / 180.0
29
28
  n = np.stack([np.sin(wdr), np.cos(wdr)], axis=axis)
30
29
 
@@ -79,7 +78,6 @@ def uv2wd(uv, axis=-1):
79
78
  :group: utils
80
79
 
81
80
  """
82
-
83
81
  if axis == -1:
84
82
  u = uv[..., 0]
85
83
  v = uv[..., 1]
@@ -1,4 +1,10 @@
1
- def write_nc(ds, fpath, round="auto", complevel=5, verbosity=1, **kwargs):
1
+ import netCDF4
2
+ from pathlib import Path
3
+
4
+ from foxes.variables import get_default_digits
5
+
6
+
7
+ def write_nc(ds, fpath, round={}, complevel=9, verbosity=1, **kwargs):
2
8
  """
3
9
  Writes a dataset to netCFD file
4
10
 
@@ -6,9 +12,9 @@ def write_nc(ds, fpath, round="auto", complevel=5, verbosity=1, **kwargs):
6
12
  ----------
7
13
  fpath: str
8
14
  Path to the output file, should be nc
9
- round: dict or str, optional
10
- The rounding definitions, or auto for
11
- default settings
15
+ round: dict
16
+ The rounding digits, falling back to defaults
17
+ if variable not found
12
18
  complevel: int
13
19
  The compression level
14
20
  verbosity: int
@@ -17,21 +23,27 @@ def write_nc(ds, fpath, round="auto", complevel=5, verbosity=1, **kwargs):
17
23
  Additional parameters for xarray.to_netcdf
18
24
 
19
25
  """
20
-
26
+ fpath = Path(fpath)
21
27
  if round is not None:
22
28
  for v in ds.coords.keys():
23
- if v in round:
29
+ d = round.get(v, get_default_digits(v))
30
+ if d is not None:
24
31
  if verbosity > 1:
25
- print(f"Rounding {v} to {round[v]} decimals")
26
- ds[v].data = ds[v].data.round(decimals=round[v])
32
+ print(f"File {fpath.name}: Rounding {v} to {d} decimals")
33
+ ds[v].data = ds[v].data.round(decimals=d)
27
34
  for v in ds.data_vars.keys():
28
- if v in round:
35
+ d = round.get(v, get_default_digits(v))
36
+ if d is not None:
29
37
  if verbosity > 1:
30
- print(f"Rounding {v} to {round[v]} decimals")
31
- ds[v].data = ds[v].data.round(decimals=round[v])
38
+ print(f"File {fpath.name}: Rounding {v} to {d} decimals")
39
+ ds[v].data = ds[v].data.round(decimals=d)
40
+
41
+ enc = None
42
+ if complevel is not None and complevel > 0:
43
+ if verbosity > 1:
44
+ print(f"File {fpath.name}: Compression level = {complevel}")
45
+ enc = {k: {"zlib": True, "complevel": complevel} for k in ds.data_vars}
32
46
 
33
47
  if verbosity > 0:
34
48
  print("Writing file", fpath)
35
-
36
- enc = {k: {"zlib": True, "complevel": complevel} for k in ds.data_vars}
37
49
  ds.to_netcdf(fpath, encoding=enc, **kwargs)
foxes/variables.py CHANGED
@@ -276,3 +276,40 @@ PA_BETA = "PA_beta"
276
276
  """ The beta parameter of the PorteAgel wake model
277
277
  :group: foxes.variables
278
278
  """
279
+
280
+ DEFAULT_DIGITS = {
281
+ WD: 3,
282
+ WS: 4,
283
+ TI: 6,
284
+ RHO: 5,
285
+ P: 3,
286
+ CT: 6,
287
+ T: 3,
288
+ YLD: 3,
289
+ CAP: 5,
290
+ EFF: 5,
291
+ }
292
+ """ The default output digits
293
+ :group: foxes.variables
294
+ """
295
+
296
+
297
+ def get_default_digits(variable):
298
+ """
299
+ Gets the default numbber of output digits
300
+
301
+ Parameters
302
+ ----------
303
+ variable: str
304
+ The variable name
305
+
306
+ Returns
307
+ -------
308
+ digits: int
309
+ The default number of output digits
310
+
311
+ """
312
+ v = amb2var.get(variable, variable)
313
+ if v in [REWS, REWS2, REWS3]:
314
+ v = WS
315
+ return DEFAULT_DIGITS.get(v, None)
@@ -1,13 +1,36 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxes
3
- Version: 0.8.1
3
+ Version: 1.0
4
4
  Summary: Farm Optimization and eXtended yield Evaluation Software
5
- Author: Fraunhofer IWES
6
- Author-email: jonas.schulte@iwes.fraunhofer.de
7
- License: MIT
8
- Project-URL: Source Code, https://github.com/FraunhoferIWES/foxes
9
- Project-URL: Bug Tracker, https://github.com/FraunhoferIWES/foxes/issues
5
+ Author: Jonas Schulte
6
+ Maintainer: Jonas Schulte
7
+ License: MIT License
8
+
9
+ Copyright (c) 2022 FraunhoferIWES
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+
29
+ Project-URL: Homepage, https://github.com/FraunhoferIWES/foxes
10
30
  Project-URL: Documentation, https://fraunhoferiwes.github.io/foxes.docs/index.html
31
+ Project-URL: Repository, https://github.com/FraunhoferIWES/foxes.git
32
+ Project-URL: Bug Tracker, https://github.com/FraunhoferIWES/foxes/issues
33
+ Project-URL: Changelog, https://github.com/FraunhoferIWES/foxes/blob/main/CHANGELOG.md
11
34
  Keywords: Wind farm,Wake modelling,Wind farm optimization
12
35
  Classifier: Topic :: Scientific/Engineering
13
36
  Classifier: Intended Audience :: Developers
@@ -28,40 +51,51 @@ Requires-Dist: matplotlib
28
51
  Requires-Dist: numpy
29
52
  Requires-Dist: pandas
30
53
  Requires-Dist: xarray
31
- Requires-Dist: dask
32
- Requires-Dist: distributed
33
54
  Requires-Dist: scipy
34
55
  Requires-Dist: netcdf4
35
56
  Requires-Dist: windrose
36
- Requires-Dist: pyarrow
37
- Provides-Extra: all
38
- Requires-Dist: windio >=1 ; extra == 'all'
39
- Requires-Dist: flake8 ; extra == 'all'
40
- Requires-Dist: pytest ; extra == 'all'
41
- Requires-Dist: foxes-opt ; extra == 'all'
42
- Requires-Dist: sphinx ; extra == 'all'
43
- Requires-Dist: sphinx-immaterial ; extra == 'all'
44
- Requires-Dist: nbsphinx ; extra == 'all'
45
- Requires-Dist: ipykernel ; extra == 'all'
46
- Requires-Dist: ipywidgets ; extra == 'all'
47
- Requires-Dist: m2r2 ; extra == 'all'
48
- Requires-Dist: lxml-html-clean ; extra == 'all'
57
+ Requires-Dist: cycler
58
+ Requires-Dist: tqdm
59
+ Requires-Dist: pyyaml
60
+ Provides-Extra: dask
61
+ Requires-Dist: dask; extra == "dask"
62
+ Requires-Dist: distributed; extra == "dask"
63
+ Requires-Dist: dask-jobqueue; extra == "dask"
64
+ Requires-Dist: setuptools; extra == "dask"
65
+ Provides-Extra: dev
66
+ Requires-Dist: flake8; extra == "dev"
67
+ Requires-Dist: pytest; extra == "dev"
68
+ Requires-Dist: jupyter; extra == "dev"
69
+ Requires-Dist: objsize; extra == "dev"
70
+ Requires-Dist: black; extra == "dev"
49
71
  Provides-Extra: doc
50
- Requires-Dist: sphinx ; extra == 'doc'
51
- Requires-Dist: sphinx-immaterial ; extra == 'doc'
52
- Requires-Dist: nbsphinx ; extra == 'doc'
53
- Requires-Dist: ipykernel ; extra == 'doc'
54
- Requires-Dist: ipywidgets ; extra == 'doc'
55
- Requires-Dist: m2r2 ; extra == 'doc'
56
- Requires-Dist: lxml-html-clean ; extra == 'doc'
72
+ Requires-Dist: sphinx; extra == "doc"
73
+ Requires-Dist: sphinx-immaterial; extra == "doc"
74
+ Requires-Dist: nbsphinx; extra == "doc"
75
+ Requires-Dist: ipykernel; extra == "doc"
76
+ Requires-Dist: ipywidgets; extra == "doc"
77
+ Requires-Dist: m2r2; extra == "doc"
78
+ Requires-Dist: lxml-html-clean; extra == "doc"
79
+ Provides-Extra: eng
80
+ Requires-Dist: multiprocess; extra == "eng"
81
+ Requires-Dist: dask; extra == "eng"
82
+ Requires-Dist: distributed; extra == "eng"
83
+ Requires-Dist: dask-jobqueue; extra == "eng"
84
+ Requires-Dist: setuptools; extra == "eng"
85
+ Requires-Dist: mpi4py; extra == "eng"
86
+ Provides-Extra: eng0
87
+ Requires-Dist: multiprocess; extra == "eng0"
88
+ Requires-Dist: dask; extra == "eng0"
89
+ Requires-Dist: distributed; extra == "eng0"
90
+ Requires-Dist: dask-jobqueue; extra == "eng0"
91
+ Requires-Dist: setuptools; extra == "eng0"
57
92
  Provides-Extra: io
58
- Requires-Dist: windio >=1 ; extra == 'io'
93
+ Requires-Dist: windio>=1; extra == "io"
59
94
  Provides-Extra: opt
60
- Requires-Dist: foxes-opt ; extra == 'opt'
61
- Provides-Extra: scripts
95
+ Requires-Dist: foxes-opt; extra == "opt"
62
96
  Provides-Extra: test
63
- Requires-Dist: flake8 ; extra == 'test'
64
- Requires-Dist: pytest ; extra == 'test'
97
+ Requires-Dist: flake8; extra == "test"
98
+ Requires-Dist: pytest; extra == "test"
65
99
 
66
100
  # Welcome to foxes
67
101
 
@@ -76,7 +110,11 @@ The software `foxes` is a modular wind farm simulation and wake modelling toolbo
76
110
  - Wake model studies, comparison and validation,
77
111
  - Wind farm simulations invoking complex model chains.
78
112
 
79
- The calculation is fully vectorized and its fast performance is owed to [dask](https://www.dask.org/). Also the parallelization on local or remote clusters is enabled via `dask`. The wind farm
113
+ The fast performance of `foxes` is owed to vectorization and parallelization,
114
+ and it is intended to be used for large wind farms and large timeseries inflow data.
115
+ The parallelization on local or remote clusters is supported, based on
116
+ [dask.distributed](https://distributed.dask.org/en/stable/).
117
+ The wind farm
80
118
  optimization capabilities invoke the [iwopy](https://github.com/FraunhoferIWES/iwopy) package which
81
119
  as well supports vectorization.
82
120