Source code for vivyd.models.hartlen_currie

from ..typing import arrf64
from .viv_model import VIVModel
from .generalized_model import GeneralizedModel

from dataclasses import dataclass
from numpy import pi, array


[docs] @dataclass(kw_only=True, slots=True) class HartlenCurrieModel(VIVModel): """ Hartlen & Currie (1970) wake-oscillator model for vortex-induced vibrations on circular cylinders :cite:`hartlen1970`. By identifying the lift, the mechanical equation of motion of the cylinder is written as .. math:: \\ddot{y} + \\frac{c}{m} \\dot{y} + \\frac{k}{m} y = \\frac{\\rho D^3}{8 \\pi^2 \\text{St}^2 m_\\text{lin}} \\omega_s^2 q, and the equation of the wake is written as .. math:: \\ddot{q} + \\left(\\frac{\\gamma}{\\omega_s} \\dot{q}^2 - \\alpha \\omega_s \\right) \\dot{q} + \\omega_s^2 q = b^* \\frac{\\omega_s}{D} \\dot{y}, 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. c_m : float, optional Specific mechanical damping, :math:`c/m`. Default is 0.05. k_m : float, optional Specific mechanical stiffness, :math:`k/m`. Default is :math:`4 \\pi^2`. m_lin : float, optional Mass per unit length of the cylinder, :math:`m_\\text{lin}`. Default is 25.0 kg/m. rho : float, optional Density of the fluid, :math:`\\rho`. Default is 1.25 kg/m³. u_inf : float, optional Free-stream velocity, :math:`U_\\infty`. Default is 1.0 m/s. gamma : float, optional Quadratic wake damping coefficient, :math:`\\gamma`. Default is 0.667. alpha : float, optional Constant wake damping coefficient, :math:`\\alpha`. Default is 0.02. b_star: float, optional Wake-coupling coefficient, :math:`b^* = b \\dfrac{\\omega_0}{\\omega_s}`, where :math:`b` is the wake-coupling coefficient as defined by Hartlen & Currie (1970) and :math:`\\omega_0` is the natural frequency of the structure. Default is 0.4. """ state_size = 4 diam : float = 0.18 """Diameter of the cylinder, :math:`D`.""" St : float = 0.18 """Strouhal number, :math:`\\text{St}`.""" c_m : float = 0.05 """Specific mechanical damping, :math:`c/m`.""" k_m : float = 4.0 * pi**2 """Specific mechanical stiffness, :math:`k/m`.""" m_lin : float = 25.0 """Mass per unit length of the cylinder, :math:`m_\\text{lin}`.""" rho : float = 1.25 """Density of the fluid, :math:`\\rho`.""" u_inf : float = 1.0 """Free-stream velocity, :math:`U_\\infty`.""" gamma : float = 0.667 """Quadratic wake damping coefficient, :math:`\\gamma`.""" alpha : float = 0.02 """Constant wake damping coefficient, :math:`\\alpha`.""" b_star: float = 0.4 """ Structure-to-wake coefficient, :math:`b^* = b \\dfrac{\\omega_0}{\\omega_s}`, where :math:`b` is the structure-to-wake coefficient as defined by Hartlen & Currie (1970) and :math:`\\omega_0` is the natural frequency of the structure. """ @property def a(self) -> float: """Wake-to-structure coupling coefficient as defined by Hartlen & Currie (1970).""" return self.rho * self.diam**2 / (2.0 * self.St_star**2 * self.m_lin) @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} \\dfrac{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 [y_dot, y, q_dot, q]. Returns: arrf64: Derivatives of the state vector indexed [dy_dot, dy, dq_dot, dq]. """ self.validate_state(state) y_dot, y, q_dot, q = state lhs = self.c_m * y_dot + self.k_m * y rhs = self.a * self.ws**2 * self.diam * q dy_dot = rhs - lhs dy = y_dot lhs = (self.gamma/self.ws * q_dot**2 - self.alpha * self.ws) * q_dot + self.ws**2 * q rhs = self.b_star * self.ws / self.diam * y_dot dq_dot = rhs - lhs dq = q_dot return array([dy_dot, dy, 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 { "c_m" : self.c_m, "k_m" : self.k_m, "B0" : self.a * self.ws**2 * self.diam, "gamma": self.alpha * self.ws, "b" : self.gamma/(self.alpha * self.ws**2), "kappa": self.ws**2, "A1" : self.b_star * self.ws / self.diam, }
[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()