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
@@ -0,0 +1,143 @@
1
+ import numpy as np
2
+ from xarray import Dataset
3
+
4
+ import foxes.constants as FC
5
+ import foxes.variables as FV
6
+ from foxes.utils import write_nc
7
+
8
+ from .output import Output
9
+
10
+ class PointCalculator(Output):
11
+ """
12
+ Computes results at given points
13
+
14
+ Attributes
15
+ ----------
16
+ algo: foxes.Algorithm
17
+ The algorithm for point calculation
18
+ farm_results: xarray.Dataset
19
+ The farm results
20
+
21
+ :group: output
22
+
23
+ """
24
+
25
+ def __init__(self, algo, farm_results, **kwargs):
26
+ """
27
+ Constructor.
28
+
29
+ Parameters
30
+ ----------
31
+ algo: foxes.Algorithm
32
+ The algorithm for point calculation
33
+ farm_results: xarray.Dataset
34
+ The farm results
35
+ kwargs: dict, optional
36
+ Additional parameters for the base class
37
+
38
+ """
39
+ super().__init__(**kwargs)
40
+ self.algo = algo
41
+ self.farm_results = farm_results
42
+
43
+ def calculate(
44
+ self,
45
+ points,
46
+ *args,
47
+ states_mean=False,
48
+ weight_turbine=0,
49
+ to_file=None,
50
+ write_vars=None,
51
+ write_pars={},
52
+ **kwargs
53
+ ):
54
+ """
55
+ Calculate point results
56
+
57
+ Parameters
58
+ ----------
59
+ points: numpy.ndarray
60
+ The points, shape: (n_points, 3)
61
+ or (n_states, n_points, 3)
62
+ args: tuple, optional
63
+ Additional arguments for algo.calc_points
64
+ states_mean: bool
65
+ Flag for taking the mean over states
66
+ weight_turbine: int, optional
67
+ Index of the turbine from which to take the weight
68
+ to_file: str, optional
69
+ Path to the output netCDF file
70
+ write_vars: list of str
71
+ The variables to be written to file, or None
72
+ for all
73
+ write_pars: dict, optional
74
+ Additional parameters for write_nc
75
+ kwargs: tuple, optional
76
+ Additional arguments for algo.calc_points
77
+
78
+ Returns
79
+ -------
80
+ point_results: xarray.Dataset
81
+ The point results. The calculated variables have
82
+ dimensions (state, point)
83
+
84
+ """
85
+ if points.shape[-1] == 3 and len(points.shape) == 3:
86
+ pts = points
87
+ p_has_s = True
88
+ elif points.shape[-1] == 3 and len(points.shape) == 2:
89
+ pts = np.zeros([self.algo.n_states] + list(points.shape), dtype=FC.DTYPE)
90
+ pts[:] = points[None, :]
91
+ p_has_s = False
92
+ else:
93
+ raise ValueError(f"Expecting point shape (n_states, n_points, 3) or (n_points, 3), got {points.shape}")
94
+
95
+ pres = self.algo.calc_points(self.farm_results, pts, *args, **kwargs)
96
+
97
+ if states_mean:
98
+ weights = self.farm_results[FV.WEIGHT].to_numpy()[:, weight_turbine]
99
+ pres = Dataset(
100
+ data_vars={
101
+ v: np.einsum('s,sp->p', weights, pres[v].to_numpy())
102
+ for v in pres.data_vars.keys()
103
+ }
104
+ )
105
+
106
+ vrs = list(pres.data_vars.keys()) if write_vars is None else write_vars
107
+ if to_file is not None:
108
+ if states_mean:
109
+ if p_has_s:
110
+ points = np.einsum('s,spd->pd', weights, points)
111
+ dvars = {
112
+ "x": ((FC.POINT,), points[..., 0]),
113
+ "y": ((FC.POINT,), points[..., 1]),
114
+ "z": ((FC.POINT,), points[..., 2])
115
+ }
116
+ dvars.update({v: ((FC.POINT,), pres[v].to_numpy())
117
+ for v in vrs})
118
+ ds = Dataset(data_vars=dvars)
119
+ else:
120
+ if p_has_s:
121
+ dvars = {
122
+ "x": ((FC.STATE, FC.POINT), points[..., 0]),
123
+ "y": ((FC.STATE, FC.POINT), points[..., 1]),
124
+ "z": ((FC.STATE, FC.POINT), points[..., 2])
125
+ }
126
+ else:
127
+ dvars = {
128
+ "x": ((FC.POINT,), points[..., 0]),
129
+ "y": ((FC.POINT,), points[..., 1]),
130
+ "z": ((FC.POINT,), points[..., 2])
131
+ }
132
+ dvars.update({v: ((FC.STATE, FC.POINT), pres[v].to_numpy())
133
+ for v in vrs})
134
+ ds = Dataset(
135
+ coords={FC.STATE: pres[FC.STATE].to_numpy()},
136
+ data_vars=dvars
137
+ )
138
+
139
+ fpath = self.get_fpath(to_file)
140
+ write_nc(ds, fpath, **write_pars)
141
+
142
+ return pres
143
+
@@ -1,2 +1,3 @@
1
1
  from .flow_plots import FlowPlots2D
2
2
  from .seq_flow_ani_plugin import SeqFlowAnimationPlugin
3
+ from .get_fig import get_fig
@@ -1,6 +1,7 @@
1
1
  import matplotlib.pyplot as plt
2
2
  import numpy as np
3
3
  from mpl_toolkits.axes_grid1 import make_axes_locatable
4
+ from xarray import Dataset
4
5
 
5
6
  from foxes.utils import wd2uv
6
7
  import foxes.variables as FV
@@ -213,7 +214,6 @@ def calc_point_results(
213
214
  **kwargs,
214
215
  ):
215
216
  """
216
-
217
217
  Helper function that calculates results at grid points.
218
218
 
219
219
  Parameters
@@ -593,3 +593,106 @@ def get_grid_yz(
593
593
  z_pos,
594
594
  g_pts.reshape(n_states, n_pts, 3),
595
595
  )
596
+
597
+ round_defaults = {v: 4 for v in FV.__dict__.keys() if isinstance(v, str)}
598
+ round_defaults[FV.WD] = 3
599
+ round_defaults[FV.TI] = 6
600
+ round_defaults[FV.RHO] = 6
601
+ round_defaults[FC.XYH] = 3
602
+ round_defaults.update({FV.var2amb[v]: round_defaults[v] for v in FV.var2amb.keys()})
603
+
604
+ def data2xr(
605
+ x_pos,
606
+ y_pos,
607
+ z_pos,
608
+ point_results,
609
+ vars=None,
610
+ round="auto",
611
+ to_file=None,
612
+ complevel=5,
613
+ verbosity=1,
614
+ ):
615
+ """
616
+ Converts the image data to xarray data
617
+
618
+ Parameter
619
+ ---------
620
+ x_pos: numpy.ndarray or float
621
+ The x grid positions, shape: (n_x, 3)
622
+ y_pos: numpy.ndarray or float
623
+ The y grid positions, shape: (n_y, 3)
624
+ z_pos: numpy.ndarray or float
625
+ The z grid positions, shape: (n_z, 3)
626
+ point_results: xarray.Dataset
627
+ Results of calc_points
628
+ vars: list of str, optional
629
+ Variable selection, or None for all
630
+ round: dict, optional
631
+ Round variables to given digits, or 'auto'
632
+ for default
633
+ to_file: str, optional
634
+ Write to nc file
635
+ complevel: int
636
+ The compression level
637
+ verbosity: int
638
+ The verbostiy level, 0 = silent
639
+
640
+ Returns
641
+ -------
642
+ ds: xarray.Dataset
643
+ The xarray data object
644
+
645
+ """
646
+ if round == "auto":
647
+ round = round_defaults
648
+ if round is not None:
649
+ x_pos = np.round(x_pos, round[FC.XYH])
650
+ y_pos = np.round(y_pos, round[FC.XYH])
651
+ z_pos = np.round(z_pos, round[FC.XYH])
652
+
653
+ if vars is None:
654
+ vars = list(point_results.data_vars.keys())
655
+ data = {}
656
+ for v in vars:
657
+ data[v] = point_results[v].to_numpy()
658
+ if v in round:
659
+ data[v] = np.round(data[v], round[v])
660
+
661
+ allc = [x_pos, y_pos, z_pos]
662
+ allcn = ["x", "y", "z"]
663
+ ci = [i for i, x in enumerate(allc) if isinstance(x, np.ndarray)]
664
+ cj = [i for i in range(3) if i not in ci][0]
665
+ cl = list(reversed([len(allc[i]) for i in ci]))
666
+ cn = list(reversed([allcn[i] for i in ci]))
667
+
668
+ coords = {}
669
+ attrs = {allcn[cj]: allc[cj].to_numpy()}
670
+ if FC.STATE in point_results.coords:
671
+ if point_results.dims[FC.STATE] > 1:
672
+ coords[FC.STATE] = point_results[FC.STATE].to_numpy()
673
+ else:
674
+ attrs[FC.STATE] = str(point_results[FC.STATE][0].to_numpy())
675
+ coords.update({
676
+ allcn[i]: allc[i] for i in reversed(ci)
677
+ })
678
+
679
+ dvars = {}
680
+ for v, d in data.items():
681
+ if len(d.shape) == 1:
682
+ dvars[v] = (cn, np.swapaxes(d.reshape(*cl), 0, 1))
683
+ else:
684
+ dvars[v] = ([FC.STATE] + cn, np.swapaxes(d.reshape(d.shape[0], *cl), 1, 2))
685
+
686
+ ds = Dataset(
687
+ coords=coords,
688
+ data_vars=dvars,
689
+ attrs=attrs
690
+ )
691
+
692
+ if to_file is not None:
693
+ if verbosity > 0:
694
+ print("Writing file", to_file)
695
+ enc = {k: {"zlib": True, "complevel": complevel} for k in ds.data_vars}
696
+ ds.to_netcdf(to_file, encoding=enc)
697
+
698
+ return ds