Source code for floris.core.wake_deflection.empirical_gauss
from typing import Any, Dict
import numpy as np
from attrs import define, field
from floris.core import (
BaseModel,
Farm,
FlowField,
Grid,
Turbine,
)
from floris.utilities import cosd, sind
[docs]
@define
class EmpiricalGaussVelocityDeflection(BaseModel):
"""
The Empirical Gauss deflection model is based on the form of previous the
Gauss deflection model (see :cite:`bastankhah2016experimental` and
:cite:`King2019Controls`) but simplifies the formulation for simpler
tuning and more independence from the velocity deficit model.
parameter_dictionary (dict): Model-specific parameters.
Default values are used when a parameter is not included
in `parameter_dictionary`. Possible key-value pairs include:
- **horizontal_deflection_gain_D** (*float*): Gain for the
maximum (y-direction) deflection achieved far downstream
of a yawed turbine.
- **vertical_deflection_gain_D** (*float*): Gain for the
maximum vertical (z-direction) deflection achieved at a
far downstream location due to rotor tilt. Specifying as
-1 will mean that vertical deflections due to tilt match
horizontal deflections due to yaw.
- **deflection_rate** (*float*): Rate at which the
deflected wake center approaches its maximum deflection.
- **mixing_gain_deflection** (*float*): Gain to set the
reduction in deflection due to wake-induced mixing.
- **yaw_added_mixing_gain** (*float*): Sets the
contribution of turbine yaw misalignment to the mixing
in that turbine's wake (similar to yaw-added recovery).
References:
.. bibliography:: /references.bib
:style: unsrt
:filter: docname in docnames
"""
horizontal_deflection_gain_D: float = field(default=3.0)
vertical_deflection_gain_D: float = field(default=-1)
deflection_rate: float = field(default=22)
mixing_gain_deflection: float = field(default=0.0)
yaw_added_mixing_gain: float = field(default=0.0)
[docs]
def prepare_function(
self,
grid: Grid,
flow_field: FlowField,
) -> Dict[str, Any]:
kwargs = {
"x": grid.x_sorted,
}
return kwargs
# @profile
[docs]
def function(
self,
x_i: np.ndarray,
y_i: np.ndarray,
yaw_i: np.ndarray,
tilt_i: np.ndarray,
mixing_i: np.ndarray,
ct_i: np.ndarray,
rotor_diameter_i: float,
*,
x: np.ndarray,
):
"""
Calculates the deflection field of the wake.
Args:
x_i (np.array): Streamwise direction grid coordinates of
the ith turbine (m).
y_i (np.array): Cross stream direction grid coordinates of
the ith turbine (m) [not used].
yaw_i (np.array): Yaw angle of the ith turbine (deg).
tilt_i (np.array): Tilt angle of the ith turbine (deg).
mixing_i (np.array): The wake-induced mixing term for the
ith turbine.
ct_i (np.array): Thrust coefficient for the ith turbine (-).
rotor_diameter_i (np.array): Rotor diameter for the ith
turbine (m).
x (np.array): Streamwise direction grid coordinates of the
flow field domain (m).
Returns:
np.array: Deflection field for the wake.
"""
# ==============================================================
deflection_gain_y = self.horizontal_deflection_gain_D * rotor_diameter_i
if self.vertical_deflection_gain_D == -1:
deflection_gain_z = deflection_gain_y
else:
deflection_gain_z = self.vertical_deflection_gain_D * rotor_diameter_i
# Convert to radians, CW yaw for consistency with other models
yaw_r = np.pi/180 * -yaw_i
tilt_r = np.pi/180 * tilt_i
A_y = (deflection_gain_y * ct_i * yaw_r) / (1 + self.mixing_gain_deflection * mixing_i)
A_z = (deflection_gain_z * ct_i * tilt_r) / (1 + self.mixing_gain_deflection * mixing_i)
# Apply downstream mask in the process
x_normalized = (x - x_i) * (x > x_i + 0.1) / rotor_diameter_i
log_term = np.log(
(x_normalized - self.deflection_rate) / (x_normalized + self.deflection_rate)
+ 2
)
deflection_y = A_y * log_term
deflection_z = A_z * log_term
return deflection_y, deflection_z
[docs]
def yaw_added_wake_mixing(
axial_induction_i,
yaw_angle_i,
downstream_distance_D_i,
yaw_added_mixing_gain
):
return (
axial_induction_i[:,:,0,0]
* yaw_added_mixing_gain
* (1 - cosd(yaw_angle_i[:,:,0,0]))
/ downstream_distance_D_i**2
)