Skip to content

Hybrid operators and multiscale constructions

Field queries can supply explicit cell owners for independent one-sided values. This evaluates only the requested point/cell pairs. TrianglePointLocator provides reusable geometric searches for planar triangular fields.

User-defined variational equations, local condensation, recursive reconstruction and distinct multiscale formulations. The variational guide describes the four blocks, global additions and current compilation limits.

All API families

Mesh, interface and variational contexts

Portable interface layouts and transport of user-defined variational blocks.

An interface binding maps selected global coefficients into the declared local trial/test trace bases. Test functionals travel through the transpose map. The maps may encode signs, permutations or dense basis changes; they never select a physical coupling sign. Numerical condensation remains owned by equations.

TraceBinding dataclass

Independent trial/test embeddings into a square global interface layout.

trial_map @ global[dofs] gives local trial trace coefficients, and test_map @ global[test_dofs] gives local test coefficients. Each map has one column per selected global coordinate. Rectangular and rank-deficient maps permit projections/restrictions; require_injective=True requests an injectivity check when the formulation needs it. Omitted maps are identities; omitted test coordinates/maps reuse the trial binding. basis_id names the executed local basis supplied by an adapter. Its identity, maps and selected coordinates enter basis_digest together. The digest identifies declared representation data, not PDE consistency.

trial_size: int property

Return the local trial basis width before transport.

test_size: int property

Return the local test basis width before transport.

__post_init__() -> None

Freeze owned coordinate maps and validate independent basis transports.

__reduce__() -> tuple[Any, tuple[Any, ...]]

Preserve immutable coefficient maps and basis identity across spawn/replay.

InterfaceSpace

Bases: Protocol

Describe global interface coordinates without requiring inheritance.

A custom implementation owns its basis convention and local support. It can use arbitrary numbering and dense changes of trace basis. Geometry, basis evaluation and native form binding are separate optional capabilities.

size: int property

Return the complete global interface coefficient dimension.

binding(cell: int) -> TraceBinding

Return independent trace maps for the selected macrocell.

ComponentTraceSpace dataclass

Interleave scalar trace coordinates for a declared vector-valued interface.

base owns the scalar basis, geometry and any continuity constraints. Coordinate components*i+j is component j of scalar coordinate i. This wrapper shares exactly the same vertices/edges as the base and introduces no normal or tangential rotation. Use bind_interface to declare value or canonical-normal transport, or TraceBinding for a different frame.

mesh: Any property

Return the unchanged scalar interface's macro mesh.

size: int property

Return the component-interleaved global coefficient dimension.

__post_init__() -> None

Validate a scalar mesh-associated layout without loading a FEM backend.

dofs(face: int) -> np.ndarray

Return one face's vector coefficients, including any shared scalar nodes.

cell_dofs(cell: int) -> np.ndarray

Preserve the scalar cell-coordinate order with interleaved components.

BoundInterface dataclass

Adapt an existing face space to the structural interface-space contract.

convention='value' preserves scalar/vector face values. 'normal' transports coefficients expressed in canonical face normals to outward macrocell normals, reusing the mesh's existing incidence signs. The adapter never infers a physical sign in B or C. Existing operators that already include orientation must use coordinates='global' when bound.

mesh: Any property

Return the macro mesh associated with the underlying trace basis.

size: int property

Return the complete scalar/component-interleaved interface dimension.

__post_init__() -> None

Require a mesh-associated trace layout and a supported convention.

binding(cell: int) -> TraceBinding

Derive local coefficient transport from the existing topology owner.

MeshHierarchy dataclass

Associate macro cells with worker-created local meshes.

local_meshes is a callable cell -> mesh or one portable mesh per macrocell. The callable runs only when a local context requests its mesh, so native objects can remain worker-owned. items selects macrocell indices and their deterministic assembly order; its default selects all. Native objects, factories and meshes retain their documented execution requirements: process execution needs picklable portable descriptions.

__init__(macro: Any, local_meshes: Callable[[int], Any] | Sequence[Any], items: Sequence[int] | None = None) -> None

Check topology association without eagerly constructing local meshes.

local_mesh(cell: int) -> Any

Construct or retrieve a local mesh belonging to this hierarchy.

validate_trace_binding(binding: TraceBinding, size: int) -> TraceBinding

Reject stale or out-of-range layouts before assembling local equations.

bind_interface(space: Any, *, convention: Literal['value', 'normal'] = 'value') -> BoundInterface

Bind a built-in face space using its declared value or normal convention.

Custom spaces implement InterfaceSpace directly and return their own TraceBinding; no inheritance, registry or native FEM dependency is needed. Tangential/component rotations require an explicitly declared custom map.

bind_local_equations(binding: TraceBinding, *, a: Any, L: Any, b: Any, c: Any, d: Any = 0, g: Any = 0, kernel: Any = None, moments: Any = None, coarse_basis: Any = None, left_kernel: Any = None, test_basis: Any = None, test_moments: Any = None, metadata: Any = None, coordinates: Literal['local', 'global'] = 'local', compiler: FormCompiler = compile_form) -> LocalEquations

Transport trace pairings independently before the existing condensation.

For maps R and S, local blocks become B R, S.T C, S.T D R and S.T g. Local volume coefficients, retained modes and their moment functionals are unchanged. coordinates='global' declares that supplied pairings already use selected global coefficients and skips this transport, preventing double orientation for existing signed coupling owners. Native forms compile in their own local integration spaces through compiler.

Mesh-associated variational contexts lowering to the existing hybrid algebra.

Mathematical signs, spaces, modes and gauges are declarations. Contexts own their coordinate binding; condensation, reduction and solving keep their current owners.

GlobalContext dataclass

Bound interface and declared retained coordinates for global forms.

Coordinates are interface first, then retained modes in hierarchy item order. The counts describe user-declared physical modes; no local PDE is solved or nullspace guessed to determine this layout. Physical load signs remain explicit.

trace_size: int property

Return the number of declared global interface coordinates.

size: int property

Return the square global dimension, including declared retained modes.

__post_init__() -> None

Freeze declared dimensions independently of a mutable custom provider.

trace_load(value: Any) -> FloatArray

Embed an interface functional, leaving retained compatibility loads zero.

interface_equation(forms: Callable[[Any, Any, Any], Any]) -> Equation

Assemble user-written global interface UFL forms in the bound coordinates.

forms(trial, test, measure) returns Equation or its (a, L) pair. The built-in adapter integrates supported edge/triangle polynomial spaces; custom spaces may declare the same capability. Retained-mode rows and columns are padded by zero, without inventing a coupling or boundary sign.

retained_dofs(cell: int) -> np.ndarray

Expose a cell's retained coordinates for explicitly assembled global forms.

boundary_data(value: Any, neumann: Mapping[int, Any] | None = None, *, order: int = 6) -> tuple[FloatArray, dict[int, float]]

Integrate weak value data and project fixed normal-density coefficients.

This returns an unsigned interface functional and fixed coefficients; callers choose its sign in their global equation. Custom spaces may implement their own boundary_data(value, neumann, order=...) capability. No Dirichlet/Neumann role is inferred from a local differential operator.

fix_faces(faces: Any, value: float = 0.0) -> dict[int, float]

Prescribe a constant face value in a declared built-in scalar/vector basis.

This prescribes the interface variable itself, without interpreting a PDE boundary condition. Nonconstant or custom data use a declared projection.

LocalContext dataclass

One worker-owned macrocell's mesh, spaces and trace coordinate binding.

Local native spaces are created lazily. The context itself never travels back to the coordinator; equation metadata must contain portable evaluation data. Custom local solvers may use only mesh/binding and assembled numerical blocks.

mesh: Any property

Return the lazily constructed portable local mesh.

macro: Any property

Return the hierarchy's macro mesh for declared material/geometry data.

binding: TraceBinding property

Return this context's single executed coefficient-map snapshot.

__post_init__() -> None

Check selected entity and trace association without creating native objects.

native_space(element: Any = None, *, degree: int = 1, shape: tuple[int, ...] = ()) -> Any

Bind a user element, or equispaced Lagrange default, to this local mesh.

Native optional libraries load only on this call. Returned NativeSpace exposes its FunctionSpace and coordinate conversions for advanced use. Its resources belong to this context and are released by close().

trace_pairings(expression: Callable[[Any, Any], Any], *, axis: Literal['columns', 'rows'] = 'columns', interface: InterfaceSpace | None = None) -> Any

Bind a user-written boundary form to each supported local trace basis.

expression(trace_value, face_measure) returns its UFL linear form. The trace value has the declared scalar/vector shape; geometry orientation is applied once by equations(), not hidden in the expression. Built-in edge and triangular polynomial traces have a native adapter; custom spaces may supply a trace_pairings(context, expression, axis=...) capability explicitly. interface selects an independent local boundary basis when a formulation has local trace unknowns as well as its global interface. Returned forms use unsigned local basis coordinates; equations() transports only the primary global pairings, while local operator blocks retain their basis.

interface_pairing(test_interface: InterfaceSpace, *, order: int = 6) -> FloatArray

Pair an independent local boundary basis with the primary interface basis.

The built-in operation is the unsigned L2 boundary mass matrix, with local test coordinates in rows and local primary trial coordinates in columns. Face numbering, union partitions and shared-vertex accumulation belong to the trace owner. Users choose its signs and block placement. A custom test interface may define interface_pairing(context, order=...). Primary global maps are applied later by equations(), exactly once.

equations(*, coordinates: Literal['local', 'global'] = 'local', **forms: Any) -> LocalEquations

Bind declared forms without exposing global DOF numbering to the provider.

Local trace coordinates are transported through the interface maps. coordinates='global' explicitly retains already oriented existing blocks. No coupling transpose, retained mode, moment or physical sign is inferred.

field(name: str, space: Any = None, *, component: int | None = None, evaluator: Callable[..., Any] | None = None, gradient_evaluator: Callable[..., Any] | None = None, reconstruction: Any = None, trace_reconstruction: Any = None, trace_dofs: Any = None, offset: Any = None, mesh: Any = None, basis_id: str = '') -> None

Declare a named native or custom field without transferring live resources.

space is an optional NativeSpace; component selects a mixed subfield. Custom fields provide an evaluator and basis_id, or expose coefficients only. reconstruction maps the local solution into field data. The optional trace_reconstruction maps global trace[trace_dofs]; offset supplies an explicit affine lifting, for example essential boundary data.

nested(problem: MultiscaleProblem[Any], *, boundary_dofs: Any = None, trace_map: Any = None, **options: Any) -> NestedEquations

Bind a child problem to the parent interface through an exact restriction.

Automatic restriction reuses the existing planar normal-trace owner for bound SkeletonSpaces. Supplied boundary_dofs/trace_map declare a complete map from selected parent GLOBAL coefficients into child boundary trace coefficients; it is not oriented again. Child boundary/gauge, injectivity and parallel restrictions remain those of NestedEquations. No projection of an unrepresentable parent trace is silently introduced.

close() -> None

Release native spaces while retaining independently owned numerical data.

__enter__() -> LocalContext

Own native resources during a manually requested local context.

__exit__(exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> None

Release spaces on every exit; bound providers already manage this lifetime.

BoundProblem dataclass

Bases: MultiscaleProblem[int]

An existing multiscale problem with mesh-associated variational contexts.

local_context(cell: int) -> LocalContext

Create an explicit context for diagnostics or a manual provider invocation.

The caller owns this context and must close any native resources it creates. Normal assemble/solve calls manage that lifetime automatically in workers.

bind_problem(hierarchy: MeshHierarchy, interface: InterfaceSpace, local_provider: Callable[[LocalContext], Any], *, global_equation: Equation | Callable[[GlobalContext], Equation] = _EMPTY_EQUATION, retained: int | tuple[int, ...] = 0, fixed: Mapping[int, float] | Callable[[GlobalContext], Mapping[int, float]] | None = None, constraints: tuple[tuple[FloatArray, float], ...] = (), compiler: FormCompiler = compile_form) -> BoundProblem

Bind meshes/spaces and user forms to the existing assemble/solve pipeline.

retained declares the number of retained modes per selected cell; a scalar count repeats it, while a tuple follows hierarchy item order. The provider receives LocalContext rather than an integer. A global callback can use the declared layout to express additional interface/retained terms. Fully manual MultiscaleProblem and custom InterfaceSpace implementations remain available.

Named field views carrying the executed coefficient and evaluation contract.

FieldDefinition dataclass

Portable description of one physical field reconstructed from a local vector.

A native nodal descriptor stores its executed basis/map. A custom evaluator has signature evaluator(mesh, coefficients, points, , cells=None); its declared basis_id identifies the coordinate convention. reconstruction maps local coefficients to the evaluator's coefficients. Without an evaluator or descriptor, the field supports coefficient access but no spatial evaluation. The reconstructed coefficients are Rlocal + T*global_trace[trace_dofs] + offset. Every trace orientation and basis change is explicit in T; no incident normal sign or local binding is inferred. All maps and the affine offset form part of the archived coefficient and basis-digest contract.

basis_matrix: FloatArray property

Return an owned read-only copy of a declared single polynomial matrix.

Nodal/native and modal evaluators declare this coordinate matrix. A custom or composite Piola basis may require several matrices and then raises TypeError. Archive this entire definition with its digest to retain cell maps, orientation and reconstruction as well as the matrix.

basis_digest: str property

Identify the executed descriptor and any additional reconstruction map.

__post_init__() -> None

Own a reconstruction map and reject ambiguous evaluation conventions.

__reduce__() -> tuple[Any, tuple[Any, ...]]

Restore an owned immutable reconstruction through the validating constructor.

DiscreteField dataclass

One reconstructed field associated with its mesh and executed basis.

Coefficients are independently owned and read-only. Separate macrocell fields preserve one-sided interface values; evaluation does not average or smooth.

mesh: Any property

Return the declared physical mesh, without constructing native resources.

basis_digest: str property

Return the field's executed basis/reconstruction identity.

portable_coefficients: FloatArray property

Delegate coefficient access in the descriptor's recorded portable order.

__post_init__() -> None

Freeze the reconstructed field's finite real coefficients.

__reduce__() -> tuple[Any, tuple[Any, ...]]

Restore immutable coefficients through the same checked field constructor.

evaluate(points: Any, *, cells: Any = None) -> FloatArray

Delegate spatial evaluation with optional explicit one-sided cell owners.

gradient(points: Any, *, cells: Any = None) -> FloatArray

Delegate physical gradients, retaining explicit one-sided cell owners.

values_and_gradient(points: Any, *, cells: Any = None) -> tuple[FloatArray, FloatArray]

Delegate values and physical gradients with a shared native sampling pass.

evaluate_field(field: DiscreteField, points: Any, *, cells: Any = None) -> FloatArray

Evaluate a declared native or custom field; reject absent capabilities.

evaluate_field_gradient(field: DiscreteField, points: Any, *, cells: Any = None) -> FloatArray

Evaluate physical derivatives in the executed native or custom field basis.

Scalar gradients have axes (point, coordinate); vector gradients use (point, component, coordinate). These are raw derivatives, not a conservative H(div) flux reconstruction. Custom fields declare gradient_evaluator with the same arguments as their value evaluator; absent capabilities fail.

portable_field_coefficients(field: DiscreteField) -> FloatArray

Return coefficients through the executed descriptor's portable coordinate map.

The result is independently owned and read-only, with mixed components selected by their stored map. This only changes ordering; it does not regenerate the basis or discard its digest. These are nodal values when the executed basis is the corresponding nodal basis. A custom field without this declared map has no automatic portable coefficient conversion.

evaluate_field_and_gradient(field: DiscreteField, points: Any, *, cells: Any = None) -> tuple[FloatArray, FloatArray]

Sample values and raw physical derivatives without duplicate native geometry.

Native descriptors share cell location, geometry pullback and executed basis tabulation. Custom fields delegate to their independent value and gradient callbacks. Output axes and one-sided conventions match evaluate_field and evaluate_field_gradient; this does not construct a conservative flux.

solution_field(solution: Any, name: str, *, recursive: bool = False) -> tuple[DiscreteField, ...]

Recover named fields in deterministic macrocell order.

With recursive=True, a cell without its own definition delegates to its recovered child solution. Cells declaring the field are visited once; their children are not also returned. Each reconstruction uses its own level's trace vector, retaining one-sided values and executed orientations.

local_trace(solution: Any, index: int, *, test: bool = False) -> FloatArray

Recover selected global coefficients in their executed local trace basis.

index is a position in deterministic assembly item order, like solution.fields. The trial map is used by default; test=True uses the independent test map. Both maps already declare geometric orientation and basis changes. This operation does not infer a physical boundary sign or average adjacent fields. Explicit equations without a stored binding have no local-trace capability.

Validated one-sided ownership for large physical point samples on triangular meshes.

TrianglePointLocator

Locate points through centroid candidates and actual barycentric containment.

Candidates are a search acceleration, never a nearest-cell interpolation. A vectorized search tests candidates nearest centroids; unresolved points use all cells, including skew or strongly graded meshes. Among valid candidates the first cKDTree result is chosen. Shared interfaces therefore select one incident side deterministically for the same mesh and query; coordinates(..., cells=...) selects an explicit independent side. Containment uses physical orientation predicates with the declared nonnegative, dimensionless barycentric tolerance. Roundoff-ambiguous signs are resolved exactly for the represented binary coordinates; zero tolerance therefore retains vertices and edges while excluding points strictly outside. Coordinates are neither moved nor averaged. Returned barycentric coordinates retain their original binary64 affine tabulation and can have roundoff-size negative entries at a geometrically valid edge. A conservative mesh bounding box excludes strictly exterior points, and bounded batches keep exhaustive fallback storage independent of query size.

__init__(mesh: TriangleMesh, *, candidates: int = 4, tolerance: float = 1e-10) -> None

Cache the actual affine maps; validate the geometric query convention.

locate(points: Any, *, allow_outside: bool = False) -> IntArray

Return one cell per point, optionally marking exterior points with -1.

By default every point must lie in the mesh within the declared barycentric tolerance. allow_outside=True preserves the query order and returns -1 only for points outside every triangle; this supports masks when sampling independent subdomains. Exterior indices must be filtered before evaluating a cell field.

coordinates(points: Any, *, cells: Any = None) -> tuple[IntArray, FloatArray]

Return owners and barycentric triples, optionally preserving declared incident sides.

Portable named nodal fields using the recorded polynomial basis and topology.

Evaluation uses archived Basix coefficient matrices directly. Mesh interfaces keep independent one-sided values through an optional explicit cell owner.

nodal_field(name: str, mesh: TriangleMesh | TetraMesh | CartesianMacroMesh, degree: int, *, components: int = 1, discontinuous: bool = False, reconstruction: Any = None, trace_reconstruction: Any = None, trace_dofs: Any = None, offset: Any = None) -> FieldDefinition

Declare a scalar/vector Pk/Qk field with portable evaluation and gradients.

Components are interleaved at each node. Continuous simplex coordinates use the package's topological nodal order; DG coordinates concatenate that local order by cell, with degree zero representing one cell value. Cartesian Qk coordinates use x-fastest nodes and the actual archived interval factors used by Qk assembly; no independent tensor basis is regenerated. reconstruction maps the user's complete local unknown vector into this field's coordinates, including block selection and scaling. The executed basis matrix and DOF map are retained by the picklable evaluators and identified by basis_id.

Broken scalar/vector polynomial fields in explicitly ordered modal coordinates.

modal_field(name: str, mesh: Any, powers: tuple[tuple[int, ...], ...], *, convention: str = 'monomial', components: int = 1, reconstruction: Any = None) -> FieldDefinition

Declare cellwise polynomial coefficients with an explicit exponent order.

monomial uses reference coordinate powers. legendre uses conventional L_j(2*x-1), normalized to one at x=1, independently in each direction. This covers complete simplex, tensor Qk and restricted complete tensor Pk spaces through the supplied multiindices. Coefficients interleave physical components within a polynomial, then concatenate cells. The actual interval coordinate matrix is archived and reused for evaluation and physical gradients.

Portable physical Piola fields with literal executed polynomial and moment matrices.

ReferenceVectorBasis dataclass

Executed reference values/divergence before orientation and physical Piola.

Native mode archives Basix's coefficient_matrix and the actual moment map. Monomial mode archives explicitly ordered component powers and the actual moment matrix. Tensor Bernstein mode additionally retains its executed triangle and interval matrices for each vector component. Evaluation never recomputes a dual basis or arbitrarily oriented nullspace.

digest: str property

Identify every executed polynomial/moment matrix and its coordinate convention.

__post_init__() -> None

Archive literal arrays through construction and pickle reconstruction.

__reduce__() -> Any

Replay archived arrays instead of native interpolation and moment solves.

__call__(points: FloatArray) -> tuple[FloatArray, FloatArray]

Return (q,basis,reference_component) values and (q,basis) divergence.

piola_field(name: str, mesh: Any, *, reference_basis: ReferenceVectorBasis, dofs: Any, orientation: Any, components: int = 1, reconstruction: Any = None, divergence: bool = False, trace_reconstruction: Any = None, trace_dofs: Any = None, offset: Any = None) -> FieldDefinition

Declare a physical vector/tensor from explicitly supplied moment and Piola maps.

The reference basis, global DOF map and per-cell orientation matrix are independent mathematical inputs. Components interleave per scalar H(div) DOF; one component returns a physical vector, d components row-wise tensor. divergence=True declares its scalar/vector divergence using the very same archived basis and maps. No continuity or physical PDE is inferred from successful algebraic evaluation. Names such as flux/stress are caller data.

hdiv_field(name: str, mesh: Any, family: Any = 'RT', *, degree: int = 0, enrichment: int = 0, components: int = 1, reconstruction: Any = None, divergence: bool = False) -> FieldDefinition

Declare a built-in moment H(div) field in its actual executed coordinate basis.

family is BDMFamily, HDiv3DFamily, or 'RT', 'tensor-RT', 'mapped-RT'. Family-specific degree conventions remain those of their volume owners. Literal native/moment/orientation matrices are archived once, and replay uses them for both physical evaluation and divergence. Pressure and broken kinematic polynomial fields have separate scalar/nodal definitions.

Physical trace integration and projection independent of a PDE or hybrid method.

trace_quadrature(space: Any, face: int, *, order: int = 6) -> tuple[IntArray, FloatArray, FloatArray, FloatArray]

Return face coordinates, physical points/weights and the executed value basis.

Shapes are (n,), (q,dimension), (q,), (q,n,value_components). Basis values use canonical face coordinates; no incidence sign is inserted. The order floor integrates each polynomial Gram matrix exactly. Nonpolynomial data can require a larger order. Scalar edge/triangle, Cartesian-component and tangential wrappers retain their basis owner's coefficients and continuity. A custom space may implement trace_quadrature(face, order=...) with this same contract, including vector or tensor values flattened by component.

trace_linear_form(space: Any, value: Any, *, faces: Iterable[int] | None = None, order: int = 6) -> FloatArray

Assemble integral(value dot test) in the declared global trace basis.

value is a scalar/vector constant or a callable evaluated at physical points with output (q,value_components). A scalar constant broadcasts to every component; scalar fields may return (q,). Signs and selected physical boundaries are caller choices. Shared coordinates accumulate contributions.

trace_bilinear_form(space: Any, coefficient: Any = 1.0, *, faces: Iterable[int] | None = None, order: int = 6) -> Any

Assemble integral(test dot coefficient trial) as a sparse trace operator.

A scalar coefficient gives an isotropic scalar/vector pairing. A constant or physical-point callable may instead supply a matrix in value components, with shape (m,m) or (q,m,m). This supports mass, reaction, Robin, impedance and tensor pairings without choosing a physical boundary convention.

project_trace(space: Any, value: Any, *, faces: Iterable[int] | None = None, order: int = 6) -> dict[int, float]

L2-project physical values onto selected trace coefficients with shared nodes.

Solve the executed Gram matrix on exactly the union of selected face DOFs. The returned coefficient map can prescribe interface values in any problem. Normal densities, Robin pseudo-tractions and physical scalar/vector traces remain distinct choices of the user-supplied value and space.

trace_boundary_data(space: Any, value: Any, prescribed: Mapping[int, Any] | None = None, *, order: int = 6) -> tuple[FloatArray, dict[int, float]]

Integrate exterior value data and project explicitly prescribed trace data.

Faces in prescribed supply fixed trace coefficients; every other exterior face supplies the unsigned functional integral(value dot test). No PDE, outward sign or physical variable is inferred. Projection is joint across prescribed faces when their coefficient coordinates are shared. Face-dependent prescribed functions use physical scalar/vector values in the owner's actual basis. Interior faces cannot be prescribed here.

Unsigned physical pairings between independently declared trace spaces.

evaluate_trace_basis(space: Any, face: int, points: FloatArray) -> tuple[IntArray, FloatArray]

Evaluate literal face coordinates as physical scalar/vector basis values.

Return shapes (n,) and (q,n,components), with no incidence normal sign. Cartesian-component and tangential wrappers retain their physical frame. Custom owners may supply trace_evaluation(face, points) with this contract. Points are physical; independently subdivided basis owners locate their own pieces. No projection, common-node identification or continuity is inferred.

interface_pairing(test_space: Any, trial_space: Any, cell: int, *, order: int = 6) -> FloatArray

Integrate unsigned test dot trial on a macrocell's complete boundary.

Rows and columns follow each owner's literal cell_dofs(cell). Edge integration uses the union of independent breakpoints. Built-in triangular partitions must be nested, including explicitly declared nonuniform refinements. Their containment is checked before the finer owner supplies the common rule. Nonnested 3D partitions require a custom common_trace_quadrature(other,face,order) owner returning physical points/weights resolving both bases. Physical components are contracted explicitly. Outward signs, coefficients and PDE choices are caller data; this same mass pairing supports diffusion, elasticity and curl traces.

Scalar boundary quadrature and assembly independent of a physical formulation.

The rules expose physical points, positive surface weights, outward normals and an executed basis/map. Coefficients may depend on points and normals, allowing Robin, impedance, reaction and weighted boundary mass terms to use one owner.

BoundaryRule dataclass

One physical facet rule in the supplied scalar coefficient convention.

basis has axes (point, local_dof), dofs selects the global local-field coordinates, and normal points out of the domain whose boundary is integrated. A caller can also supply rules for a different mesh or basis.

boundary_quadrature(mesh: TriangleMesh | TetraMesh | CartesianMacroMesh, degree: int, *, order: int = 6) -> tuple[int, tuple[BoundaryRule, ...]]

Tabulate an exterior scalar Pk/Qk nodal boundary with positive physical weights.

order counts one-dimensional Gauss points, with the degree+1 floor for exact polynomial mass integration. Only exterior facets are returned. Mesh normals use their canonical outward boundary orientation. The returned size is the complete field dimension, including nodes with zero boundary trace.

boundary_bilinear(size: int, rules: tuple[BoundaryRule, ...], coefficient: Any = 1.0) -> sparse.csc_matrix

Assemble integral_boundary coefficient*u*v in explicitly supplied coordinates.

A callback has signature coefficient(points, outward_normal) and returns scalar point values. Negative coefficients are allowed. Rules can represent a selected boundary subset or a custom basis; they define all geometry and orientation. No essential condition, PDE or solver is selected.

boundary_functional(size: int, rules: tuple[BoundaryRule, ...], datum: Any = 0.0) -> FloatArray

Assemble integral_boundary datum*v with the same coordinate/quadrature contract.

A callback has signature datum(points, outward_normal). This operation interprets neither the data as a physical flux nor its sign in an equation; both conventions belong to the formulation written by the user.

Physical normal and representation checks for explicitly declared trace fields.

normal_component_zero(samples: Any, normal: Any, *, rtol: float = 64 * np.finfo(float).eps, pointwise: bool = False) -> bool

Check sampled normal components against their declared cancellation scale.

samples has shape (points, dimension), and normal has shape (dimension,). The comparison is abs(samples @ normal) <= rtol * scale. The scale is the maximum uncancelled absolute dot product, or its value at each point when pointwise=True. No absolute amplitude floor is added. This algebraic check does not certify a callback between sampling points.

boundary_tangent_2d(space: SkeletonSpace, vector: Any, order: int = 8, faces: Iterable[int] | None = None) -> bool

Check sampled tangency on each declared edge partition in two dimensions.

The owner's partition quadrature uses order at least eight. Each face uses the maximum uncancelled dot-product scale and relative tolerance 64*eps, without an absolute amplitude floor. This is a sampled compatibility check for a constant local kernel, not a continuum certificate for a callback.

boundary_tangent_3d(space: TriangularSkeleton | PolygonalSkeleton3D, vector: Any, order: int = 8, *, faces: Iterable[int] | None = None) -> bool

Check tangency on the canonical triangulation of original 3D faces.

Triangular faces use one positive rule of order at least eight. Polygonal faces integrate through their geometry owner's triangles. Physical points use anchored affine evaluation to preserve coordinates constant on a face. Each face uses normal_component_zero with its maximum uncancelled scale and relative tolerance 64 * eps. This preserves the declared sampled compatibility convention; no unsampled continuum condition is certified.

boundary_normal_zero(space: Any, vector: Any, *, order: int = 8, faces: Iterable[int] | None = None) -> bool

Check sampled vector dot normal zero relative to its uncancelled terms.

Exterior face normals are the mesh's canonical outward normals. Quadrature resolves declared trace partitions. This is a floating-point compatibility check, not a certified continuum tangency statement for arbitrary callbacks. Exact zero data remain zero without absolute amplitude thresholds.

trace_represents(space: Any, face: int, value: Any, *, order: int = 8) -> bool

Check a scalar/vector field belongs to the declared trace at integration nodes.

A weighted least-squares solve uses the literal physical value basis and positive quadrature, avoiding a squared Gram condition number. Unresolved basis rank returns false. Residuals are checked relative to uncancelled input and projected magnitudes. The declaration does not certify unsampled values. This operation is independent of a PDE, material, gauge and solver family.

Explicit equations and shared hierarchy

User-defined local and global variational blocks, independent of a physical model.

Rows are test coordinates and columns are trial coordinates. The two equations are A u + B lambda = f and C u + D lambda = g. In particular, the sign of C is declared by the user rather than inferred from a method or equation. UFL forms are assembled by an optional native adapter; arrays are already assembled forms. Neither representation selects a PDE or a stabilization.

Equation dataclass

A bilinear form a and linear right-hand side L in declared coordinates.

A literal zero denotes a zero form with dimensions supplied by the problem. A UFL form keeps its trial/test spaces, mesh, coefficients and quadrature. An array or sparse matrix denotes an already assembled form. Global forms act on trace coordinates followed by the ordered retained cell coordinates.

LinearForms dataclass

Linear forms representing columns B or rows C in an explicit trace basis.

Every entry represents one trace basis function, including its orientation and physical units. An empty sequence requires the problem's dimensions. This representation avoids requiring cross-mesh UFL assembly: each linear form lives on its local integration mesh. It also accepts numerical vectors.

__post_init__() -> None

Freeze the sequence and reject an ambiguous pairing direction.

FormCompiler

Bases: Protocol

Assemble a real rank-one or rank-two form without changing its coordinates.

__call__(form: Any, shape: tuple[int, ...] | None = None) -> Any

Return an owned coefficient array or sparse operator of the declared shape.

LocalEquations dataclass

Define both local equations and their contribution to the global balance.

a, L, b express a(u,v)+b(lambda,v)=L(v). c, d, g express c(u,mu)+d(lambda,mu)=g(mu). dofs and test_dofs map the local trial/test trace bases to the global coordinates. They can differ in order and length. Basis functions include normal orientation; their signs are not inferred. moments and test_moments are column pairings with explicit retained trial/test modes. No kernel is discovered automatically and no stability or consistency theorem is implied.

Scalar, vector and mixed unknowns use this same contract. A method with several local fields can use a mixed UFL space or a block matrix. Native objects must remain worker-owned, with optional reuse between provider invocations and explicit close() cleanup at worker shutdown, when using spawn workers; metadata must then contain only picklable data. A 0-by-0 a declares no eliminated local coordinates: d and g then contribute the complete face equation without a local factorization.

__post_init__() -> None

Freeze explicit maps without assembling forms or inspecting native spaces.

CompiledLocalEquations dataclass

Numerical local contract and its uncondensed direct global terms.

The signed balance C is stored as test_coupling=-C.T in the shared condensation owner. matrix and load are D and g in the union trace numbering, and are added once during ordered global reduction.

columns(*forms: Any) -> LinearForms

Declare one local linear form for each global trial coordinate.

rows(*forms: Any) -> LinearForms

Declare one local linear form for each global test coordinate.

compile_form(form: Any, shape: tuple[int, ...] | None = None) -> Any

Assemble arrays, linear pairings or native UFL without importing unused FEM.

Sparse matrices remain sparse. Literal bilinear zeros use CSC storage; literal linear zeros use dense vectors. Finite wider real array precision is retained. A nonzero scalar is not silently broadcast to a vector or operator. UFL assembly currently requires a real serial DOLFINx mesh. Other backends can supply a callable compiler with this same form/shape contract.

compile_local_equations(equations: LocalEquations, compiler: FormCompiler = compile_form) -> CompiledLocalEquations

Compile four variational blocks and reuse the checked local condensation contract.

Trial and test trace maps embed into their ordered union. This permits rectangular B/C/D pairings while the complete global problem remains square. Retained compatibility equations preserve their explicit test basis and physical moments. Already assembled matrices do not pass through UFL.

Assembly, solution and recursive reconstruction of user-defined hybrid equations.

All numerical elimination delegates to the common constrained condensation and ordered contribution owners. A recursive local operator is itself another MultiscaleProblem; the same contracts apply at every scale. No physical model or method name selects the operator.

MultiscaleProblem dataclass

Bases: Generic[Item]

A global variational equation coupled to independently declared local equations.

global_equation supplies additional bilinear and linear global forms; each local provider supplies its own explicit C u + D lambda = g balance. Global coordinates are trace first, then each cell's retained modes in item order. coarse_sizes declares those counts, including zero. A global form can contain facet terms between different cells, Robin terms or other user-defined couplings. Its full reduced dimensions must match.

The provider runs once per item, inside the selected worker, and returns LocalEquations or a compiled equation record. Scalar/vector/mixed fields and recursive local operators share this API. Boundary coefficients and physical gauge rows are explicit; the package does not choose them from a PDE name.

__post_init__() -> None

Validate coordinates and form/compiler contracts without consuming the items.

from_global(equation: Equation, size: int, *, fixed: Mapping[int, float] | None = None, constraints: tuple[tuple[FloatArray, float], ...] = (), compiler: FormCompiler = compile_form) -> MultiscaleProblem[Any] classmethod

Declare a global equation with no local fields or condensation.

All size coordinates belong to the stated global trial/test basis. Essential coefficient values and physical integral constraints retain the ordinary solve contract. This supports classical reference forms or any explicitly assembled global operator through the same API.

NestedEquations dataclass

Declare a child hybrid problem with a parent boundary-trace constraint.

If the child's reduced equation is A x=f, E selects its boundary trace coordinates and M is trace_map, the local equations are -A x + E mu=-f and E.T x-M lambda=0. The global pairing is +M.T mu in the declared DSL balance C. The original physical moment is -M.T mu; negating that equation matches the shared reduced saddle convention. The local field contains child coordinates followed by boundary reactions. This is a generic equality-constrained operator, independent of a physical PDE. Explicit kernel/left_kernel are in child coordinates; their boundary reactions are lifted by the shared nesting owner.

Children leave boundary data and physical gauges to their parent. Supplied moments have one row per child coordinate and are extended by zero reaction weights. M includes every restriction and orientation; it is not inferred.

MultiscaleSolution dataclass

Bases: HybridSolution

Hybrid coefficients and recursively recovered child solutions.

children[cell] is None for a leaf local discretization. Otherwise its coordinates are exactly that cell's reconstructed field; its own fields and children recover the finer scales without another global solve.

field(name: str, *, recursive: bool = False) -> Any

Recover named views; recursive=True descends into undeclared child cells.

local_trace(index: int, *, test: bool = False) -> FloatArray

Delegate trace recovery in the executed local basis, in assembly item order.

MultiscaleSystem

Bases: HybridSystem

Assembled variational equations with application data and recursive reconstruction.

Assembly stores numerical operators, executed local bases and child systems, without retaining native UFL meshes/forms. The inherited physical moment utility can build gauge rows from local field integrals before solving.

trace_bindings: tuple[Any, ...] property

Expose executed interface maps for persistence and custom-basis replay.

with_rhs(rhs: Any, *, load_scale: Any = None) -> MultiscaleSystem

Delegate a compatible load update to :func:with_global_load.

solve(**options: Any) -> MultiscaleSolution

Delegate solution and hierarchical recovery to :func:solve_multiscale_system.

reconstruct(coordinates: Any, *, rhs: Any = None) -> MultiscaleSolution

Delegate recovery of executed coordinates to :func:reconstruct_multiscale.

with_global_load(system: MultiscaleSystem, rhs: Any, *, load_scale: Any = None) -> MultiscaleSystem

Reuse executed local responses for a new global balance right-hand side.

Retained rows enforce the existing local source's compatibility and must remain unchanged. Changing a volume source requires new local equations or explicitly cached local factors. Child operators and basis matrices are reused literally, and all local fields remain reconstructible.

solve_multiscale_system(system: MultiscaleSystem, **options: Any) -> MultiscaleSolution

Solve the declared boundary/gauge problem and recover every finer field.

Keyword overrides use the common HybridSystem solver contract. Omitting fixed and constraints uses those declared by MultiscaleProblem. Numerical criteria, original equations and basis coordinates are the same as in the shared hybrid solver.

reconstruct_multiscale(system: MultiscaleSystem, coordinates: Any, *, rhs: Any = None) -> MultiscaleSolution

Recover finer fields from executed hybrid coordinates without solving again.

rhs is the actual load at this scale, including parent coupling. This method checks the represented global equations before descending. Parent loads must not change retained leaf compatibility equations.

leaf_moment(system: MultiscaleSystem, weights: Callable[[Any], Any]) -> tuple[FloatArray, float]

Represent a physical finest-scale moment as row @ coordinates + offset.

weights(metadata) supplies one integration vector in each leaf's executed coefficient basis. Vector fields use that basis's component ordering. Child source offsets and boundary-reaction padding are included recursively. A physical gauge with prescribed moment m uses (row, m-offset) as its global constraint; no field is solved or sampled.

with_global_equation(system: MultiscaleSystem, equation: Equation, *, compiler: FormCompiler = compile_form) -> MultiscaleSystem

Add global forms without rebuilding any local operator or executed basis.

The forms act on the existing reduced coordinates. They may depend on the executed local response maps, for example a jump of reconstructed fields. This operation adds both the declared operator and load once, preserving child systems and coefficient interpretation. It returns a new system; it does not infer jump signs, penalties or stability conditions.

assemble(problem: MultiscaleProblem[Item], *, execution: ExecutionConfig = _DEFAULT_EXECUTION, solvers: SolverConfig = _DEFAULT_SOLVERS) -> MultiscaleSystem

Assemble user-defined local/global equations in serial or bounded parallel batches.

Workers build and eliminate local equations. Only the coordinator sums shared global indices, in item order. The additional global equation is assembled once after those contributions. Recursive children run serially within their owning worker, so one resource budget controls the hierarchy. Live optional native resources never cross the worker boundary.

solve(problem: MultiscaleProblem[Item] | MultiscaleSystem, *, execution: ExecutionConfig = _DEFAULT_EXECUTION, solvers: SolverConfig = _DEFAULT_SOLVERS, **options: Any) -> MultiscaleSolution

Solve a problem description or an already assembled variational hierarchy.

execution and solvers configure assembly of a problem description. An assembled system retains those settings; keyword options override its global solve, boundary coefficients and physical constraints through the same owner.

Monolithic assembly of explicitly declared leaf A/B/C/D coefficient equations.

OriginalBlocks dataclass

Original local fields followed by global trace coordinates, without elimination.

local_offsets delimits each original local vector. trace_offset starts the global trace vector. Prescribed trace indices must therefore be shifted by this offset before a caller applies essential data. No gauge, symmetry, invertibility or physical interpretation is inferred.

assemble_original_blocks(system: MultiscaleSystem) -> OriginalBlocks

Assemble the declared uncondensed equations without invoking a physical solver.

The local rows are A u+B lambda=L. Global rows sum C u+D lambda=g and the user's additional global Equation. The signed C is taken literally from the compiled test coupling, independently of B. Matrix contributions are scattered in original local/global coordinate order. The source-dependent rows come from the supplied system, including updates made through OfflineMultiscaleSystem.

This operation currently accepts leaf problems with no retained modes. Recursive hierarchies and retained-mode gauges require a separately declared original layout and are rejected instead of being flattened. It builds a larger sparse operator for direct comparisons; it does not establish stability or constitute an independent physical discretization.

Operator-independent reconstruction from physical coefficient moments.

energy_reconstruction(matrix: Any, moments: FloatArray, refinement_precision: Literal['double', 'extended'] = 'double') -> tuple[FloatArray, FloatArray]

Construct R with A R + C mu = 0 and C.T R = I.

matrix is the finite real square coefficient operator A. moments contains a nonempty set of independent real moment columns C in the original coefficient basis; they retain their physical units. The augmented A/C operator must be invertible. Moment independence alone does not prove that condition, stability of a discretization, or a coercivity estimate.

Return the reconstruction R and the represented reduction R.T A R. For a symmetric positive semidefinite A coercive on the moment-zero space, R minimizes its energy under the declared moments. For a nonsymmetric A, the same original saddle defines a constrained Galerkin reconstruction; its reduction keeps the full bilinear operator, including antisymmetry. Neither operator nor reduction is projected onto its symmetric part. Wider arithmetic follows solve_moment_system without changing rows, moment units or the original 1e-10 residual criterion.

Shared numerical operations and fixed hybrid contracts

Explicit local forms and the scoped algebraic global hybrid form.

Local expressions are opaque to the portable core. A supplied compiler owns their finite-element interpretation; the global form uses the existing hybrid trace/retained coordinates and does not compile arbitrary skeleton UFL forms.

LocalForm dataclass

Describe a(u,v) + sum_j lambda_j b_j(v) = L(v) on one cell.

a and L are compiler-owned expressions, for example UFL forms. trace_forms are the signed linear forms b_j in exactly the order of distinct nonnegative global trace_dofs. Outward/global-normal signs, spaces, quadrature and essential boundary elimination are explicit inputs. No trace orientation or boundary convention is inferred.

kernel declares literal nullspace coefficients; coarse_basis instead retains arbitrary modes without a nullspace claim. They are mutually exclusive. moment_forms has one linear physical moment per retained mode; omitting it requests the compiler's coefficient-orthogonality default. The assembled LocalProblem checks operator/nullspace compatibility and moment pairing. Those algebraic checks do not establish inf-sup stability. Forms are stored as tuples and numerical maps/bases are copied read-only.

__post_init__() -> None

Freeze the declared order and validate maps and literal mode arrays.

GlobalForm dataclass

Declare the sum of local condensed hybrid forms in explicit coordinates.

Trace coordinates occupy [0, trace_size). Retained coordinates follow in cell order with widths coarse_sizes. For each cell, its response's global_contribution supplies the bilinear block and linear load; the shared hybrid assembler sums these records on their declared indices. An empty coarse_sizes tuple declares a global form with no local cells; its complete operator must be supplied explicitly by its owning formulation. This is an algebraic global form, not an arbitrary UFL skeleton compiler.

boundary_load is a trace vector subtracted from the assembled RHS with the HybridSystem boundary convention. fixed_trace prescribes trace coefficients, for example oriented normal fluxes. Each constraints entry is (row, target) imposing row.T @ (lambda,c) = target in the full reduced coordinates. Supply physical pressure/rigid-motion gauges; neither a gauge nor a stability condition is inferred. Local field moments can be converted to these rows by HybridSystem.mean_constraint. Wider floating coefficients are preserved; records are copied on creation.

__post_init__() -> None

Validate the ordered coordinate partition, loads and physical rows.

compile_local_forms(forms: LocalForm, compiler: Callable[[LocalForm], LocalProblem]) -> LocalProblem

Compile one record while preserving its trace map and literal basis.

A compiler is an ordinary callable; no inheritance or optional backend is required. It must return a validated LocalProblem. The caller owns any compiler-native resources and must release them before returning arrays. Numerical operator and integration accuracy remain the compiler's concern. A changed map, undeclared mode or equivalent rotated basis is rejected.

Ordered local providers and assembly of explicitly declared hybrid forms.

Workers own local construction and solves. Only the coordinator accumulates shared trace entries, in macrocell order and without intermediate batch sums. The module requires no optional FEM, MPI or accelerator imports.

LocalLinearSolver

Bases: Protocol

Solve all columns of one constrained local system in its declared basis.

A callable receives owned copies of the augmented sparse operator and source/trace/retained-mode right-hand sides. Return a finite real array of the same shape as rhs, including moment multipliers. External codes or learned response models can implement this contract without inheritance. They own their native resources and may implement close() to release resident solver state when local execution ends. The original constrained operator has an independent numerical rank check, and each column is checked before decoding a local response.

__call__(matrix: Any, rhs: FloatArray) -> FloatArray

Return coefficients satisfying matrix @ result = rhs.

SolverConfig dataclass

Choose local and global algebra without changing a variational form.

Named solvers use the existing PyMHM adapters. A callable local_solver implements :class:LocalLinearSolver and is checked at the unchanged relative residual tolerance 1e-10, separately for each right-hand side. Explicit precision choices affect native correction arithmetic, not the operator, quadrature, gauge or acceptance criterion. A custom solver owns its precision policy; use the default local precision setting with it.

__post_init__() -> None

Reject ambiguous solver and precision settings before executing work.

HybridProblem dataclass

Bases: Generic[Item]

Combine a global hybrid form with an independent local provider.

items supplies one specification per macrocell, in the order declared by global_form.coarse_sizes. The provider returns LocalProblem or LocalAssembly with oriented trace maps, actual bases and physical moments. It is called exactly once per item per assembly. An iterator is consumed once; use a reusable iterable for repeated assemblies. Native resources remain worker-owned and must not cross a process boundary. A provider may retain reusable workspaces between items and implement close() for worker-lifetime cleanup. Threaded providers must keep mutable native workspaces separate across concurrent calls. Providers and items must be picklable for the spawn backend. contribution can supply explicit direct global terms in addition to a cell's Schur block. By default only the coordinator invokes a custom callback, in cell order. contribution_execution="worker" declares an independent, picklable callback that runs after the local solve on that worker; it must not write shared state or require coordinator resources. The default Schur contribution always runs on its local worker. Only the ordered coordinator reduction writes shared global entries. Set require_local_trace_coverage=False when a separate declared global form owns the remaining trace coordinates; retained intervals are checked.

__post_init__() -> None

Check the global form and provider without consuming local items.

assemble_hybrid(problem: HybridProblem[Item], *, execution: ExecutionConfig = _DEFAULT_EXECUTION, solvers: SolverConfig = _DEFAULT_SOLVERS) -> HybridSystem

Assemble a hybrid form using ordered serial work or bounded parallel jobs.

Serial execution solves and adds each cell before requesting the next item. Thread/process execution completes one batch before consuming the next; contributions are reduced individually in input order by the coordinator. With execution.pipeline=True, a rolling window replaces batch barriers; other workers continue while the coordinator scatters the next ordered block. The default Schur reduction and explicitly worker-owned callbacks run with the local solve, before that handoff. Shared faces therefore have no concurrent writes or batch-dependent sums. The declared trace and retained layout is checked against every response. Local responses are retained for reconstruction and physical mean rows; this API bounds in-flight work, not total response/global matrix storage.

solve_hybrid(problem: HybridProblem[Item], *, execution: ExecutionConfig = _DEFAULT_EXECUTION, solvers: SolverConfig = _DEFAULT_SOLVERS) -> HybridSolution

Assemble, solve and reconstruct with the declared boundaries and gauges.

fixed_trace prescribes oriented trace coefficients. constraints holds physical rows and targets in global trace/coarse coordinates. The unchanged global solver verifies the original equations after eliminating prescribed values and enforcing gauges. To derive mean rows from local physical weights, call :func:assemble_hybrid and system.mean_constraint before system.solve instead.

Validated local equations, cached responses and coefficient data contracts.

LocalProblem dataclass

A local variational problem A u + B lambda = f.

kernel contains a basis Z of the right nullspace of A; left_kernel defaults to the same basis. Distinct test and trial kernels are allowed. Alternatively, coarse_basis retains an arbitrary basis Z, including nearly null modes, in the global system. It is mutually exclusive with kernel; no nullspace claim is made for this general basis. constraints is C in C.T w = 0 and must pair nonsingularly with the retained Z; by default C=Z. Physical L2 orthogonality uses C=M Z. Signed normal orientations must already be included in B. trace_dofs maps its columns to the global skeleton. test_coupling is C in the global equation C.T u = g and defaults to B. test_basis and test_constraints specify the corresponding test-side retained modes and compatibility lifting. This permits Petrov formulations with different left/right kernels and independent B/C couplings. A declared kernel is tested at the matrix scale. Its nonzero floating-point actions A Z and A.T W are retained in the original equations through E=Z-R A Z; only exactly vanishing represented actions use the kernel shortcut. No boundary pressure constraints are applied locally.

__init__(matrix: Any, coupling: Any, load: Any, trace_dofs: Any, kernel: Any = None, constraints: Any = None, *, coarse_basis: Any = None, test_coupling: Any = None, left_kernel: Any = None, test_basis: Any = None, test_constraints: Any = None) -> None

Check finite square blocks and the declared kernel, including a zero local space.

condense(solver: str = 'scipy', *, refinement_precision: Literal['double', 'extended'] = 'double') -> LocalResponse

Delegate constrained source/trace elimination to :func:condense_local.

condensation_system() -> tuple[Any, FloatArray]

Return the constrained operator and source/trace/retained right sides.

condensation_matrix() -> Any

Return the scaled constraint operator without allocating response columns.

reconstruct(trace: Any, coarse: Any, *, retained_basis: Any = None, solver: str = 'scipy', factorization: LinearFactorization | None = None, refinement_precision: Literal['double', 'extended'] = 'double') -> FloatArray

Reconstruct physical fields through :func:reconstruct_local.

response_from_solution(solution: Any) -> LocalResponse

Decode finite real responses, preserving explicitly retained wider precision.

condensed_load(source_response: Any, *, load: Any = None, corrected_retained: bool | None = None) -> FloatArray

Project executed source responses into the original reduced Petrov right side.

with_load(load: Any, *, preserve_precision: bool = False) -> LocalProblem

Copy this contract with a different finite source vector.

The default retains the canonical double input convention. Explicit preserve_precision=True keeps real wider defect-source digits for original-equation refinement, including augmented/reduced right sides. Matrices, kernels, moment constraints and trace orientation are unchanged.

LocalAssembly dataclass

A local variational problem and optional application reconstruction data.

metadata can hold a NumPy mesh, DOF map or other application data that should return with the condensed response. Process workers require picklable inputs and metadata: do not capture or return live FEniCS, PETSc, MPI or CUDA objects. Construct native resources inside the worker, extract numerical arrays into LocalProblem, and release resources inside that worker.

__post_init__() -> None

Reject a factory payload that does not contain a validated local problem.

LocalResponse dataclass

Cached source/trace lifts and reconstructed retained modes of one cell.

retained_basis: FloatArray property

Return Z for an exact represented kernel, otherwise E=Z-R A Z.

reconstruct(trace: FloatArray, coarse: FloatArray) -> FloatArray

Evaluate cached lifts and retained modes through :func:reconstruct_response.

kernel_roundoff_bound(field: FloatArray) -> FloatArray

Bound declared-kernel evaluation through the shared reconstruction owner.

global_load() -> FloatArray

Return source-dependent reduced loads without rebuilding matrix blocks.

global_contribution(coarse_dofs: Any) -> tuple[IntArray, FloatArray, FloatArray]

Return the oriented cell block and load; see local_global_contribution.

HybridSolution dataclass

Skeleton coefficients, retained coarse amplitudes and reconstructed local fields.

residual is the verified relative compatibility defect after any componentwise declared-kernel evaluation allowance. Global solves also preserve its unadjusted value in raw_residual and its absolute norm in raw_residual_norm. Manually constructed solutions may omit these records.

Constrained local elimination and portable local assembly workers.

condense_local(problem: LocalProblem, solver: str = 'scipy', *, refinement_precision: Literal['double', 'extended'] = 'double') -> LocalResponse

Factor once for source, trace and retained responses, with explicit precision.

problem declares A u+B lambda=f and the oriented local trace columns. The response stores R f, R B and the executed retained basis E=Z-R A Z; an exactly represented kernel uses Z directly. Constraints, Petrov test data and solver residual criteria remain those of the supplied problem. Direct factors can retain corrected lifts in extended precision without changing their residual criterion. AMG local projection currently accepts only the default double-precision accumulation. AMG refines the projected original equations to relative tolerance 1e-12 while each pinned correction solve keeps its 1e-10 residual criterion. This reserves two decimal orders for source/trace combinations; their defects add with the reconstruction coefficients. This reserve does not replace the physical reconstructed-field residual criterion, checked independently. AmgX prepares the pinned operator once, reusing its hierarchy for every column and projected correction, and closes it on success or failure. Compatibility and gauge moments use the shared accurate accumulation, including contractions across retained modes. All four permitted corrections are checked against the original projected equations before acceptance.

local_condensation_system(problem: LocalProblem) -> tuple[Any, FloatArray]

Return the constrained operator and source/trace/retained-mode right sides.

The augmented operator is [[A, C_left], [C_right.T, 0]] with constraint columns scaled down only when they exceed the operator's largest entry. This change of auxiliary coordinates prevents constraints from dominating small-unit operators without magnifying constraints in mixed high-contrast saddles. It leaves the physical complement unchanged. Its inverse is never explicitly formed. Backends may factor this matrix once, retain the factorization, and solve new source columns online.

local_condensation_matrix(problem: LocalProblem) -> Any

Return the augmented operator without allocating response right-hand sides.

This is the same scaled left/right constraint operator returned by condensation_system. It permits one caller-owned factorization for several direct reconstructions, including nonsymmetric Petrov data.

local_response_from_solution(problem: LocalProblem, solution: Any) -> LocalResponse

Decode finite real responses, preserving explicitly retained wider precision.

Physical reconstruction and reduced loads in executed retained coordinates.

reconstruct_local(problem: LocalProblem, trace: Any, coarse: Any, *, retained_basis: Any = None, solver: str = 'scipy', factorization: LinearFactorization | None = None, refinement_precision: Literal['double', 'extended'] = 'double') -> FloatArray

Reconstruct local fields without storing every trace response.

trace uses local coupling-column order and coarse uses retained trial coordinates. Vectors produce one field; matching nonempty column arrays produce several fields with one factorization. With R the volumetric block of the augmented inverse, the field is R(f-B trace-A Z coarse)+Z coarse for an arbitrary retained Z. This includes nonsymmetric Petrov problems and an empty retained basis. retained_basis supplies an executed E=Z-R A Z for persisted coarse coordinates; then the field is R(f-B trace)+E coarse. Its numerical basis and orientation belong to the caller's archived coefficient contract. Only combined source columns are solved. Explicit extended precision preserves forcing and correction digits; backend factors stay double precision. A supplied factorization must match the augmented operator exactly and remains caller-owned. The linear residual uses the combined augmented RHS; full physical compatibility remains a global original-equation check.

local_condensed_load(problem: LocalProblem, source_response: Any, *, load: Any = None, corrected_retained: bool | None = None) -> FloatArray

Project executed source responses to the original reduced Petrov RHS.

source_response is R times the supplied load (the stored source by default). A vector gives one reduced RHS; nonempty column arrays give several. Real wider source/load digits are preserved. The trace part is test_coupling.T R load. General or rounded retained modes use (A.T W).T R load-W.T load; exact represented kernels use -W.T load. corrected_retained can preserve an executed LocalResponse branch. It does not change the augmented operator or test/trial conventions.

reconstruct_response(response: LocalResponse, trace: FloatArray, coarse: FloatArray) -> FloatArray

Recover one local coefficient vector from trace and retained amplitudes.

trace follows the local coupling columns, and coarse follows the executed retained basis columns. The field is source-lifts@trace+E@coarse; wider real operands follow NumPy's existing arithmetic promotion. This cached-response operation takes vectors; reconstruct_local also accepts matching nonempty RHS column arrays.

kernel_roundoff_bound(response: LocalResponse, field: FloatArray) -> FloatArray

Bound floating-point evaluation of retained kernel equations.

For declared left/right kernels only, sum the componentwise row bound gamma_(nnz_i+1) * (abs(A) @ abs(u))_i against abs(W) and include the final test projection's dot-product bound. Here gamma uses the stored double-precision operator, even for wider reconstruction. No operator entry, represented kernel action or physical residual is replaced by zero. General retained modes receive no kernel allowance.

Ordered sparse reduction of local blocks with shared trace indices.

local_global_contribution(response: LocalResponse, coarse_dofs: Any, *, direct_matrix: Any = None, direct_load: Any = None) -> tuple[IntArray, FloatArray, FloatArray]

Return indices, matrix and RHS of this cell's reduced Petrov equations.

This is the common assembly contract for serial, MPI and accelerator backends. The trace rows enforce C.T u=g; retained test rows enforce W.T (A u+B lambda-f)=0. The negative signs preserve the symmetric saddle convention whenever C=B and test/trial data coincide. direct_matrix and direct_load add explicitly declared local D/g terms to the trace rows, in the same local trace ordering. Their defaults are zero. Wider real floating digits are preserved. The same operation therefore owns four-block variational forms in serial, CPU workers and MPI.

assemble_hybrid_contributions(contributions: Iterable[tuple[IntArray, FloatArray, FloatArray]], *, trace_size: int, kernel_offsets: IntArray, boundary_load: Any = None, require_local_trace_coverage: bool = True) -> tuple[Any, FloatArray, FloatArray]

Reduce ordered cell contributions to a CSC operator, RHS and load scale.

kernel_offsets starts at trace_size and bounds each cell's retained global coordinates. Exactly one contribution per interval is consumed in iterable order, without retaining a tuple of contributions. Shared trace entries are added in that order; wider real matrix and load digits survive. The COO matrix entries remain stored until the final CSC conversion. load_scale sums absolute loads before cancellation. The weak Dirichlet boundary_load is subtracted once from the trace RHS and its absolute value added to that scale. No trace orientation, gauge or local basis is inferred. The caller supplies the executed, consistently numbered blocks. require_local_trace_coverage=False permits coordinates belonging only to an explicitly assembled global form; retained cell intervals are always checked. The complete global solver still rejects a singular operator. A single kernel offset and no contributions represent a global-only form; uncovered trace coordinates require require_local_trace_coverage=False.

Global hybrid layout, boundary elimination, gauges and physical compatibility.

HybridSystem

Assemble the global MHM equations independently of the local FEM backend.

The unknown is (lambda, c). Dirichlet traces enter through boundary_load as integrals against oriented skeleton basis functions. Prescribed Neumann flux coefficients are passed to solve as fixed DOFs. Arbitrary linear mean constraints can remove global pressure or rigid-motion nullspaces.

__init__(problems: list[LocalProblem] | tuple[LocalProblem, ...], *, boundary_load: Any = None, local_solver: str = 'scipy', local_refinement_precision: Literal['double', 'extended'] = 'double', backend: Literal['serial', 'thread', 'process'] = 'serial', workers: int | None = None, native_threads: int | None = 1, batch_size: int | None = None) -> None

Condense independent subdomains and assemble their sparse contributions.

from_local_factory(factory: Callable[[Any], LocalProblem | LocalAssembly], items: Iterable[Any], *, boundary_load: Any = None, local_solver: str = 'scipy', local_refinement_precision: Literal['double', 'extended'] = 'double', backend: Literal['serial', 'thread', 'process'] = 'serial', workers: int | None = None, native_threads: int | None = 1, batch_size: int | None = None) -> HybridSystem classmethod

Assemble and condense each independent local problem inside its worker.

factory(item) returns LocalProblem or LocalAssembly. The factory and one condensation execute together, exactly once per item; global assembly and solution remain in the parent. Input order defines response order and local_metadata, including None for a bare problem. Exceptions propagate without a serial fallback.

Serial and thread backends accept closures. The portable spawn backend requires picklable factories, items and metadata, and an executable script protected by if __name__ == '__main__':. Native FEM, PETSc, MPI and CUDA resources must be created and released inside a worker, never sent to or returned from a worker. An optional factory.close() or solver close() runs at the worker's lifetime boundary, including local failures. native_threads defaults to one thread; backend library thread safety is the factory's concern. batch_size limits submitted local jobs while preserving input order. Responses are retained before global assembly because this constructor infers the global layout. For immediate serial contribution with an explicitly declared layout, use assemble_hybrid.

from_responses(responses: Iterable[LocalResponse], *, boundary_load: Any = None, metadata: Iterable[Any] | None = None) -> HybridSystem classmethod

Assemble cached local responses without repeating any factorization.

from_contributions(contributions: Iterable[tuple[IntArray, FloatArray, FloatArray]], *, trace_size: int, coarse_sizes: Iterable[int], boundary_load: Any = None) -> HybridSystem classmethod

Assemble compact cell contributions without retaining local lifts.

Each tuple is the output of LocalResponse.global_contribution with coarse indices numbered after the trace_size skeleton unknowns. coarse_sizes declares their ordered cell partition. solve returns trace/coarse coefficients and an empty field tuple; callers reconstruct one local response at a time using the executed, persisted local basis. Physical mean rows must be supplied explicitly to solve: this compact representation cannot derive them or certify kernel evaluation roundoff.

mean_constraint(local_weights: list[FloatArray] | tuple[FloatArray, ...], value: float = 0.0) -> tuple[FloatArray, float]

Express a prescribed integral of reconstructed fields as r.T x=b.

For incompressible flow, weights integrate only the pressure components; for scalar pure Neumann diffusion, they integrate the pressure field.

with_rhs(rhs: Any, *, load_scale: Any = None) -> HybridSystem

Reuse the executed condensed matrix with a new explicit reduced load.

This compact online system retains the original trace numbering and ordered retained partitions, and returns no reconstructed fields. load_scale is the sum of absolute contributions before cancellation; omitting it uses abs(rhs). Wider real floating loads are preserved. Physical moment rows must be supplied explicitly to solve.

solve(*, solver: str = 'scipy', fixed: dict[int, float] | None = None, constraints: list[tuple[FloatArray, float]] | None = None, factorization: LinearFactorization | None = None, refinement_precision: Literal['double', 'extended'] = 'double', rtol: float | None = None) -> HybridSolution

Solve with boundary elimination and physical checks; see solve_hybrid_system.

solve_hybrid_system(system: HybridSystem, *, solver: str = 'scipy', fixed: dict[int, float] | None = None, constraints: list[tuple[FloatArray, float]] | None = None, factorization: LinearFactorization | None = None, refinement_precision: Literal['double', 'extended'] = 'double', rtol: float | None = None) -> HybridSolution

Solve the saddle system, enforce gauges and verify original equations.

A singular skeleton typically indicates missing gauges or a trace space richer than the local response space. Such systems are never repaired by an undocumented diagonal perturbation or least-squares solution. For a nonsymmetric global operator, the symmetric gauge augmentation requires constraint rows pairing with both left and right nullspaces. A supplied factorization must match the complete constrained matrix exactly. It is reused without transferring ownership, allowing repeated sources and boundary values through an offline/online preparation. Explicit refinement_precision="extended" retains correction digits in trace, coarse coefficients and reconstructed fields. Backend factors remain double precision. rtol selects the global linear-solver relative residual tolerance; None uses 1e-10 for a fresh solve or the tolerance of a supplied factorization. An explicit tolerance must match that prepared factorization. Physical compatibility and local reconstruction criteria remain unchanged. Extended arithmetic requires a wider NumPy long-double type. The original-equation residual uses the absolute local load contributions before assembly, and the net prescribed action before elimination. This accounts for cancellation roundoff without applying a relative tolerance to cancelled large prescribed fluxes or to artificial gauge equations. Prescribed elimination also admits its componentwise floating-point bound gamma_(m+1) * abs(A_fixed) @ abs(x_fixed) per physical row, where m is its number of terms and gamma uses double precision. A gauged declared kernel can additionally use the componentwise evaluation bound of its retained physical rows. This bound is consulted only after the usual compatibility test fails; it changes neither the represented operator nor the raw residual or previously accepted result. General retained modes receive no kernel allowance.

hybrid_mean_constraint(system: HybridSystem, local_weights: list[FloatArray] | tuple[FloatArray, ...], value: float = 0.0) -> tuple[FloatArray, float]

Express a prescribed integral of reconstructed fields as r.T x=b.

For incompressible flow, weights integrate only the pressure components; for scalar pure Neumann diffusion, they integrate the pressure field.

Optional defect correction of the original uncondensed hybrid equations.

HybridRefinement dataclass

Corrected physical fields and full-equation residual history in input units.

residual_norms includes the initial state and every accepted correction. It combines the original local rows, unconstrained weak-trace rows and supplied physical moments. rhs_norm uses these same rows and units; this algebraic norm is not a finite-element error estimate. Persist solution.fields with their executed evaluation basis: trace and coarse coefficients alone cannot replay the added defect-source responses. solution.residual checks free weak-trace and retained-test equations on these corrected fields; artificial gauge rows are excluded from that diagnostic. Gauge multipliers include all accepted corrections.

HybridRefinementCase dataclass

Original reduced system, executed coordinates and physical data of one case.

moments contains local physical weights and original integral targets. Compact systems additionally require moment_rows: the executed reduced rows expressing these same integrals, without subtracting source moments. The number of moments must equal the initial gauge multiplier count.

HybridRefinementLocal dataclass

One original local operator and the retained evaluation basis actually used.

Every streamed case uses the same problem and retained_basis. An optional trace_maps entry (indices, injection) for each case maps its oriented trace coefficients to the columns of problem.coupling. Omission uses problem.trace_dofs with the identity injection. The local test and trial couplings remain those of the original problem.

HybridRefinementStore

Bases: Protocol

Caller-owned bounded storage for executed fields and correction records.

Arrays have shape (local_field_size, number_of_cases) and the selected correction dtype. read_fields/write_fields access the current physical fields. write_record/read_record preserve records named initial (step zero), load (the measured original defect), forcing (the applied defect, zero for already accepted cases), source (its executed augmented inverse response), and correction (the actual physical delta). Replaying fields adds the recorded deltas to initial in step order and the executed dtype. Persist each case's returned coordinate increments and the executed local bases as well. Storage must preserve every digit; each write is read back and verified before the next operation.

read_fields(cell: int) -> FloatArray

Read the current physical fields of one cell.

write_fields(cell: int, fields: FloatArray) -> None

Store the current physical fields without narrowing their precision.

write_record(name: str, step: int, cell: int, values: FloatArray) -> None

Persist one executed array in the declared precision.

read_record(name: str, step: int, cell: int) -> FloatArray

Restore an executed array without recomputing its conditional solve.

HybridStreamRefinement dataclass

One streamed case's original residual history and executed coordinate deltas.

solution.fields is empty; physical fields remain in the supplied store. increments contains the actual trace, retained and gauge corrections in execution order. local_contract_digests covers original operators, data, evaluation bases and oriented trace maps, and is checked on every pass. The residual norm has the same physical-row convention as HybridRefinement.

refine_hybrid_stream(cases: Sequence[HybridRefinementCase], local_factory: Callable[[int], HybridRefinementLocal], store: HybridRefinementStore, *, max_steps: int = 2, min_steps: int = 0, rtol: float = 1e-10, atol: float = 0.0, solver: str = 'scipy', local_solver: str = 'scipy', refinement_precision: Literal['double', 'extended'] = 'double') -> tuple[HybridStreamRefinement, ...]

Correct original hybrid equations cellwise with a fixed condensed operator.

Cases share original local matrices and data, but may have different oriented trace spaces, boundary loads, prescribed coefficients and physical moments. Each bounded pass calls local_factory(cell) in cell order; actual local bases and all operator/data values must stay identical between passes. Local factors solve batched defect sources and are released before the next cell. The executed initial field, measured load, inverse response and actual physical increment are stored; no conditional solve is repeated for replay.

Acceptance uses the original volume rows, free weak trace rows and physical moments with max(atol, rtol*rhs_norm). Artificial gauge equations are excluded. rhs_norm includes prescribed physical trace action. The same reduced matrix is used for corrections, and prescribed trace increments are zero. No tolerance, operator entry or approximation space is modified. Compact solutions and per-case coordinate increments are returned; fields remain in store. Rejected states raise LinearSolveError and must not be published as accepted acquisitions. min_steps optionally requires further original-equation corrections even when the residual is already accepted. It is at most max_steps; zero preserves residual-based stopping. It does not certify field accuracy or change the original residual criterion.

refine_hybrid(system: HybridSystem, solution: HybridSolution, *, boundary_load: Any = None, fixed: dict[int, float] | None = None, moments: Sequence[tuple[Sequence[FloatArray], float]] = (), max_steps: int = 2, min_steps: int = 0, rtol: float = 1e-10, atol: float = 0.0, solver: str = 'scipy', local_solver: str = 'scipy', refinement_precision: Literal['double', 'extended'] = 'double') -> HybridRefinement

Refine A_i u_i+B_i lambda=f_i and the original weak trace equations.

Supply the original boundary_load (zero by default), prescribed trace coefficients fixed, and physical moments as in the initial solve. A moment is (local_weights, target); do not pass reduced gauge rows. Distinct test/trial couplings and multiple retained modes are supported.

Each correction retains the original lifts and condensed operator. Local direct factors solve only the new defect source and are released cellwise; no full uncondensed matrix is assembled. The default solution is untouched unless this function is explicitly called. max_steps=0 checks it only. Acceptance requires the full original residual to be at most max(atol, rtol*rhs_norm). Failure raises LinearSolveError with the achieved residual, including stagnation at a precision floor. Extended correction storage is explicit and requires a wider NumPy type. min_steps optionally requires original-equation corrections after the residual is already accepted, up to max_steps. Zero preserves the default stopping convention. A small residual or a requested correction count alone does not certify physical field accuracy.

Reusable MHM operators for repeated sources and fixed material/geometry.

An offline object keeps the local augmented factorizations, harmonic lifts and one constrained global factorization. Online calls may change source vectors, boundary moments and prescribed trace values, but not matrices, spaces, fixed DOF locations or the definition of physical mean constraints.

LocalFactorCache

Reuse direct factors only for exactly identical constrained local matrices.

Sources, trace couplings and retained responses may differ between cells. Keys contain the canonical CSC shape, index arrays and every numerical byte; no tolerance, geometric equivalence or approximate hashing is used. The cache owns all factors until close and is local to one process/thread of use.

size: int property

Return the number of distinct retained factorizations.

__init__(*, solver: str = 'scipy') -> None

Create an empty explicit-lifetime cache for one direct solver backend.

condense(problem: LocalProblem) -> LocalResponse

Condense one validated local problem using an exact-matrix cache entry.

close() -> None

Release all factors exactly once and invalidate further use.

__enter__() -> LocalFactorCache

Enter an open exact-matrix cache context.

__exit__(exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> None

Release cached CPU or accelerator resources on every exit path.

OfflineLocalProblem

Keep a local augmented factorization and source-independent responses.

The input LocalProblem validates the mathematical kernel/basis contract. New loads are expressed in that same test space. This object owns native solver resources and must be closed; concurrent calls are unsupported.

__init__(problem: LocalProblem, *, solver: str = 'scipy') -> None

Factor once and build the harmonic and retained-mode responses.

response(load: Any) -> LocalResponse

Solve only the new source response, reusing all homogeneous lifts.

close() -> None

Release the reusable local factorization exactly once.

__enter__() -> OfflineLocalProblem

Enter an open local-factorization context.

__exit__(exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> None

Release native resources even if an online solve fails.

OfflineHybridSystem

Prepare a fixed MHM discretization for multiple source/boundary queries.

moments contains (local_weights, target) pairs, with one physical weight vector per local problem. Their rows are fixed; their right-hand sides account for each new source lifting. Online targets may change prescribed integrals. fixed values can change, but their keys cannot.

This is an algebraic offline/online organization of the supplied method; it does not change that method into MsHHO or project arbitrary sources onto the polynomial source space of a different formulation.

original_residuals: tuple[float, float] | None property

Return the last checked original residual and physical RHS Euclidean norms.

The residual includes original local rows, free weak trace equations and physical moments. The RHS accounts for prescribed trace values. An unchecked or failed online query clears this record. These norms measure algebraic satisfaction, not approximation error or stability.

__init__(problems: Iterable[LocalProblem], *, boundary_load: Any = None, fixed: dict[int, float] | None = None, moments: Sequence[tuple[Sequence[FloatArray], float]] | None = None, local_solver: str = 'scipy', solver: str = 'scipy') -> None

Prepare local lifts and the constrained global factorization once.

solve(loads: Sequence[Any], *, boundary_load: Any = None, fixed: dict[int, float] | None = None, targets: Sequence[float] | None = None, check_original: bool = False) -> HybridSolution

Solve one new source query without rebuilding or refactoring operators.

check_original=True checks the executed solution against the original physical equations with the shared refine_hybrid(max_steps=0) criterion, residual <= 1e-10 * rhs_norm. It performs no corrections, returns the same solution, and records the norms in original_residuals.

solve_many(loads: Iterable[Sequence[Any]], **kwargs: Any) -> tuple[HybridSolution, ...]

Evaluate source cases in order while retaining all offline resources.

close() -> None

Release all local and global native resources; repeated calls are safe.

__enter__() -> OfflineHybridSystem

Enter an open offline/online context.

__exit__(exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> None

Release resources after the last query or an exception.

condense_cached(problems: Iterable[LocalProblem], *, solver: str = 'scipy') -> tuple[LocalResponse, ...]

Condense ordered cells using exact-matrix reuse within this single call.

Repeated variational sources with unchanged operators and executed bases.

OfflineMultiscaleSystem

Reuse local factors for arbitrary new volume and interface functionals.

The input system supplies A/B/C/D, retained trial/test modes, coefficient transports and field definitions. Only L, g and the additional global functional may change. Loads use the compiled test-coordinate order; balance_loads uses the compiled union of local trace coordinates. No physical method, sign, source projection or time scheme is selected.

This object owns local factor resources and must be closed. Updated systems preserve their operator and harmonic lifts literally and are independently reconstructible after close. A global factor can be reused through the ordinary solve factorization option. Source-dependent gauge targets must be recomputed from the updated system's mean_constraint or leaf_moment. A recursive hierarchy updates its child sources before assembling its parent; this leaf-source cache does not flatten that tree.

__init__(system: MultiscaleSystem, *, solver: str = 'scipy') -> None

Factor the declared local constrained operators with explicit ownership.

with_loads(local_loads: Sequence[Any], *, global_load: Any = None, balance_loads: Sequence[Any] | None = None) -> MultiscaleSystem

Return a reconstructed-source system without rebuilding any operator.

Omitted global/balance loads retain the original additional functional and g. Explicit global_load replaces that additional functional in the full trace-plus-retained layout, rather than the condensed RHS. Local compatibility contributions are recomputed from the new L.

solve(local_loads: Sequence[Any], *, global_load: Any = None, balance_loads: Sequence[Any] | None = None, **options: Any) -> MultiscaleSolution

Solve an updated source through the existing generic solver contract.

close() -> None

Release owned local factors once; previously returned systems remain usable.

__enter__() -> OfflineMultiscaleSystem

Enter the explicit lifetime of an open factor cache.

__exit__(exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None) -> None

Release resources on normal completion or an unsuccessful source query.

Recursive local MHM through a second, explicit trace constraint.

The inner hybrid unknowns and their boundary reactions form the local field of the next level. Inner volume fields are reconstructed only after the outer solve. No inverse, penalty, or implicit boundary gauge is introduced.

NestedSolution dataclass

Recovered inner hybrid coordinates, leaf fields and boundary reactions.

NestedLocalProblem dataclass

One local problem whose interior discretization is another MHM system.

Use problem in the parent :class:HybridSystem and pass the resulting local field to :meth:reconstruct. The trace map sends outer coefficients to selected inner trace coordinates; it includes every orientation and basis transformation. A kernel is declared in inner hybrid coordinates and lifted to the boundary reactions, so retained constants or rigid modes survive each condensation level.

reconstruct(field: Any) -> NestedSolution

Recover all inner local fields and check unconstrained inner equations.

moment(local_weights: list[FloatArray] | tuple[FloatArray, ...]) -> tuple[FloatArray, float]

Express a physical leaf moment as weights @ nested_field + offset.

The offset is essential when the inner source responses have nonzero moments. Subtract it from a parent physical gauge's prescribed value.

nested_trace_map(outer: SkeletonSpace, cell: int, inner: SkeletonSpace) -> tuple[IntArray, FloatArray]

Restrict oriented parent face polynomials exactly to inner boundary faces.

The inner mesh must partition the selected parent cell. Its boundary edges must lie on individual straight parent edges, and every restricted outer basis function must belong to the inner face space. Extra material cuts or smaller inner degrees cannot silently project an unrepresentable trace. Endpoint projections agree with parent breakpoints within the declared coordinate-roundoff envelope. Corrections smaller than half the child edge retain its ordering; genuine interior material cuts remain unrepresentable. Components retain the standard component-interleaved ordering.

nest_hybrid_system(inner: HybridSystem, boundary_dofs: Any, trace_map: Any, trace_dofs: Any, *, kernel: Any = None, left_kernel: Any = None, constraints: Any = None, test_constraints: Any = None) -> NestedLocalProblem

Promote an inner hybrid discretization to a parent local problem.

With A x=b the inner equations, E selecting its boundary trace and M=trace_map, the local equations are [[-A,E],[E.T,0]] [x,mu] + [0,-M] lambda = [-b,0]. Thus E.T x=M lambda and mu is minus the inner potential moment. The parent continuity pairing -M.T mu has the original physical sign.

kernel and left_kernel are arrays with one row per inner hybrid unknown, and the same number of independent columns. Their reaction parts are calculated from A and A.T. They must vanish in the selected trace coordinates and satisfy the interior homogeneous equations. Constraints have the same inner shape and are extended by zero boundary reactions. The caller supplies the physical constant/rigid modes; numerical nullspace detection does not replace this formulation contract. Distinct left and right kernels are supported when the inner method is Petrov--Galerkin.

Exact restriction of prepared local responses to nested skeletal subspaces.

moment_complement(moments: Any, *, pivots: Any = None) -> FloatArray

Construct coordinates annihilating independent declared moments.

moments is a real (n, m) matrix: its columns represent linear functionals on an n-coefficient vector. A vector declares one moment. The returned (n, n - m) matrix Z satisfies moments.T @ Z = 0. Its free-coordinate rows form the identity, in ascending coordinate order; pivot rows enforce the moments. This convention fixes scale and orientation without choosing an arbitrary numerical nullspace basis.

pivots optionally declares the m constrained coordinates. Otherwise the largest absolute entry is selected for one moment, and column-pivoted QR of moments.T selects coordinates for several moments. Near-ties in QR can depend on the numerical platform: archive the executed matrix with persisted coefficients, or supply fixed admissible pivots. No physical kernel or integration measure is inferred from these algebraic moments.

restrict_response(response: LocalResponse, injection: Any, trace_dofs: Any, *, test_injection: Any = None) -> LocalResponse

Reuse harmonic lifts on an exactly embedded trial/test trace subspace.

injection maps the new trace coefficients to the prepared trial space. test_injection defaults to the same map, or independently restricts the Petrov test space. Both maps must have full column rank. Their geometrical meaning is supplied by the caller; this operation does not project or fit unresolved traces. The local operator, source and retained spaces are fixed.

Multiscale HHO from constrained local energy minimization on triangles.

The cell and face unknowns are integral moments, an invertible change of coordinates from the polynomial coefficients in Chaumont-Frelet et al. (2022). Local reconstructions minimize diffusion energy subject to these moments. The cell moments are statically condensed, leaving the represented face system. The exact diffusion form is symmetric; its assembled operator is retained without a further projection onto its symmetric part. Both the projected-source formulation (4.6) and reconstructed-source variant (5.1) are available. The face-only case m=-1 requires the latter variant.

solve_mshho(mesh: TriangleMesh, *, permeability: Any = 1.0, source: Any = 0.0, dirichlet: Any = 0.0, skeleton: SkeletonSpace | None = None, neumann: dict[int, Any] | None = None, mean_pressure: float = 0.0, cell_degree: int = 0, degree: int = 2, local_refinement: int = 4, source_variant: Literal['projected', 'reconstructed'] = 'projected', quadrature_order: int = 6, solver: str = 'scipy', local_refinement_precision: Literal['double', 'extended'] = 'double') -> MsHHOSolution

Solve multiscale HHO with local continuous Pk energy reconstructions.

cell_degree=m and skeleton specify the coarse moment spaces; degree controls the local numerical approximation only. For m=-1, select source_variant='reconstructed' as required by Remark 5.4. Exterior Dirichlet data are imposed through face moments. neumann maps selected exterior faces to physical outward flux -A grad(u) dot n; remaining faces have Dirichlet data. All-Neumann problems require compatible total source/flux and fix the volume mean through mean_pressure. This finite-dimensional realization uses the same local variational spaces as primal MHM, allowing exact discrete equivalence checks for polynomial/projected sources. Theorem 5.1 concerns ideal local PDE solves; finite-space agreement requires matched spaces and represented source loads. The ideal projected-source flux is H(div) conforming (Lemma 4.2), whereas the reconstructed-source flux need not be (Remark 5.3). Finite local raw gradients require their own conformity check. Theorem 6.3 gives an energy estimate with piecewise H^(m+1) source and H^(ell+1) A grad(p), regular matching macrocell submeshes and material-dependent constants; it supplies no pressure L2 rate by itself. local_refinement_precision='extended' retains reconstruction, represented Galerkin operators and moment-coordinate digits through defect corrections. Factors remain binary64 and the original residual criterion stays 1e-10; platforms without a wider long-double type raise SolverUnavailableError.

Three-dimensional MsHHO on tetrahedral and convex polyhedral macro partitions.

solve_mshho_3d(mesh: TetraMesh | PolyhedralMesh, *, permeability: Any = 1.0, source: Any = 0.0, dirichlet: Any = 0.0, neumann: dict[int, Any] | None = None, skeleton: TriangularSkeleton | PolygonalSkeleton3D | None = None, cell_degree: int = 0, degree: int = 2, local_refinement: int = 2, source_variant: Literal['projected', 'reconstructed'] = 'projected', quadrature_order: int = 5, mean_pressure: float = 0.0, solver: str = 'scipy', local_refinement_precision: Literal['double', 'extended'] = 'double') -> MsHHO3DSolution

Solve MsHHO with tetrahedral Pk energy lifts and polynomial face moments.

Polyhedral faces retain one polynomial on each original polygon. Tetrahedral faces additionally permit independent aligned subdivisions. neumann prescribes physical outward Darcy flux; other exterior faces prescribe pressure. Pure Neumann data require compatibility and fix the volume mean. The face-only case m=-1 requires the reconstructed-source variant. Local numerical spaces must represent all independent volume and face moments. Theorem 5.1 concerns ideal local PDE solves, rather than arbitrary finite tetrahedral lifts. Theorem 6.3 bounds energy with piecewise H^(m+1) source, H^(ell+1) A grad(p), regular matching macrocell submeshes and material-dependent constants. Pressure L2 rates require separate evidence. Projected-source ideal flux conformity (Lemma 4.2) does not apply to reconstructed-source loads (Remark 5.3) or to generic finite local raw gradients without a conformity check. local_refinement_precision='extended' uses the same preserved moment arithmetic as the two-dimensional and polygonal solvers, without changing local spaces, represented operators or the original 1e-10 residual check.

Oriented geometry operations for polygons and star-shaped polyhedral cells.

clip_polygon(polygon: ArrayLike, axis: int, level: float, lower: bool) -> FloatArray

Intersect an ordered convex planar polygon with a closed Cartesian half-plane.

polygon contains finite real vertices with shape (n,2), without a repeated closing vertex. axis is 0 or 1. lower=True retains coordinate >= level; lower=False retains coordinate <= level. Output vertices follow the input's clockwise or counterclockwise orientation. An empty intersection has shape (0,2); point/segment intersections and repeated boundary vertices are retained for the caller's measure checks.

Computation uses binary64 and strict comparisons of represented coordinates. An intersection's clipped coordinate is set exactly to level. No geometric tolerance, vertex merging or grid snapping is inferred; applications requiring those conventions declare them before clipping. Convexity and cyclic ordering are caller hypotheses.

oriented_cell_faces(points: FloatArray, faces: list[IntArray], cells: list[IntArray]) -> tuple[IntArray, ...]

Orient each connected closed cell boundary through opposing directed edge incidences.

The global orientation is selected by its signed surface-volume integral; neither a convex hull nor an assumed interior centroid is used. The caller subsequently checks that the surface is embedded by its positive cone mesh.

kernel_center(vertices: FloatArray, origins: FloatArray, outward: FloatArray) -> tuple[FloatArray, float, bool]

Find a strictly interior ball in the intersection of all inward face half-spaces.

Convex cells retain the arithmetic vertex center. Nonconvex cells maximize the ball radius by a four-variable linear program in cell-scaled coordinates. Canonically ordered inequalities make degenerate optimal-center selection independent of face-list order. The returned radius is verified against every original face, independently of the optimizer's feasibility tolerance. An empty or unresolved kernel is rejected rather than filled by a convex hull.

validate_disjoint_cones(points: FloatArray, cells: IntArray) -> None

Reject interior overlap of tetrahedral cones using the convex separating-axis theorem.

Face normals and pairwise edge cross products are a complete axis set for two tetrahedra. Coordinates are translated/scaled before projection; touching faces, edges and the common kernel center do not constitute overlap.

triangle_in_face(corners: FloatArray, triangles: FloatArray, normal: FloatArray) -> bool

Test a fine boundary triangle against the original face's canonical triangulation.

Conforming local refinements lie within a single canonical triangle even when the original polygon is nonconvex. This preserves individual coplanar faces and does not accept a triangle spanning a reentrant notch.

Source modules

Shared real array aliases and exact discrete parameter validation.

positive_int(value: Any, name: str, minimum: int = 1) -> int

Validate a discrete parameter without silently truncating real numbers.

real_array(value: Any, name: str) -> FloatArray

Copy a finite real array into binary64 without discarding imaginary parts.

dyadic_refinement(value: Any, name: str = 'refinement') -> int

Validate a positive power of two for nested simplex subdivisions.

This is a geometric alignment condition, not a polynomial degree or mathematical stability certificate. The returned integer is unchanged.

Shared solves of represented moment-coordinate equations.

solve_moment_system(matrix: Any, rhs: Any, *, solver: str = 'scipy', refinement_precision: Literal['double', 'extended'] = 'double') -> FloatArray

Solve matrix @ result = rhs without discarding represented wider digits.

matrix is a finite real square operator; rhs is a real vector or a matrix of independent right-hand sides. The named factorization validates solvability and owns its native resources within this call. No symmetry, boundary convention or physical meaning of a coefficient is inferred.

Factors use binary64. refinement_precision='extended' retains the original operator and forcing in wider storage for two additional defect corrections and the unchanged 1e-10 check of every original RHS column. It requires a genuinely wider platform long-double representation and returns wider coefficients; it never substitutes binary64 silently. Local reconstructions, condensed operators and gauged moment equations in all supported spatial dimensions use this same operation.

Dimension-independent physical Neumann extension of the Robin MH method.

RobinBoundaryFace dataclass

Integrated boundary data in one scalar Robin multiplier basis.

The mass matrix pairs multiplier densities and auxiliary pressure traces. Coefficient is sigma.n with the outward exterior normal. Load integrates the prescribed physical flux q.n; constant represents one in this basis.

solve_robin_neumann(system: HybridSystem, trace_size: int, faces: tuple[RobinBoundaryFace, ...], volume_weights: tuple[FloatArray, ...], volume: float, mean_pressure: float, pure_neumann: bool, solver: str, precision: Literal['double', 'extended']) -> tuple[HybridSolution, dict[int, FloatArray], Any, FloatArray]

Solve symmetric boundary-pressure equations, checking physical compatibility.

Rows are S lambda + J rho=t-g_D and J.T lambda+R rho=h_N. Local coercive inverses are unchanged. The optional mean fixes the full reconstructed volume pressure, not an average of trace coefficients.

Petrov-Galerkin MHM with residual face enrichment for two-dimensional Darcy.

Equations (27)--(34) of Fernando, Martins, Pereira and Valentin (2023) use the conormal A grad(p).n. Here all stored multipliers use physical Darcy flux q.n=-A grad(p).n. Only the enriched multiplier is macro conservative.

solve_pgmhm(mesh: TriangleMesh | PolygonMesh, *, stabilization_parameter: float, permeability: Any = 1.0, source: Any = 0.0, dirichlet: Any = 0.0, neumann: dict[int, Any] | None = None, skeleton: SkeletonSpace | None = None, degree: int = 2, local_refinement: int = 1, local_meshes: tuple[TriangleMesh, ...] | None = None, quadrature_order: int = 6, ellipticity_lower_bound: float | None = None, mean_pressure: float = 0.0, solver: str = 'scipy', local_solver: str = 'scipy', local_refinement_precision: Literal['double', 'extended'] = 'double', backend: Literal['serial', 'thread', 'process'] = 'serial', workers: int | None = None) -> PGMHMSolution

Solve equations (27)--(34), including the conservative residual enrichment.

stabilization_parameter=alpha is explicit: the theorem requires alpha sufficiently small but does not provide a universal numerical threshold. The weight is alphaK_min/(2H_E), using the full macroface length, not the lengths of refined skeleton segments. The local degree must satisfy k>=ell+2. The stated uniform theorem assumes ell>=1; ell=0 is included among the article's numerical experiments. Rank/residual checks establish neither a uniform inf-sup bound nor parameter-independent conditioning.

Dirichlet faces contribute jumps against their prescribed trace. Physical Neumann faces are fixed essentially and receive no jump penalty or flux enrichment. Compatible pure Neumann data use the physical mean-pressure gauge; the local enrichment has zero volume mean. The boundary projection in equation (32) is evaluated on the common fine-trace partition so that its Pk moments agree with the Dirichlet functional in equation (29). local_refinement_precision="extended" retains residual-correction digits in both the local response and its residual enrichment. It leaves the operator and residual tolerances unchanged and requires a platform with a wider long-double type, as in :func:pymhm.linalg.linear.solve_linear.