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
@@ -0,0 +1,123 @@
1
+ from foxes.core import TurbineType
2
+
3
+
4
+ class CalculatorType(TurbineType):
5
+ """
6
+ Direct data infusion by a user function.
7
+
8
+ :group: models.turbine_types
9
+
10
+ """
11
+
12
+ def __init__(
13
+ self,
14
+ func,
15
+ out_vars,
16
+ *args,
17
+ needs_rews2=False,
18
+ needs_rews3=False,
19
+ **kwargs,
20
+ ):
21
+ """
22
+ Constructor.
23
+
24
+ Parameters
25
+ ----------
26
+ func: callable
27
+ The function to calculate farm variables, should have the signature:
28
+ f(algo, mdata, fdata, st_sel) -> dict, where the keys are
29
+ output variable names and the values are numpy.ndarrays
30
+ with shape (n_states, n_turbines).
31
+
32
+ Beware that the turbine ordering in fdata is in downwind order,
33
+ hence external data X of shape (n_states, n_turbines) in farm order
34
+ needs to be reordered by X[ssel, order] with
35
+ ssel = fdata[FV.ORDER_SSEL], order = fdata[FV.ORDER]
36
+ before using it in combination with fdata variables.
37
+ out_vars: list of str
38
+ The output variables of the function
39
+ args: tuple, optional
40
+ Additional parameters for TurbineType class
41
+ needs_rews2: bool
42
+ Flag for runs that require the REWS2 variable
43
+ needs_rews3: bool
44
+ Flag for runs that require the REWS3 variable
45
+ kwargs: dict, optional
46
+ Additional parameters for TurbineType class
47
+
48
+ """
49
+ super().__init__(*args, **kwargs)
50
+ self._func = func
51
+ self._ovars = out_vars
52
+ self._rews2 = needs_rews2
53
+ self._rews3 = needs_rews3
54
+
55
+ def needs_rews2(self):
56
+ """
57
+ Returns flag for requiring REWS2 variable
58
+
59
+ Returns
60
+ -------
61
+ flag: bool
62
+ True if REWS2 is required
63
+
64
+ """
65
+ return self._rews2
66
+
67
+ def needs_rews3(self):
68
+ """
69
+ Returns flag for requiring REWS3 variable
70
+
71
+ Returns
72
+ -------
73
+ flag: bool
74
+ True if REWS3 is required
75
+
76
+ """
77
+ return self._rews3
78
+
79
+ def output_farm_vars(self, algo):
80
+ """
81
+ The variables which are being modified by the model.
82
+
83
+ Parameters
84
+ ----------
85
+ algo: foxes.core.Algorithm
86
+ The calculation algorithm
87
+
88
+ Returns
89
+ -------
90
+ output_vars: list of str
91
+ The output variable names
92
+
93
+ """
94
+ return self._ovars
95
+
96
+ def calculate(self, algo, mdata, fdata, st_sel):
97
+ """
98
+ The main model calculation.
99
+
100
+ This function is executed on a single chunk of data,
101
+ all computations should be based on numpy arrays.
102
+
103
+ Parameters
104
+ ----------
105
+ algo: foxes.core.Algorithm
106
+ The calculation algorithm
107
+ mdata: foxes.core.MData
108
+ The model data
109
+ fdata: foxes.core.FData
110
+ The farm data
111
+ st_sel: numpy.ndarray of bool
112
+ The state-turbine selection,
113
+ shape: (n_states, n_turbines)
114
+
115
+ Returns
116
+ -------
117
+ results: dict
118
+ The resulting data, keys: output variable str.
119
+ Values: numpy.ndarray with shape (n_states, n_turbines)
120
+
121
+ """
122
+ self.ensure_output_vars(algo, fdata)
123
+ return self._func(algo, mdata, fdata, st_sel)
@@ -102,4 +102,5 @@ class NullType(TurbineType):
102
102
  Values: numpy.ndarray with shape (n_states, n_turbines)
103
103
 
104
104
  """
105
+ self.ensure_output_vars(algo, fdata)
105
106
  return {}
@@ -262,6 +262,8 @@ class WsRho2PCtFromTwo(TurbineType):
262
262
  Values: numpy.ndarray with shape (n_states, n_turbines)
263
263
 
264
264
  """
265
+ # prepare:
266
+ self.ensure_output_vars(algo, fdata)
265
267
 
266
268
  # calculate P:
267
269
  st_sel_P = (
@@ -5,8 +5,8 @@ from scipy.interpolate import interpn
5
5
  from foxes.core import TurbineType
6
6
  from foxes.utils import PandasFileHelper
7
7
  from foxes.data import PCTCURVE, parse_Pct_two_files
8
- import foxes.variables as FV
9
8
  from foxes.config import config, get_input_path
9
+ import foxes.variables as FV
10
10
 
11
11
 
12
12
  class WsTI2PCtFromTwo(TurbineType):
@@ -274,6 +274,8 @@ class WsTI2PCtFromTwo(TurbineType):
274
274
  Values: numpy.ndarray with shape (n_states, n_turbines)
275
275
 
276
276
  """
277
+ # prepare:
278
+ self.ensure_output_vars(algo, fdata)
277
279
 
278
280
  # calculate P:
279
281
  st_sel_P = (
@@ -186,6 +186,8 @@ class FarmLayoutOutput(Output):
186
186
  The image object
187
187
 
188
188
  """
189
+ if self.nofig:
190
+ return None, None
189
191
 
190
192
  if fig is None:
191
193
  fig = plt.figure(figsize=figsize)
@@ -25,7 +25,7 @@ class FarmResultsEval(Output):
25
25
 
26
26
  """
27
27
 
28
- def __init__(self, farm_results):
28
+ def __init__(self, farm_results, **kwargs):
29
29
  """
30
30
  Constructor.
31
31
 
@@ -33,8 +33,11 @@ class FarmResultsEval(Output):
33
33
  ----------
34
34
  farm_results: xarray.Dataset
35
35
  The farm results
36
+ kwargs: dict, optional
37
+ Additional parameters for the base class
36
38
 
37
39
  """
40
+ super().__init__(**kwargs)
38
41
  self.results = farm_results
39
42
 
40
43
  def weinsum(self, rhs, *vars):
@@ -96,6 +96,9 @@ class FlowPlots2D(SliceData):
96
96
  The image data, shape: (n_x, n_y)
97
97
 
98
98
  """
99
+ if self.nofig:
100
+ return None
101
+
99
102
  variables = list(set([var] + [FV.WD, FV.WS]))
100
103
  vi = variables.index(var)
101
104
  wdi = variables.index(FV.WD)
@@ -245,6 +248,9 @@ class FlowPlots2D(SliceData):
245
248
  The image data, shape: (n_x, n_y)
246
249
 
247
250
  """
251
+ if self.nofig:
252
+ return None
253
+
248
254
  variables = list(set([var] + [FV.WD, FV.WS]))
249
255
  vi = variables.index(var)
250
256
  wdi = variables.index(FV.WD)
@@ -395,6 +401,9 @@ class FlowPlots2D(SliceData):
395
401
  The image data, shape: (n_x, n_y)
396
402
 
397
403
  """
404
+ if self.nofig:
405
+ return None
406
+
398
407
  variables = list(set([var] + [FV.WD, FV.WS]))
399
408
  vi = variables.index(var)
400
409
  wdi = variables.index(FV.WD)
@@ -547,6 +556,9 @@ class FlowPlots2D(SliceData):
547
556
  or matplotlib.QuadContourSet
548
557
 
549
558
  """
559
+ if self.nofig:
560
+ yield None
561
+
550
562
  variables = list(set([var] + [FV.WD, FV.WS]))
551
563
  vi = variables.index(var)
552
564
  wdi = variables.index(FV.WD)
@@ -735,6 +747,9 @@ class FlowPlots2D(SliceData):
735
747
  or matplotlib.QuadContourSet
736
748
 
737
749
  """
750
+ if self.nofig:
751
+ yield None
752
+
738
753
  variables = list(set([var] + [FV.WD, FV.WS]))
739
754
  vi = variables.index(var)
740
755
  wdi = variables.index(FV.WD)
@@ -921,6 +936,9 @@ class FlowPlots2D(SliceData):
921
936
  or matplotlib.QuadContourSet
922
937
 
923
938
  """
939
+ if self.nofig:
940
+ yield None
941
+
924
942
  variables = list(set([var] + [FV.WD, FV.WS]))
925
943
  vi = variables.index(var)
926
944
  wdi = variables.index(FV.WD)
@@ -96,6 +96,7 @@ def get_fig(
96
96
  or matplotlib.QuadContourSet
97
97
 
98
98
  """
99
+
99
100
  # create plot:
100
101
  if fig is None:
101
102
  hfig = plt.figure(figsize=figsize)
foxes/output/output.py CHANGED
@@ -17,12 +17,14 @@ class Output:
17
17
  The output file directory
18
18
  out_fname_fun: Function, optional
19
19
  Modifies file names by f(fname)
20
+ nofig: bool
21
+ Do not show figures
20
22
 
21
23
  :group: output
22
24
 
23
25
  """
24
26
 
25
- def __init__(self, out_dir=None, out_fname_fun=None):
27
+ def __init__(self, out_dir=None, out_fname_fun=None, nofig=False):
26
28
  """
27
29
  Constructor.
28
30
 
@@ -32,12 +34,15 @@ class Output:
32
34
  The output file directory
33
35
  out_fname_fun: Function, optional
34
36
  Modifies file names by f(fname)
37
+ nofig: bool
38
+ Do not show figures
35
39
 
36
40
  """
37
41
  self.out_dir = (
38
42
  get_output_path(out_dir) if out_dir is not None else config.output_dir
39
43
  )
40
44
  self.out_fname_fun = out_fname_fun
45
+ self.nofig = nofig
41
46
 
42
47
  if not self.out_dir.is_dir():
43
48
  print(f"{type(self).__name__}: Creating output dir {self.out_dir}")
@@ -46,7 +46,7 @@ class ResultsWriter(Output):
46
46
  self.data = data
47
47
  else:
48
48
  raise KeyError(
49
- f"ResultsWriter: Either give 'farm_results' or 'data' arguments"
49
+ "ResultsWriter: Either give 'farm_results' or 'data' arguments"
50
50
  )
51
51
 
52
52
  def _get_data_vars(self, variables):
foxes/output/rose_plot.py CHANGED
@@ -250,6 +250,9 @@ class RosePlotOutput(Output):
250
250
  The plot data
251
251
 
252
252
  """
253
+ if self.nofig:
254
+ return None
255
+
253
256
  data = self.get_data(wd_sectors, ws_var, ws_bins, wd_var, **kwargs)
254
257
 
255
258
  n_wsb = data.sizes[ws_var]
@@ -337,6 +340,8 @@ class RosePlotOutput(Output):
337
340
  The wind rose data
338
341
 
339
342
  """
343
+ if self.nofig:
344
+ return None
340
345
 
341
346
  r = self.get_figure(*args, ret_data=ret_data, **kwargs)
342
347
  fpath = self.get_fpath(file_name)
@@ -560,6 +565,9 @@ class WindRoseBinPlot(Output):
560
565
  The axes object
561
566
 
562
567
  """
568
+ if self.nofig:
569
+ return None
570
+
563
571
  data = self.get_data(
564
572
  variable=variable,
565
573
  ws_bins=ws_bins,
@@ -625,6 +633,8 @@ class WindRoseBinPlot(Output):
625
633
  The wind rose data
626
634
 
627
635
  """
636
+ if self.nofig:
637
+ return None
628
638
 
629
639
  r = self.get_figure(*args, ret_data=ret_data, **kwargs)
630
640
  fpath = self.get_fpath(file_name)
@@ -77,6 +77,9 @@ class RotorPointPlot(Output):
77
77
  The plot axes
78
78
 
79
79
  """
80
+ if self.nofig:
81
+ return None
82
+
80
83
  if fig is None:
81
84
  fig = plt.figure(figsize=figsize)
82
85
  ax = fig.add_subplot(111)
@@ -69,6 +69,9 @@ class StateTurbineMap(Output):
69
69
  The plot axis
70
70
 
71
71
  """
72
+ if self.nofig:
73
+ return None
74
+
72
75
  turbines = self.results[FC.TURBINE].to_numpy()
73
76
  states = self.results[FC.STATE].to_numpy()
74
77
 
@@ -105,6 +105,9 @@ class TurbineTypeCurves(Output):
105
105
  The plot axes, one for each variable
106
106
 
107
107
  """
108
+ if self.nofig:
109
+ return None
110
+
108
111
  vars = [variables] if isinstance(variables, str) else variables
109
112
  if isinstance(titles, str):
110
113
  titles = [titles]
foxes/utils/dict.py CHANGED
@@ -6,16 +6,11 @@ class Dict(dict):
6
6
  """
7
7
  A slightly enhanced dictionary.
8
8
 
9
- Attributes
10
- ----------
11
- name: str
12
- The dictionary name
13
-
14
9
  :group: utils
15
10
 
16
11
  """
17
12
 
18
- def __init__(self, *args, name=None, **kwargs):
13
+ def __init__(self, *args, _name=None, **kwargs):
19
14
  """
20
15
  Constructor.
21
16
 
@@ -23,38 +18,28 @@ class Dict(dict):
23
18
  ----------
24
19
  *args: tuple, optional
25
20
  Arguments passed to `dict`
26
- name: str, optional
21
+ _name: str, optional
27
22
  The dictionary name
28
23
  **kwargs: dict, optional
29
24
  Arguments passed to `dict`
30
25
 
31
26
  """
32
- tmp = dict()
33
- for a in args:
34
- tmp.update(
35
- {
36
- k: (
37
- Dict(d, name=f"{name}.{k}")
38
- if isinstance(d, dict) and not isinstance(d, Dict)
39
- else d
40
- )
41
- for k, d in a.items()
42
- }
43
- )
44
-
45
- super().__init__(
46
- **tmp,
47
- **{
48
- k: (
49
- Dict(d, name=k)
50
- if isinstance(d, dict) and not isinstance(d, Dict)
51
- else d
52
- )
53
- for k, d in kwargs.items()
54
- },
55
- )
27
+ super().__init__()
28
+ self._name = _name if _name is not None else type(self).__name__
29
+ self.update(*args, **kwargs)
56
30
 
57
- self.name = name if name is not None else type(self).__name__
31
+ @property
32
+ def name(self):
33
+ """
34
+ The dictionary name
35
+
36
+ Returns
37
+ -------
38
+ name: str
39
+ The dictionary name
40
+
41
+ """
42
+ return self._name
58
43
 
59
44
  def get_item(self, key, *deflt, prnt=True):
60
45
  """
@@ -93,7 +78,7 @@ class Dict(dict):
93
78
  raise e
94
79
 
95
80
  if isinstance(data, dict) and not isinstance(data, Dict):
96
- data = Dict(data, name=f"{self.name}.{key}")
81
+ data = Dict(data, _name=f"{self.name}.{key}")
97
82
 
98
83
  return data
99
84
 
@@ -121,6 +106,25 @@ class Dict(dict):
121
106
  del self[key]
122
107
  return data
123
108
 
109
+ def __setitem__(self, key, value):
110
+ if isinstance(value, list):
111
+ out = []
112
+ for i, x in enumerate(value):
113
+ if isinstance(x, dict) and not isinstance(x, Dict):
114
+ nme = f"{self.name}.{key}"
115
+ if len(value) > 1:
116
+ nme += f".{i}"
117
+ out.append(Dict(x, _name=nme))
118
+ else:
119
+ out.append(x)
120
+ value = out
121
+ elif isinstance(value, dict) and not isinstance(value, Dict):
122
+ out = Dict(_name=f"{self.name}.{key}")
123
+ out.update(value)
124
+ value = out
125
+
126
+ super().__setitem__(key, value)
127
+
124
128
  def __getitem__(self, key):
125
129
  try:
126
130
  return super().__getitem__(key)
@@ -129,6 +133,14 @@ class Dict(dict):
129
133
  e = f"{self.name}: Cannot find key '{key}'. Known keys: {k}"
130
134
  raise KeyError(e)
131
135
 
136
+ def update(self, *args, **kwargs):
137
+ """
138
+ Update the dictionary with the key/value pairs from other, overwriting existing keys.
139
+ """
140
+ other = dict(*args, **kwargs)
141
+ for k, v in other.items():
142
+ self[k] = v
143
+
132
144
  @classmethod
133
145
  def from_yaml(self, yml_file, verbosity=1):
134
146
  """
@@ -158,7 +170,7 @@ class Dict(dict):
158
170
  data = safe_load(stream)
159
171
  if data is None:
160
172
  data = {}
161
- dct = Dict(data, name=fpath.stem)
173
+ dct = Dict(data, _name=fpath.stem)
162
174
  _print(dct, level=2)
163
175
 
164
176
  return dct
foxes/utils/factory.py CHANGED
@@ -107,7 +107,7 @@ class Factory:
107
107
  f"Factory '{name_template}': Require indicator before variable '{v}' in template, e.g. '{v}<{v}>'"
108
108
  )
109
109
 
110
- self.options = Dict(name=f"{self._pre[0]}_options")
110
+ self.options = Dict(_name=f"{self._pre[0]}_options")
111
111
  for v, o in options.items():
112
112
  if v not in self.variables:
113
113
  raise KeyError(
@@ -121,7 +121,7 @@ class Factory:
121
121
  raise TypeError(
122
122
  f"Factory '{name_template}': Found option for variable '{v}' that is not a str, {k}"
123
123
  )
124
- self.options[v] = Dict(name=f"{self._pre[0]}_options_{v}", **o)
124
+ self.options[v] = Dict(_name=f"{self._pre[0]}_options_{v}", **o)
125
125
  elif hasattr(o, "__call__"):
126
126
  self.options[v] = o
127
127
  else:
@@ -31,24 +31,32 @@ def write_nc(
31
31
  Additional parameters for xarray.to_netcdf
32
32
 
33
33
  """
34
+
35
+ def _round(x, v, d):
36
+ """Helper function to round values"""
37
+ if d is not None:
38
+ if verbosity > 1:
39
+ print(f"File {fpath.name}: Rounding {v} to {d} decimals")
40
+ try:
41
+ x = x.astype(np.float32)
42
+ except ValueError:
43
+ pass
44
+ try:
45
+ return np.round(x, d)
46
+ except Exception:
47
+ pass
48
+ return x
49
+
34
50
  fpath = Path(fpath)
35
51
  if round is not None:
36
52
  crds = {}
37
- for v in ds.coords.keys():
53
+ for v, x in ds.coords.items():
38
54
  d = round.get(v, get_default_digits(v))
39
- if d is not None:
40
- if verbosity > 1:
41
- print(f"File {fpath.name}: Rounding {v} to {d} decimals")
42
- crds[v] = np.round(ds[v].to_numpy(), d)
43
- else:
44
- crds[v] = ds[v].to_numpy()
55
+ crds[v] = _round(x.to_numpy(), v, d)
45
56
  dvrs = {}
46
- for v in ds.data_vars.keys():
57
+ for v, x in ds.data_vars.items():
47
58
  d = round.get(v, get_default_digits(v))
48
- if d is not None:
49
- if verbosity > 1:
50
- print(f"File {fpath.name}: Rounding {v} to {d} decimals")
51
- dvrs[v] = (ds[v].dims, np.round(ds[v].to_numpy(), d))
59
+ dvrs[v] = (x.dims, _round(x.to_numpy(), v, d))
52
60
  ds = Dataset(coords=crds, data_vars=dvrs)
53
61
 
54
62
  enc = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: foxes
3
- Version: 1.4
3
+ Version: 1.5.1
4
4
  Summary: Farm Optimization and eXtended yield Evaluation Software
5
5
  Author: Jonas Schulte
6
6
  Maintainer: Jonas Schulte
@@ -36,7 +36,6 @@ Classifier: Topic :: Scientific/Engineering
36
36
  Classifier: Intended Audience :: Developers
37
37
  Classifier: Intended Audience :: Science/Research
38
38
  Classifier: Programming Language :: Python :: 3
39
- Classifier: Programming Language :: Python :: 3.8
40
39
  Classifier: Programming Language :: Python :: 3.9
41
40
  Classifier: Programming Language :: Python :: 3.10
42
41
  Classifier: Programming Language :: Python :: 3.11
@@ -45,60 +44,41 @@ Classifier: Programming Language :: Python :: 3.13
45
44
  Classifier: License :: OSI Approved :: MIT License
46
45
  Classifier: Operating System :: OS Independent
47
46
  Classifier: Development Status :: 4 - Beta
48
- Requires-Python: >=3.8
47
+ Requires-Python: >=3.9
49
48
  Description-Content-Type: text/markdown
50
49
  License-File: LICENSE
51
- Requires-Dist: matplotlib
52
- Requires-Dist: numpy
53
- Requires-Dist: pandas
54
- Requires-Dist: xarray
55
- Requires-Dist: scipy
56
- Requires-Dist: cycler
57
- Requires-Dist: tqdm
58
- Requires-Dist: pyyaml
59
- Requires-Dist: h5netcdf
50
+ Requires-Dist: cycler>=0.10
51
+ Requires-Dist: h5netcdf>=1.0
52
+ Requires-Dist: matplotlib>=3.8
53
+ Requires-Dist: numpy>=1.26
54
+ Requires-Dist: pandas>=2.0
55
+ Requires-Dist: pyyaml>=4.0
56
+ Requires-Dist: scipy>=1.12
57
+ Requires-Dist: tqdm>=2.0
58
+ Requires-Dist: xarray>=2023
60
59
  Provides-Extra: opt
61
- Requires-Dist: foxes-opt; extra == "opt"
60
+ Requires-Dist: foxes-opt>=0.5; extra == "opt"
62
61
  Provides-Extra: dask
63
- Requires-Dist: dask; extra == "dask"
64
- Requires-Dist: distributed; extra == "dask"
65
- Requires-Dist: dask-jobqueue; extra == "dask"
66
- Requires-Dist: setuptools; extra == "dask"
67
- Provides-Extra: eng
68
- Requires-Dist: multiprocess; extra == "eng"
69
- Requires-Dist: dask; extra == "eng"
70
- Requires-Dist: distributed; extra == "eng"
71
- Requires-Dist: dask-jobqueue; extra == "eng"
72
- Requires-Dist: setuptools; extra == "eng"
73
- Requires-Dist: mpi4py; extra == "eng"
74
- Requires-Dist: ray; extra == "eng"
75
- Provides-Extra: eng0
76
- Requires-Dist: multiprocess; extra == "eng0"
77
- Requires-Dist: dask; extra == "eng0"
78
- Requires-Dist: distributed; extra == "eng0"
79
- Requires-Dist: dask-jobqueue; extra == "eng0"
80
- Requires-Dist: setuptools; extra == "eng0"
81
- Requires-Dist: ray; extra == "eng0"
82
- Provides-Extra: test
83
- Requires-Dist: flake8; extra == "test"
84
- Requires-Dist: pytest; extra == "test"
62
+ Requires-Dist: dask>=2022.0; extra == "dask"
63
+ Requires-Dist: distributed>=2022.0; extra == "dask"
64
+ Requires-Dist: dask-jobqueue>=0.8; extra == "dask"
65
+ Requires-Dist: setuptools>=61.0; extra == "dask"
85
66
  Provides-Extra: doc
86
- Requires-Dist: setuptools; extra == "doc"
87
- Requires-Dist: sphinx; extra == "doc"
88
- Requires-Dist: sphinx-immaterial; extra == "doc"
89
- Requires-Dist: nbsphinx; extra == "doc"
90
- Requires-Dist: ipykernel; extra == "doc"
91
- Requires-Dist: ipywidgets; extra == "doc"
92
- Requires-Dist: m2r2; extra == "doc"
93
- Requires-Dist: lxml_html_clean; extra == "doc"
94
- Requires-Dist: dask; extra == "doc"
95
- Requires-Dist: distributed; extra == "doc"
96
- Provides-Extra: dev
97
- Requires-Dist: flake8; extra == "dev"
98
- Requires-Dist: pytest; extra == "dev"
99
- Requires-Dist: jupyter; extra == "dev"
100
- Requires-Dist: objsize; extra == "dev"
101
- Requires-Dist: ruff; extra == "dev"
67
+ Requires-Dist: setuptools>=61.0; extra == "doc"
68
+ Requires-Dist: sphinx>=5.0; extra == "doc"
69
+ Requires-Dist: sphinx-immaterial>=0.10; extra == "doc"
70
+ Requires-Dist: nbsphinx>=0.5; extra == "doc"
71
+ Requires-Dist: ipykernel>=5.0; extra == "doc"
72
+ Requires-Dist: ipywidgets>=5.0; extra == "doc"
73
+ Requires-Dist: m2r2>=0.2; extra == "doc"
74
+ Requires-Dist: lxml_html_clean>=0.4; extra == "doc"
75
+ Requires-Dist: dask>=2022.0; extra == "doc"
76
+ Requires-Dist: distributed>=2022.0; extra == "doc"
77
+ Provides-Extra: test
78
+ Requires-Dist: flake8>=0.1; extra == "test"
79
+ Requires-Dist: pytest>=7.0; extra == "test"
80
+ Provides-Extra: utils
81
+ Requires-Dist: objsize>=0.5; extra == "utils"
102
82
  Dynamic: license-file
103
83
 
104
84
  # Welcome to foxes
@@ -159,7 +139,7 @@ Evaluation Software"`
159
139
 
160
140
  ## Requirements
161
141
 
162
- The supported Python versions are `Python 3.8`...`3.13`.
142
+ The supported Python versions are `Python 3.9`...`3.13`.
163
143
 
164
144
  ## Installation
165
145