API Orientation
TIDE’s public API is organized around one idea: the electromagnetic model changes during inversion, while the numerical experiment usually does not. The API therefore separates model tensors from the operator that owns geometry, discretization, execution, and storage policy.
The six domain objects
Section titled “The six domain objects”| Object | Owns | Changes during inversion? |
|---|---|---|
EMModel | epsilon, sigma, mu, optional dispersion | Yes |
Discretization | spacing, dt, stencil, CPML, optional maximum velocity | Usually no |
Acquisition | source and receiver indices | Usually no |
Experiment | acquisition, source samples, nt, components, signal conditioning | Usually no |
ExecutionOptions | backend, fallback, reference mode, thread count | No |
StorageOptions | snapshot location, compression, memory limits, chunking | No |
Keeping these roles separate prevents a common inversion bug: rebuilding a solver with slightly different numerical settings on every iteration.
Constructing an operator
Section titled “Constructing an operator”import torchimport tide
ny, nx = 80, 120dt = 4.0e-11nt = 400
model = tide.EMModel( epsilon=torch.full((ny, nx), 4.0), sigma=torch.zeros(ny, nx), mu=torch.ones(ny, nx),)
source = tide.ricker(8.0e8, nt, dt).reshape(1, 1, nt)source_location = torch.tensor([[[10, 50]]], dtype=torch.long)receiver_location = torch.tensor([[[10, 70], [10, 90]]], dtype=torch.long)
operator = tide.MaxwellTM( tide.Discretization( spacing=0.02, dt=dt, stencil=4, boundary=tide.CPML(12), ), tide.Experiment( tide.Acquisition(source_location, receiver_location), source, ), execution=tide.ExecutionOptions( fallback=tide.FallbackPolicy.REFERENCE, ),)
result = operator(model)print(result.receiver_data.shape) # torch.Size([400, 1, 2])ForwardResult.receiver_data is the quantity used by most workflows. ForwardResult.final_state contains the final padded wavefields and CPML state, which can be passed back to lower-level continuation workflows when needed.
Operators are reusable
Section titled “Operators are reusable”A MaxwellTM or Maxwell3D instance contains no trainable material parameters. Reuse it with different EMModel values:
background = operator(model)
perturbed = tide.EMModel( epsilon=model.epsilon * 1.05, sigma=model.sigma, mu=model.mu,)changed = operator(perturbed)Reusing the operator makes the fixed experiment visible in code and avoids coupling optimization state to propagation configuration.
Explicit derivatives
Section titled “Explicit derivatives”operator.linearize(model) fixes the point at which derivatives are evaluated. The returned session provides:
direction = tide.EMDirection( epsilon=torch.ones_like(model.epsilon),)
with operator.linearize(model) as linearized: born_data = linearized.jvp(direction).receiver_data gradient = linearized.vjp(torch.ones_like(linearized.primal.receiver_data))
print(born_data.shape)print(gradient.epsilon.shape)Use a context manager. A derivative session may own forward snapshots, host buffers, or temporary files, and with guarantees deterministic release.
Standard autograd still works
Section titled “Standard autograd still works”For a scalar objective, ordinary PyTorch code is often shortest:
epsilon = model.epsilon.clone().requires_grad_(True)trial = tide.EMModel(epsilon, model.sigma, model.mu)predicted = operator(trial).receiver_dataloss = predicted.square().mean()loss.backward()print(epsilon.grad.shape)Use explicit jvp, vjp, and second_vjp when implementing linearized imaging, Gauss-Newton, Hessian-vector products, or derivative tests. Use standard autograd when a scalar loss and model gradient are sufficient.
Backend policy is explicit
Section titled “Backend policy is explicit”BackendPreference.AUTO selects a supported native implementation when available. FallbackPolicy.REFERENCE permits a compatible Python path. FallbackPolicy.ERROR turns unsupported combinations into an immediate error. No solver-specific silent fallback is intended.
Before a large run, inspect backend availability and verify the exact combination of dimension, dtype, device, storage mode, derivative operation, and callback use that the run requires.
Continue reading
Section titled “Continue reading”- Modeling explains units, resolution, and model construction.
- Maxwell operators documents the structured forward and derivative contracts.
- Storage explains snapshot lifetime and memory trade-offs.
- Workflow covers shot batching and receiver objectives.