foxes 1.4__py3-none-any.whl → 1.5__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 (85) hide show
  1. docs/source/conf.py +1 -1
  2. examples/field_data_nc/run.py +1 -1
  3. examples/streamline_wakes/run.py +2 -2
  4. examples/yawed_wake/run.py +3 -1
  5. foxes/algorithms/downwind/downwind.py +5 -5
  6. foxes/algorithms/downwind/models/init_farm_data.py +58 -28
  7. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  8. foxes/core/algorithm.py +5 -5
  9. foxes/core/data.py +75 -4
  10. foxes/core/data_calc_model.py +4 -2
  11. foxes/core/engine.py +33 -40
  12. foxes/core/farm_data_model.py +16 -13
  13. foxes/core/model.py +19 -1
  14. foxes/core/point_data_model.py +19 -14
  15. foxes/core/rotor_model.py +1 -0
  16. foxes/core/wake_deflection.py +3 -3
  17. foxes/data/states/point_cloud_100.nc +0 -0
  18. foxes/data/states/weibull_cloud_4.nc +0 -0
  19. foxes/data/states/weibull_grid.nc +0 -0
  20. foxes/engines/dask.py +3 -6
  21. foxes/engines/default.py +2 -2
  22. foxes/engines/numpy.py +11 -10
  23. foxes/engines/pool.py +20 -11
  24. foxes/engines/single.py +8 -6
  25. foxes/input/farm_layout/__init__.py +1 -0
  26. foxes/input/farm_layout/from_arrays.py +68 -0
  27. foxes/input/states/__init__.py +7 -1
  28. foxes/input/states/dataset_states.py +710 -0
  29. foxes/input/states/field_data.py +531 -0
  30. foxes/input/states/multi_height.py +2 -0
  31. foxes/input/states/one_point_flow.py +1 -0
  32. foxes/input/states/point_cloud_data.py +618 -0
  33. foxes/input/states/scan.py +2 -0
  34. foxes/input/states/single.py +2 -0
  35. foxes/input/states/states_table.py +13 -23
  36. foxes/input/states/weibull_sectors.py +182 -77
  37. foxes/input/states/wrg_states.py +1 -1
  38. foxes/input/yaml/dict.py +25 -24
  39. foxes/input/yaml/windio/read_attributes.py +40 -27
  40. foxes/input/yaml/windio/read_farm.py +12 -10
  41. foxes/input/yaml/windio/read_outputs.py +25 -15
  42. foxes/input/yaml/windio/read_site.py +121 -12
  43. foxes/input/yaml/windio/windio.py +22 -10
  44. foxes/input/yaml/yaml.py +1 -0
  45. foxes/models/model_book.py +16 -15
  46. foxes/models/rotor_models/__init__.py +1 -0
  47. foxes/models/rotor_models/centre.py +1 -1
  48. foxes/models/rotor_models/direct_infusion.py +241 -0
  49. foxes/models/turbine_models/calculator.py +16 -3
  50. foxes/models/turbine_models/kTI_model.py +1 -0
  51. foxes/models/turbine_models/lookup_table.py +2 -0
  52. foxes/models/turbine_models/power_mask.py +1 -0
  53. foxes/models/turbine_models/rotor_centre_calc.py +2 -0
  54. foxes/models/turbine_models/sector_management.py +1 -0
  55. foxes/models/turbine_models/set_farm_vars.py +3 -8
  56. foxes/models/turbine_models/table_factors.py +2 -0
  57. foxes/models/turbine_models/thrust2ct.py +1 -0
  58. foxes/models/turbine_models/yaw2yawm.py +2 -0
  59. foxes/models/turbine_models/yawm2yaw.py +2 -0
  60. foxes/models/turbine_types/PCt_file.py +2 -4
  61. foxes/models/turbine_types/PCt_from_two.py +1 -0
  62. foxes/models/turbine_types/__init__.py +1 -0
  63. foxes/models/turbine_types/calculator_type.py +123 -0
  64. foxes/models/turbine_types/null_type.py +1 -0
  65. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
  66. foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
  67. foxes/output/farm_layout.py +2 -0
  68. foxes/output/farm_results_eval.py +4 -1
  69. foxes/output/flow_plots_2d/flow_plots.py +18 -0
  70. foxes/output/flow_plots_2d/get_fig.py +1 -0
  71. foxes/output/output.py +6 -1
  72. foxes/output/results_writer.py +1 -1
  73. foxes/output/rose_plot.py +10 -0
  74. foxes/output/rotor_point_plots.py +3 -0
  75. foxes/output/state_turbine_map.py +3 -0
  76. foxes/output/turbine_type_curves.py +3 -0
  77. foxes/utils/dict.py +46 -34
  78. foxes/utils/factory.py +2 -2
  79. {foxes-1.4.dist-info → foxes-1.5.dist-info}/METADATA +32 -52
  80. {foxes-1.4.dist-info → foxes-1.5.dist-info}/RECORD +84 -76
  81. foxes/input/states/field_data_nc.py +0 -833
  82. {foxes-1.4.dist-info → foxes-1.5.dist-info}/WHEEL +0 -0
  83. {foxes-1.4.dist-info → foxes-1.5.dist-info}/entry_points.txt +0 -0
  84. {foxes-1.4.dist-info → foxes-1.5.dist-info}/licenses/LICENSE +0 -0
  85. {foxes-1.4.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
@@ -98,7 +98,7 @@ class StatesTable(States):
98
98
  self._N = None
99
99
  self._tvars = None
100
100
  self._profiles = None
101
- self._data_source = data_source
101
+ self._data = data_source
102
102
 
103
103
  @property
104
104
  def data_source(self):
@@ -115,7 +115,7 @@ class StatesTable(States):
115
115
  raise ValueError(
116
116
  f"States '{self.name}': Cannot access data_source while running"
117
117
  )
118
- return self._data_source
118
+ return self._data
119
119
 
120
120
  def reset(self, algo=None, states_sel=None, states_loc=None, verbosity=0):
121
121
  """
@@ -210,13 +210,13 @@ class StatesTable(States):
210
210
  if isinstance(self.data_source, pd.DataFrame):
211
211
  data = self.data_source
212
212
  else:
213
- self._data_source = get_input_path(self.data_source)
213
+ self._data = get_input_path(self.data_source)
214
214
  if not self.data_source.is_file():
215
215
  if verbosity > 0:
216
216
  print(
217
217
  f"States '{self.name}': Reading static data '{self.data_source}' from context '{STATES}'"
218
218
  )
219
- self._data_source = algo.dbook.get_file_path(
219
+ self._data = algo.dbook.get_file_path(
220
220
  STATES, self.data_source.name, check_raw=False
221
221
  )
222
222
  if verbosity > 0:
@@ -343,10 +343,10 @@ class StatesTable(States):
343
343
  super().set_running(algo, data_stash, sel, isel, verbosity)
344
344
 
345
345
  data_stash[self.name] = dict(
346
- data_source=self._data_source,
346
+ data_source=self._data,
347
347
  inds=self.__inds,
348
348
  )
349
- del self._data_source, self.__inds
349
+ del self._data, self.__inds
350
350
 
351
351
  def unset_running(
352
352
  self,
@@ -378,7 +378,7 @@ class StatesTable(States):
378
378
  super().unset_running(algo, data_stash, sel, isel, verbosity)
379
379
 
380
380
  data = data_stash[self.name]
381
- self._data_source = data.pop("data_source")
381
+ self._data = data.pop("data_source")
382
382
  self.__inds = data.pop("inds")
383
383
 
384
384
  def calculate(self, algo, mdata, fdata, tdata):
@@ -407,23 +407,13 @@ class StatesTable(States):
407
407
  (n_states, n_targets, n_tpoints)
408
408
 
409
409
  """
410
+ self.ensure_output_vars(algo, tdata)
411
+
410
412
  for i, v in enumerate(self._tvars):
411
- if v in tdata:
412
- tdata[v][:] = mdata[self.DATA][:, i, None, None]
413
- else:
414
- tdata[v] = np.zeros(
415
- (tdata.n_states, tdata.n_targets, tdata.n_tpoints),
416
- dtype=config.dtype_double,
417
- )
418
- tdata[v][:] = mdata[self.DATA][:, i, None, None]
419
- tdata.dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
413
+ tdata[v][:] = mdata[self.DATA][:, i, None, None]
420
414
 
421
415
  for v, f in self.fixed_vars.items():
422
- tdata[v] = np.full(
423
- (tdata.n_states, tdata.n_targets, tdata.n_tpoints),
424
- f,
425
- dtype=config.dtype_double,
426
- )
416
+ tdata[v][:] = f
427
417
 
428
418
  z = tdata[FC.TARGETS][..., 2]
429
419
  for v, p in self._profiles.items():
@@ -572,7 +562,7 @@ class TabStates(StatesTable):
572
562
 
573
563
  sel = weights > 0
574
564
 
575
- self._data_source = pd.DataFrame(
565
+ self._data = pd.DataFrame(
576
566
  index=np.arange(np.sum(sel)),
577
567
  data={
578
568
  FV.WS: ws[sel],
@@ -580,7 +570,7 @@ class TabStates(StatesTable):
580
570
  FV.WEIGHT: weights[sel],
581
571
  },
582
572
  )
583
- self._data_source.index.name = FC.STATE
573
+ self._data.index.name = FC.STATE
584
574
 
585
575
  return super().load_data(algo, verbosity)
586
576
 
@@ -29,6 +29,8 @@ class WeibullSectors(StatesTable):
29
29
  Subset selection via xr.Dataset.sel()
30
30
  isel: dict
31
31
  Subset selection via xr.Dataset.isel()
32
+ rpars: dict
33
+ Additional parameters for reading the file
32
34
  RDICT: dict
33
35
  Default xarray file reading parameters
34
36
 
@@ -46,6 +48,7 @@ class WeibullSectors(StatesTable):
46
48
  var2ncvar={},
47
49
  sel=None,
48
50
  isel=None,
51
+ read_pars={},
49
52
  **kwargs,
50
53
  ):
51
54
  """
@@ -67,6 +70,8 @@ class WeibullSectors(StatesTable):
67
70
  Subset selection via xr.Dataset.sel()
68
71
  isel: dict, optional
69
72
  Subset selection via xr.Dataset.isel()
73
+ read_pars: dict
74
+ Additional parameters for reading the file
70
75
  kwargs: dict, optional
71
76
  Additional arguments for the base class
72
77
 
@@ -76,6 +81,7 @@ class WeibullSectors(StatesTable):
76
81
  self.var2ncvar = var2ncvar
77
82
  self.sel = sel if sel is not None else {}
78
83
  self.isel = isel if isel is not None else {}
84
+ self.rpars = read_pars
79
85
 
80
86
  if FV.WS not in self.ovars:
81
87
  raise ValueError(
@@ -87,39 +93,37 @@ class WeibullSectors(StatesTable):
87
93
  f"States '{self.name}': Cannot have '{v}' as output variable"
88
94
  )
89
95
 
90
- self._original_data_source = None
96
+ self._original_data = None
91
97
 
92
98
  def __repr__(self):
93
- return f"{type(self).__name__}(ws_bins={self._n_ws})"
99
+ return f"{type(self).__name__}(n_wd={self._n_wd}, n_ws={self._n_ws})"
94
100
 
95
- def load_data(self, algo, verbosity=0):
101
+ def _read_data(self, algo, point_coord=None, verbosity=0):
96
102
  """
97
- Load and/or create all model data that is subject to chunking.
98
-
99
- Such data should not be stored under self, for memory reasons. The
100
- data returned here will automatically be chunked and then provided
101
- as part of the mdata object during calculations.
103
+ Extracts data from file or Dataset.
102
104
 
103
105
  Parameters
104
106
  ----------
105
107
  algo: foxes.core.Algorithm
106
108
  The calculation algorithm
109
+ point_coord: str, optional
110
+ The coordinate name representing the point index
107
111
  verbosity: int
108
112
  The verbosity level, 0 = silent
109
113
 
110
114
  Returns
111
115
  -------
112
- idata: dict
113
- The dict has exactly two entries: `data_vars`,
114
- a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
115
- and `coords`, a dict with entries `dim_name_str -> dim_array`
116
+ data: xarray.Dataset
117
+ The input data
116
118
 
117
119
  """
120
+ # store original data
121
+ if self._original_data is not None:
122
+ self._data = self._original_data
123
+ self._original_data = None
118
124
 
119
- if self._original_data_source is not None:
120
- self._data_source = self._original_data_source
121
- self._original_data_source = None
122
-
125
+ # read file or grab data
126
+ cwd = self.var2ncvar.get(FV.WD, FV.WD)
123
127
  if isinstance(self.data_source, (str, PathLike)):
124
128
  fpath = get_input_path(self.data_source)
125
129
  if not fpath.is_file():
@@ -130,96 +134,197 @@ class WeibullSectors(StatesTable):
130
134
  fpath = algo.dbook.get_file_path(STATES, fpath.name, check_raw=False)
131
135
  if verbosity > 0:
132
136
  print(f"Path: {fpath}")
133
- elif verbosity:
137
+ elif verbosity > 0:
134
138
  print(f"States '{self.name}': Reading file {fpath}")
135
139
  rpars = dict(self.RDICT, **self.rpars)
136
140
  if fpath.suffix == ".nc":
137
141
  data = open_dataset(fpath, engine=config.nc_engine, **rpars)
138
142
  else:
139
- data = PandasFileHelper().read_file(fpath, **rpars).to_xarray()
140
- self._original_data_source = data
143
+ data = PandasFileHelper().read_file(fpath, **rpars)
144
+ data.index.name = cwd
145
+ data = data.to_xarray()
146
+ self._original_data = data
141
147
 
142
148
  elif isinstance(self.data_source, Dataset):
143
149
  data = self.data_source
144
150
 
145
151
  elif isinstance(self.data_source, pd.DataFrame):
146
- data = self.data_source.to_xarray()
152
+ data = self.data_source
153
+ data.index.name = cwd
154
+ data = data.to_xarray()
147
155
 
156
+ # optionally select a subset
148
157
  if self.isel is not None and len(self.isel):
149
158
  data = data.isel(**self.isel)
150
159
  if self.sel is not None and len(self.sel):
151
160
  data = data.sel(**self.sel)
152
161
 
153
- wsn = self.var2ncvar.get(FV.WS, FV.WS)
162
+ # remove wd 360 from the end, if wd 0 is given:
163
+ wd = data[cwd].to_numpy()
164
+ if wd[0] == 0.0 and wd[-1] == 360.0:
165
+ data = data.isel({cwd: np.s_[:-1]})
166
+
167
+ # construct wind speed bins and bin deltas
168
+ cws = self.var2ncvar.get(FV.WS, FV.WS)
154
169
  if self.ws_bins is not None:
155
170
  wsb = self.ws_bins
156
- elif wsn in data:
157
- wsb = data[wsn].to_numpy()
171
+ wss = 0.5 * (wsb[:-1] + wsb[1:])
172
+ elif cws in data:
173
+ wss = data[cws].to_numpy()
174
+ wsb = np.zeros((len(wss) + 1,), dtype=config.dtype_double)
175
+ wsb[1:-1] = 0.5 * (wss[1:] + wss[:-1])
176
+ wsb[0] = wss[0] - 0.5 * wsb[1]
177
+ wsb[-1] = wss[-1] + 0.5 * wsb[-2]
178
+ self.ws_bins = wsb
158
179
  else:
159
180
  raise ValueError(
160
- f"States '{self.name}': Expecting ws_bins argument, since '{wsn}' not found in data"
181
+ f"States '{self.name}': Expecting ws_bins argument, since '{cws}' not found in data"
161
182
  )
162
- wss = 0.5 * (wsb[:-1] + wsb[1:])
163
183
  wsd = wsb[1:] - wsb[:-1]
164
184
  n_ws = len(wss)
165
- self._n_ws = n_ws
166
185
  del wsb
167
186
 
168
- secn = None
169
- n_secs = None
170
- if self._original_data_source is None:
171
- self._original_data_source = self.data_source
172
- self._data_source = {}
187
+ # prepare data binning
188
+ if self._original_data is None:
189
+ self._original_data = self.data_source
190
+ cpt = (
191
+ self.var2ncvar.get(FC.POINT, FC.POINT) if point_coord is not None else None
192
+ )
193
+ n_wd = data.sizes[cwd]
194
+ self.BIN_WD = self.var("bin_wd")
195
+ self.BIN_WS = self.var("bin_ws")
196
+ self.POINT = self.var("point")
197
+ if cpt is None:
198
+ n_pt = 0
199
+ shp = (n_wd, n_ws)
200
+ dms = (self.BIN_WD, self.BIN_WS)
201
+ else:
202
+ n_pt = data.sizes[cpt]
203
+ shp = (n_wd, n_ws, n_pt)
204
+ dms = (self.BIN_WD, self.BIN_WS, self.POINT)
205
+
206
+ # create binned data
207
+ self._data = {
208
+ FV.WD: np.zeros(shp, dtype=config.dtype_double),
209
+ FV.WS: np.zeros(shp, dtype=config.dtype_double),
210
+ }
211
+ if cpt is None:
212
+ self._data[FV.WD][:] = data[cwd].to_numpy()[:, None]
213
+ self._data[FV.WS][:] = wss[None, :]
214
+ else:
215
+ self._data[FV.WD][:] = data[cwd].to_numpy()[:, None, None]
216
+ self._data[FV.WS][:] = wss[None, :, None]
173
217
  for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT] + self.ovars:
174
- if v != FV.WS and v not in self.fixed_vars:
175
- c = self.var2ncvar.get(v, v)
176
- if c not in data:
218
+ if v not in [FV.WS, FV.WD] and v not in self.fixed_vars:
219
+ w = self.var2ncvar.get(v, v)
220
+ if w not in data:
177
221
  raise KeyError(
178
- f"States '{self.name}': Missing variable '{c}' in data, found {list(data.data_vars.keys())}"
179
- )
180
- d = data[c]
181
- if len(d.dims) == 0:
182
- self.fixed_vars[v] = float(d.to_numpy())
183
- continue
184
- elif len(d.dims) != 1:
185
- raise ValueError(
186
- f"States '{self.name}': Expecting single dimension for variable '{c}', got {d.dims}"
187
- )
188
- elif secn is None:
189
- secn = d.dims[0]
190
- n_secs = data.sizes[secn]
191
- elif d.dims[0] != secn:
192
- raise ValueError(
193
- f"States '{self.name}': Expecting dimension '{secn}' for variable '{c}', got {d.dims}"
222
+ f"States '{self.name}': Missing variable '{w}' in data, found {list(data.data_vars.keys())}"
194
223
  )
195
- self._data_source[v] = np.zeros(
196
- (n_secs, n_ws), dtype=config.dtype_double
197
- )
198
- self._data_source[v][:] = d.to_numpy()[:, None]
199
- self._data_source[FV.WS] = np.zeros((n_secs, n_ws), dtype=config.dtype_double)
200
- self._data_source[FV.WS][:] = wss[None, :]
201
- del wss
202
-
203
- self._data_source[FV.WEIGHT] *= weibull_weights(
204
- ws=self._data_source[FV.WS],
205
- ws_deltas=wsd[None, :],
206
- A=self._data_source.pop(FV.WEIBULL_A),
207
- k=self._data_source.pop(FV.WEIBULL_k),
224
+ d = data[w]
225
+ iws = d.dims.index(cws) if cws in d.dims else -1
226
+ iwd = d.dims.index(cwd) if cwd in d.dims else -1
227
+ ipt = d.dims.index(cpt) if cpt is not None and cpt in d.dims else -1
228
+ d = d.to_numpy()
229
+ if v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT]:
230
+ if cws in data[w].dims:
231
+ raise ValueError(
232
+ f"States '{self.name}': Cannot have '{cws}' as dimension in variable '{v}', got {data[w].dims}"
233
+ )
234
+ if cwd not in data[w].dims:
235
+ raise ValueError(
236
+ f"States '{self.name}': Expecting '{cwd}' as dimension in variable '{v}', got {data[w].dims}"
237
+ )
238
+ if iws < 0 and iwd < 0 and ipt < 0:
239
+ self.fixed_vars[v] = d.to_numpy()
240
+ elif iws >= 0 and iwd >= 0 and ipt >= 0:
241
+ self._data[v] = np.moveaxis(d, [iwd, iws, ipt], [0, 1, 2])
242
+ elif iws >= 0 and iwd >= 0 and ipt < 0:
243
+ if cpt is None:
244
+ self._data[v] = np.moveaxis(d, [iwd, iws], [0, 1])
245
+ else:
246
+ self._data[v] = np.zeros(shp, dtype=config.dtype_double)
247
+ self._data[v][:] = np.moveaxis(d, [iwd, iws], [0, 1])[
248
+ :, :, None
249
+ ]
250
+ elif iws >= 0 and iwd < 0 and ipt >= 0:
251
+ self._data[v] = np.zeros(shp, dtype=config.dtype_double)
252
+ self._data[v][:] = np.moveaxis(d, [iws, ipt], [0, 1])[None, :, :]
253
+ elif iws < 0 and iwd >= 0 and ipt >= 0:
254
+ self._data[v] = np.zeros(shp, dtype=config.dtype_double)
255
+ self._data[v][:] = np.moveaxis(d, [iwd, ipt], [0, 1])[:, None, :]
256
+ elif iws >= 0 and iwd < 0 and ipt < 0:
257
+ self._data[v] = np.zeros(shp, dtype=config.dtype_double)
258
+ if cpt is None:
259
+ self._data[v][:] = d[None, :]
260
+ else:
261
+ self._data[v][:] = d[None, :, None]
262
+ elif iws < 0 and iwd >= 0 and ipt < 0:
263
+ self._data[v] = np.zeros(shp, dtype=config.dtype_double)
264
+ if cpt is None:
265
+ self._data[v][:] = d[:, None]
266
+ else:
267
+ self._data[v][:] = d[:, None, None]
268
+ elif iws < 0 and iwd < 0 and ipt >= 0:
269
+ self._data[v] = np.zeros(shp, dtype=config.dtype_double)
270
+ self._data[v][:] = d[None, None, :]
271
+
272
+ # compute Weibull weights
273
+ self._data[FV.WEIGHT] *= weibull_weights(
274
+ ws=wss[None, :, None] if cpt is not None else wss[None, :],
275
+ ws_deltas=wsd[None, :, None] if cpt is not None else wsd[None, :],
276
+ A=self._data.pop(FV.WEIBULL_A),
277
+ k=self._data.pop(FV.WEIBULL_k),
208
278
  )
209
279
 
210
- # remove wd 360 from the end, if wd 0 is given:
211
- if FV.WD in self._data_source:
212
- if np.all(self._data_source[FV.WD][0] == 0.0) and np.all(
213
- self._data_source[FV.WD][-1] == 360.0
214
- ):
215
- for v in self._data_source.keys():
216
- self._data_source[v] = self._data_source[v][:-1]
217
- n_secs -= 1
218
-
219
- N = n_secs * n_ws
220
- for v in self._data_source.keys():
221
- self._data_source[v] = self._data_source[v].reshape(N)
222
- self._data_source = pd.DataFrame(data=self._data_source, index=np.arange(N))
223
- self._data_source.index.name = FC.STATE
280
+ # translate binned data to states
281
+ self._n_pt = n_pt
282
+ self._n_wd = n_wd
283
+ self._n_ws = n_ws
284
+ self._N = n_wd * n_ws
285
+ self._data = Dataset(
286
+ data_vars={v: (dms, d) for v, d in self._data.items()},
287
+ )
288
+
289
+ return data
290
+
291
+ def load_data(self, algo, verbosity=0):
292
+ """
293
+ Load and/or create all model data that is subject to chunking.
294
+
295
+ Such data should not be stored under self, for memory reasons. The
296
+ data returned here will automatically be chunked and then provided
297
+ as part of the mdata object during calculations.
298
+
299
+ Parameters
300
+ ----------
301
+ algo: foxes.core.Algorithm
302
+ The calculation algorithm
303
+ verbosity: int
304
+ The verbosity level, 0 = silent
305
+
306
+ Returns
307
+ -------
308
+ idata: dict
309
+ The dict has exactly two entries: `data_vars`,
310
+ a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
311
+ and `coords`, a dict with entries `dim_name_str -> dim_array`
312
+
313
+ """
314
+ self._read_data(algo, verbosity=0)
315
+
316
+ tmp = {}
317
+ for v, d in self._data.data_vars.items():
318
+ if self.POINT in d.dims:
319
+ raise TypeError(
320
+ f"States '{self.name}': Variable '{v}' has unsupported dimension '{self.POINT}', dims = {d.dims}"
321
+ )
322
+ else:
323
+ tmp[v] = d.to_numpy().reshape(self._N)
324
+ self._data = tmp
325
+ del tmp
326
+
327
+ self._data = pd.DataFrame(data=self._data, index=np.arange(self._N))
328
+ self._data.index.name = FC.STATE
224
329
 
225
330
  return super().load_data(algo, verbosity)
@@ -229,8 +229,8 @@ class WRGStates(States):
229
229
  (n_states, n_targets, n_tpoints)
230
230
 
231
231
  """
232
-
233
232
  # prepare:
233
+ self.ensure_output_vars(algo, tdata)
234
234
  n_states = tdata.n_states
235
235
  n_targets = tdata.n_targets
236
236
  n_tpoints = tdata.n_tpoints
foxes/input/yaml/dict.py CHANGED
@@ -110,7 +110,7 @@ def read_dict(
110
110
  t = mbook.sources.get_item(s)
111
111
  c = mbook.base_classes.get_item(s)
112
112
  ms = [
113
- Dict(m, name=f"{mdict.name}.s{i}") for i, m in enumerate(mlst)
113
+ Dict(m, _name=f"{mdict.name}.s.{i}") for i, m in enumerate(mlst)
114
114
  ]
115
115
  for m in ms:
116
116
  mname = m.pop_item("name")
@@ -128,10 +128,7 @@ def read_dict(
128
128
  if algo is None:
129
129
  _print("Creating wind farm")
130
130
  fdict = idict.get_item("wind_farm")
131
- lyts = [
132
- Dict(lo, name=f"{fdict.name}.layout{i}")
133
- for i, lo in enumerate(fdict.pop_item("layouts"))
134
- ]
131
+ lyts = fdict.pop_item("layouts")
135
132
  farm = WindFarm(**fdict)
136
133
  for lyt in lyts:
137
134
  add_fun = getattr(farm_layout, lyt.pop_item("function"))
@@ -251,6 +248,7 @@ def run_obj_function(
251
248
  fdict,
252
249
  algo,
253
250
  rlabels,
251
+ nofig=False,
254
252
  verbosity=None,
255
253
  ):
256
254
  """
@@ -266,6 +264,8 @@ def run_obj_function(
266
264
  The algorithm
267
265
  rlabels: dict
268
266
  Storage for result variables
267
+ nofig: bool
268
+ Do not show figures, overrules settings from fdict
269
269
  verbosity: int, optional
270
270
  The verbosity level, 0 = silent
271
271
 
@@ -310,9 +310,9 @@ def run_obj_function(
310
310
  results = f(*args, **fdict)
311
311
 
312
312
  # pyplot shortcuts:
313
- if plt_show:
313
+ if not nofig and plt_show:
314
314
  plt.show()
315
- if plt_close:
315
+ if not nofig and plt_close:
316
316
  results = None
317
317
  plt.close()
318
318
 
@@ -346,6 +346,7 @@ def run_outputs(
346
346
  point_results=None,
347
347
  extra_sig={},
348
348
  ret_rlabels=False,
349
+ nofig=False,
349
350
  verbosity=None,
350
351
  ):
351
352
  """
@@ -366,6 +367,8 @@ def run_outputs(
366
367
  arguments (key) with data (value)
367
368
  ret_rlabels: bool
368
369
  Flag for returning results variables
370
+ nofig: bool
371
+ Do not show figures, overrules settings from idict
369
372
  verbosity: int, optional
370
373
  The verbosity level, 0 = silent
371
374
 
@@ -387,24 +390,19 @@ def run_outputs(
387
390
  print(*args, **kwargs)
388
391
 
389
392
  out = []
390
- rlabels = Dict(name="result_labels")
393
+ rlabels = Dict(_name="result_labels")
391
394
  if "outputs" in idict:
392
- odicts = [
393
- Dict(odict, name=f"{idict.name}.output{i}")
394
- for i, odict in enumerate(idict["outputs"])
395
- ]
395
+ odicts = idict["outputs"]
396
396
 
397
397
  for i, d in enumerate(odicts):
398
398
  if "output_type" in d:
399
+ d["nofig"] = nofig
399
400
  ocls = d.pop_item("output_type")
400
401
  _print(f"\nRunning output {i}: {ocls}")
401
402
  d0 = dict(output_type=ocls)
402
403
  d0.update(d)
403
404
 
404
- flist = [
405
- Dict(f, name=f"{d.name}.function{j}")
406
- for j, f in enumerate(d.pop_item("functions"))
407
- ]
405
+ flist = d.pop_item("functions")
408
406
 
409
407
  o = get_output_obj(
410
408
  ocls, d, algo, farm_results, point_results, extra_sig=extra_sig
@@ -419,10 +417,7 @@ def run_outputs(
419
417
  o = _get_object(rlabels, ocls)
420
418
  d0 = dict(object=ocls)
421
419
  d0.update(d)
422
- flist = [
423
- Dict(f, name=f"{d.name}.function{j}")
424
- for j, f in enumerate(d.pop_item("functions"))
425
- ]
420
+ flist = d.pop_item("functions")
426
421
 
427
422
  else:
428
423
  raise KeyError(
@@ -431,7 +426,7 @@ def run_outputs(
431
426
 
432
427
  fres = []
433
428
  for fdict in flist:
434
- results = run_obj_function(o, fdict, algo, rlabels, verbosity)
429
+ results = run_obj_function(o, fdict, algo, rlabels, nofig, verbosity)
435
430
  fres.append(results)
436
431
  out.append((d0, fres))
437
432
 
@@ -441,7 +436,7 @@ def run_outputs(
441
436
  return out if not ret_rlabels else out, rlabels
442
437
 
443
438
 
444
- def run_dict(idict, *args, verbosity=None, **kwargs):
439
+ def run_dict(idict, *args, nofig=False, verbosity=None, **kwargs):
445
440
  """
446
441
  Runs foxes from dictionary input
447
442
 
@@ -451,6 +446,8 @@ def run_dict(idict, *args, verbosity=None, **kwargs):
451
446
  The input parameter dictionary
452
447
  args: tuple, optional
453
448
  Additional parameters for read_dict
449
+ nofig: bool
450
+ Do not show figures, overrules settings from idict
454
451
  verbosity: int, optional
455
452
  Force a verbosity level, 0 = silent, overrules
456
453
  settings from idict
@@ -480,7 +477,7 @@ def run_dict(idict, *args, verbosity=None, **kwargs):
480
477
  algo, engine = read_dict(idict, *args, verbosity=verbosity, **kwargs)
481
478
 
482
479
  # run farm calculation:
483
- rdict = idict.get_item("calc_farm", Dict(name=idict.name + ".calc_farm"))
480
+ rdict = idict.get_item("calc_farm", Dict(_name=idict.name + ".calc_farm"))
484
481
  if rdict.pop_item("run", True):
485
482
  _print("Running calc_farm")
486
483
  farm_results = algo.calc_farm(**rdict)
@@ -504,7 +501,11 @@ def run_dict(idict, *args, verbosity=None, **kwargs):
504
501
  out += (point_results,)
505
502
 
506
503
  # run outputs:
507
- out += (run_outputs(idict, algo, farm_results, point_results, verbosity=verbosity),)
504
+ out += (
505
+ run_outputs(
506
+ idict, algo, farm_results, point_results, nofig=nofig, verbosity=verbosity
507
+ ),
508
+ )
508
509
 
509
510
  # shutdown engine, if created above:
510
511
  if engine is not None: