Stokes Equations#
Interface#
- class pystopt.stokes.StokesInterface(ambient_dim: int)[source]#
Generic interface for solutions and representations of Stokes flow.
The various functionality associated with the StokesInterface
is
implemented through a singledispatch()
setup. Basically all
interested parties can implement a subset of the following functions by
registering it, e.g. using
@velocity.register(MyType)
def _velocity_interface(self: MyType, *args, **kwargs):
# compute some symbolic or explicit value related to the velocity
return u
All the classes in this section implement a subset of this interface with different input arguments.
- pystopt.stokes.streamfunction(self: StokesInterface, *args, **kwargs)[source]#
- pystopt.stokes.velocity(self: StokesInterface, *args, **kwargs)[source]#
- pystopt.stokes.pressure(self: StokesInterface, *args, **kwargs)[source]#
- pystopt.stokes.traction(self: StokesInterface, *args, **kwargs)[source]#
The traction is the normal component of the stress tensor, i.e. \(\mathbf{n} \cdot \sigma \triangleq n_i \sigma_{ij}\).
- pystopt.stokes.tangent_traction(self: StokesInterface, *args, **kwargs)[source]#
This is the tangential component of the stress tensor, i.e. \(\mathbf{t}^\alpha \cdot \sigma \triangleq t_i^\alpha \sigma_{ij}\), where \(\alpha \in \{1, \dots, d - 1\}\) is a basis for the tangent space.
- pystopt.stokes.normal_velocity_gradient(self: StokesInterface, *args, **kwargs)[source]#
This is the normal component of the velocity gradient, i.e. \(\mathbf{n} \cdot \nabla \mathbf{u} \triangleq n_i \nabla_i u_j\).
- pystopt.stokes.tangent_velocity_gradient(self: StokesInterface, *args, **kwargs)[source]#
This is the tangential component of the velocity gradient, i.e. \(\mathbf{t}^\alpha \cdot \nabla \mathbf{u} \triangleq t_i^\alpha \nabla_i u_j\).
- pystopt.stokes.normal_velocity_laplacian(self: StokesInterface, *args, **kwargs)[source]#
This is the normal component of the velocity Laplacian, i.e. \(\mathbf{n} \cdot \Delta \mathbf{u} \triangleq n_j \nabla_i \nabla_i u_j\).
- pystopt.stokes.normal_velocity_hessian(self: StokesInterface, *args, **kwargs)[source]#
This is the normal component of the velocity Hessian, i.e. \(\mathbf{n} \cdot \nabla \nabla \mathbf{u} \cdot \mathbf{n} \triangleq n_i n_k \nabla_i \nabla_k u_j\).
- pystopt.stokes.deltaf(self: StokesInterface, *args, **kwargs)[source]#
This is the jump in traction at the interface. In non-dimensional variables, for a viscosity ratio \(\lambda\), it is
\[[[\mathbf{n} \cdot \sigma]] = \mathbf{n} \cdot \sigma_+ - \lambda \mathbf{n} \cdot \sigma_+.\]
- pystopt.stokes.deltau(self: StokesInterface, *args, **kwargs)[source]#
This is the jump in velocity at the interface. In all current applications, this is zero.
Layer Potential Kernels#
All of the classes in this section implement pystopt.stokes.StokesInterface
with the arguments
@velocity.register(Wrapper)
def _wrapper_velocity(
self: Wrapper, density, *, qbx_forced_limit=None):
pass
and similar for the other variables. The only departure from this interface
are pystopt.stokes.tangent_traction()
and
pystopt.stokes.tangent_velocity_gradient()
which have
@tangent_traction.register(Wrapper)
def _wrapper_traction(
self: Wrapper, density, *, tangent_idx, qbx_forced_limit=None):
pass
to specific which tangent vector in the basis to use. The tangent basis
is obtained by pytential.symbolic.primitives.tangential_onb()
.
- class pystopt.stokes.Stresslet(ambient_dim: int)[source]#
Wrapper for
sumpy.kernel.StressletKernel
andpytential.symbolic.stokes.StressletWrapper
.The wrapper handles the application of the Stresslet kernel \(T_{ijk}\), the associated pressure kernel \(\Pi_{ij}\) and associated stress kernel \(\Theta_{ijkl}\) to a given density. The notation and definitions can be found in [Pozrikidis1992].
- ambient_dim#
- class pystopt.stokes.Stokeslet(ambient_dim)[source]#
Wrapper for
sumpy.kernel.StokesletKernel
andpytential.symbolic.stokes.StokesletWrapper
.The wrapper handles the application of the Stokeslet kernel \(G_{ij}\), the associated pressure kernel \(P_{i}\) and associated stress kernel \(T_{ijk}\) to a given density. The notation and definitions can be found in [Pozrikidis1992].
- class pystopt.stokes.StokesletJumpRelations(ambient_dim: int)[source]#
Jump relations for all the layer potential operators constructed in
Stokeslet
.
- class pystopt.stokes.StokesKernel(ambient_dim: int, base_kernel: Any)[source]#
Bases:
StokesInterface
- class pystopt.stokes.StokesJumpRelations(ambient_dim: int)[source]#
Bases:
StokesInterface
Generic Stokes jump relations.
Layer Potentials#
The TwoPhaseStokesRepresentation
implements
pystopt.stokes.StokesInterface
with the following arguments
@velocity.register(TwoPhaseStokesRepresentation)
def _velocity_repr(self, density, *, side=None, qbx_forced_limit=None):
pass
and similar for the other variables. It also implements the functionality
for pystopt.operators.RepresentationInterface
.
- class pystopt.stokes.TwoPhaseStokesRepresentation(knl: StokesKernel, jmp: StokesJumpRelations, bc: TwoPhaseStokesBoundaryCondition, kernel_arguments: Dict[str, Any] | None = None)[source]#
Bases:
RepresentationInterface
,StokesInterface
- __init__(knl: StokesKernel, jmp: StokesJumpRelations, bc: TwoPhaseStokesBoundaryCondition, kernel_arguments: Dict[str, Any] | None = None) None [source]#
- Parameters:
knl – a Stokes kernel-like
Stokeslet
.jmp – jump relations for the kernels in knl.
bc – farfield boundary conditions.
- class pystopt.stokes.TwoPhaseSingleLayerStokesRepresentation(bc: TwoPhaseStokesBoundaryCondition, kernel_arguments: Dict[str, Any] | None = None)[source]#
Bases:
TwoPhaseStokesRepresentation
Constructs a complete representation (layer potentials and jumps) for a single-layer (Stokeslet) representation of the velocity
\[u_i(\mathbf{x}) = \int_\Sigma G_{ij}(\mathbf{x}, \mathbf{y}) q_j(\mathbf{y}) \,\mathrm{d}S.\]and all the variables described by
Stokeslet
. The construction largely corresponds to Section 5.3 from [Pozrikidis1992].
Solving#
The StokesSolution
class implements pystopt.stokes.StokesInterface
functions with the arguments
@velocity.register(StokesSolution)
def _solution_velocity(self: StokesSolution, *,
side=None, qbx_forced_limit=None, dofdesc=None):
pass
and similar for the other variables.
- class pystopt.stokes.StokesSolution(actx: ArrayContext, source: pytential.symbolic.primitives.DOFDescriptor, places: pytential.GeometryCollection, density: ndarray, op: TwoPhaseStokesRepresentation, context: Dict[str, Any], density_name: str = 'q')[source]#
Bases:
object
Represents the result of solving a Stokes layer potential, e.g. by
single_layer_solve()
.- op#
- class pystopt.stokes.TwoPhaseSingleLayerStokesSolver(sym_op: TwoPhaseStokesRepresentation, *, viscosity_ratio, context=None, gmres_arguments=None)[source]#
Simple wrapper around
single_layer_solve()
.- __init__(sym_op: TwoPhaseStokesRepresentation, *, viscosity_ratio, context=None, gmres_arguments=None)[source]#
- pystopt.stokes.single_layer_solve(actx, places, op, *, lambdas, sources=None, context=None, gmres_arguments=None)[source]#
Solves a two-phase Stokes problem.
- Parameters:
places – a
GeometryCollection
or any input that can be passed to its constructor.op – a
TwoPhaseStokesRepresentation
instance that describes the integral equation.sources – a list of identifiers in places on which to solve.
lambdas – a list of viscosity ratios for each source domain.
- Returns:
Boundary Conditions#
All subclasses of TwoPhaseStokesBoundaryCondition
implement
pystopt.stokes.StokesInterface
with the arguments
@svelocity.register(TwoPhaseStokesBoundaryCondition)
def _bc_velocity(self: TwoPhaseStokesBoundaryCondition):
pass
and similar for the remamining variables.
- class pystopt.stokes.YoungLaplaceJumpCondition(ambient_dim: int, capillary_number_name: str = 'ca')[source]#
Bases:
TractionJumpCondition
Constant surface tension jump condition. It is given by
\[[\![ \mathbf{f} ]\!] = \frac{1}{\mathrm{Ca}} \kappa \mathbf{n}.\]- capillary_number_name#
Name of the symbolic variable representing the Capillary number.
- class pystopt.stokes.VariableYoungLaplaceJumpCondition(ambient_dim: int, capillary_number_name: str = 'ca', surface_tension_name: str = 'gamma')[source]#
Bases:
YoungLaplaceJumpCondition
Variable surface tension jump condition. It is given by
\[[\![ \mathbf{f} ]\!] = \frac{1}{\mathrm{Ca}} (\gamma \kappa \mathbf{n} + \nabla_\Sigma \gamma),\]where \(\nabla_\Sigma\) is the tangential gradient on the surface \(\Sigma\).
- surface_tension_name#
Name of the symbolic variable representing the surface tension coefficient.
- class pystopt.stokes.GravityJumpCondition(ambient_dim: int, direction: int, bond_number_name: str = 'bo')[source]#
Bases:
TractionJumpCondition
Gravity-based jump condition. It is given by
\[[\![ \mathbf{f} ]\!] = \frac{1}{\mathrm{Bo}} x_d \mathbf{n}.\]- direction#
Integer indicating the axis direction in which gravity actx.
- bond_number_name#
Name of the symbolic variable representing the Bond number.
- class pystopt.stokes.TwoPhaseStokesBoundaryCondition(ambient_dim: int, deltafs: Tuple[TractionJumpCondition, ...])[source]#
Bases:
object
Boundary conditions for a generic two-phase Stokes flow.
- ambient_dim#
- deltafs#
A
tuple
ofTractionJumpCondition
that are summed together to obtain the full jump condition.
- __init__(ambient_dim: int, deltafs: Tuple[TractionJumpCondition, ...]) None #
- class pystopt.stokes.CapillaryBoundaryCondition(ambient_dim: int, deltafs: Tuple[TractionJumpCondition, ...])[source]#
Bases:
TwoPhaseStokesBoundaryCondition
Boundary conditions for a two-phase Stokes flow in the presence of constant surface tension at the interface.
- capillary_number#
Symbolic variable representing the Capillary number.
- class pystopt.stokes.FarfieldCapillaryBoundaryCondition(ambient_dim: int, deltafs: Tuple[TractionJumpCondition, ...], uinf: ndarray, pinf: pytential.symbolic.primitives.var, finf: ndarray, tinf: ndarray, dudninf: ndarray, dudtinf: ndarray, ddudninf: pytential.symbolic.primitives.var, dduinf: pytential.symbolic.primitives.var)[source]#
Bases:
CapillaryBoundaryCondition
Farfield boundary conditions for constant surface tension Stokes flow.
- pystopt.stokes.get_farfield_boundary_from_name(ambient_dim: int, name: str, **kwargs: Any) FarfieldCapillaryBoundaryCondition [source]#
- pystopt.stokes.get_extensional_farfield(ambient_dim: int, *, alpha: float = 0.5, pinf: float = 0.0, axis: int = 2, capillary_number_name: str = 'ca') FarfieldCapillaryBoundaryCondition [source]#
Extensional farfield flow with constant surface tension
\[\begin{split}\mathbf{u}_\infty = \begin{cases} (\alpha x, -\alpha y), & \quad d = 2, \\ (\alpha x, \alpha y, -2 \alpha z), & \quad d = 3, \end{cases}\end{split}\]where the location of the \(-2 \alpha\) can be controlled by the axis argument. Setting axis to \(-1\) extends the 2D case to 3D by padding with zero.
- Parameters:
alpha – strain rate.
pinf – constant farfield pressure.
axis – can define the plane in which the extensional flow acts for a three-dimensional flow, but is ignored in two dimensions.
- Returns:
- pystopt.stokes.get_uniform_farfield(ambient_dim: int, *, uinf: float | ndarray = 1.0, pinf: float = 0.0, capillary_number_name: str = 'ca') FarfieldCapillaryBoundaryCondition [source]#
Uniform farfield flow with constant surface tension.
\[\mathbf{u}^\infty = (U, V, W)\]- Parameters:
uinf – an
ndarray
of size ambient_dim or a single number, in which case the velocity field is set to be \((U_\infty, 0, 0)\).pinf – constant farfield pressure.
- Returns:
- pystopt.stokes.get_bezier_uniform_farfield(ambient_dim: int, points_or_order: int | Tuple[ndarray, ...], *, tmax: float | pytential.symbolic.primitives.var, pinf: float = 0.0, tau: str | pytential.symbolic.primitives.var = 'tau', capillary_number_name: str = 'ca') FarfieldCapillaryBoundaryCondition [source]#
Time-dependent uniform farfield flow with constant surface tension.
The control points in ps define a curve
\[\mathbf{p}(\tau) = \sum \mathbf{p}_i \phi_i(\tau),\]where \(\phi_i(\tau)\), for the normalized time variable \(\tau \in [0, 1]\), are the Bézier curve basis functions for the respective order. The velocity field is then given by
\[\mathbf{u}^\infty(\tau) = \frac{\mathrm{d} \mathbf{p}}{\mathrm{d} \tau}.\]- Parameters:
points_or_order – a set of control points used to form the Bézier curve. The number of points also defines the order of the curve. If this is a single integer, the points are defined symbolically and named
"p{i}"
.pinf – constant farfield pressure.
tau – variable name for the parametrization of the Bézier curve. This is expected to be normalized to \([0, 1]\) by the user when the expression is eventually evaluated.
- Returns:
- pystopt.stokes.get_shear_farfield(ambient_dim: int, *, alpha: float = 1.0, pinf: float = 0.0, capillary_number_name: str = 'ca') FarfieldCapillaryBoundaryCondition [source]#
Shear farfield flow with constant surface tension.
\[\mathbf{u}^\infty = (\alpha y, 0, 0)\]- Parameters:
alpha – shear strength.
- pystopt.stokes.get_solid_body_rotation_farfield(ambient_dim: int, *, omega: float | ndarray = 1.0, pinf: float = 0.0, capillary_number_name: str = 'ca') FarfieldCapillaryBoundaryCondition [source]#
Solid body rotation flow with constant surface tension.
\[\mathbf{u}^\infty = \mathbf{\omega} \times \mathbf{x},\]where \(\mathbf{omega}\) is the axis of the solid body rotation. If a scalar is given, the axis is set to \((0, 0, \omega)\). For the 2D case, we omega can only be a scalar and the rotation is always in the \(x-y\) plane.
- Parameters:
omega – magnitude or axis of rotation.
- pystopt.stokes.get_helical_farfield(ambient_dim: int, *, tmax: float | pytential.symbolic.primitives.var, height: float | pytential.symbolic.primitives.var = 1.0, omega: float | pytential.symbolic.primitives.var = 6.283185307179586, pinf: float | pytential.symbolic.primitives.var = 0.0, capillary_number_name: str = 'ca') FarfieldCapillaryBoundaryCondition [source]#
Analytical Solutions#
All subclasses of AnalyticStokesSolution
implement
pystopt.stokes.StokesInterface
with the arguments
@svelocity.register(AnalyticStokesSolution)
def _velocity_solution(self: AnalyticStokesSolution, side: int):
pass
and similar for the remamining variables. In the case of the jumps, the side can be omitted for obvious reasons.
- class pystopt.stokes.SympySolution(pressure: Expr, velocity: ndarray, traction: ndarray, normal_velocity_gradient: ndarray, tangent_traction: ndarray, tangent_velocity_gradient: ndarray, normal_velocity_laplacian: Expr, normal_velocity_hessian: Expr, streamfunction: Expr = None)[source]#
- class pystopt.stokes.AnalyticStokesSolution(ambient_dim: int, *, viscosity_ratio_name: str = 'viscosity_ratio', capillary_number_name: str = 'ca')[source]#
Bases:
StokesInterface
Analytical solution to a two-phase Stokes flow.
- property farfield: TwoPhaseStokesBoundaryCondition#
The farfield boundary conditions for this solution.
- property as_sympy: PymbolicToSympyMapper#
A mapper used to translate an expression to
sympy
.
- __getitem__(side: int) SympySolution [source]#
- Parameters:
side – interior (
-1
) or exterior (+1
) solution.- Returns:
a
SympySolution
with the solution on the respective side.
- class pystopt.stokes.SphericalStokesSolution(*, radius=1.0, viscosity_ratio_name='viscosity_ratio', capillary_number_name='ca')[source]#
Bases:
AnalyticStokesSolution
Two-phase Stokes solutions on a sphere.
- class pystopt.stokes.PolarStokesSolution(*, radius: float = 1.0, uinf: float = 1.0, pinf: float = 0.0, alpha: float | None = None, viscosity_ratio_name: str = 'viscosity_ratio', capillary_number_name: str = 'ca')[source]#
Bases:
AnalyticStokesSolution
Two-phase Stokes solutions on a circle.
- class pystopt.stokes.HadamardRybczynski(*, radius=1.0, alpha=None, uinf=1.0, pinf=0.0, capillary_number_name='ca', viscosity_ratio_name='viscosity_ratio')[source]#
Bases:
SphericalStokesSolution
Hadamard-Rybczynski solution.
The Hadamard-Rybczynski solution is an axisymmetric solution in a uniform farfield flow. It allows stream function solutions of the form
\[\psi_\pm = \left( \frac{A_\pm}{r} + B_\pm r + C_\pm r^2 + D_\pm r^4 \right) \sin^2 \theta,\]where the constants are determined (as a one-parameter family) by the boundary conditions
mass conservation at the interface \([\![ \mathbf{u} ]\!] = 0\).
jump in normal traction at the interface \([\![ \mathbf{f} \cdot \mathbf{n} ]\!] = \kappa / \mathrm{Ca}\).
jump in tangential traction at the interface \([\![ \mathbf{f} \cdot \mathbf{t} ]\!] = 0\).
finite solutions at the origin and at infinity.
For details, see Equation 3-7 in [Clift1978] and the surrounding discussion.
- __init__(*, radius=1.0, alpha=None, uinf=1.0, pinf=0.0, capillary_number_name='ca', viscosity_ratio_name='viscosity_ratio')[source]#
- Parameters:
alpha – parameter for the solution. If None, the classic solution from [Clift1978] is computed.
uinf – magnitude of the \(x\) component of farfield velocity field.
pinf – farfield pressure field.
- class pystopt.stokes.Taylor(*, radius=1.0, alpha=1.0, pinf=0.0, capillary_number_name='ca', viscosity_ratio_name='viscosity_ratio')[source]#
Bases:
SphericalStokesSolution
Taylor solution.
This is a fully three-dimensional solution in an extensional flow. For details see [Taylor1932].
Adjoint Boundary Conditions#
- pystopt.stokes.make_static_adjoint_boundary_conditions(ambient_dim: int, cost: ShapeFunctional) AdjointBoundaryCondition [source]#
Construct a
AdjointBoundaryCondition
based on the static jump conditionsAdjointTractionJumpCondition
.
- pystopt.stokes.make_unsteady_adjoint_boundary_conditions(ambient_dim: int, cost: ShapeFunctional, *, xstar_name: str = 'xstar') AdjointBoundaryCondition [source]#
Construct a
AdjointBoundaryCondition
based on the quasi-static jump conditionsUnsteadyAdjointTractionJumpCondition
.
- class pystopt.stokes.AdjointTractionJumpCondition(ambient_dim: int, cost: ShapeFunctional)[source]#
Bases:
TractionJumpCondition
Defines adjoint boundary conditions for the static Stokes system.
In the static case, the jump conditions are entirely defined by the cost function. In particular, we have that
\[[\![ \mathbf{f}^* ]\!] = \nabla_{\mathbf{u}} J.\]- cost#
- class pystopt.stokes.UnsteadyAdjointTractionJumpCondition(ambient_dim: int, cost: ShapeFunctional, xstar_name: str = 'xstar')[source]#
Bases:
AdjointTractionJumpCondition
Defines adjoint boundary conditions for the quasi-static Stokes system.
In the quasi-static case, the jump conditions are defined by the cost function and the adjoint variable constraining the forward kinematic condition. We have that
\[[\![ \mathbf{f}^* ]\!] = x^* \mathbf{n} + \nabla_{\mathbf{u}} J,\]under the assumptions that the forward kinematic condition is given by
\[\dot{\mathbf{x}} = (\mathbf{u} \cdot \mathbf{n}) \mathbf{n}.\]- xstar_name#
- xstar#
- class pystopt.stokes.AdjointBoundaryCondition(ambient_dim: int, deltafs: Tuple[TractionJumpCondition, ...])[source]#
Bases:
TwoPhaseStokesBoundaryCondition
Adjoint boundary conditions for a static Stokes system.
Implements the interface of
StokesInterface
with the signature:sti.velocity(adjoint_bc)
- ambient_dim#
- cost#
- __init__(ambient_dim: int, deltafs: Tuple[TractionJumpCondition, ...]) None #