Source code for osaft.solutions.king1934.scattering

from __future__ import annotations

import numpy as np

from osaft import log
from osaft.core.backgroundfields import WaveType
from osaft.core.frequency import Frequency
from osaft.core.functions import BesselFunctions as Bf
from osaft.core.functions import LegendreFunctions as Leg
from osaft.core.functions import exp
from osaft.core.geometries import Sphere
from osaft.core.helper import StringFormatter as SF
from osaft.core.variable import ActiveListVariable
from osaft.solutions.base_scattering import (
    BaseScattering,
    BaseScatteringRigidParticle,
)
from osaft.solutions.king1934.base import BaseKing

NDArray = np.ndarray


[docs]class ScatteringField(BaseKing, BaseScatteringRigidParticle, BaseScattering): """Scattering field class for King (1934) :param f: Frequency [Hz] :param R_0: Radius of the sphere [m] :param rho_s: Density of the fluid-like sphere [kg/m^3] :param rho_f: Density of the fluid [kg/m^3] :param c_f: Speed of sound of the fluid [m/s] :param p_0: Pressure amplitude of the field [Pa] :param wave_type: Type of incident wave (traveling/standing) :param position: Position in the standing wave field [rad] :param N_max: Highest order mode included in the computation [-] """ def __init__( self, f: Frequency | float | int, R_0: Sphere | float | int, rho_s: float, rho_f: float, c_f: float, p_0: float, wave_type: WaveType, position: None | float = None, N_max: int = 5, ) -> None: """Constructor method""" # init of parent class BaseKing.__init__( self, f, R_0, rho_s, rho_f, c_f, p_0, wave_type, position, ) BaseScattering.__init__(self, N_max) # Dependent variables self._A_dash_n = ActiveListVariable(self._compute_A_dash_n, "A_dash_n") self._A_dash_n.is_computed_by( self.field._A_in, self._alpha, self._rho_tilde, ) if type(self) is ScatteringField: log.info(str(self)) log.debug(repr(self)) def __repr__(self): return ( f"{type(self)}(f={self.f}, R_0={self.R_0}, " f"rho_s={self.rho_s}, rho_f={self.rho_f}, c_f={self.c_f}, " f"p_0={self.p_0}, position={self.position}, " f"wave_type={self.wave_type}, N_max={self.N_max})" ) def __str__(self): out = "King's solution to the Scattering field" out += " with following properties: \n" out += SF.get_str_text("Wave type", "", self.wave_type, "") out += SF.get_str_text("Frequency", "f", self.f, "Hz") out += SF.get_str_text("Pressure", "p_0", self.p_0, "Pa") out += SF.get_str_text( "Position", "d", self.position, "rad", ) out += SF.get_str_text( "Wavelength", "lambda", self.field.lambda_f, "m", ) out += "Fluid\n" out += SF.get_str_text( "Density", "rho_f", self.rho_f, "kg/m^3", ) out += SF.get_str_text( "Sound Speed", "c_0", self.c_f, "m/s", ) out += SF.get_str_text( "Compressibility", "kappa_f", self.kappa_f, "1/Pa", ) out += "Particle\n" out += SF.get_str_text( "Radius", "R_0", self.R_0, "m", ) out += SF.get_str_text( "Density", "rho_s", self.rho_s, "kg/m^3", ) out += "Other\n" out += SF.get_str_text( "#modes", "N_max", self.N_max, None, ) return out # ----------------------------------------------------- # User-facing Methods # -----------------------------------------------------
[docs] def particle_velocity(self, t: float) -> float: """Particle velocity Returns the value of the particle velocity in the direction of the axis of rotational symmetry of the radiation field in [m/s] :param t: time [s] """ out = exp(-1j * self.omega * t) * self.A_in(1) / self.alpha**3 out *= self.k_f / self.rho_tilde out /= self.F_n(1, self.alpha) - 1j * self.G_n(1, self.alpha) return out
# ----------------------------------------------------- # Coefficients # -----------------------------------------------------
[docs] def potential_coefficient(self, n: int) -> complex: return -self.A_dash_n(n)
[docs] @staticmethod def phi_n(n: int, arg: float) -> complex: r"""From King equation (22) Returns :math:`\phi_n` :param n: mode :param arg: argument for spherical Bessel function """ return -Bf.bessely(n, arg) * arg ** (-n)
[docs] @staticmethod def psi_n(n: int, arg: float) -> complex: r"""From King equation (22) Returns :math:`\psi_n` :param n: mode :param arg: argument for spherical Bessel function """ return Bf.besselj(n, arg) * arg ** (-n)
[docs] def F_n(self, n: int, arg: float) -> float: """From King equation (30) and (31) Returns :math:`F_n` :param n: mode :param arg: argument for spherical Bessel function """ out = self.alpha**2 * self.phi_n(n + 1, arg) if n == 1: out -= (1 - 1 / self.rho_tilde) * self.phi_n(n, arg) else: out -= n * self.phi_n(n, arg) return out
[docs] def G_n(self, n: int, arg: float) -> complex: """From King equation (30) and (31) Returns :math:`G_n` :param n: mode :param arg: argument for spherical Bessel function """ out = self.alpha**2 * self.psi_n(n + 1, arg) if n == 1: out -= (1 - 1 / self.rho_tilde) * self.psi_n(n, arg) else: out -= n * self.psi_n(n, arg) return out
[docs] def A_dash_n(self, n: int) -> complex: r"""From King equation (21), (28) potential from 28 to form of 21 Returns Scattering field coefficient :math:`A^{\prime}_{n}` :param n: mode number """ return self._A_dash_n.item(n)
def _compute_A_dash_n(self, n: int) -> complex: out = -self.A_in(n) * self.G_n(n, self.alpha) out /= self.G_n(n, self.alpha) + 1j * self.F_n(n, self.alpha) return out # ----------------------------------------------------- # Methods # -----------------------------------------------------
[docs] def Phi_scattering( self, r: float | NDArray | list[float], theta: float | NDArray | list[float], t: float | NDArray | list[float], ) -> complex: r"""King equation (28) for scattering potential :math:`\Phi_{\mathrm{scattering}}` :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param t: time [s] """ def Phi_n(n: int): num = -self.G_n(n, self.alpha) num *= self.A_in(n) * Bf.hankelh2(n, r * self.k_f) denom = self.G_n(n, self.alpha) denom += 1j * self.F_n(n, self.alpha) coefficient = num / denom out = exp(-1j * self.omega * t) out *= Leg.cos_monomial(n, theta, coefficient) return out out = 0 for n in range(self.N_max + 1): out += Phi_n(n) return out
[docs] def Phi_incident( self, r: float | NDArray | list[float], theta: float | NDArray | list[float], t: float | NDArray | list[float], ) -> complex: r"""King equation (28) for scattering potential :math:`\Phi_{\mathrm{incident}}` :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param t: time [s] """ def Phi_n(n: int): coefficient = self.A_in(n) * Bf.besselj(n, r * self.k_f) out = exp(-1j * self.omega * t) out *= Leg.cos_monomial(n, theta, coefficient) return out out = 0 for n in range(self.N_max + 1): out += Phi_n(n) return out
[docs] def V_r_sc( self, n: int, r: float | NDArray | list[float], ) -> complex: """Implements :meth:`osaft.solutions.base_scattering.BaseScattering.\ V_r_sc` """ return self.A_dash_n(n) * self.k_f * Bf.d1_hankelh2(n, self.k_f * r)
[docs] def V_theta_sc( self, n: int, r: float | NDArray | list[float], ) -> complex: """Implements :meth:`osaft.solutions.base_scattering.BaseScattering.\ V_theta_sc` """ return self.A_dash_n(n) * Bf.hankelh2(n, self.k_f * r) / r
if __name__ == "__main__": pass