Source code for zefir.potential.flows.source

"""
Source/Sink flow implementation.

This module provides the SourceFlow class representing a source or sink flow
with radial flow pattern emanating from or converging to a point.
"""

import numpy as np
from ...typing import Tuple, CplxNDArray, ParamType
from .base import ComplexPotential, FlowMetadata, InvalidDerivLevel


[docs] class SourceFlow(ComplexPotential): """A source/sink flow defined by its flow rate and center. A source (or sink) flow represents fluid emanating from (or converging to) a point. The complex potential is given by: .. math:: f(z) = \\frac{q_v}{2\\pi} \\log(z - z_0) where :math:`q_v` is the flow rate (positive for source, negative for sink) and :math:`z_0` is the center position. Parameters ---------- flow_rate : float Flow rate q_v (positive for source, negative for sink) center : Tuple[float, float] or complex Position (x, y) or complex number representing the center Attributes ---------- _center : complex Complex representation of the center position _intensity : float Scaled intensity (flow_rate / 2π) _original_flow_rate : float Original flow rate value Examples -------- >>> flow = SourceFlow(1.0, (0.5, 0.0)) >>> z = np.array([1+0j, 2+0j, 0+1j]) >>> potential = flow(z) >>> velocity = flow.velocity(z) """ metadata = FlowMetadata( "Source/Sink", { "flow_rate": { "type": ParamType.FLOAT, "default": 1.0, "min": -100, "max": 100 }, "center": { "type": ParamType.VECTOR2, "default": [0.0, 0.0], "min": -10, "max": 10, "labels": ["X center", "Y center"] } }, has_position=True )
[docs] def __init__(self, flow_rate:float, center:Tuple[float, float]|complex): if isinstance(center, complex): self._center = center else: self._center = complex(*center) self._intensity = flow_rate/(2*np.pi) self._original_flow_rate = flow_rate
[docs] def __call__( self, z: CplxNDArray, deriv:int=0) -> CplxNDArray: """Evaluate the complex potential or its derivative. Parameters ---------- z : CplxNDArray Complex array of points where the potential is evaluated deriv : int, optional Derivative level: 0 for potential, 1 for velocity Returns ------- CplxNDArray Complex potential (deriv=0) or velocity (deriv=1) Raises ------ InvalidDerivLevel If deriv is not 0 or 1 """ if deriv == 0: return self._intensity*np.log(z-self._center) elif deriv == 1: return self._intensity/(z-self._center) else: raise InvalidDerivLevel()
[docs] def update_parameters(self, params: dict): """Update flow parameters from a dictionary. Parameters ---------- params : dict Dictionary with keys "flow_rate" and/or "center" """ for param_name, value in params.items(): if param_name == "flow_rate": self._intensity = value / (2 * np.pi) self._original_flow_rate = value elif param_name == "center": if isinstance(value, (list, tuple)): value = complex(*value) self._center = value elif hasattr(self, f'_{param_name}'): setattr(self, f'_{param_name}', value)
[docs] def get_parameters(self) -> dict: """Get current parameter values as a dictionary. Returns ------- dict Dictionary with "flow_rate" and "center" keys """ return { "flow_rate": self._original_flow_rate, "center": [self._center.real, self._center.imag] }