Source code for vivyd.models.rigo_andrianne_denoel
from ..typing import arrf64
from .viv_model import VIVModel
from .generalized_model import GeneralizedModel
from dataclasses import dataclass
from numpy import array, pi
[docs]
@dataclass(kw_only=True, slots=True)
class RigoAndrianneDenoelModel(VIVModel):
"""
Rigo, Andrianne & Denoël (2022) wake-oscillator model for the evolution of
the wake alone, without coupling to the structure :cite:`rigo2022`. The
equation of the wake is written as
.. math::
\\ddot{q} - \\left(\\alpha q^2 + \\frac{\\gamma}{\\omega_s^2} \\dot{q}^2 + \\delta \\right) \\omega_s \\dot{q} + \\omega_s^2 q = 0
with
.. math::
\\omega_s = 2 \\pi \\text{St} \\frac{U_\\infty}{D}.
Parameters
----------
diam : float, optional
Diameter of the cylinder, :math:`D`. Default is 0.18 m.
St : float, optional
Strouhal number, :math:`\\text{St}`. Default is 0.18.
u_inf : float, optional
Free-stream velocity, :math:`U_\\infty`. Default is 1.0 m/s.
alpha : float, optional
Van der Pol wake nonlinearity parameter, :math:`\\alpha`. Default is -0.085.
gamma : float, optional
Rayleigh wake nonlinearity parameter, :math:`\\gamma`. Default is 0.009.
delta : float, optional
Constant wake damping parameter, :math:`\\delta`. Default is 0.057.
"""
state_size = 2
diam : float = 0.18
"""Diameter of the cylinder, :math:`D`."""
St : float = 0.18
"""Strouhal number, :math:`\\text{St}`."""
u_inf: float = 1.0
"""Free-stream velocity, :math:`U_\\infty`."""
alpha: float = - 0.085
"""Van der Pol wake nonlinearity parameter, :math:`\\alpha`."""
gamma: float = 0.009
"""Rayleigh wake nonlinearity parameter, :math:`\\gamma`."""
delta: float = 0.057
"""Constant wake damping parameter, :math:`\\delta`."""
@property
def St_star(self) -> float:
"""Angular Strouhal number, :math:`\\text{St}^* = 2 \\pi \\text{St}`."""
return 2.0 * pi * self.St
@property
def ws(self) -> float:
"""Strouhal's vortex shedding pulsation, :math:`\\omega_s = 2 \\pi \\text{St} \\frac{U_\\infty}{D}`."""
return self.St_star * self.u_inf / self.diam
[docs]
def rhs(self, t: float, state: arrf64, **kwargs) -> arrf64:
"""
Compute the right-hand side of the system of ODEs.
Args:
t: Time.
state: State vector indexed [q_dot, q].
Returns:
arrf64: Derivatives of the state vector indexed [dq_dot, dq].
"""
self.validate_state(state)
q_dot, q = state
dq_dot = (self.alpha * q**2 + self.gamma / self.ws**2 * q_dot**2 + self.delta) * self.ws * q_dot - self.ws**2 * q
dq = q_dot
return array([dq_dot, dq])
@property
def generalized_params(self) -> dict[str, float]:
"""
A dictionary containing the parameters of the model in a format
compatible with the constructor of :class:`GeneralizedModel`.
"""
return {
"gamma": self.delta*self.ws,
"a" : -self.alpha/self.delta,
"b" : -self.gamma/(self.delta*self.ws**2),
"kappa": self.ws**2
}
[docs]
def to_generalized(self) -> GeneralizedModel:
"""
Returns
-------
GeneralizedModel
A generalized model instance equivalent to the present model.
"""
return GeneralizedModel(**self.generalized_params)
[docs]
def to_taichi(self) -> GeneralizedModel:
"""
Returns
-------
GeneralizedModel
A Taichi-compatible generalized model instance equivalent to the
present model.
"""
return self.to_generalized()
[docs]
def get_lift_coefficient(self, state: arrf64, Cl0: float) -> float:
"""
Compute the lift coefficient from the state vector.
Args:
state: State vector indexed [q_dot, q].
Cl0: Lift coefficient at zero angle of attack.
Returns:
float: Lift coefficient.
"""
q = state[1]
return q * Cl0 / 2.0