Meshing

Contents

Meshing#

Spectral Meshes#

class pystopt.mesh.SpectralConnectionBatch(from_group_index: int, node_indices: ndarray)[source]#

Bases: UniqueConnectionBatch

Describes transporting elements on a spectral mesh.

class pystopt.mesh.SpectralConnectionElementGroup(noutputs: int, batches: Tuple[UniqueConnectionBatch, ...])[source]#

Bases: ABC, UniqueConnectionElementGroup

Holds batches and spectral element information.

dim#
nspec#

Number of spectral coefficients to represent the noutputs DOFs.

spat_shape#

Shape of the spatial grid.

abstract to_spectral(actx: ArrayContext, ary: Any) Any[source]#

Transforms an array of shape spat_shape into its spectral coefficients.

Parameters:

ary – an array of type arraycontext.ArrayContext.array_types.

Returns:

an array of type arraycontext.ArrayContext.array_types.

abstract from_spectral(actx: ArrayContext, ary: Any) Any[source]#

Transforms an array of spectral coefficients of shape (nspec, 1) back to its spatial representation.

Parameters:

ary – an array of type arraycontext.ArrayContext.array_types.

Returns:

an array of type arraycontext.ArrayContext.array_types.

class pystopt.mesh.SpectralGridConnection(*args: Any, **kwargs: Any)[source]#

Bases: DiscretizationConnection

Transports from the spectral grid to the spectral coefficients.

groups#

A tuple of SpectralConnectionElementGroups used for the connection to the spectral grid.

pystopt.mesh.make_spectral_connections(discr: SpectralDiscretization, specgroups: Tuple[SpectralConnectionElementGroup, ...]) Tuple[DiscretizationConnection, DiscretizationConnection][source]#
pystopt.mesh.update_spectral_connections_for_factory(to_discr: SpectralDiscretization, from_discr: SpectralDiscretization, group_factory: meshmode.discretization.poly_element.ElementGroupFactory | None = None) Tuple[DiscretizationConnection, DiscretizationConnection][source]#
class pystopt.mesh.SpectralDiscretization(*args: Any, **kwargs: Any)[source]#

Bases: Discretization

specgroups#

A list of SpectralConnectionElementGroup that are used in to_spectral_conn and from_spectral_conn.

to_spectral_conn#

A DiscretizationConnection used to transport from the discretization DOFs to the spectral coefficients.

from_spectral_conn#

A DiscretizationConnection used to transport from the spectral coefficients to the discretization DOFs.

spectral_num_reference_derivative(ref_axes: Tuple[int, ...], ary: ArrayOrContainerT) ArrayOrContainerT[source]#

Takes derivatives by doing a roundtrip through spectral space.

Parameters:

ref_axes – a list of axis indices, e.g. in 1D a list of [0, 0, 0] would take the third derivative of ary.

Fourier (2D)#

class pystopt.mesh.FourierConnectionBatch(from_group_index: int, node_indices: ndarray)[source]#

Bases: SpectralConnectionBatch

class pystopt.mesh.FourierConnectionElementGroup(noutputs: int, batches: Tuple[FourierConnectionBatch, ...], is_real: bool = False)[source]#

Bases: SpectralConnectionElementGroup

class pystopt.mesh.FourierDiscretization(*args: Any, **kwargs: Any)[source]#

Bases: SpectralDiscretization

pystopt.mesh.make_fourier_discretization(actx: ArrayContext, nelements: int | Tuple[int, ...], *, curve_fn: Callable[[ndarray], ndarray], order: int, group_factory: meshmode.discretization.poly_element.ElementGroupFactory | None = None, mesh_unit_nodes: ndarray | None = None, use_spectral_derivative: bool = True, is_real: bool = False) Tuple[FourierDiscretization, ndarray][source]#
pystopt.mesh.fourier.polar_angle(x: ndarray) DOFArray[source]#
pystopt.mesh.fourier.find_modes_for_tolerance(actx: ArrayContext, curve_fn: Callable[[ndarray], ndarray], *, rtol: float = 1e-08, kmin: int = 1, step: int = 2) int[source]#

Finds a minimum number of nodes required to represent a given curve.

The implementation uses a simple iterative approach where for each \(k\), the geometry is interpolated to a fine grid and compared to the exact geometry provided by curve_fn. If the relative \(\ell^2\) error is sufficiently small, the algorithms is stopped.

Parameters:
  • rtol – relative tolerance in error between the geometry approximated with a given \(k\) modes and the exact geometry.

  • kmin – starting number of modes.

  • step – increase in number of Fourier modes each time the error is too large.

Returns:

an approximate number of Fourier modes required to represent the geometry described by curve_fn to the given relative tolerance rtol.

pystopt.mesh.fourier.visualize_fourier_modes(fig_or_filename: str | bytes | PathLike[str] | IOBase, actx: ArrayContext, discr: FourierDiscretization, names_and_fields: Sequence[Tuple[str, Any]], *, markers: Sequence[str] | None = None, n_max_modes: float | None = None, semilogy: bool = True, overwrite: bool = False) None[source]#

Write out the Fourier modes of the given fields.

Arg:

fig_or_filename: if a matplotlib.figure.Figure, then the fields are added to the current axis.

Parameters:
  • n_max_modes – number of modes to plot, regardless of the number of modes in the discr. If the discretization has a complex FFT, then the slice -n_max_modes:n_max_modes is plotted.

  • semilogy – if True, the modes are plotted in a log scale.

Spherical Harmonics (3D)#

class pystopt.mesh.SphericalHarmonicConnectionBatch(from_group_index: int, node_indices: ndarray, itheta: slice | None = None, theta: ndarray | None = None, phi: ndarray | None = None)[source]#

Bases: SpectralConnectionBatch

class pystopt.mesh.SphericalHarmonicConnectionElementGroup(batches: Sequence[SphericalHarmonicConnectionBatch], sh: Any, neltheta: int, nelphi: int, is_real: bool = True)[source]#

Bases: SpectralConnectionElementGroup

sh#

An instance of the shtns main data structure.

theta#

The longitutinal \(\theta \in [-\pi/2, \pi/2]\) coordinates on the uniform spatial grid of sh.

phi#

The latitudinal \(\phi \in [0, 2 \pi]\) coordinates on the uniform spatial grid of sh.

class pystopt.mesh.SphericalHarmonicDiscretization(*args: Any, **kwargs: Any)[source]#

Bases: SpectralDiscretization

pystopt.mesh.make_spharm_discretization(actx: ArrayContext, nellon: int, nellat: int, *, surface_fn: Callable[[ndarray, ndarray], ndarray], order: int, lmax: int | None = None, mmax: int | None = None, polar_opt: float = 1e-10, stol: float = 1e-10, group_factory: meshmode.discretization.poly_element.ElementGroupFactory | None = None, mesh_unit_nodes: bool | ndarray = False, use_spectral_derivative: bool = True, _visualize: bool = False) Discretization[source]#
Parameters:
  • nellon – (approximate) number of elements in the longitudinal direction with \(\phi \in [0, 2 \pi)\).

  • nellat – (approximate) number of elements in the latitudinal direction with \(\theta \in [0, \pi)\).

  • surface_fn – a Callable that takes \((\theta, \phi)\) and returns and array of shape (3, ...).

  • order – desired order of the discretization.

  • mesh_unit_nodes – if this is True then the unit nodes of the provided group_factory are used. If False, equidistant nodes are unused. Otherwise, if a specific set of unit nodes is provided, it is used as is.

  • lmax – maximum spherical harmonic degree.

  • mmax – maximum spherical harmonic order.

  • polar_opt – tolerance for singularities near poles.

  • stol – if in debug mode, this tolerance is used to check how well the spherical harmonics approximate the surface by doing a roundtrip.

pystopt.mesh.spharm.visualize_spharm_modes(fig_or_filename: str | bytes | PathLike[str] | IOBase, discr: SphericalHarmonicDiscretization, names_and_fields: Sequence[Tuple[str, DOFArrayT]], *, semilogy: bool = True, mode: str = 'imshow', component: str = 'abs', layout: str = 'horizontal', max_degree_or_order: int | None = None, overwrite: bool = False) None[source]#

Visualize spherical harmonic modes of a given set of arrays.

The mode can be one of:

  • "imshow", which plots all the modes using imshow.

  • "byorder", which uses line plots to plot \(f^m_{\cdot}\) for each order \(m\), i.e. a vertical slice through imshow.

  • "bydegree", which uses line plots to plot \(f^{\cdot}_n\) for each degree \(n\), i.e. a horizontal slice through imshow.

Parameters:
  • mode – type of the plot to use in the visualization.

  • component – can be one of "real", "imag" or "abs", to visualize the real, imaginary or absolute value of each component.

  • layout – can be one of "horizontal" or "vertical" and is used to determine how to stack the multiple arrays in names_and_fields.

  • max_degree_or_order – a cutoff used when mode is "bydegree" or "byorder" to determine the maximum value to plot.

Generation#

class pystopt.mesh.MeshGenerator(name: str | None = None, mesh_order: int | None = None, target_order: int | None = None, group_factory_cls: Type[meshmode.discretization.poly_element.ElementGroupFactory] = meshmode.discretization.poly_element.InterpolatoryQuadratureGroupFactory, mesh_unit_nodes: ndarray | None = None, use_default_mesh_unit_nodes: bool = True, use_spectral_derivative: bool = True, offset: ndarray | None = None, transform_matrix: float | ndarray | None = None)[source]#

Bases: ABC

dim#
ambient_dim#
name#
mesh_order#
target_order#
group_factory_cls#
mesh_unit_nodes#
use_default_mesh_unit_nodes#
use_spectral_derivative#
offset#
transform_matrix#
default_group_factory(order: int | None = None) meshmode.discretization.poly_element.ElementGroupFactory[source]#
default_mesh_unit_nodes_for_factory(group_factory: meshmode.discretization.poly_element.ElementGroupFactory) ndarray | None[source]#
pystopt.mesh.get_mesh_generator_from_name(name, **kwargs)[source]#

Construct a specific mesh generator from its name.

circle = build_mesh_from_name("circle", radius=np.pi)
mesh = circle.get_mesh(resolution=32, mesh_order=4)
Parameters:
  • name – name of one of the existing mesh generators.

  • kwargs – any additional arguments that can be passed to the generator.

Returns:

a MeshGenerator.

pystopt.mesh.generate_discretization(gen: Any, actx: ArrayContext, resolution: int | Tuple[int, ...]) Discretization[source]#
pystopt.mesh.generate_discretization(gen: FourierGenerator, actx: ArrayContext, resolution: int | Tuple[int, ...]) Discretization
pystopt.mesh.generate_discretization(gen: SPHARMGenerator, actx: ArrayContext, resolution: int | Tuple[int, ...]) Discretization
class pystopt.mesh.FourierGenerator(name: str = '_fourier_unknown', mesh_order: int | None = None, target_order: int | None = None, group_factory_cls: Type[meshmode.discretization.poly_element.ElementGroupFactory] = meshmode.discretization.poly_element.InterpolatoryQuadratureGroupFactory, mesh_unit_nodes: ndarray | None = None, use_default_mesh_unit_nodes: bool = True, use_spectral_derivative: bool = True, offset: ndarray | None = None, transform_matrix: float | ndarray | None = None, curve: Callable[[ndarray], ndarray] | None = None, rfft: bool = False)[source]#

Bases: MeshGenerator

curve#
class pystopt.mesh.SPHARMGenerator(name: str = '_spharm_unknown', mesh_order: int | None = None, target_order: int | None = None, group_factory_cls: Type[meshmode.discretization.poly_element.ElementGroupFactory] = meshmode.discretization.poly_element.InterpolatoryQuadratureGroupFactory, mesh_unit_nodes: ndarray | None = None, use_default_mesh_unit_nodes: bool = True, use_spectral_derivative: bool = True, offset: ndarray | None = None, transform_matrix: float | ndarray | None = None, surface: Callable[[ndarray, ndarray], ndarray] | None = None, lmax: int | None = None, mmax: int | None = None, polar_opt: float | None = 1e-10)[source]#

Bases: MeshGenerator

surface#
lmax#
mmax#
polar_opt#
pystopt.mesh.generation.ellipse_from_axes(t: ndarray, *, a: float = 2.0, b: float = 1.0) ndarray[source]#

Generate an ellipse parametrized by t given its axes.

\[\begin{split}\begin{bmatrix} r(t) \cos 2 \pi t \\ r(t) \sin 2 \pi t \end{bmatrix}, \quad \text{where } r(t) = \frac{a b}{\sqrt{(b \cos 2 \pi t)^2 + (a \sin 2 \pi t)^2}}\end{split}\]
Parameters:
  • a – major axis.

  • b – minor axis.

pystopt.mesh.generation.fourier_ufo(t: ndarray, *, a: float = 3.0, b: float = 1.0, k: int = 4) ndarray[source]#

Generate a potato parametrized by t.

\[\begin{split}\begin{bmatrix} r(t) \cos 2 \pi t \\ r(t) \sin 2 \pi t \end{bmatrix}, \quad \text{where } r(t) = \sqrt{(b \cos 2 \pi t)^2 + (a \sin 2 \pi t)^2} + \cos^2 (2 \pi k t)\end{split}\]
pystopt.mesh.generation.spharm_sphere(theta: ndarray, phi: ndarray, *, radius: float = 1.0) ndarray[source]#

Generate a sphere parametrized by \((\theta, \phi)\).

\[\begin{split}\begin{bmatrix} r \sin \theta \cos \phi \\ r \sin \theta \sin \phi \\ r \cos \theta \end{bmatrix}\end{split}\]
Parameters:

radius – sphere radius.

pystopt.mesh.generation.spharm_spheroid(theta: ndarray, phi: ndarray, *, radius: float = 1.0, aspect_ratio: float = 2.0) ndarray[source]#

Generate a spheroid parametrized by \((\theta, \phi)\).

\[\begin{split}\begin{bmatrix} r \sin \theta \cos \phi \\ r \sin \theta \sin \phi \\ \alpha r \cos \theta \end{bmatrix}\end{split}\]

where \(\alpha\) is the aspect ratio.

Parameters:
  • radius – spheroid radius.

  • aspect_ratio – aspect ratio of the spheroid.

pystopt.mesh.generation.spharm_ufo(theta: ndarray, phi: ndarray, *, k: float = 4.0, a: float = 2.0, b: float = 1.0, aspect_ratio: float = 0.5) ndarray[source]#

Generate a potato parametrized by \((\theta, \phi)\).

\[\begin{split}\begin{bmatrix} r(\theta) \sin \theta \cos \phi \\ r(\theta) \sin \theta \sin \phi \\ \alpha r(\theta) \cos \theta \end{bmatrix}, \quad \text{where } r(\theta) = \sqrt{(b \cos \theta)^2 + (a \sin \theta)^2} + \cos^2 (k \theta)\end{split}\]

where \(\alpha\) is the aspect ratio.

pystopt.mesh.generation.spharm_urchin(theta: ndarray, phi: ndarray, *, m: int = 2, n: int = 3, k: float = 3.0) ndarray[source]#

Generate a potato parametrized by \((\theta, \phi)\).

\[\begin{split}\begin{bmatrix} r(\theta, \phi) \sin \theta \cos \phi \\ r(\theta, \phi) \sin \theta \sin \phi \\ r(\theta, \phi) \cos \theta \end{bmatrix}, \quad \text{where } r(\theta, \phi) = 1 + \exp \big(-k Y^m_n(\theta, \phi)\big)\end{split}\]

where \(Y^m_n\) is the spherical harmonic of order \(m\) and degree \(n\).

Reconstruction#

pystopt.mesh.update_discr_mesh_from_nodes(actx: ArrayContext, discr: SpectralDiscretization, nodes: ndarray, *, keep_vertices: bool = True, atol: float | None = None) Mesh[source]#
Parameters:
  • discr – previous SpectralDiscretization.

  • nodes – a node array with the same number of DOFs as the one in discr.

  • keep_vertices – if True, the nodes are also used to reconstruct the vertices. As the discretization is discontinuous, vertices are averaged over all elements to obtain a unique value.

  • atol – a floating point tolerance used to check if the unit nodes of the discretization groups are the same as the unit nodes of the mesh element groups.

Returns:

a Mesh with the same structure as discr.mesh, but with nodes interpolated from nodes.

pystopt.mesh.update_discr_from_nodes(actx: ArrayContext, discr: SpectralDiscretization, nodes: ndarray, *, group_factory: meshmode.discretization.poly_element.ElementGroupFactory | None = None, keep_vertices: bool = False) SpectralDiscretization[source]#
Parameters:
  • discr – previous Discretization.

  • nodes – a node array with the same number of DOFs as the one in discr.

  • group_factory – a group factory used to construct the new discretization (should match the one used to construct discr in most cases). A default is provided if discr has a single group from meshmode.discretization.poly_element.

Returns:

a Discretization with the same structure (i.e. number of groups, DOFs, etc) as discr, but with nodes interpolated from nodes.

pystopt.mesh.update_discr_from_spectral(actx: ArrayContext, discr: SpectralDiscretization, xlm: ndarray, *, group_factory: meshmode.discretization.poly_element.ElementGroupFactory | None = None, keep_vertices: bool = False) SpectralDiscretization[source]#
Parameters:
  • discr – a SpectralDiscretization.

  • xlm – a DOFArray of spectral coefficients for the new nodes.

  • group_factory – element group factory for the polynomial discretization.

pystopt.mesh.merge_disjoint_spectral_discretizations(actx, discretizations)[source]#
Parameters:

discretizations – a list of SpectralDiscretizations.

Returns:

A single SpectralDiscretization, where all the meshes have been merged using merge_disjoint_meshes().

pystopt.mesh.generate_random_discr_array(actx: ArrayContext, generator: MeshGenerator, ndiscrs: int, *, resolution: int, radius: float, bbox: ndarray | None = None, origin: ndarray | None = None, gap: float | None = None, allowed_failures: int = 100, rng: Generator | None = None) SpectralDiscretization[source]#

Constructs a random and disjoint set of discretizations in bbox.

If a bounding box bbox is not provided, one is approximated from ndiscrs, radius and gap, such that approximately ndiscrs**(1/dim) discretizations can fit in each dimension.

Parameters:
  • ndiscrs – desired number of discretizations to generate.

  • bbox – bounding box in which to generate the discretizations. The bounding box an array of shape (2, dim) and is described in terms of its closest (to \(-\infty\)) and furthest (to \(+\infty\)) corners (i.e. lower left and upper right in 2d).

  • allowed_failures – discretizations are generated randomly inside the bounding box and can overlap (based on radius). If an overlap occurs, another attempt is made. Then, allowed_failures controls how many attempts can be made before failing.

  • origin – origin of the bounding box, which is is closest point to \(-\infty\). If bbox is provided, this value is ignored.

  • radius – radius of the smallest ball that contains the unshifted geometry from generator.

  • gap – approximate gap (based on radius) between the discretization in the lattice.

  • resolution – passed on to generate_discretization().

pystopt.mesh.generate_uniform_discr_array(actx: ArrayContext, generator: MeshGenerator, shape: Tuple[int, ...], *, resolution: int, radius: float, origin: ndarray | None = None, mask: ndarray | None = None, gap: float | None = None) SpectralDiscretization[source]#

Constructs a merged uniform lattice of repeated discretizations from generator.

Parameters:
  • shape – the number of repetitions of the discretization in each dimension.

  • origin – origin (or center) of the lattice.

  • mask – an array of size np.prod(shape), which can be used to remove certain entries in the lattice.

  • radius – radius of the smallest ball that contains the unshifted geometry from generator.

  • gap – approximate gap (based on radius) between the discretization in the lattice.

Connections#

class pystopt.mesh.UniqueConnectionBatch(from_group_index: int, node_indices: ndarray)[source]#

Bases: object

nelements#
nunit_nodes#
node_indices#

An array of size (nelements, nunit_nodes) mapping the nodes in each element to a unique numbering.

from_group_index#

An integer indicating to which element group in from_discr the data should be interpolated.

class pystopt.mesh.UniqueConnectionInterpolationBatch(from_group_index: int, node_indices: ndarray, to_resampling_mat: Any, from_resampling_mat: Any)[source]#

Bases: UniqueConnectionBatch

to_resampling_mat#
from_resampling_mat#

Both to_resampling_mat and from_resampling_mat are frozen matrices used to interpolate the unit nodes in each element.

class pystopt.mesh.UniqueConnectionElementGroup(noutputs: int, batches: Tuple[UniqueConnectionBatch, ...])[source]#

Bases: object

dim#
nelements#
noutputs#

Number of unique degrees of freedom in the group.

batches#

A list of UniqueConnectionBatchs describing the transport to the unique degrees of freedom and back. It is assumed that the UniqueConnectionBatch.node_indices from the batches fill all noutputs.

class pystopt.mesh.UniqueDOFConnectionBase(*args: Any, **kwargs: Any)[source]#

Bases: DiscretizationConnection

class pystopt.mesh.ToUniqueDOFConnection(*args: Any, **kwargs: Any)[source]#

Bases: UniqueDOFConnectionBase

class pystopt.mesh.FromUniqueDOFConnection(*args: Any, **kwargs: Any)[source]#

Bases: UniqueDOFConnectionBase

pystopt.mesh.make_to_mesh_connection(actx: ArrayContext, discr: Discretization) DiscretizationConnection[source]#
pystopt.mesh.make_from_mesh_connection(actx: ArrayContext, discr: Discretization) DiscretizationConnection[source]#
pystopt.mesh.make_to_unique_mesh_vertex_connection(discr: Discretization) ToUniqueDOFConnection[source]#
pystopt.mesh.make_from_unique_mesh_vertex_connection(discr: Discretization) FromUniqueDOFConnection[source]#
pystopt.mesh.make_unique_mesh_vertex_connections(discr: Discretization) Tuple[ToUniqueDOFConnection, FromUniqueDOFConnection][source]#
pystopt.mesh.make_same_layout_connection(actx, to_discr, from_discr)[source]#

A version of make_same_mesh_connection() that only checks that the two discretizations have the same layout, not exactly the same underlying meshes.

In this case, the layout is implied by the types of the mesh element groups and the number of elements in each group.

Stabilization#

class pystopt.stabilization.PassiveStabilizerCallable(*args, **kwargs)[source]#

Bases: Protocol

A callable used by CustomPassiveStabilizer that follows the signature of make_velocity_field().

__call__(actx: ArrayContext, places: pytential.GeometryCollection, velocity: ndarray, *, dofdesc: pytential.symbolic.primitives.DOFDescriptor) ndarray[source]#

Call self as a function.

class pystopt.stabilization.PassiveStabilizer[source]#

Bases: object

Passive stabilization of a discretization / mesh is done by constructing a tangential velocity field that improves the mesh quality.

discr#
make_velocity_field(actx: ArrayContext, places: pytential.GeometryCollection, velocity: ndarray, *, dofdesc: pytential.symbolic.primitives.DOFDescriptor) ndarray[source]#

This method is called by __call__() to construct the velocity field. It is not meant to be called directly, but as a way for subclasses to provide the basic functionality.

Returns:

a velocity field on dofdesc.

__call__(places: pytential.GeometryCollection, velocity: ndarray, *, force_normalize: bool = False, scale_to_velocity: bool = False, dofdesc: pytential.symbolic.primitives.DOFDescriptorLike | None = None) ndarray[source]#
Parameters:
  • velocity – a given initial velocity field. Its tangential components can be used as an initial guess for passive stabilization.

  • force_tangential – if True, projects the velocity field obtained from make_velocity_field() to the tangent space.

  • force_normalize – if True, normalizes the velocity field obtained from make_velocity_field() in the standard \(\ell^\infty\) norm.

  • sale_to_velocity – if True scales the velocity field obtained from make_velocity_field() to have the same \(\ell^\infty\) norm as velocity.

Returns:

a tangential velocity field on dofdesc.

class pystopt.stabilization.CustomPassiveStabilizer(func: PassiveStabilizerCallable)[source]#

Bases: PassiveStabilizer

__init__(func: PassiveStabilizerCallable)[source]#
pystopt.stabilization.make_stabilizer_from_name(name: str, **kwargs: Any) PassiveStabilizer[source]#

Build passive or active stabilizers.

Parameters:
  • name – a string name for the stabilizer.

  • kwargs – a dict of arguments to pass to the constructor.

class pystopt.stabilization.Loewenberg1996Stabilizer(*, vlambda: float = 1.0, alpha: float | None = None, beta: float | None = None, gamma: float | None = None)[source]#

Bases: PassiveStabilizer

Implements the tangential forcing from [Loewenberg1996].

The tangential velocity field is given by

\[\mathbf{w}_i \triangleq N^{\gamma} \frac{1}{1 + \lambda} \sum_{j} \left\{ 1 + \alpha \frac{\|\mathbf{x}_i - \mathbf{x}_j\|}{h(\mathbf{x}_j)} + \beta \kappa_j^{\gamma} \right\} \Delta S_j (\mathbf{x}_i - \mathbf{x}_j),\]

where \(N\) is the number of vertices in the geometry, \(\lambda\) is the viscosity ratio and \(\Delta S_j\) is the dual area around the vertex \(\mathbf{x}_j\). In [Loewenberg1996], the authors take \(\gamma = 3/2, \alpha = 4\) and \(\beta = 1\).

[Loewenberg1996] (1,2)

M. Loewenberg, E. J. Hinch, Numerical Simulation of a Concentrated Emulsion in Shear Flow, Journal of Fluid Mechanics, Vol. 321, pp. 395, 1996, DOI.

alpha#
beta#
gamma#
__init__(*, vlambda: float = 1.0, alpha: float | None = None, beta: float | None = None, gamma: float | None = None) None[source]#
__call__(places: pytential.GeometryCollection, velocity: ndarray, *, force_normalize: bool = False, scale_to_velocity: bool = False, dofdesc: pytential.symbolic.primitives.DOFDescriptorLike | None = None) ndarray#
Parameters:
  • velocity – a given initial velocity field. Its tangential components can be used as an initial guess for passive stabilization.

  • force_tangential – if True, projects the velocity field obtained from make_velocity_field() to the tangent space.

  • force_normalize – if True, normalizes the velocity field obtained from make_velocity_field() in the standard \(\ell^\infty\) norm.

  • sale_to_velocity – if True scales the velocity field obtained from make_velocity_field() to have the same \(\ell^\infty\) norm as velocity.

Returns:

a tangential velocity field on dofdesc.

class pystopt.stabilization.Loewenberg2001Stabilizer(*, alpha: float | None = None)[source]#

Bases: PassiveStabilizer

Implements the tangential forcing from [loewenberg2001].

[loewenberg2001]

V. Cristini, J. Bławzdziewicz, M. Loewenberg, An Adaptive Mesh Algorithm for Evolving Surfaces: Simulations of Drop Breakup and Coalescence, Journal of Computational Physics, Vol. 168, pp. 445–463, 2001, DOI.

alpha#
__init__(*, alpha: float | None = None) None[source]#
class pystopt.stabilization.Kropinski2001Stabilizer(*, alpha: float | None = None, beta: float | None = None)[source]#

Bases: PassiveStabilizer

Implements the tangential forcing from [Kropinski2001].

The class implements a combination of the forcing \(\mathbf{T}_1\) from Equation 20, which seeks to maintain the arclength of each element, and the forcing \(\mathbf{T}_2\) from Equation 21, which seeks to cluster points in regions of higher curvature. The final forcing is

\[\mathbf{w} = \alpha \mathbf{T}_1 + \beta \mathbf{T}_2,\]

where the coefficients are given by alpha and beta.

[Kropinski2001]

M. C. A. Kropinski, An Efficient Numerical Method for Studying Interfacial Motion in Two-Dimensional Creeping Flows, Journal of Computational Physics, Vol. 171, pp. 479–508, 2001, DOI.

alpha#
beta#
__init__(*, alpha: float | None = None, beta: float | None = None) None[source]#
__call__(places: pytential.GeometryCollection, velocity: ndarray, *, force_normalize: bool = False, scale_to_velocity: bool = False, dofdesc: pytential.symbolic.primitives.DOFDescriptorLike | None = None) ndarray#
Parameters:
  • velocity – a given initial velocity field. Its tangential components can be used as an initial guess for passive stabilization.

  • force_tangential – if True, projects the velocity field obtained from make_velocity_field() to the tangent space.

  • force_normalize – if True, normalizes the velocity field obtained from make_velocity_field() in the standard \(\ell^\infty\) norm.

  • sale_to_velocity – if True scales the velocity field obtained from make_velocity_field() to have the same \(\ell^\infty\) norm as velocity.

Returns:

a tangential velocity field on dofdesc.

class pystopt.stabilization.Veerapaneni2011Stabilizer(*, optimized: bool = False, nmax: int | None = None, alpha: Callable[[ArrayContext, SpectralConnectionElementGroup], Any] | None = None)[source]#

Bases: PassiveStabilizer

Implements the tangential forcing from [Veerapaneni2011].

The forcing is given as the gradient of the functional

\[E[\mathbf{x}] = \frac{1}{2} \sum_{n, m} (1 - \alpha^m_n)^2 \langle \mathbf{x}, Y^m_n \rangle^2,\]

where \(Y^m_n\) are the spherical harmonics and \(\langle \cdot, \cdot \rangle\) is the inner product on the unit sphere. Unlike [Veerapaneni2011], we use \(1 - \alpha^m_n\), where \(\alpha^m_n\) are the coefficients of a corresponding filter operator.

[Veerapaneni2011] (1,2)

S. K. Veerapaneni, A. Rahimian, G. Biros, D. Zorin, A Fast Algorithm for Simulating Vesicle Flows in Three Dimensions, Journal of Computational Physics, Vol. 230, pp. 5610–5634, 2011, DOI.

alpha#
__init__(*, optimized: bool = False, nmax: int | None = None, alpha: Callable[[ArrayContext, SpectralConnectionElementGroup], Any] | None = None) None[source]#
Parameters:
  • nmax – maximum spherical harmonic degree. If no attenuation alpha is given, then this is used in the default ideal filter, otherwise it is ignored.

  • alpha – a callable used to obtain the attenuation factor. By default, an ideal filter in the degree \(n\) of the Spherical Harmonics is used.

class pystopt.stabilization.Zinchenko2002Stabilizer(*, alpha: float | None = None, beta: float | None = None, optim_options: Dict[str, Any] | None = None, verbose: bool = False)[source]#
class pystopt.stabilization.Zinchenko2013Stabilizer(*, alpha: float | None = None, beta: float | None = None, curvature_power: float | None = None, curvature_eps: float | None = None, optim_options: Dict[str, Any] | None = None, verbose: bool = False)[source]#