Source code for osaft.solutions.base_streaming

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Optional

import numpy as np

from osaft.core.functions import LegendreFunctions as Leg


[docs]class BaseStreaming(ABC): """ Base class for the Streaming Field that defines the common interface. This base class is used for axisymmetrical models. """ # Required properties by child class # ------------------------------------------------------------------------- # Abstract Methods # ------------------------------------------------------------------------- @property @abstractmethod def range_N_max(self): pass @property @abstractmethod def range_1_N_max(self): pass
[docs] @abstractmethod def Phi(self, l: int, r: float) -> float: """:math:`\\Phi_l(r)` :param l: index l :param r: radial coordinate [m] :return: Phi_l(r) """ pass
[docs] @abstractmethod def d_Phi(self, l: int, r: float) -> float: """:math:`\\partial_r \\Phi_l(r)` :param l: index l :param r: radial coordinate [m] :return: d_Phi_l(l, r) """ pass
[docs] @abstractmethod def Psi(self, l: int, r: float) -> float: """:math:`\\Psi_l(r)` :param l: index l :param r: radial coordinate [m] :return: Psi_l(l, r) """ pass
[docs] @abstractmethod def d_Psi(self, l: int, r: float) -> float: """:math:`\\partial_r \\Psi_l(r)` :param l: index l :param r: radial coordinate [m] :return: d_Psi(l, r) """ pass
[docs] @abstractmethod def V_S_r(self, l: int, r: float, ac: bool) -> float: """:math:`V_{Srl}(r)` :param l: index l :param r: radial coordinate [m] :param ac: if True only the incident field contribution """ pass
[docs] @abstractmethod def V_S_theta(self, l: int, r: float, ac: bool) -> float: """:math:`V_{S \\theta l}(r)` :param l: index l :param r: radial coordinate [m] :param ac: if True only the incident field contribution """ pass
# ------------------------------------------------------------------------- # User Facing Methods # -------------------------------------------------------------------------
[docs] def radial_Stokes_drift_coefficients( self, r: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Radial Stokes drift coefficient [m/s] (Eq. F8) :param r: radial coordinate [m] :param mode: mode :return: radial Stokes drift coefficient """ def legendre_coeffs(l, x): return self.V_S_r(l, x, False) - self.V_S_r(l, x, True) if mode is not None: if mode > 0: return legendre_coeffs(mode, r) else: return 0 else: return np.array( [0.0] + [legendre_coeffs(n, r) for n in self.range_1_N_max], )
[docs] def radial_Stokes_drift( self, r: float, theta: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Radial Stokes drift velocity [m/s] (Eq. F6) :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param mode: mode :return: radial Stokes drift velocity """ if mode is not None: return Leg.cos_monomial( mode, theta, self.radial_Stokes_drift_coefficients(r, mode), ) else: return Leg.cos_poly( theta, self.radial_Stokes_drift_coefficients(r), )
[docs] def tangential_Stokes_drift_coefficients( self, r: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Tangential Stokes drift coefficient [m/s] (Eq. F9) :param r: radial coordinate [m] :param mode: mode :return: tangential Stokes drift coefficient """ def legendre_coeffs(l, x): return self.V_S_theta(l, x, False) - self.V_S_theta(l, x, True) if mode is not None: if mode > 0: return legendre_coeffs(mode, r) else: return 0 else: return np.array( [0.0] + [legendre_coeffs(n, r) for n in self.range_1_N_max], )
[docs] def tangential_Stokes_drift( self, r: float, theta: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Tangential Stokes drift velocity [m/s] (Eq. F7) :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param mode: mode :return: tangential Stokes drift velocity """ if mode is not None: return Leg.first_cos_monomial( mode, theta, self.tangential_Stokes_drift_coefficients(r, mode), ) else: return Leg.first_cos_poly( theta, self.tangential_Stokes_drift_coefficients(r), )
[docs] def radial_Euler_streaming_coefficients( self, r: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Radial Euler streaming coefficient [m/s] (Eq. 47) :param r: radial coordinate [m] :param mode: mode :return: radial Euler streaming coefficient """ def legendre_coeffs(l, x): return self.d_Phi(l, x) - l * (l + 1) / x * self.Psi(l, x) if mode is not None: if mode > 0: return legendre_coeffs(mode, r) else: return 0 else: return np.array( [0.0] + [legendre_coeffs(n, r) for n in self.range_1_N_max], )
[docs] def radial_Euler_streaming( self, r: float, theta: float | np.ndarray, mode: Optional[int] = None, ) -> float | np.ndarray: """Radial Euler streaming velocity [m/s] (Eq. 47) :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param mode: mode :return: radial Euler streaming velocity """ if mode is not None: return Leg.cos_monomial( mode, theta, self.radial_Euler_streaming_coefficients(r, mode), ) else: return Leg.cos_poly( theta, self.radial_Euler_streaming_coefficients(r), )
[docs] def tangential_Euler_streaming_coefficients( self, r: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Tangential Euler streaming coefficient [m/s] (Eq. 48) :param r: radial coordinate [m] :param mode: mode :return: tangential Euler streaming coefficient """ def legendre_coeffs(l, x): return (self.Phi(l, x) - self.Psi(l, x)) / x - self.d_Psi(l, x) if mode is not None: if mode > 0: return legendre_coeffs(mode, r) else: return 0 else: return np.array( [0.0] + [legendre_coeffs(n, r) for n in self.range_1_N_max], )
[docs] def tangential_Euler_streaming( self, r: float, theta: float | np.ndarray, mode: Optional[int] = None, ) -> float | np.ndarray: """Tangential Euler streaming coefficient [m/s] (Eq. 48) :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param mode: mode :return: tangential Euler streaming coefficients """ if mode is not None: return Leg.first_cos_monomial( mode, theta, self.tangential_Euler_streaming_coefficients(r, mode), ) else: return Leg.first_cos_poly( theta, self.tangential_Euler_streaming_coefficients(r), )
[docs] def radial_Lagrange_streaming_coefficients( self, r: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Radial Lagrange streaming coefficient [m/s] (Eq. 51) :param r: radial coordinate [m] :param mode: mode :return: radial Lagrange streaming coefficient """ if mode is not None: return ( self.radial_Euler_streaming_coefficients(r, mode) + self.radial_Stokes_drift_coefficients(r, mode) ) else: return ( self.radial_Euler_streaming_coefficients(r) + self.radial_Stokes_drift_coefficients(r) )
[docs] def tangential_Lagrange_streaming_coefficients( self, r: float, mode: Optional[int] = None, ) -> float | np.ndarray: """Tangential Lagrange streaming coefficient [m/s] (Eq. 52) :param r: radial coordinate [m] :param mode: mode :return: tangential Lagrange streaming coefficient """ if mode is not None: return ( self.tangential_Euler_streaming_coefficients(r, mode) + self.tangential_Stokes_drift_coefficients(r, mode) ) else: return ( self.tangential_Euler_streaming_coefficients(r) + self.tangential_Stokes_drift_coefficients(r) )
[docs] def radial_Lagrange_streaming( self, r: float, theta: float | np.ndarray, mode: Optional[int] = None, ) -> float: """ Returns the value for the radial Lagrange streaming velocity in [m/s]. This method must be implemented by every theory to have a common interface for other modules. :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param mode: mode, if `None` all modes to `N_max` """ if mode is not None: return ( self.radial_Euler_streaming(r, theta, mode) + self.radial_Stokes_drift(r, theta, mode) ) else: return ( self.radial_Euler_streaming(r, theta) + self.radial_Stokes_drift(r, theta) )
[docs] def tangential_Lagrange_streaming( self, r: float, theta: float | np.ndarray, mode: Optional[int] = None, ) -> float: """ Returns the value for the tangential Lagrange streaming velocity in [m/s]. This method must be implemented by every theory to have a common interface for other modules. :param r: radial coordinate [m] :param theta: tangential coordinate [rad] :param mode: mode, if `None` all modes to `N_max` """ if mode is not None: return ( self.tangential_Euler_streaming(r, theta, mode) + self.tangential_Stokes_drift(r, theta, mode) ) else: return ( self.tangential_Euler_streaming(r, theta) + self.tangential_Stokes_drift(r, theta) )
if __name__ == '__main__': pass