foxes 1.4__py3-none-any.whl → 1.5.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 (95) hide show
  1. docs/source/conf.py +1 -1
  2. examples/abl_states/run.py +58 -56
  3. examples/dyn_wakes/run.py +110 -118
  4. examples/field_data_nc/run.py +23 -21
  5. examples/multi_height/run.py +8 -6
  6. examples/scan_row/run.py +89 -87
  7. examples/sector_management/run.py +40 -38
  8. examples/states_lookup_table/run.py +6 -4
  9. examples/streamline_wakes/run.py +10 -8
  10. examples/timelines/run.py +100 -98
  11. examples/timeseries/run.py +71 -76
  12. examples/wind_rose/run.py +27 -25
  13. examples/yawed_wake/run.py +85 -81
  14. foxes/algorithms/downwind/downwind.py +5 -5
  15. foxes/algorithms/downwind/models/init_farm_data.py +58 -28
  16. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  17. foxes/core/algorithm.py +6 -5
  18. foxes/core/data.py +75 -4
  19. foxes/core/data_calc_model.py +4 -2
  20. foxes/core/engine.py +33 -40
  21. foxes/core/farm_data_model.py +16 -13
  22. foxes/core/model.py +19 -1
  23. foxes/core/point_data_model.py +19 -14
  24. foxes/core/rotor_model.py +1 -0
  25. foxes/core/wake_deflection.py +3 -3
  26. foxes/data/states/point_cloud_100.nc +0 -0
  27. foxes/data/states/weibull_cloud_4.nc +0 -0
  28. foxes/data/states/weibull_grid.nc +0 -0
  29. foxes/engines/dask.py +3 -6
  30. foxes/engines/default.py +2 -2
  31. foxes/engines/numpy.py +11 -10
  32. foxes/engines/pool.py +21 -11
  33. foxes/engines/single.py +8 -6
  34. foxes/input/farm_layout/__init__.py +1 -0
  35. foxes/input/farm_layout/from_arrays.py +68 -0
  36. foxes/input/states/__init__.py +7 -1
  37. foxes/input/states/dataset_states.py +710 -0
  38. foxes/input/states/field_data.py +531 -0
  39. foxes/input/states/multi_height.py +2 -0
  40. foxes/input/states/one_point_flow.py +1 -0
  41. foxes/input/states/point_cloud_data.py +618 -0
  42. foxes/input/states/scan.py +2 -0
  43. foxes/input/states/single.py +2 -0
  44. foxes/input/states/states_table.py +13 -23
  45. foxes/input/states/weibull_sectors.py +182 -77
  46. foxes/input/states/wrg_states.py +1 -1
  47. foxes/input/yaml/dict.py +25 -24
  48. foxes/input/yaml/windio/read_attributes.py +40 -27
  49. foxes/input/yaml/windio/read_farm.py +12 -10
  50. foxes/input/yaml/windio/read_outputs.py +25 -15
  51. foxes/input/yaml/windio/read_site.py +121 -12
  52. foxes/input/yaml/windio/windio.py +22 -10
  53. foxes/input/yaml/yaml.py +1 -0
  54. foxes/models/model_book.py +16 -15
  55. foxes/models/rotor_models/__init__.py +1 -0
  56. foxes/models/rotor_models/centre.py +1 -1
  57. foxes/models/rotor_models/direct_infusion.py +241 -0
  58. foxes/models/turbine_models/calculator.py +16 -3
  59. foxes/models/turbine_models/kTI_model.py +1 -0
  60. foxes/models/turbine_models/lookup_table.py +2 -0
  61. foxes/models/turbine_models/power_mask.py +1 -0
  62. foxes/models/turbine_models/rotor_centre_calc.py +2 -0
  63. foxes/models/turbine_models/sector_management.py +1 -0
  64. foxes/models/turbine_models/set_farm_vars.py +3 -8
  65. foxes/models/turbine_models/table_factors.py +2 -0
  66. foxes/models/turbine_models/thrust2ct.py +1 -0
  67. foxes/models/turbine_models/yaw2yawm.py +2 -0
  68. foxes/models/turbine_models/yawm2yaw.py +2 -0
  69. foxes/models/turbine_types/PCt_file.py +2 -4
  70. foxes/models/turbine_types/PCt_from_two.py +1 -0
  71. foxes/models/turbine_types/__init__.py +1 -0
  72. foxes/models/turbine_types/calculator_type.py +123 -0
  73. foxes/models/turbine_types/null_type.py +1 -0
  74. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
  75. foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
  76. foxes/output/farm_layout.py +2 -0
  77. foxes/output/farm_results_eval.py +4 -1
  78. foxes/output/flow_plots_2d/flow_plots.py +18 -0
  79. foxes/output/flow_plots_2d/get_fig.py +1 -0
  80. foxes/output/output.py +6 -1
  81. foxes/output/results_writer.py +1 -1
  82. foxes/output/rose_plot.py +10 -0
  83. foxes/output/rotor_point_plots.py +3 -0
  84. foxes/output/state_turbine_map.py +3 -0
  85. foxes/output/turbine_type_curves.py +3 -0
  86. foxes/utils/dict.py +46 -34
  87. foxes/utils/factory.py +2 -2
  88. foxes/utils/xarray_utils.py +20 -12
  89. {foxes-1.4.dist-info → foxes-1.5.1.dist-info}/METADATA +32 -52
  90. {foxes-1.4.dist-info → foxes-1.5.1.dist-info}/RECORD +94 -86
  91. foxes/input/states/field_data_nc.py +0 -833
  92. {foxes-1.4.dist-info → foxes-1.5.1.dist-info}/WHEEL +0 -0
  93. {foxes-1.4.dist-info → foxes-1.5.1.dist-info}/entry_points.txt +0 -0
  94. {foxes-1.4.dist-info → foxes-1.5.1.dist-info}/licenses/LICENSE +0 -0
  95. {foxes-1.4.dist-info → foxes-1.5.1.dist-info}/top_level.txt +0 -0
@@ -82,7 +82,9 @@ if __name__ == "__main__":
82
82
 
83
83
  # set turbines in yaw
84
84
  yawm = np.array([[args.yawm, args.yawm2]])
85
- mbook.turbine_models["set_yawm"] = foxes.models.turbine_models.SetFarmVars()
85
+ mbook.turbine_models["set_yawm"] = foxes.models.turbine_models.SetFarmVars(
86
+ pre_rotor=True
87
+ )
86
88
  mbook.turbine_models["set_yawm"].add_var(FV.YAWM, yawm)
87
89
 
88
90
  # create states
@@ -112,93 +114,95 @@ if __name__ == "__main__":
112
114
  wake_deflection=args.deflection,
113
115
  partial_wakes=args.pwakes,
114
116
  mbook=mbook,
115
- engine=args.engine,
117
+ )
118
+
119
+ with foxes.Engine.new(
120
+ engine_type=args.engine,
116
121
  n_procs=args.n_cpus,
117
122
  chunk_size_states=args.chunksize_states,
118
123
  chunk_size_points=args.chunksize_points,
119
- )
124
+ ):
125
+ # calculate farm results
126
+ farm_results = algo.calc_farm()
127
+ print("\nResults data:\n", farm_results)
120
128
 
121
- # calculate farm results
122
- farm_results = algo.calc_farm()
123
- print("\nResults data:\n", farm_results)
129
+ if not args.nofig:
130
+ # xy horizontal flow plot
131
+ print("\nHorizontal flow figure output:")
132
+ o = foxes.output.FlowPlots2D(algo, farm_results)
133
+ g = o.gen_states_fig_xy(
134
+ args.var, resolution=10, xmin=-500, xmax=3000, rotor_color="red"
135
+ )
136
+ fig = next(g)
137
+ plt.show()
138
+ plt.close(fig)
124
139
 
125
- if not args.nofig:
126
- # xy horizontal flow plot
127
- print("\nHorizontal flow figure output:")
128
- o = foxes.output.FlowPlots2D(algo, farm_results)
129
- g = o.gen_states_fig_xy(
130
- args.var, resolution=10, xmin=-500, xmax=3000, rotor_color="red"
131
- )
132
- fig = next(g)
133
- plt.show()
134
- plt.close(fig)
140
+ # yz flow plot
141
+ print("\nVertical flow figure output:")
142
+ o = foxes.output.FlowPlots2D(algo, farm_results)
143
+ g = o.gen_states_fig_yz(
144
+ args.var,
145
+ resolution=5,
146
+ x=750,
147
+ ymin=-200,
148
+ ymax=200,
149
+ zmin=0,
150
+ zmax=250,
151
+ rotor_color="red",
152
+ verbosity=0,
153
+ )
154
+ fig = next(g)
155
+ plt.show()
156
+ plt.close(fig)
135
157
 
136
- # yz flow plot
137
- print("\nVertical flow figure output:")
138
- o = foxes.output.FlowPlots2D(algo, farm_results)
139
- g = o.gen_states_fig_yz(
140
- args.var,
141
- resolution=5,
142
- x=750,
143
- ymin=-200,
144
- ymax=200,
145
- zmin=0,
146
- zmax=250,
147
- rotor_color="red",
148
- verbosity=0,
149
- )
150
- fig = next(g)
151
- plt.show()
152
- plt.close(fig)
158
+ # add capacity and efficiency to farm results
159
+ o = foxes.output.FarmResultsEval(farm_results)
160
+ o.add_capacity(algo)
161
+ o.add_capacity(algo, ambient=True)
162
+ o.add_efficiency()
153
163
 
154
- # add capacity and efficiency to farm results
155
- o = foxes.output.FarmResultsEval(farm_results)
156
- o.add_capacity(algo)
157
- o.add_capacity(algo, ambient=True)
158
- o.add_efficiency()
159
-
160
- # state-turbine results
161
- farm_df = farm_results.to_dataframe()
162
- print("\nFarm results data:\n")
163
- print(
164
- farm_df[
165
- [
166
- FV.X,
167
- FV.AMB_REWS,
168
- FV.REWS,
169
- FV.AMB_TI,
170
- FV.TI,
171
- FV.AMB_P,
172
- FV.P,
173
- FV.WD,
174
- FV.YAW,
175
- FV.YAWM,
164
+ # state-turbine results
165
+ farm_df = farm_results.to_dataframe()
166
+ print("\nFarm results data:\n")
167
+ print(
168
+ farm_df[
169
+ [
170
+ FV.X,
171
+ FV.AMB_REWS,
172
+ FV.REWS,
173
+ FV.AMB_TI,
174
+ FV.TI,
175
+ FV.AMB_P,
176
+ FV.P,
177
+ FV.WD,
178
+ FV.YAW,
179
+ FV.YAWM,
180
+ ]
176
181
  ]
177
- ]
178
- )
179
- print()
182
+ )
183
+ print()
180
184
 
181
- # results by turbine
182
- turbine_results = o.reduce_states(
183
- {
184
- FV.AMB_P: "weights",
185
- FV.P: "weights",
186
- FV.AMB_CAP: "weights",
187
- FV.CAP: "weights",
188
- }
189
- )
190
- turbine_results[FV.AMB_YLD] = o.calc_turbine_yield(
191
- algo=algo, annual=True, ambient=True
192
- )
193
- turbine_results[FV.YLD] = o.calc_turbine_yield(algo=algo, annual=True)
194
- turbine_results[FV.EFF] = turbine_results[FV.P] / turbine_results[FV.AMB_P]
195
- print("\nResults by turbine:\n")
196
- print(turbine_results)
185
+ # results by turbine
186
+ turbine_results = o.reduce_states(
187
+ {
188
+ FV.AMB_P: "weights",
189
+ FV.P: "weights",
190
+ FV.AMB_CAP: "weights",
191
+ FV.CAP: "weights",
192
+ }
193
+ )
194
+ turbine_results[FV.AMB_YLD] = o.calc_turbine_yield(
195
+ algo=algo, annual=True, ambient=True
196
+ )
197
+ turbine_results[FV.YLD] = o.calc_turbine_yield(algo=algo, annual=True)
198
+ turbine_results[FV.EFF] = turbine_results[FV.P] / turbine_results[FV.AMB_P]
199
+ print("\nResults by turbine:\n")
200
+ print(turbine_results)
197
201
 
198
- # power results
199
- P0 = o.calc_mean_farm_power(ambient=True)
200
- P = o.calc_mean_farm_power()
201
- print(f"\nFarm power : {P / 1000:.1f} MW")
202
- print(f"Farm ambient power: {P0 / 1000:.1f} MW")
203
- print(f"Farm efficiency : {o.calc_farm_efficiency() * 100:.2f} %")
204
- print(f"Annual farm yield : {turbine_results[FV.YLD].sum():.2f} GWh.")
202
+ # power results
203
+ P0 = o.calc_mean_farm_power(ambient=True)
204
+ P = o.calc_mean_farm_power()
205
+ print(f"\nFarm power : {P / 1000:.1f} MW")
206
+ print(f"Farm ambient power: {P0 / 1000:.1f} MW")
207
+ print(f"Farm efficiency : {o.calc_farm_efficiency() * 100:.2f} %")
208
+ print(f"Annual farm yield : {turbine_results[FV.YLD].sum():.2f} GWh.")
@@ -477,7 +477,7 @@ class Downwind(Algorithm):
477
477
  # 2) calculate ambient rotor results:
478
478
  mlist.models.append(self.rotor_model)
479
479
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
480
- calc_pars[-1].update({"store": True})
480
+ calc_pars[-1]["store"] = True
481
481
 
482
482
  # 3) run post-rotor turbine models via farm controller:
483
483
  mlist.models.append(self.farm_controller)
@@ -508,7 +508,7 @@ class Downwind(Algorithm):
508
508
  def _launch_parallel_farm_calc(
509
509
  self,
510
510
  mlist,
511
- *data,
511
+ model_data,
512
512
  outputs=None,
513
513
  normalize=False,
514
514
  **kwargs,
@@ -520,8 +520,8 @@ class Downwind(Algorithm):
520
520
  ----------
521
521
  mlist: foxes.models.FarmDataModelList
522
522
  The model list
523
- data: tuple of xarray.Dataset
524
- The (mdata, fdata) inputs
523
+ model_data: xarray.Dataset
524
+ The initial model data
525
525
  outputs: list of str, optional
526
526
  The output variables, or None for defaults
527
527
  normalize: bool
@@ -538,7 +538,7 @@ class Downwind(Algorithm):
538
538
  """
539
539
  out_vars = self.farm_vars if outputs is None else outputs
540
540
  farm_results = get_engine().run_calculation(
541
- self, mlist, *data, out_vars=out_vars, **kwargs
541
+ self, mlist, model_data, out_vars=out_vars, **kwargs
542
542
  )
543
543
 
544
544
  if normalize:
@@ -74,17 +74,17 @@ class InitFarmData(FarmDataModel):
74
74
  n_states = fdata.n_states
75
75
  n_turbines = algo.n_turbines
76
76
 
77
- # define FV.TXYH as vector [X, Y, H]:
78
- fdata[FV.TXYH] = np.full(
79
- (n_states, n_turbines, 3), np.nan, dtype=config.dtype_double
77
+ # add and set X, Y, H, D:
78
+ fdata.add(
79
+ FV.TXYH,
80
+ np.zeros((n_states, n_turbines, 3), dtype=config.dtype_double),
81
+ (FC.STATE, FC.TURBINE, FC.XYH),
82
+ )
83
+ fdata.add(
84
+ FV.D,
85
+ np.zeros((n_states, n_turbines), dtype=config.dtype_double),
86
+ (FC.STATE, FC.TURBINE),
80
87
  )
81
- fdata.dims[FV.TXYH] = (FC.STATE, FC.TURBINE, FC.XYH)
82
- for i, v in enumerate([FV.X, FV.Y, FV.H]):
83
- fdata[v] = fdata[FV.TXYH][..., i]
84
- fdata.dims[v] = (FC.STATE, FC.TURBINE)
85
-
86
- # set X, Y, H, D:
87
- fdata[FV.D] = np.zeros((n_states, n_turbines), dtype=config.dtype_double)
88
88
  for ti, t in enumerate(algo.farm.turbines):
89
89
  if len(t.xy.shape) == 1:
90
90
  fdata[FV.TXYH][:, ti, :2] = t.xy[None, :]
@@ -103,34 +103,64 @@ class InitFarmData(FarmDataModel):
103
103
  D = algo.farm_controller.turbine_types[ti].D
104
104
  fdata[FV.D][:, ti] = D
105
105
 
106
- # calc WD and YAW at rotor centres:
106
+ # calc WD at rotor centres:
107
107
  svrs = algo.states.output_point_vars(algo)
108
108
  tdata = TData.from_points(points=fdata[FV.TXYH], variables=svrs)
109
109
  sres = algo.states.calculate(algo, mdata, fdata, tdata)
110
- fdata[FV.WD] = sres[FV.WD][:, :, 0]
110
+ fdata.add(
111
+ FV.WD,
112
+ sres[FV.WD][:, :, 0],
113
+ (FC.STATE, FC.TURBINE),
114
+ )
115
+ fdata.add(
116
+ FV.AMB_WD,
117
+ fdata[FV.WD].copy(),
118
+ (FC.STATE, FC.TURBINE),
119
+ )
111
120
  del tdata, sres, svrs
112
121
 
113
- # calculate and inverse:
122
+ # calculate downwind order:
114
123
  order = algo.wake_frame.calc_order(algo, mdata, fdata)
115
124
  ssel = np.zeros_like(order)
116
125
  ssel[:] = np.arange(n_states)[:, None]
117
- fdata[FV.ORDER] = order
118
- fdata[FV.ORDER_SSEL] = ssel
119
- fdata[FV.ORDER_INV] = np.zeros_like(order)
120
- fdata[FV.ORDER_INV][ssel, order] = np.arange(n_turbines)[None, :]
121
126
 
122
127
  # apply downwind order to all data:
123
- fdata[FV.TXYH] = fdata[FV.TXYH][ssel, order]
128
+ for data in [fdata, mdata]:
129
+ for k in data.keys():
130
+ if (
131
+ k not in [FV.X, FV.Y, FV.H]
132
+ and tuple(data.dims[k][:2]) == (FC.STATE, FC.TURBINE)
133
+ and np.any(data[k] != data[k][0, 0, None, None])
134
+ ):
135
+ data[k][:] = data[k][ssel, order]
136
+
137
+ # add derived data:
124
138
  for i, v in enumerate([FV.X, FV.Y, FV.H]):
125
- fdata[v] = fdata[FV.TXYH][..., i]
126
- for v in [FV.D, FV.WD]:
127
- if np.any(fdata[v] != fdata[v][0, 0, None, None]):
128
- fdata[v] = fdata[v][ssel, order]
129
- fdata[FV.YAW] = fdata[FV.WD].copy()
130
- for k in mdata.keys():
131
- if tuple(mdata.dims[k][:2]) == (FC.STATE, FC.TURBINE) and np.any(
132
- mdata[k] != mdata[k][0, 0, None, None]
133
- ):
134
- mdata[k] = mdata[k][ssel, order]
139
+ fdata.add(
140
+ v,
141
+ fdata[FV.TXYH][:, :, i],
142
+ (FC.STATE, FC.TURBINE),
143
+ )
144
+ fdata.add(
145
+ FV.YAW,
146
+ fdata[FV.WD].copy(),
147
+ (FC.STATE, FC.TURBINE),
148
+ )
149
+ fdata.add(
150
+ FV.ORDER,
151
+ order,
152
+ (FC.STATE, FC.TURBINE),
153
+ )
154
+ fdata.add(
155
+ FV.ORDER_SSEL,
156
+ ssel,
157
+ (FC.STATE, FC.TURBINE),
158
+ )
159
+ fdata.add(
160
+ FV.ORDER_INV,
161
+ np.zeros_like(order),
162
+ (FC.STATE, FC.TURBINE),
163
+ )
164
+ fdata[FV.ORDER_INV][ssel, order] = np.arange(n_turbines)[None, :]
135
165
 
136
166
  return {v: fdata[v] for v in self.output_farm_vars(algo)}
@@ -65,5 +65,5 @@ class SetAmbFarmResults(FarmDataModel):
65
65
 
66
66
  """
67
67
  for v in self.vars:
68
- fdata[FV.var2amb[v]] = fdata[v].copy()
68
+ fdata.add(FV.var2amb[v], fdata[v].copy(), fdata.dims[v])
69
69
  return {v: fdata[v] for v in self.output_farm_vars(algo)}
foxes/core/algorithm.py CHANGED
@@ -63,8 +63,8 @@ class Algorithm(Model):
63
63
  self.__farm = farm
64
64
  self.__mbook = mbook
65
65
  self.__dbook = StaticData() if dbook is None else dbook
66
- self.__idata_mem = Dict(name="idata_mem")
67
- self.__chunk_store = Dict(name="chunk_store")
66
+ self.__idata_mem = Dict(_name="idata_mem")
67
+ self.__chunk_store = Dict(_name="chunk_store")
68
68
 
69
69
  if len(engine_pars):
70
70
  if "engine_type" in engine_pars:
@@ -558,7 +558,7 @@ class Algorithm(Model):
558
558
  "n_states": n_states,
559
559
  "n_targets": n_targets,
560
560
  },
561
- name=f"chunk_store_{i0}_{t0}",
561
+ _name=f"chunk_store_{i0}_{t0}",
562
562
  )
563
563
 
564
564
  self.chunk_store[key][name] = data.copy() if copy else data
@@ -638,11 +638,11 @@ class Algorithm(Model):
638
638
  """
639
639
  chunk_store = self.chunk_store
640
640
  if new_chunk_store is None:
641
- self.__chunk_store = Dict(name="chunk_store")
641
+ self.__chunk_store = Dict(_name="chunk_store")
642
642
  elif isinstance(new_chunk_store, Dict):
643
643
  self.__chunk_store = new_chunk_store
644
644
  else:
645
- self.__chunk_store = Dict(name="chunk_store")
645
+ self.__chunk_store = Dict(_name="chunk_store")
646
646
  self.__chunk_store.update(new_chunk_store)
647
647
  return chunk_store
648
648
 
@@ -912,6 +912,7 @@ class Algorithm(Model):
912
912
  isel=isel,
913
913
  **kwargs,
914
914
  )
915
+ self.reset_chunk_store(chunk_store)
915
916
 
916
917
  # reset to not running:
917
918
  self.unset_running(
foxes/core/data.py CHANGED
@@ -53,7 +53,7 @@ class Data(Dict):
53
53
  The data container name
54
54
 
55
55
  """
56
- super().__init__(name=name)
56
+ super().__init__(_name=name)
57
57
 
58
58
  self.update(data)
59
59
  self.dims = dims
@@ -109,12 +109,12 @@ class Data(Dict):
109
109
  or the corresponding index
110
110
 
111
111
  """
112
- if FC.STATE not in self:
113
- return None
114
- elif counter:
112
+ if counter:
115
113
  if self.__states_i0 is None:
116
114
  raise KeyError(f"Data '{self.name}': states_i0 requested but not set")
117
115
  return self.__states_i0
116
+ elif FC.STATE not in self:
117
+ return None
118
118
  else:
119
119
  return self[FC.STATE][0]
120
120
 
@@ -394,6 +394,74 @@ class FData(Data):
394
394
  f"FData '{self.name}': Missing '{x}' in sizes, got {sorted(list(self.sizes.keys()))}"
395
395
  )
396
396
 
397
+ @classmethod
398
+ def from_sizes(cls, n_states, n_turbines, *args, callback=None, **kwargs):
399
+ """
400
+ Create Data object from model data
401
+
402
+ Parameters
403
+ ----------
404
+ n_states: int
405
+ The number of states
406
+ n_turbines: int
407
+ The number of turbines
408
+ args: tuple, optional
409
+ Additional parameters for the constructor
410
+ callback: Function, optional
411
+ Function f(data, dims) that manipulates
412
+ the data and dims dicts before construction
413
+ kwargs: dict, optional
414
+ Additional parameters for the constructor
415
+
416
+ Returns
417
+ -------
418
+ data: Data
419
+ The data object
420
+
421
+ """
422
+ data = cls(*args, **kwargs)
423
+ data.sizes[FC.STATE] = n_states
424
+ data.sizes[FC.TURBINE] = n_turbines
425
+
426
+ if callback is not None:
427
+ callback(data, data.dims)
428
+
429
+ return data
430
+
431
+ @classmethod
432
+ def from_mdata(cls, mdata, *args, callback=None, **kwargs):
433
+ """
434
+ Create Data object from model data
435
+
436
+ Parameters
437
+ ----------
438
+ mdata: MData
439
+ The model data
440
+ args: tuple, optional
441
+ Additional parameters for the constructor
442
+ callback: Function, optional
443
+ Function f(data, dims) that manipulates
444
+ the data and dims dicts before construction
445
+ kwargs: dict, optional
446
+ Additional parameters for the constructor
447
+
448
+ Returns
449
+ -------
450
+ data: Data
451
+ The data object
452
+
453
+ """
454
+ data = cls(*args, **kwargs)
455
+ for v in [FC.STATE, FC.TURBINE]:
456
+ data[v] = mdata[v]
457
+ data.dims[v] = mdata.dims[v]
458
+ data.sizes[v] = mdata.sizes[v]
459
+
460
+ if callback is not None:
461
+ callback(data, data.dims)
462
+
463
+ return data
464
+
397
465
  @classmethod
398
466
  def from_dataset(cls, ds, *args, mdata=None, callback=None, **kwargs):
399
467
  """
@@ -427,6 +495,9 @@ class FData(Data):
427
495
  if FC.STATE not in data:
428
496
  data[FC.STATE] = mdata[FC.STATE]
429
497
  dims[FC.STATE] = mdata.dims[FC.STATE]
498
+ if FC.TURBINE not in data:
499
+ data[FC.TURBINE] = mdata[FC.TURBINE]
500
+ dims[FC.TURBINE] = mdata.dims[FC.TURBINE]
430
501
  if callback is not None:
431
502
  callback(data, dims)
432
503
 
@@ -45,8 +45,10 @@ class DataCalcModel(Model):
45
45
  ----------
46
46
  algo: foxes.core.Algorithm
47
47
  The calculation algorithm
48
- data: tuple of foxes.core.Data
49
- The input data
48
+ data: tuple of foxes.core.Data, optional
49
+ The input data, typically either (mdata, fdata) in
50
+ the case of farm calculations, or (mdata, fdata, tdata)
51
+ for point data calculations
50
52
  parameters: dict, optional
51
53
  The calculation parameters
52
54
 
foxes/core/engine.py CHANGED
@@ -6,7 +6,6 @@ from xarray import Dataset
6
6
 
7
7
  from .data import MData, FData, TData
8
8
  from foxes.utils import new_instance
9
- from foxes.config import config
10
9
  import foxes.constants as FC
11
10
 
12
11
  __global_engine_data__ = dict(
@@ -350,8 +349,9 @@ class Engine(ABC):
350
349
 
351
350
  Returns
352
351
  -------
353
- data: list of foxes.core.Data
354
- Either [mdata, fdata] or [mdata, fdata, tdata]
352
+ data: tuple of foxes.core.Data
353
+ The input data for the chunk calculation,
354
+ either (mdata, fdata) or (mdata, fdata, tdata)
355
355
 
356
356
  """
357
357
  # prepare:
@@ -370,51 +370,37 @@ class Engine(ABC):
370
370
  )
371
371
 
372
372
  # create fdata:
373
- if point_data is None:
374
-
375
- def cb(data, dims):
376
- n_states = i1_states - i0_states
377
- for o in set(out_vars).difference(data.keys()):
378
- data[o] = np.full(
379
- (n_states, algo.n_turbines), np.nan, dtype=config.dtype_double
380
- )
381
- dims[o] = (FC.STATE, FC.TURBINE)
382
-
373
+ if farm_data is not None:
374
+ fdata = FData.from_dataset(
375
+ farm_data,
376
+ mdata=mdata,
377
+ s_states=s_states,
378
+ callback=None,
379
+ states_i0=i0_states,
380
+ copy=True,
381
+ )
383
382
  else:
384
- cb = None
385
- fdata = FData.from_dataset(
386
- farm_data,
387
- mdata=mdata,
388
- s_states=s_states,
389
- callback=cb,
390
- states_i0=i0_states,
391
- copy=True,
392
- )
383
+ fdata = FData.from_mdata(
384
+ mdata=mdata,
385
+ states_i0=i0_states,
386
+ )
393
387
 
394
388
  # create tdata:
395
- tdata = None
396
- if point_data is not None:
397
-
398
- def cb(data, dims):
399
- n_states = i1_states - i0_states
400
- n_targets = i1_targets - i0_targets
401
- for o in set(out_vars).difference(data.keys()):
402
- data[o] = np.full(
403
- (n_states, n_targets, 1), np.nan, dtype=config.dtype_double
404
- )
405
- dims[o] = (FC.STATE, FC.TARGET, FC.TPOINT)
406
-
407
- tdata = TData.from_dataset(
389
+ tdata = (
390
+ TData.from_dataset(
408
391
  point_data,
409
392
  mdata=mdata,
410
393
  s_states=s_states,
411
394
  s_targets=s_targets,
412
- callback=cb,
395
+ callback=None,
413
396
  states_i0=i0_states,
414
397
  copy=True,
415
398
  )
399
+ if point_data is not None
400
+ else None
401
+ )
416
402
 
417
- return [d for d in [mdata, fdata, tdata] if d is not None]
403
+ return (mdata, fdata) if tdata is None else (mdata, fdata, tdata)
418
404
 
419
405
  def combine_results(
420
406
  self,
@@ -535,7 +521,14 @@ class Engine(ABC):
535
521
  )
536
522
 
537
523
  @abstractmethod
538
- def run_calculation(self, algo, model, model_data, farm_data, point_data=None):
524
+ def run_calculation(
525
+ self,
526
+ algo,
527
+ model,
528
+ model_data=None,
529
+ farm_data=None,
530
+ point_data=None,
531
+ ):
539
532
  """
540
533
  Runs the model calculation
541
534
 
@@ -543,12 +536,12 @@ class Engine(ABC):
543
536
  ----------
544
537
  algo: foxes.core.Algorithm
545
538
  The algorithm object
546
- model: foxes.core.DataCalcModel
539
+ model: foxes.core.DataCalcModel, optional
547
540
  The model that whose calculate function
548
541
  should be run
549
542
  model_data: xarray.Dataset
550
543
  The initial model data
551
- farm_data: xarray.Dataset
544
+ farm_data: xarray.Dataset, optional
552
545
  The initial farm data
553
546
  point_data: xarray.Dataset, optional
554
547
  The initial point data