Ordinary tensor ODEs
For dy/dt = f(t, y), use TensorState and tensor_rhs without writing
lifecycle hooks. The adapter runs on the existing drivers and returns their
ordinary IntegrationResult, with the new tensor available as result.state.y.
This complete float64 CPU example is also saved in examples/tensor_ode.py.
"""Ordinary tensor ODE: python examples/tensor_ode.py."""
import math
import torch
from warpSPHIntegrators import TensorState, tensor_rhs, get_scheme
from warpSPHIntegrators.schemes import filter_schemes
from warpSPHIntegrators.schemes import ExplicitRK
def run_example():
# Scalar, vector or batched floating-point tensors use the same interface.
initial = torch.tensor([1., 2.], dtype=torch.float64)
state = TensorState(initial, t=0.)
scheme = get_scheme(ExplicitRK.dormandPrince) # registered Dormand-Prince 5(4)
rhs = tensor_rhs(lambda t, y, rate: -rate*y, rate=2.)
for _ in range(100):
result = scheme(state, .01, rhs)
state = result.state
assert torch.allclose(state.y, initial * math.exp(-2), rtol=1e-8, atol=1e-10)
return result
if __name__ == '__main__':
result = run_example()
pairs = filter_schemes(family='ExplicitRK', has_error_estimate=True, supports_reuse=True)
print(f't={result.state.t:.2f}, y={result.state.y.tolist()}, reusable pairs={len(pairs)}')
Scalar, vector and batched tensors preserve shape, dtype, device and autograd
connections. Supply a nonempty floating-point tensor; each derivative must have
exactly the same shape, dtype and device. Treat RHS inputs as read-only. Integer
and complex states are not supported by this adapter. Bind named parameters in
tensor_rhs(f, rate=...) or close over them; solver/logging kwargs do not reach
f(t, y). Positional step arguments do reach f.
Discovery and driver requirements
filter_schemes returns registered records in catalog order. Filters combine
with AND; no matches returns an empty tuple, and invalid criteria raise ValueError.
from warpSPHIntegrators.schemes import filter_schemes
pairs = filter_schemes(family='ExplicitRK', min_order=5,
has_error_estimate=True, supports_reuse=True,
state_kind='tensor')
assert pairs
assert all(s.order >= 5 and s.has_error_estimate for s in pairs)
Other filters include exact/max order, implicit solves, dense output, history,
separability, drift-field support and available RHS capabilities. An empty
available_capabilities set excludes ETD2RK, whose linear action is mandatory;
optional split accessors do not restrict combined-RHS methods.
The adapter supports the 135 catalog records whose metadata.state_kind is
tensor. Geometric and Newmark methods require a position/velocity system;
using their records with TensorState fails before stepping. Use the
full state protocol for those methods and SPH fields. The catalog
also retains separability/force assumptions and history requirements; consult
the family page before choosing a method.
Splits, history and estimates
tensor_rhs accepts IMEXRHS and SemilinearRHS whose callbacks use (t, y);
their declared capabilities remain intact. For example, a linear stiff mode:
import math
import torch
from warpSPHIntegrators import TensorState, tensor_rhs, get_scheme, get_scheme
from warpSPHIntegrators.adapters import SemilinearRHS
state = TensorState(torch.ones(2, dtype=torch.float64))
rhs = tensor_rhs(SemilinearRHS(linear=lambda t, y: -10*y))
result = get_scheme('ETD2RK')(state, .1, rhs)
assert torch.allclose(result.state.y, torch.full_like(state.y, math.exp(-1)))
For multistep methods, pass history=StepHistory(maxlen=...) and thread
result.history into subsequent calls; metadata.history_length gives the
required number of retained previous entries. A missing history repeatedly uses
startup, and changing dt restarts history. estimate_error_norm(result) and
propose_dt(..., order=scheme.estimate_order) remain caller-driven helpers;
DP5 dense output takes the initial state and result.stages.
The adapter preserves the chosen driver's gradient semantics. Explicit and implicit tensor state/parameter paths are tested. ROS3P/EXPRB32 freeze operators; their existing gradient qualifications still apply, including incomplete differentiation through parameter-dependent frozen operators. Use the run API for fixed/adaptive trajectories, acceptance, sampling, events and restart checkpoints.
Choose an explicit method identity
Use get_scheme(ExplicitRK.dormandPrince) for Dormand–Prince 5(4), or
ExplicitRK.tsit5 for Tsitouras 5(4). Use filter_schemes for requirements such
as order, estimates or state kind. An order alone does not identify a suitable
method: stiffness, force structure, stability and solve cost also matter.
See method selection and step/solver options.