foxes 1.1.1__py3-none-any.whl → 1.2.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 (155) hide show
  1. docs/source/conf.py +3 -1
  2. examples/abl_states/run.py +5 -5
  3. examples/dyn_wakes/run.py +2 -2
  4. examples/induction/run.py +5 -5
  5. examples/random_timeseries/run.py +13 -13
  6. examples/scan_row/run.py +12 -7
  7. examples/sector_management/run.py +11 -7
  8. examples/single_state/run.py +5 -5
  9. examples/tab_file/run.py +1 -1
  10. examples/timelines/run.py +1 -1
  11. examples/timeseries/run.py +5 -5
  12. examples/timeseries_slurm/run.py +5 -5
  13. examples/wind_rose/run.py +1 -1
  14. examples/yawed_wake/run.py +5 -5
  15. foxes/__init__.py +13 -2
  16. foxes/algorithms/downwind/downwind.py +21 -6
  17. foxes/algorithms/downwind/models/init_farm_data.py +5 -2
  18. foxes/algorithms/downwind/models/point_wakes_calc.py +0 -1
  19. foxes/algorithms/iterative/iterative.py +1 -1
  20. foxes/algorithms/sequential/sequential.py +5 -4
  21. foxes/config/__init__.py +1 -0
  22. foxes/config/config.py +134 -0
  23. foxes/constants.py +15 -6
  24. foxes/core/algorithm.py +46 -30
  25. foxes/core/axial_induction_model.py +18 -0
  26. foxes/core/data.py +2 -1
  27. foxes/core/engine.py +43 -49
  28. foxes/core/farm_controller.py +22 -3
  29. foxes/core/farm_data_model.py +6 -2
  30. foxes/core/ground_model.py +19 -0
  31. foxes/core/model.py +2 -1
  32. foxes/core/partial_wakes_model.py +9 -21
  33. foxes/core/point_data_model.py +22 -2
  34. foxes/core/rotor_model.py +9 -21
  35. foxes/core/states.py +2 -17
  36. foxes/core/turbine_model.py +2 -18
  37. foxes/core/turbine_type.py +2 -18
  38. foxes/core/vertical_profile.py +8 -20
  39. foxes/core/wake_frame.py +9 -25
  40. foxes/core/wake_model.py +24 -20
  41. foxes/core/wake_superposition.py +19 -0
  42. foxes/data/__init__.py +1 -1
  43. foxes/data/static_data.py +0 -7
  44. foxes/engines/dask.py +4 -3
  45. foxes/engines/single.py +1 -1
  46. foxes/input/__init__.py +1 -1
  47. foxes/input/farm_layout/from_csv.py +3 -1
  48. foxes/input/farm_layout/from_file.py +10 -10
  49. foxes/input/farm_layout/from_json.py +4 -3
  50. foxes/input/farm_layout/grid.py +3 -3
  51. foxes/input/states/__init__.py +1 -1
  52. foxes/input/states/create/random_abl_states.py +5 -3
  53. foxes/input/states/field_data_nc.py +36 -15
  54. foxes/input/states/multi_height.py +26 -15
  55. foxes/input/states/one_point_flow.py +6 -5
  56. foxes/input/states/{scan_ws.py → scan.py} +42 -52
  57. foxes/input/states/single.py +15 -6
  58. foxes/input/states/slice_data_nc.py +18 -12
  59. foxes/input/states/states_table.py +17 -10
  60. foxes/input/yaml/__init__.py +3 -0
  61. foxes/input/yaml/dict.py +381 -0
  62. foxes/input/yaml/windio/__init__.py +4 -0
  63. foxes/input/{windio → yaml/windio}/get_states.py +7 -7
  64. foxes/input/{windio → yaml/windio}/read_attributes.py +61 -40
  65. foxes/input/{windio → yaml/windio}/read_farm.py +34 -43
  66. foxes/input/{windio → yaml/windio}/read_fields.py +11 -10
  67. foxes/input/yaml/windio/read_outputs.py +147 -0
  68. foxes/input/yaml/windio/windio.py +269 -0
  69. foxes/input/yaml/yaml.py +103 -0
  70. foxes/models/partial_wakes/axiwake.py +7 -6
  71. foxes/models/partial_wakes/centre.py +3 -2
  72. foxes/models/partial_wakes/segregated.py +5 -2
  73. foxes/models/point_models/set_uniform_data.py +5 -3
  74. foxes/models/rotor_models/centre.py +2 -2
  75. foxes/models/rotor_models/grid.py +5 -5
  76. foxes/models/rotor_models/levels.py +6 -6
  77. foxes/models/turbine_models/kTI_model.py +3 -1
  78. foxes/models/turbine_models/lookup_table.py +7 -4
  79. foxes/models/turbine_models/power_mask.py +14 -8
  80. foxes/models/turbine_models/sector_management.py +4 -2
  81. foxes/models/turbine_models/set_farm_vars.py +53 -23
  82. foxes/models/turbine_models/table_factors.py +8 -7
  83. foxes/models/turbine_models/yaw2yawm.py +0 -1
  84. foxes/models/turbine_models/yawm2yaw.py +0 -1
  85. foxes/models/turbine_types/CpCt_file.py +6 -3
  86. foxes/models/turbine_types/CpCt_from_two.py +6 -3
  87. foxes/models/turbine_types/PCt_file.py +7 -6
  88. foxes/models/turbine_types/PCt_from_two.py +11 -2
  89. foxes/models/turbine_types/TBL_file.py +3 -4
  90. foxes/models/turbine_types/wsrho2PCt_from_two.py +19 -11
  91. foxes/models/turbine_types/wsti2PCt_from_two.py +19 -11
  92. foxes/models/vertical_profiles/abl_log_neutral_ws.py +1 -1
  93. foxes/models/vertical_profiles/abl_log_stable_ws.py +1 -1
  94. foxes/models/vertical_profiles/abl_log_unstable_ws.py +1 -1
  95. foxes/models/vertical_profiles/abl_log_ws.py +1 -1
  96. foxes/models/wake_frames/dynamic_wakes.py +17 -9
  97. foxes/models/wake_frames/farm_order.py +4 -3
  98. foxes/models/wake_frames/rotor_wd.py +3 -1
  99. foxes/models/wake_frames/seq_dynamic_wakes.py +14 -7
  100. foxes/models/wake_frames/streamlines.py +9 -6
  101. foxes/models/wake_frames/timelines.py +21 -14
  102. foxes/models/wake_frames/yawed_wakes.py +3 -1
  103. foxes/models/wake_models/induction/vortex_sheet.py +0 -1
  104. foxes/models/wake_models/ti/crespo_hernandez.py +2 -1
  105. foxes/models/wake_models/wind/bastankhah14.py +3 -2
  106. foxes/models/wake_models/wind/bastankhah16.py +2 -1
  107. foxes/models/wake_models/wind/turbopark.py +9 -7
  108. foxes/models/wake_superpositions/ws_product.py +0 -1
  109. foxes/output/__init__.py +2 -1
  110. foxes/output/calc_points.py +7 -4
  111. foxes/output/farm_layout.py +30 -18
  112. foxes/output/farm_results_eval.py +61 -38
  113. foxes/output/grids.py +8 -7
  114. foxes/output/output.py +9 -20
  115. foxes/output/plt.py +19 -0
  116. foxes/output/results_writer.py +10 -11
  117. foxes/output/rose_plot.py +448 -224
  118. foxes/output/rotor_point_plots.py +7 -3
  119. foxes/output/slice_data.py +1 -1
  120. foxes/output/state_turbine_map.py +5 -1
  121. foxes/output/state_turbine_table.py +7 -3
  122. foxes/output/turbine_type_curves.py +7 -2
  123. foxes/utils/__init__.py +1 -2
  124. foxes/utils/dict.py +107 -3
  125. foxes/utils/geopandas_utils.py +3 -2
  126. foxes/utils/subclasses.py +69 -0
  127. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/METADATA +18 -18
  128. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/RECORD +145 -145
  129. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/WHEEL +1 -1
  130. foxes-1.2.1.dist-info/entry_points.txt +3 -0
  131. tests/0_consistency/iterative/test_iterative.py +65 -67
  132. tests/0_consistency/partial_wakes/test_partial_wakes.py +58 -61
  133. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +56 -53
  134. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +41 -41
  135. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +34 -34
  136. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +57 -52
  137. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +58 -54
  138. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +80 -76
  139. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +80 -76
  140. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +58 -51
  141. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +101 -103
  142. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +67 -64
  143. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +58 -54
  144. examples/windio/run.py +0 -29
  145. foxes/data/states/windio_timeseries_5000.nc +0 -0
  146. foxes/data/windio/DTU_10MW_turbine.yaml +0 -10
  147. foxes/data/windio/__init__.py +0 -0
  148. foxes/data/windio/windio_5turbines_timeseries.yaml +0 -79
  149. foxes/input/windio/__init__.py +0 -11
  150. foxes/input/windio/read_outputs.py +0 -172
  151. foxes/input/windio/runner.py +0 -183
  152. foxes/input/windio/windio.py +0 -193
  153. foxes/utils/windrose_plot.py +0 -152
  154. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/LICENSE +0 -0
  155. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,7 @@ from cycler import cycler
4
4
  import matplotlib.pyplot as plt
5
5
 
6
6
  from .output import Output
7
+ from foxes.config import config
7
8
  import foxes.variables as FV
8
9
  import foxes.constants as FC
9
10
 
@@ -63,7 +64,12 @@ class FarmResultsEval(Output):
63
64
  fields = []
64
65
  for v in vars:
65
66
  if isinstance(v, str):
66
- fields.append(self.results[v].to_numpy())
67
+ vdata = self.results[v].to_numpy()
68
+ nns = np.sum(np.isnan(vdata))
69
+ assert (
70
+ nns == 0
71
+ ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
72
+ fields.append(vdata)
67
73
  else:
68
74
  fields.append(v)
69
75
  if nas is None:
@@ -98,7 +104,7 @@ class FarmResultsEval(Output):
98
104
  vars_op: dict
99
105
  The operation per variable. Key: str, the variable
100
106
  name. Value: str, the operation, choices
101
- are: sum, mean, min, max.
107
+ are: weights, mean_no_weights, sum, min, max.
102
108
 
103
109
  Returns
104
110
  -------
@@ -110,23 +116,27 @@ class FarmResultsEval(Output):
110
116
 
111
117
  rdata = {}
112
118
  for v, op in vars_op.items():
113
- if op == "mean":
114
- rdata[v] = self.weinsum("t", v)
119
+ vdata = self.results[v].to_numpy()
120
+ nns = np.sum(np.isnan(vdata))
121
+ assert (
122
+ nns == 0
123
+ ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
124
+
125
+ if op == "weights":
126
+ rdata[v] = self.weinsum("t", vdata)
127
+ elif op == "mean_no_weights":
128
+ rdata[v] = np.mean(vdata, axis=0)
115
129
  elif op == "sum":
116
- vdata = self.results[v].to_numpy()
117
130
  rdata[v] = np.sum(vdata, axis=0)
118
131
  elif op == "min":
119
- vdata = self.results[v].to_numpy()
120
132
  rdata[v] = np.min(vdata, axis=0)
121
133
  elif op == "max":
122
- vdata = self.results[v].to_numpy()
123
134
  rdata[v] = np.max(vdata, axis=0)
124
135
  elif op == "std":
125
- vdata = self.results[v].to_numpy()
126
136
  rdata[v] = np.std(vdata, axis=0)
127
137
  else:
128
138
  raise KeyError(
129
- f"Unknown operation '{op}' for variable '{v}'. Please choose: sum, mean, min, max"
139
+ f"Unknown operation '{op}' for variable '{v}'. Please choose: weights, mean_no_weights, sum, min, max"
130
140
  )
131
141
 
132
142
  data = pd.DataFrame(index=range(n_turbines), data=rdata)
@@ -143,7 +153,7 @@ class FarmResultsEval(Output):
143
153
  vars_op: dict
144
154
  The operation per variable. Key: str, the variable
145
155
  name. Value: str, the operation, choices
146
- are: sum, mean, min, max.
156
+ are: weights, mean_no_weights, sum, min, max.
147
157
 
148
158
  Returns
149
159
  -------
@@ -155,20 +165,25 @@ class FarmResultsEval(Output):
155
165
 
156
166
  rdata = {}
157
167
  for v, op in vars_op.items():
158
- if op == "mean":
159
- rdata[v] = self.weinsum("s", v)
168
+ vdata = self.results[v].to_numpy()
169
+ nns = np.sum(np.isnan(vdata))
170
+ assert (
171
+ nns == 0
172
+ ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
173
+
174
+ if op == "weights":
175
+ rdata[v] = self.weinsum("s", vdata)
176
+ elif op == "mean_no_weights":
177
+ rdata[v] = np.mean(vdata, axis=1)
160
178
  elif op == "sum":
161
- vdata = self.results[v].to_numpy()
162
179
  rdata[v] = np.sum(vdata, axis=1)
163
180
  elif op == "min":
164
- vdata = self.results[v].to_numpy()
165
181
  rdata[v] = np.min(vdata, axis=1)
166
182
  elif op == "max":
167
- vdata = self.results[v].to_numpy()
168
183
  rdata[v] = np.max(vdata, axis=1)
169
184
  else:
170
185
  raise KeyError(
171
- f"Unknown operation '{op}' for variable '{v}'. Please choose: sum, mean, min, max"
186
+ f"Unknown operation '{op}' for variable '{v}'. Please choose: weights, mean_no_weights, sum, min, max"
172
187
  )
173
188
 
174
189
  data = pd.DataFrame(index=states, data=rdata)
@@ -204,29 +219,32 @@ class FarmResultsEval(Output):
204
219
  rdata = {}
205
220
  for v, op in turbines_op.items():
206
221
  vdata = sdata[v].to_numpy()
207
- if op == "mean":
208
- if states_op[v] == "mean":
222
+ nns = np.sum(np.isnan(vdata))
223
+ assert (
224
+ nns == 0
225
+ ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
226
+
227
+ if op == "weights":
228
+ if states_op[v] == "weights":
209
229
  rdata[v] = self.weinsum("", v)
210
230
  else:
211
- vdata = sdata[v].to_numpy()
212
231
  rdata[v] = self.weinsum("", vdata[None, :])
232
+ elif op == "mean_no_weights":
233
+ rdata[v] = np.sum(vdata)
213
234
  elif op == "sum":
214
- vdata = sdata[v].to_numpy()
215
235
  rdata[v] = np.sum(vdata)
216
236
  elif op == "min":
217
- vdata = sdata[v].to_numpy()
218
237
  rdata[v] = np.min(vdata)
219
238
  elif op == "max":
220
- vdata = sdata[v].to_numpy()
221
239
  rdata[v] = np.max(vdata)
222
240
  else:
223
241
  raise KeyError(
224
- f"Unknown operation '{op}' for variable '{v}'. Please choose: sum, mean, min, max"
242
+ f"Unknown operation '{op}' for variable '{v}'. Please choose: sum, mean, min, max, weights"
225
243
  )
226
244
 
227
245
  return rdata
228
246
 
229
- def calc_states_mean(self, vars):
247
+ def calc_states_mean(self, vars, use_weights=True):
230
248
  """
231
249
  Calculates the mean wrt states.
232
250
 
@@ -234,6 +252,8 @@ class FarmResultsEval(Output):
234
252
  ----------
235
253
  vars: list of str
236
254
  The variables
255
+ use_weights: bool
256
+ Flag for using states weights for the mean
237
257
 
238
258
  Returns
239
259
  -------
@@ -241,9 +261,10 @@ class FarmResultsEval(Output):
241
261
  The results per turbine
242
262
 
243
263
  """
264
+ r = "weights" if use_weights else "mean_no_weights"
244
265
  if isinstance(vars, str):
245
- return self.reduce_states({vars: "mean"})
246
- return self.reduce_states({v: "mean" for v in vars})
266
+ return self.reduce_states({vars: r})
267
+ return self.reduce_states({v: r for v in vars})
247
268
 
248
269
  def calc_states_sum(self, vars):
249
270
  """
@@ -290,7 +311,7 @@ class FarmResultsEval(Output):
290
311
  The results per state
291
312
 
292
313
  """
293
- return self.reduce_turbines({v: "mean" for v in vars})
314
+ return self.reduce_turbines({v: "mean_no_weights" for v in vars})
294
315
 
295
316
  def calc_turbine_sum(self, vars):
296
317
  """
@@ -324,7 +345,7 @@ class FarmResultsEval(Output):
324
345
  The fully contracted results
325
346
 
326
347
  """
327
- op = {v: "mean" for v in vars}
348
+ op = {v: "weights" for v in vars}
328
349
  return self.reduce_all(states_op=op, turbines_op=op)
329
350
 
330
351
  def calc_farm_sum(self, vars):
@@ -361,7 +382,7 @@ class FarmResultsEval(Output):
361
382
 
362
383
  """
363
384
  v = FV.P if not ambient else FV.AMB_P
364
- cdata = self.reduce_all(states_op={v: "mean"}, turbines_op={v: "sum"})
385
+ cdata = self.reduce_all(states_op={v: "weights"}, turbines_op={v: "sum"})
365
386
  return cdata[v]
366
387
 
367
388
  def calc_turbine_yield(
@@ -409,7 +430,7 @@ class FarmResultsEval(Output):
409
430
  if algo is not None and P_unit_W is None:
410
431
  P_unit_W = np.array(
411
432
  [FC.P_UNITS[t.P_unit] for t in algo.farm_controller.turbine_types],
412
- dtype=FC.DTYPE,
433
+ dtype=config.dtype_double,
413
434
  )[:, None]
414
435
  elif algo is None and P_unit_W is not None:
415
436
  pass
@@ -472,10 +493,10 @@ class FarmResultsEval(Output):
472
493
  if algo is not None and P_nom is None:
473
494
  P_nom = np.array(
474
495
  [t.P_nominal for t in algo.farm_controller.turbine_types],
475
- dtype=FC.DTYPE,
496
+ dtype=config.dtype_double,
476
497
  )
477
498
  elif algo is None and P_nom is not None:
478
- P_nom = np.array(P_nom, dtype=FC.DTYPE)
499
+ P_nom = np.array(P_nom, dtype=config.dtype_double)
479
500
  else:
480
501
  raise KeyError("Expecting either 'algo' or 'P_nom'")
481
502
 
@@ -535,10 +556,12 @@ class FarmResultsEval(Output):
535
556
  The verbosity level, 0 = silent
536
557
 
537
558
  """
538
- P = self.results[FV.P]
539
- P0 = self.results[FV.AMB_P] + 1e-14
540
- self.results[FV.EFF] = P / P0 # add to farm results
541
- if verbosity:
559
+ P = self.results[FV.P].to_numpy()
560
+ P0 = np.maximum(self.results[FV.AMB_P].to_numpy(), 1e-12)
561
+ eff = np.minimum(P / P0, 1)
562
+ eff[P < 1e-10] = 0
563
+ self.results[FV.EFF] = (self.results[FV.AMB_P].dims, eff)
564
+ if verbosity > 0:
542
565
  print("Efficiency added to farm results")
543
566
 
544
567
  def calc_farm_efficiency(self):
@@ -552,8 +575,8 @@ class FarmResultsEval(Output):
552
575
 
553
576
  """
554
577
  P = self.calc_mean_farm_power()
555
- P0 = self.calc_mean_farm_power(ambient=True) + 1e-14
556
- return P / P0
578
+ P0 = np.maximum(self.calc_mean_farm_power(ambient=True), 1e-14)
579
+ return np.minimum(P / P0, 1)
557
580
 
558
581
  def gen_stdata(
559
582
  self,
foxes/output/grids.py CHANGED
@@ -3,6 +3,7 @@ import pandas as pd
3
3
  from xarray import Dataset
4
4
 
5
5
  from foxes.utils import wd2uv, write_nc
6
+ from foxes.config import config
6
7
  import foxes.variables as FV
7
8
  import foxes.constants as FC
8
9
 
@@ -151,7 +152,7 @@ def get_grid_xy(
151
152
  N_x, N_y = len(x_pos), len(y_pos)
152
153
  n_pts = len(x_pos) * len(y_pos)
153
154
  z_pos = 0.5 * (z_min + z_max)
154
- g_pts = np.zeros((n_states, N_x, N_y, 3), dtype=FC.DTYPE)
155
+ g_pts = np.zeros((n_states, N_x, N_y, 3), dtype=config.dtype_double)
155
156
  g_pts[:, :, :, 0] = x_pos[None, :, None]
156
157
  g_pts[:, :, :, 1] = y_pos[None, None, :]
157
158
  g_pts[:, :, :, 2] = z_pos
@@ -248,7 +249,7 @@ def get_grid_xz(
248
249
  n_y = np.cross(n_z, n_x)
249
250
 
250
251
  # project to axes:
251
- xyz = np.zeros((n_states, n_turbines, 3), dtype=FC.DTYPE)
252
+ xyz = np.zeros((n_states, n_turbines, 3), dtype=config.dtype_double)
252
253
  xyz[:, :, 0] = farm_results[FV.X]
253
254
  xyz[:, :, 1] = farm_results[FV.Y]
254
255
  xyz[:, :, 2] = farm_results[FV.H]
@@ -297,7 +298,7 @@ def get_grid_xz(
297
298
  N_x, N_z = len(x_pos), len(z_pos)
298
299
  n_pts = len(x_pos) * len(z_pos)
299
300
  y_pos = 0.5 * (y_min + y_max)
300
- g_pts = np.zeros((n_states, N_x, N_z, 3), dtype=FC.DTYPE)
301
+ g_pts = np.zeros((n_states, N_x, N_z, 3), dtype=config.dtype_double)
301
302
  g_pts[:] += x_pos[None, :, None, None] * n_x[None, None, None, :]
302
303
  g_pts[:] += y_pos * n_y[None, None, None, :]
303
304
  g_pts[:] += z_pos[None, None, :, None] * n_z[None, None, None, :]
@@ -394,7 +395,7 @@ def get_grid_yz(
394
395
  n_y = np.cross(n_z, n_x)
395
396
 
396
397
  # project to axes:
397
- xyz = np.zeros((n_states, n_turbines, 3), dtype=FC.DTYPE)
398
+ xyz = np.zeros((n_states, n_turbines, 3), dtype=config.dtype_double)
398
399
  xyz[:, :, 0] = farm_results[FV.X]
399
400
  xyz[:, :, 1] = farm_results[FV.Y]
400
401
  xyz[:, :, 2] = farm_results[FV.H]
@@ -443,7 +444,7 @@ def get_grid_yz(
443
444
  N_y, N_z = len(y_pos), len(z_pos)
444
445
  n_pts = len(y_pos) * len(z_pos)
445
446
  x_pos = 0.5 * (x_min + x_max)
446
- g_pts = np.zeros((n_states, N_y, N_z, 3), dtype=FC.DTYPE)
447
+ g_pts = np.zeros((n_states, N_y, N_z, 3), dtype=config.dtype_double)
447
448
  g_pts[:] += x_pos * n_x[None, None, None, :]
448
449
  g_pts[:] += y_pos[None, :, None, None] * n_y[None, None, None, :]
449
450
  g_pts[:] += z_pos[None, None, :, None] * n_z[None, None, None, :]
@@ -491,7 +492,7 @@ def np2np_p(data, a_pos, b_pos):
491
492
  n_a = len(a_pos)
492
493
  n_b = len(b_pos)
493
494
  n_v = len(data)
494
- out = np.zeros((n_a, n_b, n_v), dtype=FC.DTYPE)
495
+ out = np.zeros((n_a, n_b, n_v), dtype=config.dtype_double)
495
496
  for vi, (v, d) in enumerate(data.items()):
496
497
  out[:, :, vi] = d.reshape(n_a, n_b)
497
498
  return out
@@ -526,7 +527,7 @@ def np2np_sp(data, states, a_pos, b_pos):
526
527
  n_a = len(a_pos)
527
528
  n_b = len(b_pos)
528
529
  n_v = len(data)
529
- out = np.zeros((n_s, n_a, n_b, n_v), dtype=FC.DTYPE)
530
+ out = np.zeros((n_s, n_a, n_b, n_v), dtype=config.dtype_double)
530
531
  for vi, (v, d) in enumerate(data.items()):
531
532
  out[:, :, :, vi] = d.reshape(n_s, n_a, n_b)
532
533
  return out
foxes/output/output.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from pathlib import Path
2
2
 
3
- from foxes.utils import PandasFileHelper, all_subclasses
3
+ from foxes.config import config, get_path
4
+ from foxes.utils import PandasFileHelper, new_instance, all_subclasses
4
5
 
5
6
 
6
7
  class Output:
@@ -33,9 +34,13 @@ class Output:
33
34
  Modifies file names by f(fname)
34
35
 
35
36
  """
36
- self.out_dir = Path(out_dir) if out_dir is not None else None
37
+ self.out_dir = get_path(out_dir) if out_dir is not None else config.out_dir
37
38
  self.out_fname_fun = out_fname_fun
38
39
 
40
+ if not self.out_dir.is_dir():
41
+ print(f"{type(self).__name__}: Creating output dir {self.out_dir}")
42
+ self.out_dir.mkdir(parents=True)
43
+
39
44
  def get_fpath(self, fname):
40
45
  """
41
46
  Gets the total file path
@@ -54,7 +59,7 @@ class Output:
54
59
  fnm = Path(fname)
55
60
  if self.out_fname_fun is not None:
56
61
  fnm = self.out_fname_fun(fnm)
57
- return self.out_dir / fnm if self.out_dir is not None else fnm
62
+ return self.out_dir / fnm if self.out_dir is not None else get_path(fnm)
58
63
 
59
64
  def write(self, file_name, data, format_col2var={}, format_dict={}, **kwargs):
60
65
  """
@@ -111,20 +116,4 @@ class Output:
111
116
  Additional parameters for the constructor
112
117
 
113
118
  """
114
-
115
- if output_type is None:
116
- return None
117
-
118
- allc = all_subclasses(cls)
119
- found = output_type in [scls.__name__ for scls in allc]
120
-
121
- if found:
122
- for scls in allc:
123
- if scls.__name__ == output_type:
124
- return scls(*args, **kwargs)
125
-
126
- else:
127
- estr = "Output type '{}' is not defined, available types are \n {}".format(
128
- output_type, sorted([i.__name__ for i in allc])
129
- )
130
- raise KeyError(estr)
119
+ return new_instance(cls, output_type, *args, **kwargs)
foxes/output/plt.py ADDED
@@ -0,0 +1,19 @@
1
+ from matplotlib import pyplot
2
+
3
+ from .output import Output
4
+
5
+
6
+ class plt(Output):
7
+ """
8
+ Class that runs plt commands
9
+
10
+ :group: output
11
+
12
+ """
13
+
14
+ def __getattr__(self, name):
15
+ return getattr(pyplot, name)
16
+
17
+ def savefig(self, fname, *args, **kwargs):
18
+ fpath = super().get_fpath(fname)
19
+ pyplot.savefig(fpath, *args, **kwargs)
@@ -1,8 +1,8 @@
1
1
  import pandas as pd
2
2
  from xarray import Dataset
3
3
 
4
- import foxes.constants as FC
5
4
  from foxes.utils import write_nc
5
+ import foxes.constants as FC
6
6
 
7
7
  from .output import Output
8
8
 
@@ -70,7 +70,7 @@ class ResultsWriter(Output):
70
70
 
71
71
  def write_csv(
72
72
  self,
73
- file_path,
73
+ file_name,
74
74
  variables=None,
75
75
  turbine_names=False,
76
76
  state_turbine_table=False,
@@ -82,8 +82,8 @@ class ResultsWriter(Output):
82
82
 
83
83
  Parameters
84
84
  ----------
85
- file_path: str
86
- Path for the csv file
85
+ file_name: str
86
+ Name of the csv file
87
87
  variables: dict or list of str, optional
88
88
  The variables to be written. If a dict, then
89
89
  the keys are the foxes variables and the values
@@ -101,7 +101,7 @@ class ResultsWriter(Output):
101
101
 
102
102
  """
103
103
  if verbosity:
104
- print(f"ResultsWriter: Writing file '{file_path}'")
104
+ print(f"ResultsWriter: Writing file '{file_name}'")
105
105
 
106
106
  data, variables = self._get_data_vars(variables)
107
107
  data.reset_index(inplace=True)
@@ -133,12 +133,11 @@ class ResultsWriter(Output):
133
133
  else:
134
134
  data.set_index([FC.STATE, tix], inplace=True)
135
135
 
136
- fpath = self.get_fpath(file_path)
137
- super().write(fpath, data, format_col2var=fc2v, **kwargs)
136
+ super().write(file_name, data, format_col2var=fc2v, **kwargs)
138
137
 
139
138
  def write_nc(
140
139
  self,
141
- file_path,
140
+ file_name,
142
141
  variables=None,
143
142
  turbine_names=False,
144
143
  verbosity=1,
@@ -149,8 +148,8 @@ class ResultsWriter(Output):
149
148
 
150
149
  Parameters
151
150
  ----------
152
- file_path: str
153
- Path for the nc file
151
+ file_name: str
152
+ The nc file name
154
153
  variables: dict or list of str, optional
155
154
  The variables to be written. If a dict, then
156
155
  the keys are the foxes variables and the values
@@ -185,5 +184,5 @@ class ResultsWriter(Output):
185
184
  },
186
185
  )
187
186
 
188
- fpath = self.get_fpath(file_path)
187
+ fpath = self.get_fpath(file_name)
189
188
  write_nc(ds, fpath, verbosity=verbosity, **kwargs)