Mondaic

salvus.mesh.algorithms.dual

salvus.mesh.algorithms.dual salvus mesh algorithms dual

Functions for constructing dual meshes from unstructured primal meshes.

Functions

construct_chord()

def construct_chord(
    facet: Facet2D | Facet3D, elm_idx: types.int_, dual: sp_sparse.sparray
) -> Chord: ...

Construct a chord from a dual mesh.

For more information on chords and their utility in 2- and 3-D, see:

Peter Murdoch, Steven Benzley, Ted Blacker, Scott A. Mitchell, The
spatial twist continuum: A connectivity based method for representing
all-hexahedral finite element meshes, Finite Elements in Analysis and
Design, Volume 28, Issue 2, 1997.
Parameters
  • facet Facet2D | Facet3D — The facet to start the chord from.
  • elm_idx types.int_ — The index of the starting element.
  • dual sp_sparse.sparray — The facet dual adjacency matrix from construct_facet_dual, in any sparse format; it is walked by element-wise indexing, so it is cast to CSR here.
Returns Chord — The chord.

construct_facet_dual()

def construct_facet_dual(
    n_dim: int, connectivity: npt.NDArray
) -> sp_sparse.coo_array: ...

Construct the facet dual connectivity from the primal mesh connectivity.

The dual mesh is constructed using element centers of the primal mesh as vertices, and connects these vertices across shared facets. This is the facet analogue of the vertex dual (construct_vertex_dual), which instead connects mesh corner nodes across shared element edges.

Parameters
  • n_dim int — The number of spatial dimensions.
  • connectivity npt.NDArray — The primal mesh connectivity array.
Returns sp_sparse.coo_array — The dual mesh connectivity as a sparse adjacency matrix. Users that need fast indexing or comparisons should cast it (e.g., with .tocsr()).

construct_vertex_dual()

def construct_vertex_dual(
    first_order_connectivity: npt.NDArray[np.int64], npoint: int, ndim: int
) -> sp_sparse.coo_array: ...

Construct the vertex dual (corner-node adjacency) of a mesh.

Two corner nodes are adjacent when they share a first-order element edge. The returned matrix is the symmetric, unit-weighted adjacency of that graph.

This is the vertex analogue of the facet dual (construct_facet_dual), which instead connects element centres across shared facets. Equivalently, the adjacency is the off-diagonal part of d1 @ d1.T, where d1 is the vertex-edge boundary operator (1-chains to 0-chains) of the mesh’s chain complex; d1 @ d1.T additionally carries each node’s degree on its diagonal.

Parameters
  • first_order_connectivity npt.NDArray[np.int64] — The element corner connectivity, shape (nelem, n_corners), with each element’s corners in counterclockwise-winding order; its edges define the adjacency.
  • npoint int — The total number of nodes the adjacency spans.
  • ndim int — The dimensionality of the mesh (2 or 3).
Returns sp_sparse.coo_array — A sparse array with shape (npoint, npoint) that has a unit entry for every pair of edge-connected nodes. Users that need fast indexing or repeated matrix products should cast it (e.g., with .tocsr()).

stack_along_chord()

def stack_along_chord(
    chord: Chord, section: npt.NDArray, n_lay_per_elm: types.int_ = 1
) -> tuple[npt.NDArray, npt.NDArray]: ...

Stack degrees of freedom (DOFs) along a mesh chord.

DOFs will be stacked along n_lay_per_elm tangent planes within each element, with the 1st layer coinciding with the element’s facet DOFs. The returned arrays are is four dimensional with shape (n_elm, 2, n_lay_per_elm, n_dof_per_fac), where:

- `n_elm` is the number of elements in the chord
- `2` corresponds to the two facets defining the chord
- `n_lay_per_elm` is the number of stacked layers per element
- `n_dof_per_fac` is the number of DOFs per facet

With respect to the ordering of the returned arrays:

- The first axis indexes elements along the chord
- The second axis indexes the entry and exit facet, respectively
- The third axis indexes layers within each element, sorted from
  the target facet inwards
- The fourth axis indexes DOFs along each facet, in tensor product
  ordering

For example, in 2-D with n_lay_per_elm = 2, the stacking order is as follows on a 2-element quad mesh, with a chord moving from element 0 to element 1:

+-----------------+
|  s(1, 1, 0, :)  |
|  s(1, 1, 1, :)  |
|                 |
|                 |
|  s(1, 0, 1, :)  |
|  s(1, 0, 0, :)  |
+-----------------+
|  s(0, 1, 0, :)  |
|  s(0, 1, 1, :)  |
|                 |
|                 |
|  s(0, 0, 1, :)  |
|  s(0, 0, 0, :)  |
+-----------------+

and each occurrence of s in the above indexes all the DOFs along a plane tangent to the closet horizontal facet.

Two arrays are returned. The first contains the local DOF indices within each element, while the second contains the corresponding global DOF indices from the provided section array. When using these arrays to index fields, the following is equivalent:

Local indexing array (loc_stack):

np.take_along_axis(
    local_field[chord.elements],
    loc_stack.reshape(chord.n_elm, -1)[..., np.newaxis],
    axis=1
)

where the trailing np.newaxis for the reshape is used to broadcast over field components (exclude this part if the field is scalar).

Global indexing array (glb_stack):

global_field[glb_stack]

where global_field is a continuous global vector defined over the mesh. In particular, the following equality holds:

np.take_along_axis(
    mesh.get_element_nodes()[chord.elements],
    loc_stack.reshape(chord.n_elm, -1)[..., np.newaxis],
    axis=1,
) == mesh.points[glb_stack].reshape(chord.n_elm, -1, mesh.ndim)
Parameters
  • chord Chord — The chord to stack along.
  • section npt.NDArray — The global -> local section (typically a mesh’s connectivity).
  • n_lay_per_elm types.int_ — The number of DOF layers within each element.
Returns tuple[npt.NDArray, npt.NDArray] — A tuple of arrays (loc_stack, glb_stack) containing the local and global stacked DOF indices, respectively.

Classes

Chord

class Chord(builtins.object):
    def __init__(
        self, n_dim: typing.Literal[2, 3], chord: npt.NDArray
    ) -> None: ...

A chord is an array of elements that are related via shared facets.

For more information on chords and their utility in 2- and 3-D, see:

Peter Murdoch, Steven Benzley, Ted Blacker, Scott A. Mitchell, The
spatial twist continuum: A connectivity based method for representing
all-hexahedral finite element meshes, Finite Elements in Analysis and
Design, Volume 28, Issue 2, 1997.
Parameters
  • n_dim typing.Literal[2, 3] — The number of spatial dimensions.
  • chord npt.NDArray — The chord as a 2-D array with each row containing and element_index and outgoing facet index pair.
Attributes
elements npt.NDArray

Get the element indices along the chord.

facets npt.NDArray

Get the facet indices along the chord.

local_facets npt.NDArray

Get the local facets along the chord.

n_elm int

Get the number of elements in the chord.

Facet2D

class Facet2D(enum.IntEnum):
    def __init__(self): ...

Facet enumeration for 2D elements.

Facet3D

class Facet3D(enum.IntEnum):
    def __init__(self): ...

Facet enumeration for 3D elements.