tensormesh.operator

Condenser

class Condenser(dirichlet_mask: Tensor, dirichlet_value: Tensor | None = None)[源代码]

基类:Module

Static-condensation operator for Dirichlet boundary conditions.

Partitions a global system \(K u = f\) into inner (free) DOFs and outer (Dirichlet) DOFs and condenses the prescribed values into the right-hand side:

\[K_{ii}\, u_i = f_i - K_{io}\, u_o.\]
参数:
  • dirichlet_mask (Tensor) -- 1D boolean tensor of shape \([n_{\text{dof}}]\). True marks DOFs whose value is prescribed.

  • dirichlet_value (Tensor, optional) -- 1D tensor of shape \([n_{\text{dof}}]\) (a full vector — only the entries where dirichlet_mask is True are read) or \([n_{\text{outer\_dof}}]\) (already restricted to the boundary). Defaults to all zeros.

dirichlet_mask

Boolean mask of shape \([n_{\text{dof}}]\).

Type:

Tensor

dirichlet_value

Prescribed values restricted to the boundary, shape \([n_{\text{outer\_dof}}]\).

Type:

Tensor

inner_row, inner_col

Row/column indices of the inner block \(K_{ii}\) in local inner-DOF numbering. Populated lazily on the first call.

Type:

Tensor or None

ou2in_row, ou2in_col

Row/column indices of the coupling block \(K_{io}\) in local numbering. Populated lazily.

Type:

Tensor or None

is_inner_edge, is_ou2in_edge

Boolean masks over the matrix's COO edge list selecting the \(K_{ii}\) / \(K_{io}\) entries.

Type:

Tensor or None

is_inner_dof, is_outer_dof

Boolean masks over the global DOFs.

Type:

Tensor or None

inner_shape, ou2in_shape

Shapes of \(K_{ii}\) and \(K_{io}\).

Type:

tuple of int or None

n_inner_dof, n_outer_dof, n_dof

DOF counts.

Type:

int or None

layout_hash

Sparsity-pattern hash cached from the first input matrix; used to detect a pattern change on subsequent calls.

Type:

int or None

K_ou2in

Cached \(K_{io}\) block; reused by condense_rhs().

Type:

SparseMatrix or None

备注

Condenser is a torch.nn.Module. All tensor-valued attributes (dirichlet_mask, dirichlet_value, and the lazily computed index buffers) are registered as PyTorch buffers, so condenser.to(device) / condenser.cuda() / condenser.cpu() move them together with the input system.

The first call to __call__ lazily computes the inner / outer edge masks and caches them on the instance. Subsequent calls reuse the cached layout as long as the input SparseMatrix has the same sparsity pattern (checked via matrix.layout_hash). The lazy buffers are registered with persistent=False so they are not saved into state_dict.

示例

import torch
from tensormesh import Mesh, Condenser
from tensormesh.assemble import LaplaceElementAssembler

mesh = Mesh.gen_rectangle(chara_length=0.2)
K    = LaplaceElementAssembler.from_mesh(mesh)()
f    = torch.ones(mesh.n_points, dtype=mesh.dtype)

# Homogeneous Dirichlet on the whole boundary
condenser = Condenser(mesh.boundary_mask)

# Condense: returns (K_inner, f_inner) — note this is __call__,
# NOT a separate "condense_matrix" method.
K_inner, f_inner = condenser(K, f)

# Solve the inner system and recover the full solution
u_inner = K_inner.solve(f_inner)
u       = condenser.recover(u_inner)

For time-dependent boundary data, update the prescribed values between solves via update_dirichlet(), then re-condense only the right-hand side with condense_rhs() (cheaper than rebuilding K_inner).

__init__(dirichlet_mask: Tensor, dirichlet_value: Tensor | None = None)[源代码]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

layout_signature: Tuple | None
update_dirichlet(dirichlet_value: Tensor)[源代码]

Replace the cached prescribed boundary values.

Useful for time-dependent or parameter-swept problems where only the right-hand side changes between solves; the cached \(K_{io}\) block (populated by __call__) is preserved.

参数:

dirichlet_value (Tensor) -- 1D tensor of shape \([n_{\text{dof}}]\) or \([n_{\text{outer\_dof}}]\), with the same conventions as the dirichlet_value argument to __init__().

condense_rhs(rhs: Tensor) Tensor[源代码]

Condense the right-hand side only, reusing the cached matrix layout.

\[f_i \leftarrow f_i - K_{io}\, u_o.\]

Use this after a first __call__ to re-condense f when the matrix is unchanged but the load vector changes (e.g. between time steps).

参数:

rhs (Tensor) -- Global right-hand side of shape \([n_{\text{dof}}, \ldots]\).

返回:

Condensed right-hand side of shape \([n_{\text{inner\_dof}}, \ldots]\).

返回类型:

Tensor

抛出:

AssertionError -- If __call__ has not been invoked yet: the operator has no cached \(K_{io}\) block to apply.

recover(u: Tensor) Tensor[源代码]

Recover the full-DOF solution from an inner-DOF solution.

Scatters the condensed solution u back into the free-DOF slots and writes the prescribed boundary values into the constrained slots.

参数:

u (Tensor) -- Inner-system solution of shape \([n_{\text{inner\_dof}}, \ldots]\).

返回:

Full-system solution of shape \([n_{\text{dof}}, \ldots]\).

返回类型:

Tensor

restrict(f: Tensor) Tensor[源代码]

Project a full-DOF vector down to inner DOFs.

Pure linear restriction \(f_i \leftarrow f|_{\text{inner}}\), with no Dirichlet-value correction. Use this when the right-hand side has no implicit Dirichlet contribution to subtract — for example, the per-stage right-hand side of a time-integration scheme such as tensormesh.ode.ImplicitLinearRungeKutta, where the time-derivative at a Dirichlet DOF is zero by construction and so the \(-K_{io}\,u_o\) term in condense_rhs() would over-apply the boundary correction.

Unlike Condenser.__call__ / condense_rhs(), restrict does not require the matrix layout to be cached first: it only needs dirichlet_mask.

参数:

f (Tensor) -- Full-DOF vector of shape \([n_{\text{dof}}, \ldots]\).

返回:

Inner-DOF vector of shape \([n_{\text{inner\_dof}}, \ldots]\).

返回类型:

Tensor

prolong(f_inner: Tensor) Tensor[源代码]

Lift an inner-DOF vector up to full DOF with zeros on the boundary.

Pure linear prolongation: inner entries are scattered into the free-DOF slots, constrained slots are filled with zero — not with dirichlet_value. Use this when the quantity being lifted should vanish on the boundary regardless of the prescribed Dirichlet value, e.g. the per-stage slope of a time integrator (since a fixed-value DOF has zero time-derivative).

Like restrict(), prolong only needs dirichlet_mask and does not require the matrix layout to be cached first.

参数:

f_inner (Tensor) -- Inner-DOF vector of shape \([n_{\text{inner\_dof}}, \ldots]\).

返回:

Full-DOF vector of shape \([n_{\text{dof}}, \ldots]\) with zeros in the constrained slots.

返回类型:

Tensor

BlochReducer

class BlochReducer(points: Tensor | ndarray | Sequence, lattice_vectors: Tensor | ndarray | Sequence, dofs_per_node: int = 1, tol: float | None = None, sign: int = -1)[源代码]

基类:Module

Bloch-Floquet periodic reduction of an assembled FEM operator.

参数:
  • points (array-like, shape [n_nodes, dim]) -- Nodal coordinates of the unit-cell mesh. Opposite periodic faces must carry matching nodes (e.g. a mesh built with gmsh.model.mesh.setPeriodic); a node on the +a_j face is paired with its image one lattice vector back.

  • lattice_vectors (array-like, shape [n_lat, dim]) -- The periodic lattice vectors a_j (1, 2 or 3 of them). Pass only the directions that are actually periodic — e.g. a single vector for a waveguide periodic in one direction.

  • dofs_per_node (int, optional) --

    Number of DOFs per node (1 for scalar acoustics/Helmholtz, dim for elasticity, 6 for a 3D frame). Default 1.

    The components are assumed node-major (component-interleaved): DOF d of node i lives at global index i * dofs_per_node + d, so the global vector is [n0_x, n0_y, n1_x, n1_y, ...]. This is the layout TensorMesh's vector assemblers and projector produce -- the NodeAssembler integral is returned flatten()-ed from shape [n_nodes, dofs_per_node] -- so a Bloch reduction of a vector operator assembled by LinearElasticityElementAssembler lines up with its K/M without any DOF re-ordering.

  • tol (float, optional) -- Absolute coordinate tolerance for node matching (default scales with the bounding box: 1e-7 * diag).

  • sign (int, optional) -- Sign convention of the Floquet phase exp(sign * i k·R); -1 (default) gives u(r+R) = exp(-i k·R) u(r) on the master→slave map. The eigenvalues are independent of this choice.

n_nodes, n_masters

Node counts before / after reduction.

Type:

int

n_dof, n_reduced_dof

DOF counts before / after reduction (n_* * dofs_per_node).

Type:

int

备注

Like Condenser, this is a torch.nn.Module; the pairing buffers move with .to(device). The pairing is computed once at construction (geometry only); reduce() is called per wavevector.

__init__(points: Tensor | ndarray | Sequence, lattice_vectors: Tensor | ndarray | Sequence, dofs_per_node: int = 1, tol: float | None = None, sign: int = -1)[源代码]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

reduce(matrix, k)[源代码]

Return the reduced operator T(k)^H A T(k).

参数:
  • matrix (SparseMatrix or Tensor) -- Assembled operator of shape [n_dof, n_dof] (real or complex). A SparseMatrix is reduced sparsely (COO index remap + coalesce) and returns a SparseMatrix; a dense torch.Tensor is reduced densely and returns a dense complex torch.Tensor (handy for hand-assembled systems such as a beam / truss lattice that does not go through the sparse assembler).

  • k (array-like, shape [dim]) -- Wavevector.

返回:

Reduced operator of shape [n_reduced_dof, n_reduced_dof] (complex).

返回类型:

SparseMatrix or Tensor

reduce_system(K: SparseMatrix, M: SparseMatrix, k)[源代码]

Convenience: reduce a stiffness/mass pair, (K_r, M_r).

recover(u_reduced: Tensor, k) Tensor[源代码]

Scatter a reduced-DOF field back to all DOFs with the Floquet phase.

The scatter-back counterpart of reduce(), named to mirror recover():

u_full[i] = exp(sign i k·R_i) * u_reduced[master(i)].

参数:
  • u_reduced (torch.Tensor, shape [n_reduced_dof, ...])

  • k (array-like, shape [dim])