foxes 1.2.5__py3-none-any.whl → 1.3__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 (52) hide show
  1. examples/quickstart/run.py +17 -0
  2. foxes/__init__.py +1 -1
  3. foxes/algorithms/downwind/downwind.py +9 -15
  4. foxes/algorithms/downwind/models/farm_wakes_calc.py +13 -7
  5. foxes/algorithms/downwind/models/init_farm_data.py +4 -4
  6. foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
  7. foxes/algorithms/downwind/models/set_amb_point_results.py +1 -1
  8. foxes/algorithms/iterative/models/farm_wakes_calc.py +6 -3
  9. foxes/algorithms/sequential/models/seq_state.py +0 -18
  10. foxes/algorithms/sequential/sequential.py +5 -18
  11. foxes/constants.py +6 -0
  12. foxes/core/data.py +44 -18
  13. foxes/core/engine.py +19 -1
  14. foxes/core/farm_data_model.py +1 -0
  15. foxes/core/rotor_model.py +42 -38
  16. foxes/core/states.py +2 -47
  17. foxes/input/states/__init__.py +1 -0
  18. foxes/input/states/field_data_nc.py +39 -61
  19. foxes/input/states/multi_height.py +31 -54
  20. foxes/input/states/one_point_flow.py +22 -21
  21. foxes/input/states/scan.py +6 -19
  22. foxes/input/states/single.py +5 -17
  23. foxes/input/states/states_table.py +15 -37
  24. foxes/input/states/wrg_states.py +148 -36
  25. foxes/models/partial_wakes/rotor_points.py +8 -2
  26. foxes/models/partial_wakes/segregated.py +9 -4
  27. foxes/models/rotor_models/centre.py +6 -4
  28. foxes/models/wake_frames/seq_dynamic_wakes.py +5 -2
  29. foxes/models/wake_frames/timelines.py +10 -0
  30. foxes/output/farm_layout.py +12 -4
  31. foxes/output/farm_results_eval.py +36 -12
  32. foxes/output/rose_plot.py +20 -2
  33. foxes/output/slice_data.py +16 -19
  34. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/METADATA +10 -8
  35. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/RECORD +52 -51
  36. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/WHEEL +1 -1
  37. tests/0_consistency/iterative/test_iterative.py +2 -3
  38. tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
  39. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
  40. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
  41. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -2
  42. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -3
  43. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -3
  44. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -3
  45. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -3
  46. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
  47. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -2
  48. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -3
  49. tests/3_examples/test_examples.py +3 -2
  50. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/LICENSE +0 -0
  51. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/entry_points.txt +0 -0
  52. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/top_level.txt +0 -0
foxes/core/rotor_model.py CHANGED
@@ -60,6 +60,10 @@ class RotorModel(FarmDataModel):
60
60
  """
61
61
  if self.calc_vars is None:
62
62
  vrs = algo.states.output_point_vars(algo)
63
+ assert (
64
+ FV.WEIGHT not in vrs
65
+ ), f"Rotor '{self.name}': States '{algo.states.name}' output_point_vars contain '{FV.WEIGHT}', please remove"
66
+
63
67
  if FV.WS in vrs:
64
68
  self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
65
69
  else:
@@ -72,6 +76,9 @@ class RotorModel(FarmDataModel):
72
76
 
73
77
  self.calc_vars = sorted(self.calc_vars)
74
78
 
79
+ if FV.WEIGHT not in self.calc_vars:
80
+ self.calc_vars.append(FV.WEIGHT)
81
+
75
82
  return self.calc_vars
76
83
 
77
84
  @abstractmethod
@@ -174,9 +181,7 @@ class RotorModel(FarmDataModel):
174
181
  elif res.shape[1] == 1:
175
182
  fdata[v][:, downwind_index] = res[:, 0]
176
183
  else:
177
- raise ValueError(
178
- f"Rotor model '{self.name}': downwind_index is not None, but results shape for '{v}' has more than one turbine, {res.shape}"
179
- )
184
+ fdata[v, downwind_index] = res[:, downwind_index]
180
185
 
181
186
  def eval_rpoint_results(
182
187
  self,
@@ -184,7 +189,7 @@ class RotorModel(FarmDataModel):
184
189
  mdata,
185
190
  fdata,
186
191
  tdata,
187
- weights,
192
+ rpoint_weights,
188
193
  downwind_index=None,
189
194
  copy_to_ambient=False,
190
195
  ):
@@ -207,7 +212,7 @@ class RotorModel(FarmDataModel):
207
212
  The farm data
208
213
  tdata: foxes.core.TData
209
214
  The target point data
210
- weights: numpy.ndarray
215
+ rpoint_weights: numpy.ndarray
211
216
  The rotor point weights, shape: (n_rpoints,)
212
217
  downwind_index: int, optional
213
218
  The index in the downwind order
@@ -233,7 +238,7 @@ class RotorModel(FarmDataModel):
233
238
  wd = tdata[FV.WD]
234
239
  ws = tdata[FV.WS]
235
240
  uvp = wd2uv(wd, ws, axis=-1)
236
- uv = np.einsum("stpd,p->std", uvp, weights)
241
+ uv = np.einsum("stpd,p->std", uvp, rpoint_weights)
237
242
 
238
243
  wd = None
239
244
  vdone = []
@@ -243,7 +248,6 @@ class RotorModel(FarmDataModel):
243
248
  wd = uv2wd(uv, axis=-1)
244
249
  self._set_res(fdata, v, wd, downwind_index)
245
250
  vdone.append(v)
246
-
247
251
  elif v == FV.WS:
248
252
  ws = np.linalg.norm(uv, axis=-1)
249
253
  self._set_res(fdata, v, ws, downwind_index)
@@ -265,7 +269,7 @@ class RotorModel(FarmDataModel):
265
269
 
266
270
  for v in self.calc_vars:
267
271
  if v == FV.REWS:
268
- rews = np.maximum(np.einsum("stp,p->st", wsp, weights), 0.0)
272
+ rews = np.maximum(np.einsum("stp,p->st", wsp, rpoint_weights), 0.0)
269
273
  self._set_res(fdata, v, rews, downwind_index)
270
274
  del rews
271
275
  vdone.append(v)
@@ -278,12 +282,14 @@ class RotorModel(FarmDataModel):
278
282
  if uvp.shape[2] > 1:
279
283
  rews2 = np.sqrt(
280
284
  np.maximum(
281
- np.einsum("stp,p->st", np.sign(wsp) * wsp**2, weights),
285
+ np.einsum(
286
+ "stp,p->st", np.sign(wsp) * wsp**2, rpoint_weights
287
+ ),
282
288
  0.0,
283
289
  )
284
290
  )
285
291
  else:
286
- rews2 = np.sqrt(np.einsum("stp,p->st", wsp**2, weights))
292
+ rews2 = np.sqrt(np.einsum("stp,p->st", wsp**2, rpoint_weights))
287
293
  self._set_res(fdata, v, rews2, downwind_index)
288
294
  del rews2
289
295
  vdone.append(v)
@@ -295,10 +301,12 @@ class RotorModel(FarmDataModel):
295
301
  # turbine axis direction:
296
302
  if uvp.shape[2] > 1:
297
303
  rews3 = np.maximum(
298
- np.einsum("stp,p->st", wsp**3, weights), 0.0
304
+ np.einsum("stp,p->st", wsp**3, rpoint_weights), 0.0
299
305
  ) ** (1.0 / 3.0)
300
306
  else:
301
- rews3 = (np.einsum("stp,p->st", wsp**3, weights)) ** (1.0 / 3.0)
307
+ rews3 = (np.einsum("stp,p->st", wsp**3, rpoint_weights)) ** (
308
+ 1.0 / 3.0
309
+ )
302
310
  self._set_res(fdata, v, rews3, downwind_index)
303
311
  del rews3
304
312
  vdone.append(v)
@@ -307,8 +315,10 @@ class RotorModel(FarmDataModel):
307
315
  del uvp
308
316
 
309
317
  for v in self.calc_vars:
310
- if v not in vdone:
311
- res = np.einsum("stp,p->st", tdata[v], weights)
318
+ if v not in vdone and (
319
+ fdata[v].shape[1] > 1 or downwind_index is None or downwind_index == 0
320
+ ):
321
+ res = np.einsum("stp,p->st", tdata[v], rpoint_weights)
312
322
  self._set_res(fdata, v, res, downwind_index)
313
323
  if copy_to_ambient and v in FV.var2amb:
314
324
  fdata[FV.var2amb[v]] = fdata[v].copy()
@@ -319,10 +329,8 @@ class RotorModel(FarmDataModel):
319
329
  mdata,
320
330
  fdata,
321
331
  rpoints=None,
322
- weights=None,
323
- store_rpoints=False,
324
- store_rweights=False,
325
- store_amb_res=False,
332
+ rpoint_weights=None,
333
+ store=False,
326
334
  downwind_index=None,
327
335
  ):
328
336
  """
@@ -339,16 +347,11 @@ class RotorModel(FarmDataModel):
339
347
  rpoints: numpy.ndarray, optional
340
348
  The rotor points, or None for automatic for
341
349
  this rotor. Shape: (n_states, n_turbines, n_rpoints, 3)
342
- weights: numpy.ndarray, optional
350
+ rpoint_weights: numpy.ndarray, optional
343
351
  The rotor point weights, or None for automatic
344
352
  for this rotor. Shape: (n_rpoints,)
345
- store_rpoints: bool, optional
346
- Switch for storing rotor points to mdata
347
- store_rweights: bool, optional
348
- Switch for storing rotor point weights to mdata
349
- store_amb_res: bool, optional
350
- Switch for storing ambient rotor point reults as they
351
- come from the states to mdata
353
+ store: bool, optional
354
+ Flag for storing ambient rotor point results
352
355
  downwind_index: int, optional
353
356
  Only compute for index in the downwind order
354
357
 
@@ -364,18 +367,12 @@ class RotorModel(FarmDataModel):
364
367
  rpoints = mdata.get(
365
368
  FC.ROTOR_POINTS, self.get_rotor_points(algo, mdata, fdata)
366
369
  )
367
- if store_rpoints:
368
- algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
369
-
370
370
  if downwind_index is not None:
371
371
  rpoints = rpoints[:, downwind_index, None]
372
+ if rpoint_weights is None:
373
+ rpoint_weights = mdata.get_item(FC.TWEIGHTS, self.rotor_point_weights())
372
374
 
373
- if weights is None:
374
- weights = mdata.get(FC.TWEIGHTS, self.rotor_point_weights())
375
- if store_rweights:
376
- algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, weights, mdata=mdata)
377
-
378
- tdata = TData.from_tpoints(rpoints, weights)
375
+ tdata = TData.from_tpoints(rpoints, rpoint_weights)
379
376
  svars = algo.states.output_point_vars(algo)
380
377
  for v in svars:
381
378
  tdata.add(
@@ -386,16 +383,23 @@ class RotorModel(FarmDataModel):
386
383
 
387
384
  sres = algo.states.calculate(algo, mdata, fdata, tdata)
388
385
  tdata.update(sres)
386
+ if FV.WEIGHT not in tdata:
387
+ raise KeyError(
388
+ f"Rotor '{self.name}': States '{algo.states.name}' failed to provide '{FV.WEIGHT}' in tdata"
389
+ )
389
390
 
390
- if store_amb_res:
391
- algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres.copy(), mdata=mdata)
391
+ if store:
392
+ algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
393
+ algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, rpoint_weights, mdata=mdata)
394
+ algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres, mdata=mdata)
395
+ algo.add_to_chunk_store(FC.WEIGHT_RES, tdata[FV.WEIGHT], mdata=mdata)
392
396
 
393
397
  self.eval_rpoint_results(
394
398
  algo,
395
399
  mdata,
396
400
  fdata,
397
401
  tdata,
398
- weights,
402
+ rpoint_weights,
399
403
  downwind_index,
400
404
  copy_to_ambient=True,
401
405
  )
foxes/core/states.py CHANGED
@@ -43,24 +43,6 @@ class States(PointDataModel):
43
43
  """
44
44
  return list(range(self.size()))
45
45
 
46
- @abstractmethod
47
- def weights(self, algo):
48
- """
49
- The statistical weights of all states.
50
-
51
- Parameters
52
- ----------
53
- algo: foxes.core.Algorithm
54
- The calculation algorithm
55
-
56
- Returns
57
- -------
58
- weights: numpy.ndarray
59
- The weights, shape: (n_states, n_turbines)
60
-
61
- """
62
- pass
63
-
64
46
  def reset(self, algo=None, states_sel=None, states_loc=None, verbosity=0):
65
47
  """
66
48
  Reset the states, optionally select states
@@ -106,19 +88,9 @@ class States(PointDataModel):
106
88
  if sinds is not None:
107
89
  idata["coords"][FC.STATE] = sinds
108
90
 
109
- weights = self.weights(algo)
110
- if len(weights.shape) != 2:
111
- raise ValueError(
112
- f"States '{self.name}': Wrong weights dimension, expecing ({FC.STATE}, {FC.TURBINE}), got shape {weights.shape}"
113
- )
114
- if weights.shape[1] != algo.n_turbines:
115
- raise ValueError(
116
- f"States '{self.name}': Wrong size of second axis dimension '{FC.TURBINE}': Expecting {algo.n_turbines}, got {weights.shape[1]}"
117
- )
118
- idata["data_vars"][FV.WEIGHT] = ((FC.STATE, FC.TURBINE), weights)
119
-
120
91
  return idata
121
92
 
93
+ @abstractmethod
122
94
  def output_point_vars(self, algo):
123
95
  """
124
96
  The variables which are being modified by the model.
@@ -134,7 +106,7 @@ class States(PointDataModel):
134
106
  The output variable names
135
107
 
136
108
  """
137
- return [FV.WS, FV.WD, FV.TI, FV.RHO]
109
+ pass
138
110
 
139
111
  def __add__(self, s):
140
112
  if isinstance(s, list):
@@ -245,23 +217,6 @@ class ExtendedStates(States):
245
217
  """
246
218
  return self.states.index()
247
219
 
248
- def weights(self, algo):
249
- """
250
- The statistical weights of all states.
251
-
252
- Parameters
253
- ----------
254
- algo: foxes.core.Algorithm
255
- The calculation algorithm
256
-
257
- Returns
258
- -------
259
- weights: numpy.ndarray
260
- The weights, shape: (n_states, n_turbines)
261
-
262
- """
263
- return self.states.weights(algo)
264
-
265
220
  def output_point_vars(self, algo):
266
221
  """
267
222
  The variables which are being modified by the model.
@@ -14,5 +14,6 @@ from .one_point_flow import (
14
14
  OnePointFlowMultiHeightTimeseries,
15
15
  OnePointFlowMultiHeightNCTimeseries,
16
16
  )
17
+ from .wrg_states import WRGStates
17
18
 
18
19
  from . import create
@@ -16,7 +16,6 @@ def _read_nc_file(
16
16
  fpath,
17
17
  coords,
18
18
  vars,
19
- weight_var,
20
19
  nc_engine,
21
20
  sel,
22
21
  isel,
@@ -30,18 +29,7 @@ def _read_nc_file(
30
29
  f"Missing coordinate '{c}' in file {fpath}, got: {list(data.coords.keys())}"
31
30
  )
32
31
  if minimal:
33
- weights = None
34
- if weight_var is not None:
35
- if weight_var not in data.data_vars:
36
- raise KeyError(
37
- f"Missing weight var '{weight_var}' in file {fpath}, found: {list(data.data_vars.keys())}"
38
- )
39
- if data[weight_var].dims != (coords[0],):
40
- raise ValueError(
41
- f"Wrong dimensions for variable '{weight_var}' in file {fpath}. Expecting {(coords[0],)}, got {data[weight_var].dims}"
42
- )
43
- weights = data[weight_var].to_numpy()
44
- return data[coords[0]].to_numpy(), weights
32
+ return data[coords[0]].to_numpy()
45
33
  else:
46
34
  data = data[vars]
47
35
  data.attrs = {}
@@ -175,7 +163,7 @@ class FieldDataNC(States):
175
163
  super().__init__()
176
164
 
177
165
  self.states_coord = states_coord
178
- self.ovars = output_vars
166
+ self.ovars = list(output_vars)
179
167
  self.fixed_vars = fixed_vars
180
168
  self.x_coord = x_coord
181
169
  self.y_coord = y_coord
@@ -196,7 +184,6 @@ class FieldDataNC(States):
196
184
  self._N = None
197
185
 
198
186
  self.__data_source = data_source
199
- self.__weights = None
200
187
  self.__inds = None
201
188
 
202
189
  @property
@@ -298,6 +285,18 @@ class FieldDataNC(States):
298
285
  dtype=config.dtype_double,
299
286
  )
300
287
 
288
+ weights = None
289
+ if self.weight_ncvar is not None:
290
+ if self.weight_ncvar not in ds.data_vars:
291
+ raise KeyError(
292
+ f"States '{self.name}': Missing weights variable '{self.weight_ncvar}' in data, found {sorted(list(ds.data_vars.keys()))}"
293
+ )
294
+ if ds[self.weight_ncvar].dims != (self.states_coord,):
295
+ raise ValueError(
296
+ f"States '{self.name}': Weights variable '{self.weight_ncvar}' has wrong dimensions. Expecting {(self.states_coord,)}, got {ds[self.weight_ncvar].dims}"
297
+ )
298
+ weights = ds[self.weight_ncvar].to_numpy()
299
+
301
300
  if verbosity > 1:
302
301
  print(f"\n{self.name}: Data ranges")
303
302
  for v, i in self._dkys.items():
@@ -307,7 +306,7 @@ class FieldDataNC(States):
307
306
  f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100*nn/len(d.flat):.2f}%)"
308
307
  )
309
308
 
310
- return sts, h, y, x, data
309
+ return sts, h, y, x, data, weights
311
310
 
312
311
  def output_point_vars(self, algo):
313
312
  """
@@ -356,7 +355,9 @@ class FieldDataNC(States):
356
355
 
357
356
  # check variables:
358
357
  for v in self.ovars:
359
- if v not in self.var2ncvar and v not in self.fixed_vars:
358
+ if v == FV.WEIGHT and self.weight_ncvar is None:
359
+ pass
360
+ elif v not in self.var2ncvar and v not in self.fixed_vars:
360
361
  raise ValueError(
361
362
  f"States '{self.name}': Variable '{v}' neither found in var2ncvar not in fixed_vars"
362
363
  )
@@ -413,7 +414,6 @@ class FieldDataNC(States):
413
414
  _read_nc_file,
414
415
  files,
415
416
  coords=coords,
416
- weight_var=self.weight_ncvar,
417
417
  vars=vars,
418
418
  nc_engine=config.nc_engine,
419
419
  isel=self.isel,
@@ -440,23 +440,15 @@ class FieldDataNC(States):
440
440
  )
441
441
  if self.load_mode == "preload":
442
442
  self.__data_source.load()
443
- if self.weight_ncvar is not None:
444
- self.__weights = self.__data_source[self.weight_ncvar].to_numpy()
445
443
  self.__inds = self.__data_source[self.states_coord].to_numpy()
446
444
  self._N = len(self.__inds)
447
445
 
448
446
  elif self.load_mode == "fly":
449
- self.__inds, weights = zip(*self.__data_source)
447
+ self.__inds = self.__data_source
450
448
  self.__data_source = fpath
451
449
  self._files_maxi = {f: len(inds) for f, inds in zip(files, self.__inds)}
452
450
  self.__inds = np.concatenate(self.__inds, axis=0)
453
451
  self._N = len(self.__inds)
454
- if weights[0] is not None:
455
- self.__weights = np.zeros(
456
- (self._N, algo.n_turbines), dtype=config.dtype_double
457
- )
458
- self.__weights[:] = np.concatenate(weights, axis=0)[:, None]
459
- del weights
460
452
 
461
453
  else:
462
454
  raise KeyError(
@@ -468,11 +460,6 @@ class FieldDataNC(States):
468
460
  self.__inds, format=self.time_format
469
461
  ).to_numpy()
470
462
 
471
- if self.__weights is None:
472
- self.__weights = np.full(
473
- (self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
474
- )
475
-
476
463
  # ensure WD and WS get the first two slots of data:
477
464
  self._dkys = {}
478
465
  if FV.WS in self.ovars:
@@ -492,8 +479,11 @@ class FieldDataNC(States):
492
479
  self.H = self.var(FV.H)
493
480
  self.VARS = self.var("vars")
494
481
  self.DATA = self.var("data")
482
+ self.WEIGHT = self.var(FV.WEIGHT)
495
483
 
496
- __, h, y, x, data = self._get_data(self.data_source, coords, verbosity)
484
+ __, h, y, x, data, weights = self._get_data(
485
+ self.data_source, coords, verbosity
486
+ )
497
487
  self._prl_coords = coords
498
488
 
499
489
  coos = (FC.STATE, self.H, self.Y, self.X, self.VARS)
@@ -504,6 +494,8 @@ class FieldDataNC(States):
504
494
  idata["coords"][self.X] = x
505
495
  idata["coords"][self.VARS] = list(self._dkys.keys())
506
496
  idata["data_vars"][self.DATA] = data
497
+ if weights is not None:
498
+ idata["data_vars"][self.WEIGHT] = ((FC.STATE,), weights)
507
499
 
508
500
  return idata
509
501
 
@@ -540,10 +532,9 @@ class FieldDataNC(States):
540
532
  super().set_running(algo, data_stash, sel, isel, verbosity)
541
533
 
542
534
  data_stash[self.name] = dict(
543
- weights=self.__weights,
544
535
  inds=self.__inds,
545
536
  )
546
- del self.__weights, self.__inds
537
+ del self.__inds
547
538
 
548
539
  if self.load_mode == "preload":
549
540
  data_stash[self.name]["data_source"] = self.__data_source
@@ -579,7 +570,6 @@ class FieldDataNC(States):
579
570
  super().unset_running(algo, data_stash, sel, isel, verbosity)
580
571
 
581
572
  data = data_stash[self.name]
582
- self.__weights = data.pop("weights")
583
573
  self.__inds = data.pop("inds")
584
574
 
585
575
  if self.load_mode == "preload":
@@ -628,27 +618,6 @@ class FieldDataNC(States):
628
618
  """
629
619
  return self.ovars
630
620
 
631
- def weights(self, algo):
632
- """
633
- The statistical weights of all states.
634
-
635
- Parameters
636
- ----------
637
- algo: foxes.core.Algorithm
638
- The calculation algorithm
639
-
640
- Returns
641
- -------
642
- weights: numpy.ndarray
643
- The weights, shape: (n_states, n_turbines)
644
-
645
- """
646
- if self.running:
647
- raise ValueError(
648
- f"States '{self.name}': Cannot access weights while running"
649
- )
650
- return self.__weights
651
-
652
621
  def calculate(self, algo, mdata, fdata, tdata):
653
622
  """
654
623
  The main model calculation.
@@ -690,6 +659,7 @@ class FieldDataNC(States):
690
659
  y = mdata[self.Y]
691
660
  h = mdata[self.H]
692
661
  data = mdata[self.DATA].copy()
662
+ weights = mdata.get(self.WEIGHT, None)
693
663
  coords = self._prl_coords
694
664
 
695
665
  # case lazy:
@@ -697,7 +667,7 @@ class FieldDataNC(States):
697
667
  i0 = mdata.states_i0(counter=True)
698
668
  s = slice(i0, i0 + n_states)
699
669
  ds = self.data_source.isel({self.states_coord: s}).load()
700
- __, h, y, x, data = self._get_data(ds, coords, verbosity=0)
670
+ __, h, y, x, data, weights = self._get_data(ds, coords, verbosity=0)
701
671
  del ds
702
672
 
703
673
  # case fly:
@@ -725,7 +695,6 @@ class FieldDataNC(States):
725
695
  _read_nc_file(
726
696
  fpath,
727
697
  coords=coords,
728
- weight_var=self.weight_ncvar,
729
698
  vars=vars,
730
699
  nc_engine=config.nc_engine,
731
700
  isel=isel,
@@ -742,7 +711,7 @@ class FieldDataNC(States):
742
711
  ), f"States '{self.name}': Missing states for load_mode '{self.load_mode}': (i0, i1) = {(i0, i1)}"
743
712
 
744
713
  data = xr.concat(data, dim=self.states_coord)
745
- __, h, y, x, data = self._get_data(data, coords, verbosity=0)
714
+ __, h, y, x, data, weights = self._get_data(data, coords, verbosity=0)
746
715
 
747
716
  else:
748
717
  raise KeyError(
@@ -858,7 +827,7 @@ class FieldDataNC(States):
858
827
  out[FV.WD] = uv2wd(uv, axis=-1)
859
828
  del uv
860
829
  for v in self.ovars:
861
- if v not in out:
830
+ if v != FV.WEIGHT and v not in out:
862
831
  if v in self._dkys:
863
832
  out[v] = data[..., self._dkys[v]]
864
833
  else:
@@ -866,4 +835,13 @@ class FieldDataNC(States):
866
835
  (n_states, n_pts), self.fixed_vars[v], dtype=config.dtype_double
867
836
  )
868
837
 
838
+ # add weights:
839
+ if weights is not None:
840
+ tdata[FV.WEIGHT] = weights[:, None, None]
841
+ else:
842
+ tdata[FV.WEIGHT] = np.full(
843
+ (mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
844
+ )
845
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
846
+
869
847
  return {v: d.reshape(n_states, n_targets, n_tpoints) for v, d in out.items()}