foxes 0.5.0.2__py3-none-any.whl → 0.5.2__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 (66) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +41 -46
  3. foxes/algorithms/downwind/models/point_wakes_calc.py +4 -9
  4. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -22
  5. foxes/core/algorithm.py +1 -1
  6. foxes/core/data_calc_model.py +26 -2
  7. foxes/core/partial_wakes_model.py +1 -1
  8. foxes/core/rotor_model.py +36 -2
  9. foxes/core/turbine_model.py +36 -0
  10. foxes/core/turbine_type.py +35 -1
  11. foxes/core/wake_frame.py +39 -3
  12. foxes/core/wake_model.py +36 -0
  13. foxes/models/model_book.py +129 -89
  14. foxes/models/turbine_models/rotor_centre_calc.py +1 -2
  15. foxes/models/turbine_types/CpCt_file.py +13 -3
  16. foxes/models/turbine_types/CpCt_from_two.py +14 -4
  17. foxes/models/vertical_profiles/abl_log_neutral_ws.py +32 -5
  18. foxes/models/vertical_profiles/abl_log_stable_ws.py +32 -4
  19. foxes/models/vertical_profiles/abl_log_unstable_ws.py +32 -4
  20. foxes/models/vertical_profiles/abl_log_ws.py +50 -18
  21. foxes/models/wake_frames/yawed_wakes.py +15 -9
  22. foxes/models/wake_models/induction/__init__.py +1 -1
  23. foxes/models/wake_models/induction/rankine_half_body.py +33 -7
  24. foxes/models/wake_models/ti/crespo_hernandez.py +6 -1
  25. foxes/models/wake_models/ti/iec_ti.py +5 -3
  26. foxes/models/wake_models/wind/__init__.py +2 -2
  27. foxes/models/wake_models/wind/{bastankhah.py → bastankhah14.py} +11 -14
  28. foxes/models/wake_models/wind/{porte_agel.py → bastankhah16.py} +24 -16
  29. foxes/models/wake_models/wind/turbopark.py +11 -22
  30. foxes/models/wake_superpositions/__init__.py +9 -5
  31. foxes/models/wake_superpositions/ti_linear.py +134 -0
  32. foxes/models/wake_superpositions/ti_max.py +134 -0
  33. foxes/models/wake_superpositions/{ti_superp.py → ti_pow.py} +15 -57
  34. foxes/models/wake_superpositions/ti_quadratic.py +134 -0
  35. foxes/models/wake_superpositions/ws_linear.py +170 -0
  36. foxes/models/wake_superpositions/ws_max.py +173 -0
  37. foxes/models/wake_superpositions/ws_pow.py +175 -0
  38. foxes/models/wake_superpositions/{product.py → ws_product.py} +43 -22
  39. foxes/models/wake_superpositions/ws_quadratic.py +170 -0
  40. foxes/output/__init__.py +4 -0
  41. foxes/output/calc_points.py +143 -0
  42. foxes/output/flow_plots_2d/__init__.py +1 -0
  43. foxes/output/flow_plots_2d/common.py +104 -1
  44. foxes/output/flow_plots_2d/flow_plots.py +237 -569
  45. foxes/output/flow_plots_2d/get_fig.py +183 -0
  46. foxes/output/flow_plots_2d/seq_flow_ani_plugin.py +0 -1
  47. foxes/output/grids.py +705 -0
  48. foxes/output/output.py +58 -11
  49. foxes/output/results_writer.py +101 -17
  50. foxes/output/round.py +10 -0
  51. foxes/output/slice_data.py +900 -0
  52. foxes/utils/__init__.py +5 -3
  53. foxes/utils/exec_python.py +56 -0
  54. foxes/utils/geopandas_utils.py +294 -0
  55. foxes/utils/pandas_utils.py +175 -0
  56. foxes/utils/plotly_utils.py +19 -0
  57. foxes/utils/xarray_utils.py +38 -0
  58. {foxes-0.5.0.2.dist-info → foxes-0.5.2.dist-info}/METADATA +1 -1
  59. {foxes-0.5.0.2.dist-info → foxes-0.5.2.dist-info}/RECORD +63 -49
  60. foxes/models/wake_superpositions/linear.py +0 -242
  61. foxes/models/wake_superpositions/max.py +0 -258
  62. foxes/models/wake_superpositions/quadratic.py +0 -252
  63. {foxes-0.5.0.2.dist-info → foxes-0.5.2.dist-info}/LICENSE +0 -0
  64. {foxes-0.5.0.2.dist-info → foxes-0.5.2.dist-info}/WHEEL +0 -0
  65. {foxes-0.5.0.2.dist-info → foxes-0.5.2.dist-info}/top_level.txt +0 -0
  66. {foxes-0.5.0.2.dist-info → foxes-0.5.2.dist-info}/zip-safe +0 -0
foxes/output/output.py CHANGED
@@ -1,5 +1,6 @@
1
- from foxes.utils import PandasFileHelper, all_subclasses
1
+ from pathlib import Path
2
2
 
3
+ from foxes.utils import PandasFileHelper, all_subclasses
3
4
 
4
5
  class Output:
5
6
  """
@@ -8,12 +9,53 @@ class Output:
8
9
  The job of this class is to provide handy
9
10
  helper functions.
10
11
 
12
+ Attributes
13
+ ----------
14
+ out_dir: pathlib.Path
15
+ The output file directory
16
+ out_fname_fun: Function, optional
17
+ Modifies file names by f(fname)
18
+
11
19
  :group: output
12
20
 
13
21
  """
14
22
 
15
- @classmethod
16
- def write(cls, file_path, data, format_col2var={}, format_dict={}, **kwargs):
23
+ def __init__(self, out_dir=None, out_fname_fun=None):
24
+ """
25
+ Constructor.
26
+
27
+ Parameters
28
+ ----------
29
+ out_dir: str, optional
30
+ The output file directory
31
+ out_fname_fun: Function, optional
32
+ Modifies file names by f(fname)
33
+
34
+ """
35
+ self.out_dir = Path(out_dir) if out_dir is not None else None
36
+ self.out_fname_fun = out_fname_fun
37
+
38
+ def get_fpath(self, fname):
39
+ """
40
+ Gets the total file path
41
+
42
+ Parameters
43
+ ----------
44
+ fname: str
45
+ The file name
46
+
47
+ Returns
48
+ -------
49
+ fpath: pathlib.Path
50
+ The total file path
51
+
52
+ """
53
+ fnm = Path(fname)
54
+ if self.out_fname_fun is not None:
55
+ fnm = self.out_fname_fun(fnm)
56
+ return self.out_dir/fnm if self.out_dir is not None else fnm
57
+
58
+ def write(self, file_name, data, format_col2var={}, format_dict={}, **kwargs):
17
59
  """
18
60
  Writes data to file via pandas.
19
61
 
@@ -21,16 +63,16 @@ class Output:
21
63
 
22
64
  Parameters
23
65
  ----------
24
- file_path: string
25
- The path to the output file
66
+ file_name: str
67
+ The output file name
26
68
  data: pandas.DataFrame
27
69
  The data
28
70
  format_col2var: dict
29
- Mapping from column names to flappy variables,
71
+ Mapping from column names to foxes variables,
30
72
  for formatting
31
73
  format_dict: dict
32
74
  Dictionary with format entries for columns, e.g.
33
- {FV.P: '{:.4f}'}. Note that the keys are flappy variables
75
+ {FV.P: '{:.4f}'}. Note that the keys are foxes variables
34
76
 
35
77
  """
36
78
  fdict = {}
@@ -41,8 +83,9 @@ class Output:
41
83
  elif v in PandasFileHelper.DEFAULT_FORMAT_DICT:
42
84
  fdict[c] = PandasFileHelper.DEFAULT_FORMAT_DICT[v]
43
85
 
44
- PandasFileHelper.write_file(data, file_path, fdict, **kwargs)
45
-
86
+ fpath = self.get_fpath(file_name)
87
+ PandasFileHelper.write_file(data, fpath, fdict, **kwargs)
88
+
46
89
  @classmethod
47
90
  def print_models(cls):
48
91
  """
@@ -53,7 +96,7 @@ class Output:
53
96
  print(n)
54
97
 
55
98
  @classmethod
56
- def new(cls, model_type, **kwargs):
99
+ def new(cls, model_type, *args, **kwargs):
57
100
  """
58
101
  Run-time output model factory.
59
102
 
@@ -61,6 +104,10 @@ class Output:
61
104
  ----------
62
105
  model_type: string
63
106
  The selected derived class name
107
+ args: tuple, optional
108
+ Additional parameters for the constructor
109
+ kwargs: dict, optional
110
+ Additional parameters for the constructor
64
111
 
65
112
  """
66
113
 
@@ -73,7 +120,7 @@ class Output:
73
120
  if found:
74
121
  for scls in allc:
75
122
  if scls.__name__ == model_type:
76
- return scls(**kwargs)
123
+ return scls(*args, **kwargs)
77
124
 
78
125
  else:
79
126
  estr = "Output type '{}' is not defined, available types are \n {}".format(
@@ -1,6 +1,10 @@
1
- from .output import Output
1
+ import pandas as pd
2
+ from xarray import Dataset
3
+
2
4
  import foxes.constants as FC
5
+ from foxes.utils import write_nc
3
6
 
7
+ from .output import Output
4
8
 
5
9
  class ResultsWriter(Output):
6
10
  """
@@ -15,7 +19,7 @@ class ResultsWriter(Output):
15
19
 
16
20
  """
17
21
 
18
- def __init__(self, farm_results=None, data=None):
22
+ def __init__(self, farm_results=None, data=None, **kwargs):
19
23
  """
20
24
  Constructor.
21
25
 
@@ -25,8 +29,12 @@ class ResultsWriter(Output):
25
29
  The farm results, if data is None
26
30
  data: pandas.DataFrame, optional
27
31
  The data, if farm_results is None
32
+ kwargs: dict, optional
33
+ Additional parameters for the base class
28
34
 
29
35
  """
36
+ super().__init__(**kwargs)
37
+
30
38
  if farm_results is not None and data is None:
31
39
  self.data = farm_results.to_dataframe().reset_index()
32
40
  self.data[FC.TNAME] = farm_results[FC.TNAME].to_numpy()[
@@ -39,12 +47,32 @@ class ResultsWriter(Output):
39
47
  raise KeyError(
40
48
  f"ResultsWriter: Either give 'farm_results' or 'data' arguments"
41
49
  )
50
+
51
+ def _get_data_vars(self, variables):
52
+ """ Helper function for variable gathering """
53
+ data = self.data
54
+ if variables is None:
55
+ pass
56
+ elif isinstance(variables, dict):
57
+ inds = {
58
+ s: variables.pop(s) for s in self.data.index.names if s in variables
59
+ }
60
+ if len(variables):
61
+ data = data[list(variables.keys())].rename(variables, axis=1)
62
+ if len(inds):
63
+ for s, ns in inds.items():
64
+ data = data.rename_axis(index={s: ns})
65
+ else:
66
+ data = self.data[list(variables)]
67
+
68
+ return data, data.columns.tolist()
42
69
 
43
70
  def write_csv(
44
71
  self,
45
72
  file_path,
46
73
  variables=None,
47
74
  turbine_names=False,
75
+ state_turbine_table=False,
48
76
  verbosity=1,
49
77
  **kwargs,
50
78
  ):
@@ -62,6 +90,9 @@ class ResultsWriter(Output):
62
90
  written.
63
91
  turbine_names: bool
64
92
  Use turbine names instead of turbine indices
93
+ state_turbine_table: bool
94
+ Flag for writing a single variable into turbine columns
95
+ for state rows
65
96
  verbosity: int
66
97
  The verbosity level, 0 = silent
67
98
  kwargs: dict, optional
@@ -71,22 +102,75 @@ class ResultsWriter(Output):
71
102
  if verbosity:
72
103
  print(f"ResultsWriter: Writing file '{file_path}'")
73
104
 
74
- if variables is None:
75
- data = self.data
76
- elif isinstance(variables, dict):
77
- inds = {
78
- s: variables.pop(s) for s in self.data.index.names if s in variables
79
- }
80
- data = self.data
81
- if len(variables):
82
- data = data[list(variables.keys())].rename(variables, axis=1)
83
- if len(inds):
84
- for s, ns in inds.items():
85
- data = data.rename_axis(index={s: ns})
105
+ data, variables = self._get_data_vars(variables)
106
+ data.reset_index(inplace=True)
107
+ fc2v = kwargs.pop("format_col2var", {})
108
+ tix = FC.TNAME if turbine_names else FC.TURBINE
109
+
110
+ if state_turbine_table:
111
+ if len(variables) != 1:
112
+ raise ValueError(f"state_turbine_table can only be written for a single variable, got {variables}")
113
+ v = variables[0]
114
+ cnames = {t: f"{v}_T{t:04d}" if tix == FC.TURBINE else f"{v}_{t}" for t in data[tix]}
115
+ for ti, (t, g) in enumerate(data.reset_index().set_index(FC.STATE).groupby(tix)):
116
+ if ti == 0:
117
+ odata = pd.DataFrame(index=g.index.to_numpy(), columns=list(cnames.values()))
118
+ odata.index.name = g.index.name
119
+ cname = cnames[t]
120
+ odata[cname] = g[v].to_numpy().copy()
121
+ fc2v[cname] = v
122
+ data = odata
86
123
  else:
87
- data = self.data[list(variables)]
124
+ data.set_index([FC.STATE, tix], inplace=True)
88
125
 
126
+ fpath = self.get_fpath(file_path)
127
+ super().write(fpath, data, format_col2var=fc2v, **kwargs)
128
+
129
+ def write_nc(
130
+ self,
131
+ file_path,
132
+ variables=None,
133
+ turbine_names=False,
134
+ verbosity=1,
135
+ **kwargs,
136
+ ):
137
+ """
138
+ Writes a netCDF file
139
+
140
+ Parameters
141
+ ----------
142
+ file_path: str
143
+ Path the the csv file
144
+ variables: dict or list of str, optional
145
+ The variables to be written. If a dict, then
146
+ the keys are the foxes variables and the values
147
+ the column names. If None, then all data will be
148
+ written.
149
+ turbine_names: bool
150
+ Use turbine names instead of turbine indices
151
+ verbosity: int
152
+ The verbosity level, 0 = silent
153
+ kwargs: dict, optional
154
+ Additional parameters for write_nc()
155
+
156
+ """
157
+ data, variables = self._get_data_vars(variables)
158
+ states = data.index.get_level_values(0).unique()
159
+ n_states = len(states)
160
+ n_turbines = len(data.index.get_level_values(1).unique())
161
+
162
+ crds = {FC.STATE: states}
89
163
  if turbine_names:
90
- data = data.reset_index().set_index([FC.STATE, FC.TNAME])
164
+ idx = pd.IndexSlice
165
+ crds[FC.TURBINE] = self.data.loc[idx[0, :], FC.TNAME].to_numpy()
166
+
167
+ ds = Dataset(
168
+ coords=crds,
169
+ data_vars={
170
+ v: ((FC.STATE, FC.TURBINE), data[v].to_numpy().reshape(n_states, n_turbines))
171
+ for v in variables
172
+ }
173
+ )
91
174
 
92
- super().write(file_path, data, **kwargs)
175
+ fpath = self.get_fpath(file_path)
176
+ write_nc(ds, fpath, verbosity=verbosity, **kwargs)
foxes/output/round.py ADDED
@@ -0,0 +1,10 @@
1
+ import foxes.variables as FV
2
+ import foxes.constants as FC
3
+
4
+ round_defaults = {v: 4 for v in FV.__dict__.keys() if isinstance(v, str)}
5
+ round_defaults[FV.WD] = 3
6
+ round_defaults[FV.YAW] = 3
7
+ round_defaults[FV.TI] = 6
8
+ round_defaults[FV.RHO] = 6
9
+ round_defaults[FC.XYH] = 3
10
+ round_defaults.update({FV.var2amb[v]: round_defaults[v] for v in FV.var2amb.keys()})