foxes 0.5.1__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 +132 -85
  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.1.dist-info → foxes-0.5.2.dist-info}/METADATA +1 -1
  59. {foxes-0.5.1.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.1.dist-info → foxes-0.5.2.dist-info}/LICENSE +0 -0
  64. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/WHEEL +0 -0
  65. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/top_level.txt +0 -0
  66. {foxes-0.5.1.dist-info → foxes-0.5.2.dist-info}/zip-safe +0 -0
foxes/utils/__init__.py CHANGED
@@ -2,14 +2,16 @@
2
2
  General utilities.
3
3
  """
4
4
  from .wind_dir import wd2uv, wd2wdvec, wdvec2wd, uv2wd, delta_wd
5
- from .pandas_helpers import PandasFileHelper
5
+ from .pandas_utils import PandasFileHelper
6
+ from .xarray_utils import write_nc
6
7
  from .subclasses import all_subclasses
7
8
  from .dict import Dict
8
9
  from .data_book import DataBook
9
- from .plotly_helpers import show_plotly_fig
10
+ from .plotly_utils import show_plotly_fig
10
11
  from .cubic_roots import cubic_roots
11
- from .geopandas_helpers import read_shp, shp2csv, read_shp_polygons, shp2geom2d
12
+ from .geopandas_utils import read_shp, shp2csv, read_shp_polygons, shp2geom2d
12
13
  from .load import import_module
14
+ from .exec_python import exec_python
13
15
 
14
16
  from . import two_circles
15
17
  from . import abl
@@ -0,0 +1,56 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import xarray as xr
4
+ import matplotlib.pyplot as plt
5
+
6
+ def exec_python(s, indicator="%", newline=";", globals=globals(), locals={}):
7
+ """
8
+ Executes strings that start with the
9
+ indicator as python commands, returns one value
10
+
11
+ Example:
12
+ s = "%p%N=10;p=np.zeros((N,3));p[:,0]=50;p[:,1]=np.linspace(0,7000,N);p[:,2]=119"
13
+
14
+ Parameters
15
+ ----------
16
+ s: list, dict or object
17
+ The source to by analyzed
18
+ indicator: str
19
+ The indicator that trigger python evaluation
20
+ newline: str
21
+ The new line indicator
22
+ globals: dict
23
+ The global namespace
24
+ locals: dict
25
+ The local namespace
26
+
27
+ Returns
28
+ -------
29
+ out: list, dict or object
30
+ The same structure, but all python
31
+ strings evaluated
32
+
33
+ :group: utils
34
+
35
+ """
36
+ if isinstance(s, str):
37
+ L = len(indicator)
38
+ if len(s) > L and s[:L] == indicator:
39
+ a = s[L:]
40
+ if not indicator in a:
41
+ exec(a, globals, locals)
42
+ else:
43
+ ilist = a.split(indicator)
44
+ if len(ilist) != 2:
45
+ raise ValueError(f"Expecting at most 2 occurences of '{indicator}', found {len(ilist)}: {s}")
46
+ v, b = ilist
47
+ for c in b.split(newline):
48
+ exec(c, globals, locals)
49
+ return locals[v]
50
+ elif isinstance(s, list):
51
+ return [exec_python(a, indicator) for a in s]
52
+ elif isinstance(s, tuple):
53
+ return tuple(exec_python(list(s), indicator))
54
+ elif isinstance(s, dict):
55
+ return {k: exec_python(a, indicator) for k, a in s.items()}
56
+ return s
@@ -0,0 +1,294 @@
1
+ import numpy as np
2
+ import argparse
3
+
4
+ import foxes.constants as FC
5
+ from .dict import Dict
6
+ from .geom2d import AreaUnion, ClosedPolygon
7
+
8
+ try:
9
+ import geopandas as gpd
10
+
11
+ IMPORT_GPD_OK = True
12
+ except ImportError:
13
+ gpd = None
14
+ IMPORT_GPD_OK = False
15
+
16
+ try:
17
+ import utm
18
+
19
+ IMPORT_UTM_OK = True
20
+ except ImportError:
21
+ utm = None
22
+ IMPORT_UTM_OK = False
23
+
24
+
25
+ def check_import_gpd():
26
+ """
27
+ Checks if library import worked,
28
+ raises error otherwise.
29
+ """
30
+ if not IMPORT_GPD_OK:
31
+ print("\n\nFailed to import geopandas. Please install, either via pip:\n")
32
+ print(" pip install geopandas\n")
33
+ print("or via conda:\n")
34
+ print(" conda install -c conda-forge geopandas\n")
35
+ raise ImportError("Failed to import geopandas")
36
+
37
+
38
+ def check_import_utm():
39
+ """
40
+ Checks if library import worked,
41
+ raises error otherwise.
42
+ """
43
+ if not IMPORT_UTM_OK:
44
+ print("\n\nFailed to import utm. Please install, either via pip:\n")
45
+ print(" pip install utm\n")
46
+ print("or via conda:\n")
47
+ print(" conda install -c conda-forge utm\n")
48
+ raise ImportError("Failed to import utm")
49
+
50
+
51
+ def read_shp(fname, **kwargs):
52
+ """
53
+ Read a shape file
54
+
55
+ Parameters
56
+ ----------
57
+ fname: str
58
+ Path to the .shp file
59
+ kwargs: dict, optional
60
+ Additional parameters for geopandas.read_file()
61
+
62
+ Returns
63
+ -------
64
+ data: geopandas.GeoDataFrame
65
+ The data frame in WSG84
66
+
67
+ :group: utils
68
+
69
+ """
70
+ check_import_gpd()
71
+ gpdf = gpd.read_file(fname, **kwargs)
72
+ return gpdf.to_crs("EPSG:4326") # Convert to WGS84
73
+
74
+
75
+ def shp2csv(ifile, ofile, in_kwargs={}, out_kwargs={}, verbosity=1):
76
+ """
77
+ Read shape file, write csv file
78
+
79
+ Parameters
80
+ ----------
81
+ iname: str
82
+ Path to the input .shp file
83
+ oname: str
84
+ Path to the output .csv file
85
+ in_kwargs: dict
86
+ Additional parameters for geopandas.read_file()
87
+ out_kwargs: dict
88
+ Additional parameters for geopandas to_csv()
89
+ verbosity: int
90
+ The verbosity level, 0 = silent
91
+
92
+ :group: utils
93
+
94
+ """
95
+ if verbosity > 0:
96
+ print("Reading file", ifile)
97
+
98
+ gpdf = read_shp(ifile, **in_kwargs)
99
+
100
+ if verbosity > 0:
101
+ print("Writing file", ofile)
102
+
103
+ gpdf.to_csv(ofile, **out_kwargs)
104
+
105
+ return gpdf
106
+
107
+
108
+ def _extract_poly_coords(geom):
109
+ """
110
+ Helper function for shapefile reading
111
+ """
112
+ if geom.geom_type == "Polygon":
113
+ exterior_coords = geom.exterior.coords[:]
114
+ interior_coords = []
115
+ for interior in geom.interiors:
116
+ interior_coords.append(interior.coords[:])
117
+ elif geom.geom_type == "MultiPolygon":
118
+ exterior_coords = []
119
+ interior_coords = []
120
+ for part in geom.geoms:
121
+ epe, epi = _extract_poly_coords(part) # Recursive call
122
+ exterior_coords.append(epe)
123
+ interior_coords.append(epi)
124
+ else:
125
+ raise ValueError("Unhandled geometry type: " + repr(geom.type))
126
+ return exterior_coords, interior_coords
127
+
128
+
129
+ def read_shp_polygons(
130
+ fname,
131
+ names=None,
132
+ name_col="Name",
133
+ geom_col="geometry",
134
+ to_utm=True,
135
+ ret_utm_zone=False,
136
+ **kwargs,
137
+ ):
138
+ """
139
+ Reads the polygon points from a shp file.
140
+
141
+ Parameters
142
+ ----------
143
+ fname: str
144
+ Path to the .shp file
145
+ names: list: of str, optinal
146
+ The names of the polygons to be extracted. All by
147
+ default
148
+ name_col: int
149
+ Column that contains the area names
150
+ geom_col: str
151
+ The geometry column
152
+ to_utm: bool or str, optional
153
+ Convert to UTM coordinates. If str, then UTM zone
154
+ plus letter, e.g. "32U"
155
+ ret_utm_zone: bool
156
+ Return UTM zone plus letter as str
157
+ kwargs: dict, optional
158
+ Additional parameters for geopandas.read_shp()
159
+
160
+ Returns
161
+ -------
162
+ point_dict_exterior: dict
163
+ Dict with list of array of points. Key: area name,
164
+ Value: list:np.ndarray, shape of latter: (n_points, 2)
165
+ point_dict_interior: dict
166
+ Dict with list of array of points. Key: area name,
167
+ Value: list:np.ndarray, shape of latter: (n_points, 2)
168
+ utm_zone_str: str, optional
169
+ The utem zone plus letter as str, e.g. "32U"
170
+
171
+ :group: utils
172
+
173
+ """
174
+
175
+ pdf = read_shp(fname, **kwargs)
176
+ pnames = list(pdf[name_col])
177
+
178
+ utmz = None
179
+ utml = None
180
+ apply_utm = False
181
+ if isinstance(to_utm, str) or to_utm == True:
182
+ apply_utm = True
183
+ check_import_utm()
184
+ utmz = int(to_utm[:-1]) if isinstance(to_utm, str) else None
185
+ utml = to_utm[-1] if isinstance(to_utm, str) else None
186
+
187
+ exterior = Dict()
188
+ interior = Dict()
189
+ names = pnames if names is None else names
190
+ for name in names:
191
+ if name == name: # exclude nan values
192
+ if not name in pnames:
193
+ raise KeyError(
194
+ f"Name '{name}' not found in file '{fname}'. Names: {pnames}"
195
+ )
196
+
197
+ a = pdf.loc[pnames.index(name), geom_col]
198
+ epe, epi = _extract_poly_coords(a)
199
+
200
+ def _to_utm(poly):
201
+ nonlocal utmz, utml
202
+ utm_poly = np.zeros_like(poly)
203
+ utm_poly[:, 0], utm_poly[:, 1], utmz, utml = utm.from_latlon(
204
+ poly[:, 1],
205
+ poly[:, 0],
206
+ force_zone_number=utmz,
207
+ force_zone_letter=utml,
208
+ )
209
+ return utm_poly
210
+
211
+ def _to_numpy(data):
212
+ if not len(data):
213
+ return []
214
+ if isinstance(data[0], tuple):
215
+ out = np.array(data, dtype=FC.DTYPE)
216
+ return _to_utm(out) if apply_utm else out
217
+ return [_to_numpy(d) for d in data]
218
+
219
+ exterior[name] = _to_numpy(epe)
220
+ interior[name] = _to_numpy(epi)
221
+
222
+ if ret_utm_zone:
223
+ return exterior, interior, f"{utmz}{utml}"
224
+ else:
225
+ return exterior, interior
226
+
227
+
228
+ def shp2geom2d(*args, ret_utm_zone=False, **kwargs):
229
+ """
230
+ Read shapefile into geom2d geometry
231
+
232
+ Parameters
233
+ ----------
234
+ args: tuple, optional
235
+ Arguments for read_shp_polygons()
236
+ ret_utm_zone: bool
237
+ Return UTM zone plus letter as str
238
+ kwargs: dict, optional
239
+ Keyword arguments for read_shp_polygons()
240
+
241
+ Returns
242
+ -------
243
+ geom: foxes.tools.geom2D.AreaGeometry
244
+ The geometry object
245
+ utm_zone_str: str, optional
246
+ The utem zone plus letter as str, e.g. "32U"
247
+
248
+ :group: utils
249
+
250
+ """
251
+
252
+ exint = read_shp_polygons(*args, ret_utm_zone=ret_utm_zone, **kwargs)
253
+
254
+ def _create_geom(data):
255
+ if not len(data):
256
+ return None
257
+ if isinstance(data, dict):
258
+ gs = [_create_geom(g) for g in data.values()]
259
+ gs = [g for g in gs if g is not None]
260
+ return AreaUnion(gs) if len(gs) else None
261
+ if isinstance(data, np.ndarray) and len(data.shape) == 2:
262
+ return ClosedPolygon(data)
263
+ gs = [_create_geom(g) for g in data]
264
+ gs = [g for g in gs if g is not None]
265
+ return AreaUnion(gs) if len(gs) else None
266
+
267
+ gext = _create_geom(exint[0])
268
+ gint = _create_geom(exint[1])
269
+ geom = gext - gint if gint is not None else gext
270
+
271
+ if ret_utm_zone:
272
+ return geom, exint[2]
273
+ else:
274
+ return geom
275
+
276
+
277
+ if __name__ == "__main__":
278
+ # define arguments and options:
279
+ parser = argparse.ArgumentParser()
280
+ parser.add_argument("shp_file", help="The input .shp file")
281
+ parser.add_argument("-n", "--names", help="Area names", default=None, nargs="+")
282
+ parser.add_argument(
283
+ "--no_utm", help="switch off conversion to UTM", action="store_true"
284
+ )
285
+ args = parser.parse_args()
286
+
287
+ g = shp2geom2d(args.shp_file, to_utm=not args.no_utm, names=args.names)
288
+
289
+ import matplotlib.pyplot as plt
290
+
291
+ fig, ax = plt.subplots()
292
+ g.add_to_figure(ax)
293
+ plt.show()
294
+ plt.close(fig)
@@ -0,0 +1,175 @@
1
+ import pandas as pd
2
+ from pathlib import Path
3
+ import xarray
4
+ from copy import deepcopy
5
+
6
+ import foxes.variables as FV
7
+
8
+
9
+ class PandasFileHelper:
10
+ """
11
+ This class helps reading and writing data
12
+ to files via pandas.
13
+
14
+ Attributes
15
+ ----------
16
+ DEFAULT_READING_PARAMETERS: dict
17
+ Default parameters for file reading
18
+ for the supported file formats
19
+ DEFAULT_WRITING_PARAMETERS: dict
20
+ Default parameters for file writing
21
+ for the supported file formats
22
+ DATA_FILE_FORMAT: list:str
23
+ The supported file formats for data export
24
+ DEFAULT_FORMAT_DICT: dict
25
+ Default column formatting
26
+
27
+ :group: utils
28
+
29
+ """
30
+
31
+ DEFAULT_READING_PARAMETERS = {
32
+ "csv": {},
33
+ "csv.gz": {},
34
+ "csv.bz2": {},
35
+ "csv.zip": {},
36
+ "h5": {},
37
+ "nc": {},
38
+ }
39
+
40
+ DEFAULT_WRITING_PARAMETERS = {
41
+ "csv": {},
42
+ "csv.gz": {},
43
+ "csv.bz2": {},
44
+ "csv.zip": {},
45
+ "h5": {"key": "foxes", "mode": "w"},
46
+ "nc": {},
47
+ }
48
+
49
+ DEFAULT_FORMAT_DICT = {
50
+ FV.WD: "{:.3f}",
51
+ FV.AMB_WD: "{:.3f}",
52
+ FV.YAW: "{:.3f}",
53
+ FV.AMB_YAW: "{:.3f}",
54
+ FV.WS: "{:.4f}",
55
+ FV.AMB_WS: "{:.4f}",
56
+ FV.REWS: "{:.4f}",
57
+ FV.AMB_REWS: "{:.4f}",
58
+ FV.REWS2: "{:.4f}",
59
+ FV.AMB_REWS2: "{:.4f}",
60
+ FV.REWS3: "{:.4f}",
61
+ FV.AMB_REWS3: "{:.4f}",
62
+ FV.TI: "{:.6f}",
63
+ FV.AMB_TI: "{:.6f}",
64
+ FV.RHO: "{:.5f}",
65
+ FV.AMB_RHO: "{:.5f}",
66
+ FV.P: "{:.3f}",
67
+ FV.AMB_P: "{:.3f}",
68
+ FV.CT: "{:.6f}",
69
+ FV.AMB_CT: "{:.6f}",
70
+ FV.T: "{:.3f}",
71
+ FV.AMB_T: "{:.3f}",
72
+ FV.YLD: "{:.3f}",
73
+ FV.AMB_YLD: "{:.3f}",
74
+ FV.CAP: "{:.5f}",
75
+ FV.AMB_CAP: "{:.5f}",
76
+ FV.EFF: "{:.5f}",
77
+ }
78
+
79
+ DATA_FILE_FORMATS = list(DEFAULT_READING_PARAMETERS.keys())
80
+
81
+ @classmethod
82
+ def read_file(cls, file_path, **kwargs):
83
+ """
84
+ Helper for reading data according to file ending.
85
+
86
+ Parameters
87
+ ----------
88
+ file_path: str
89
+ The path to the file
90
+ **kwargs: dict, optional
91
+ Parameters forwarded to the pandas reading method.
92
+
93
+ Returns
94
+ -------
95
+ pandas.DataFrame :
96
+ The data
97
+
98
+ """
99
+ fpath = Path(file_path)
100
+ fname = fpath.name
101
+ sfx = ".".join(fname.split(".")[1:])
102
+ f = None
103
+ for fmt in cls.DATA_FILE_FORMATS:
104
+ if sfx[:3] == "csv":
105
+ f = pd.read_csv
106
+ elif sfx == "h5":
107
+ f = pd.read_hdf
108
+ elif sfx == "nc":
109
+ f = lambda fname, **pars: xarray.open_dataset(
110
+ fname, **pars
111
+ ).to_dataframe()
112
+
113
+ if f is not None:
114
+ pars = deepcopy(cls.DEFAULT_READING_PARAMETERS[fmt])
115
+ pars.update(kwargs)
116
+ return f(file_path, **pars)
117
+
118
+ raise KeyError(
119
+ f"Unknown file format '{fname}'. Supported formats: {cls.DATA_FILE_FORMATS}"
120
+ )
121
+
122
+ @classmethod
123
+ def write_file(cls, data, file_path, format_dict={}, **kwargs):
124
+ """
125
+ Helper for writing data according to file ending.
126
+
127
+ Parameters
128
+ ----------
129
+ data: pandas.DataFrame
130
+ The data
131
+ file_path: str
132
+ The path to the file
133
+ format_dict: dict
134
+ Dictionary with format entries for
135
+ columns, e.g. '{:.4f}'
136
+ **kwargs: dict, optional
137
+ Parameters forwarded to the pandas writing method.
138
+
139
+ """
140
+
141
+ fdict = deepcopy(cls.DEFAULT_FORMAT_DICT)
142
+ fdict.update(format_dict)
143
+
144
+ out = pd.DataFrame(index=data.index, columns=data.columns)
145
+ for c in data.columns:
146
+ if c in fdict.keys():
147
+ out[c] = data[c].map(
148
+ lambda x: fdict[c].format(x) if not pd.isna(x) else x
149
+ )
150
+ else:
151
+ out[c] = data[c]
152
+
153
+ fpath = Path(file_path)
154
+ fname = fpath.name
155
+ sfx = ".".join(fname.split(".")[1:])
156
+ f = None
157
+ for fmt in cls.DATA_FILE_FORMATS:
158
+ if sfx[:3] == "csv":
159
+ f = out.to_csv
160
+ elif sfx == "h5":
161
+ f = out.to_hdf
162
+ elif sfx == "nc":
163
+ f = out.to_netcdf
164
+
165
+ if f is not None:
166
+ pars = cls.DEFAULT_WRITING_PARAMETERS[fmt]
167
+ pars.update(kwargs)
168
+
169
+ f(file_path, **pars)
170
+
171
+ return
172
+
173
+ raise KeyError(
174
+ f"Unknown file format '{file_path}'. Supported formats: {cls.DATA_FILE_FORMATS}"
175
+ )
@@ -0,0 +1,19 @@
1
+ import plotly.io as pio
2
+ import io
3
+ from PIL import Image
4
+
5
+
6
+ def show_plotly_fig(fig):
7
+ """
8
+ Displays a plotly figure in a window
9
+
10
+ Reference:
11
+ https://stackoverflow.com/questions/53570384/plotly-how-to-make-a-standalone-plot-in-a-window
12
+
13
+ :group: utils
14
+
15
+ """
16
+ buf = io.BytesIO()
17
+ pio.write_image(fig, buf)
18
+ img = Image.open(buf)
19
+ img.show()
@@ -0,0 +1,38 @@
1
+
2
+ def write_nc(ds, fpath, round="auto", complevel=5, verbosity=1, **kwargs):
3
+ """
4
+ Writes a dataset to netCFD file
5
+
6
+ Parameters
7
+ ----------
8
+ fpath: str
9
+ Path to the output file, should be nc
10
+ round: dict or str, optional
11
+ The rounding definitions, or auto for
12
+ default settings
13
+ complevel: int
14
+ The compression level
15
+ verbosity: int
16
+ The verbosity level, 0 = silent
17
+ kwargs: dict, optional
18
+ Additional parameters for xarray.to_netcdf
19
+
20
+ """
21
+
22
+ if round is not None:
23
+ for v in ds.coords.keys():
24
+ if v in round:
25
+ if verbosity > 1:
26
+ print(f"Rounding {v} to {round[v]} decimals")
27
+ ds[v].data = ds[v].data.round(decimals=round[v])
28
+ for v in ds.data_vars.keys():
29
+ if v in round:
30
+ if verbosity > 1:
31
+ print(f"Rounding {v} to {round[v]} decimals")
32
+ ds[v].data = ds[v].data.round(decimals=round[v])
33
+
34
+ if verbosity > 0:
35
+ print("Writing file", fpath)
36
+
37
+ enc = {k: {"zlib": True, "complevel": complevel} for k in ds.data_vars}
38
+ ds.to_netcdf(fpath, encoding=enc, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxes
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: Farm Optimization and eXtended yield Evaluation Software
5
5
  Author: Fraunhofer IWES
6
6
  Author-email: jonas.schmidt@iwes.fraunhofer.de