Source code for floris.core.wake_deflection.jimenez


from typing import Any, Dict

import numexpr as ne
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 JimenezVelocityDeflection(BaseModel): """ Jiménez wake deflection model, derived from :cite:`jdm-jimenez2010application`. References: .. bibliography:: /references.bib :style: unsrt :filter: docname in docnames :keyprefix: jdm- """ kd: float = field(default=0.05) ad: float = field(default=0.0) bd: 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, turbulence_intensity_i: np.ndarray, ct_i: np.ndarray, rotor_diameter_i: np.ndarray, *, x: np.ndarray, ): """ Calculates the deflection field of the wake in relation to the yaw of the turbine. This is coded as defined in [1]. Args: x_locations (np.array): streamwise locations in wake y_locations (np.array): spanwise locations in wake z_locations (np.array): vertical locations in wake (not used in Jiménez) turbine (:py:class:`floris.core.turbine.Turbine`): Turbine object coord (:py:meth:`floris.core.turbine_map.TurbineMap.coords`): Spatial coordinates of wind turbine. flow_field (:py:class:`floris.core.flow_field.FlowField`): Flow field object. Returns: deflection (np.array): Deflected wake centerline. This function calculates the deflection of the entire flow field given the yaw angle and Ct of the current turbine """ # NOTE: Its important to remember the rules of broadcasting here. # An operation between two np.arrays of different sizes involves # broadcasting. First, the rank and then the dimensions are compared. # If the ranks are different, new dimensions of size 1 are added to # the missing dimensions. Then, arrays can be combined (arithmetic) # if corresponding dimensions are either the same size or 1. # https://numpy.org/doc/stable/user/basics.broadcasting.html # Here, many dimensions are 1, but these are essentially treated # as a scalar value for that dimension. # angle of deflection xi_init = cosd(yaw_i) * sind(yaw_i) * ct_i / 2.0 """ delta_x = x - x_i # yaw displacement A = 15 * (2 * self.kd * delta_x / rotor_diameter_i + 1) ** 4.0 + xi_init ** 2.0 B = (30 * self.kd / rotor_diameter_i) B *= ( 2 * self.kd * delta_x / rotor_diameter_i + 1 ) ** 5.0 C = xi_init * rotor_diameter_i * (15 + xi_init ** 2.0) D = 30 * self.kd yYaw_init = (xi_init * A / B) - (C / D) # corrected yaw displacement with lateral offset # This has the same shape as the grid deflection = yYaw_init + self.ad + self.bd * delta_x """ # Numexpr - do not change below without corresponding changes above. kd = self.kd ad = self.ad bd = self.bd delta_x = ne.evaluate("x - x_i") A = ne.evaluate("15 * (2 * kd * delta_x / rotor_diameter_i + 1) ** 4.0 + xi_init ** 2.0") B = ne.evaluate("(30 * kd / rotor_diameter_i)") B = ne.evaluate("B * ( 2 * kd * delta_x / rotor_diameter_i + 1 ) ** 5.0") C = ne.evaluate("xi_init * rotor_diameter_i * (15 + xi_init ** 2.0)") D = ne.evaluate("30 * kd") yYaw_init = ne.evaluate("(xi_init * A / B) - (C / D)") deflection = ne.evaluate("yYaw_init + ad + bd * delta_x") return deflection