Solo project · JOSS paper submitted
Sim-Debugger
Conservation-law monitoring for numerical simulations
Sim-Debugger instruments a simulation, monitors invariants during the run, and reports failures in physics language rather than vague generic debugging output.
Why conservation law monitoring matters
Numerical simulations of physical systems should preserve the invariants implied by the underlying model. Total energy, momentum, charge, and similar quantities are often the first place a broken integrator or missing term will reveal itself.
Traditional debugging tools do not really help with that. They can tell you where time was spent or what a variable was at one instant, but not when the simulation stopped respecting the physics it was supposed to represent.
How the tool hooks into a simulation
The idea is to wrap an existing simulation loop with monitors instead of rewriting the simulation from scratch. Users register invariants, run the program, and let the tool track how those quantities move as the state evolves.
That structure makes the tool useful across different domains. A particle pusher, an N-body simulation, or a fluid code can all expose the quantities that matter and let Sim-Debugger watch for the moment they start drifting.
import numpy as np
from sim_debugger import monitor, invariant
@invariant("total_energy")
def energy(state):
v = state["velocity"]
return 0.5 * state["mass"] * np.dot(v, v)
@monitor(dt=0.01, steps=50000)
def boris_step(state, E, B, dt):
q, m = state["charge"], state["mass"]
v_minus = state["velocity"] + (q * dt / (2 * m)) * E
t = (q * dt / (2 * m)) * B
s = 2 * t / (1 + np.dot(t, t))
v_prime = v_minus + np.cross(v_minus, t)
v_plus = v_minus + np.cross(v_prime, s)
state["velocity"] = v_plus + (q * dt / (2 * m)) * E
state["position"] += state["velocity"] * dt
return stateOutput
The output speaks to the language of the simulation author. Instead of saying a scalar changed, it says that total energy drifted by a certain amount, when that drift became noticeable, and what kind of numerical mistake the pattern is consistent with.
$ sim-debugger run boris_pusher.py --dt 0.01 --steps 50000 [sim-debugger] Initial energy: 4.500000e+02 J [step 10000] total_energy: 4.500013e+02 J (+0.0003%) [step 20000] total_energy: 4.500028e+02 J (+0.0006%) [step 30000] total_energy: 4.500891e+02 J (+0.020%) [step 40000] total_energy: 4.518700e+02 J (+0.416%) VIOLATION DETECTED at step 40000 Quantity: total energy Drift: +0.416% over 40,000 steps Onset: step ~28,000 Likely cause: E-field coupling introduces secular energy error at large |E|*dt. Suggestion: reduce dt in high-field regions
Importance to me
Sim-Debugger captures the part of my work that is most concerned with trust in scientific computation. It is not enough for a simulation to run. It has to remain physically meaningful, and the tooling around it should make that easy to inspect.