Source code for zefir.potential.flows.vortex
"""
Vortex flow implementation.
This module provides the SingularVortexFlow class representing a potential vortex
with circular streamlines around a center point.
"""
import numpy as np
from ...typing import Tuple, CplxNDArray, ParamType
from .base import ComplexPotential, FlowMetadata, InvalidDerivLevel
[docs]
class SingularVortexFlow(ComplexPotential):
"""A vortex flow defined by its intensity and center.
A potential vortex (or line vortex) represents irrotational flow with circular
streamlines around a center point. The complex potential is:
.. math:: f(z) = -\\frac{iK}{2\\pi} \\log(z - z_0)
where :math:`K` is the circulation intensity and :math:`z_0` is the center.
Parameters
----------
intensity : float
Vortex intensity K (circulation)
center : Tuple[float, float] or complex
Position (x, y) or complex number representing the vortex center
Attributes
----------
_center : complex
Complex representation of the vortex center
_intensity : float
Scaled intensity (intensity / 2π)
_original_intensity : float
Original intensity value
Examples
--------
>>> flow = SingularVortexFlow(1.0, (0.0, 0.0))
>>> z = np.array([1+0j, 0+1j, -1+0j])
>>> potential = flow(z)
>>> velocity = flow.velocity(z)
"""
metadata = FlowMetadata(
"Vortex",
{
"intensity": {
"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, intensity:float, center:Tuple[float, float]|complex):
if isinstance(center, complex):
self._center = center
else:
self._center = complex(*center)
self._intensity = intensity/(2*np.pi)
self._original_intensity = intensity
[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 -1j*self._intensity*np.log(z-self._center)
elif deriv == 1:
return -1j*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 "intensity" and/or "center"
"""
for param_name, value in params.items():
if param_name == "intensity":
self._intensity = value / (2 * np.pi)
self._original_intensity = 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 "intensity" and "center" keys
"""
return {
"intensity": self._original_intensity,
"center": [self._center.real, self._center.imag]
}