Skip to main content

Physical operator splitting

ConservativeDissipativeRHS declares two autonomous physical parts. LieTrotter, Strang, Yoshida4 and compose build parameterized fixed-step schemes over existing one-step integrators. They remain outside the fixed catalog; pass the returned scheme to solve or call it directly. The 137 existing registrations are intact.

"""Physical operator splitting: python examples/operator_splitting.py."""

import math
import torch
from warpSPHIntegrators.wrappers import (
ConservativeDissipativeRHS, Strang, LinearExponentialFlow,
)
from warpSPHIntegrators.adapters import SemilinearRHS
from warpSPHIntegrators import TensorState, tensor_rhs, solve


def run_example():
# q' = v, v' = -4*q - .5*v: motion and damping are separate maps.
initial = TensorState(torch.tensor([1., 0.], dtype=torch.float64))
damping = torch.diag(torch.tensor([0., -.5], dtype=torch.float64))
rhs = tensor_rhs(ConservativeDissipativeRHS(
conservative=lambda t, y: torch.stack((y[1], -4*y[0])),
dissipative=SemilinearRHS(linear=lambda t, y: damping@y)))
method = Strang('RK4', LinearExponentialFlow(damping))
result = solve(method, initial, 1., rhs, dt=.01)
omega = math.sqrt(4 - .25**2)
exact = torch.tensor([
math.exp(-.25)*(math.cos(omega) + .25/omega*math.sin(omega)),
-4/omega*math.exp(-.25)*math.sin(omega)], dtype=torch.float64)
assert method.order == 2
assert result.state.t == 1.
assert torch.linalg.vector_norm(result.state.y-exact) < 1e-4
assert torch.equal(initial.y, torch.tensor([1., 0.], dtype=torch.float64))
return result


if __name__ == '__main__':
result = run_example()
print(f't={result.state.t}, [q, v]={result.state.y.tolist()}, steps={result.accepted_steps}')

Accuracy and structural checks​

Lie–Trotter advances each part once and is first order. Strang applies a half dissipative step, a full conservative step, then another dissipative half. Its order is the minimum of two and the sub-integrator orders. A backward-Euler half therefore reports/measures order one. Second-order sub-integrators suffice for second-order accuracy; symmetry is additionally needed for time reversibility and the usual higher-order symmetric-composition arguments. Explicit midpoint is a tested second-order example without that symmetry.

The current driver requires a declared autonomous split. Component pseudo-times are reset to the outer start, and the returned state ends at t+dt; adding both component clocks would double-advance physical time. Non-autonomous composition needs an explicit clock extension and remains unsupported. Timestep-dependent compatible-energy maps are not silently treated as autonomous vector fields.

Physical names alone do not certify a Hamiltonian. check_contracts checks additivity and zero dissipative position rate; require_separable=True adds mechanical probes. classify_separable measures conservative force dependence on velocity at several perturbed velocities, checks position rate equals velocity and rejects evolving extra integrated quantities. This catches the thermal-energy shortcut even when force itself appears velocity-independent. These are local structural diagnostics, not global mathematical or variational proofs. Unsupported AD and missing mechanical tags produce a non-certified verdict. Geometric conservative sub-integrators require these checks before stepping. Transported PDE scalar values should use TensorState, not particle-position tags.

LinearExponentialFlow(matrix_or_provider) advances a declared homogeneous linear part with Torch matrix_exp in flattened integrated-field order. It checks matrix shape/device/dtype and the declared action at the current state. The dense matrix path preserves state and matrix-parameter gradients and is intended for small systems. Sparse/Krylov flow implementations for large SPH remain application work; a declared operator depending on frozen configuration must remain fixed within its subflow. Implicit midpoint supports nonlinear dissipative vector fields through the existing JFNK/IFT path. Neither method removes a separate convective CFL bound.

Lifecycle, ownership and options​

Composition snapshots the caller and calls outer initialize/finalize once. Inner steps retain preprocess/postprocess and copied-field propagation; they skip outer finalization and call optional initialize_substep instead of outer initialize. A custom finalize must declare composition_compatible=True and handle grouped composition_substeps. Its return/update arguments are component results/stages, and weights are their composition coefficients, not a combined Butcher quadrature. Existing compatible-energy SPH finalizers require a dedicated substep work design. No such production integration is claimed here.

Bind per-part options through conservative_options and dissipative_options. Common step kwargs are passed to each part, with bound part options overriding them. Full-protocol RHS/hooks must accept their consumer's kwargs, including the internal substep flag and split-part label; Tensor callbacks receive only their bound parameters. A failed sub-solve propagates its status without outer finalize; solve rolls back the candidate and transaction. Precision-floor handling remains the run API's explicit policy after the complete composition is assembled.

The runner supports accepted callbacks, fixed-grid output and in-memory restart for the bound recipe. Supply the same RHS/parameters/operator/options on restart. Adaptive estimates, dense interpolation, events, FSAL and multistep sub-integrators are unsupported. Component stages are component derivatives, not a global FSAL stage. Generic compose accepts orders one/two and refuses negative dissipative coefficients; backward physical integration retains its ordinary signed-step behavior.

Yoshida4(conservative, LinearExponentialFlow(matrix), negative_step_limit=.5) is a separate fourth-order recipe. It uses the symmetric triple jump from Yoshida (1990), Eq. 2.11, with adjacent exact D flows combined. It requires a supported symmetric conservative integrator and a static Euclidean-dissipative matrix. Each negative D step must satisfy abs(tau)*norm(matrix, 2) <= negative_step_limit. The default bound is an engineering restriction on anti-diffusive growth, not a theorem of unconditional stability. Strong damping is rejected before initialization. Generic nonlinear or stiff negative dissipative flows and arbitrary higher-order recipes are unsupported.

Toy problems and measurements​

For the oscillator q'=v, v'=-4*q-.5*v, the conservative step advances q'=v, v'=-4*q, and the dissipative step holds q fixed while multiplying velocity by exp(-.5*tau). These two simple maps separate mechanical motion from damping. The complete oscillator has a known solution, so trajectory errors can be measured without an SPH model or thermodynamic closure.

The split oscillator and periodic Burgers cases verify orders one/two/four, mass, state/parameter gradients, failure propagation and lifecycle ownership. Implicit and exponential diffusion stay bounded at 8–82 times the explicit diffusion step bound; the explicit control is unstable. Accuracy still requires suitable steps. Strang with Verlet/exact damping has phase-space determinant exp(-.5*h) to roundoff; the restricted fourth-order recipe matches within 1e-9. Unsplit RK4 has a measurable defect at the same step. The oscillator's mechanical-energy change plus trapezoidal integrated viscous loss converges at order two. These are constant-damping toy diagnostics, not general SPH conservation claims.

A fixed-step static exact-flow benchmark merges two neighboring dissipative half-flows: 20 steps use 21 flows instead of 40 and agree to roundoff. The benchmark changes lifecycle boundaries and is not an automatic runner optimization; callbacks, synchronized samples and non-exact/variable-step flows need a separate representation and ownership design.

The known oscillator and PDE examples qualify the composition behavior without requiring a new physics model. Entropy/compatible-energy SPH and large sparse exponential flows still need application-specific checks. Nyström and the other one-step configurations fit only where their state, force and quadrature contracts match the physical subflow. The validation record keeps the measurements and application limits.