Skip to content

Fix and update AdaptiveSDE benchmarks (#126)#1605

Open
jitendravjh wants to merge 5 commits into
SciML:masterfrom
jitendravjh:fix-adaptivesde-benchmarks
Open

Fix and update AdaptiveSDE benchmarks (#126)#1605
jitendravjh wants to merge 5 commits into
SciML:masterfrom
jitendravjh:fix-adaptivesde-benchmarks

Conversation

@jitendravjh

@jitendravjh jitendravjh commented Jun 29, 2026

Copy link
Copy Markdown

Fixes #126. This is the AdaptiveSDE small-grant work (declared in SciML/sciml.ai#242).

The benchmarks weren't building. The main blocker was the manual Distributed parallelism (addprocs/@everywhere/ParallelDataTransfer.sendto), which Weave can't run, plus some bitrot against the current interfaces. Both files now use EnsembleProblem + EnsembleThreads() and weave cleanly.

A few things changed along the way. Dropped DiffEqMonteCarlo (the Monte Carlo runs go through EnsembleProblem now) and the unused Distributed/ParallelDataTransfer. Renamed calculate_monte_errors to calculate_ensemble_errors (fields unchanged) and added DiffEqBase as a dep. Fixed the keyword drift too, maxIters became maxiters, and I kept SciMLLogging.None() since a Bool verbose isn't accepted anymore. Also moved to ctx.sim_id for per-trajectory seeding and sol.u[i] for indexing. And there was a small existing bug in qmaxDetermination where the "other problems" loop was re-running problem 1 instead of probs[k], that's fixed now. Project.toml/Manifest.toml are updated to match.

I validated both files by weaving them locally at reduced and medium scale (Ns=[5,5,5], 200 trajectories, full qmax sweep). No errors, and the plots regenerate fine.

One thing to flag, the qmax-on-Oval2 runs all hit DtLessThanMin across the whole sweep (SRIW1 at abstol=2^-15 on Oval2). This matches the original solve settings so the port is faithful, but that section won't show qmax differentiation as-is, happy to relax the tolerances there if you'd prefer.

Modernize the AdaptiveSDE benchmark set so it builds under the current
SciML interfaces and the Weave build server.

- Replace manual Distributed parallelism (addprocs/@everywhere/
  ParallelDataTransfer.sendto) with multithreaded EnsembleProblem +
  EnsembleThreads(), which Weave can execute.
- Drop the removed DiffEqMonteCarlo dependency; the Monte Carlo runs now
  use the standard EnsembleProblem interface.
- Rename DiffEqBase.calculate_monte_errors -> calculate_ensemble_errors
  (error_means/error_medians/elapsedTime fields are unchanged) and add
  DiffEqBase as a direct dependency.
- Fix solver keyword drift: maxIters -> maxiters; keep SciMLLogging.None()
  for verbosity (Bool verbose is no longer supported).
- Use ctx.sim_id (EnsembleContext) for per-trajectory seeding and index
  trajectories via sol.u[i] rather than the flattened sol[i].
- qmaxDetermination: the 'other problems' loop now builds the ensemble
  from probs[k] instead of always re-running problem 1.
- Update Project.toml/Manifest.toml: add DiffEqBase, drop unused
  Distributed/ParallelDataTransfer, refresh the manifest.
@jitendravjh

jitendravjh commented Jul 1, 2026

Copy link
Copy Markdown
Author

@ChrisRackauckas the CI run for benchmarks/AdaptiveSDE timed out at 24h. It's not a build error, both files weave fine locally at reduced scale. It's just the workload, AdaptiveEfficiencyTests runs 1000 trajectories × up to 23 tolerance levels (down to abstol=2^-24) × 3 RSwM algorithms × 3 problems, so it doesn't finish in 24h even with EnsembleThreads() across all cores. The scale is inherited from the original, and the port itself is faster than the old addprocs(2) version.

Could you let me know what runtime limit or parameter scale you'd want here, trajectories, length of the Ns tolerance sweep, and num_runs for qmax? I'll dial it down to something that completes. Or if you'd rather keep full scale on dedicated infra with a longer time limit, that works too.

Let me know if you have any thoughts, happy to iterate further on your suggestions.

@AdityaPandeyCN

Copy link
Copy Markdown
Contributor

Did the runner actually pick up this benchmark? Iterations are never a problem as they are expected to run for longer duration. If it timed out because no runner picked it(which looks like the case here) you will have to wait

@jitendravjh

Copy link
Copy Markdown
Author

Thanks @AdityaPandeyCN, so it's runner availability, not the workload. I'll keep the parameters at full scale then. Happy to wait for a runner to pick it up.

@ChrisRackauckas

Copy link
Copy Markdown
Member
k was 1. The number of Adaptive Fails is 9999. Elapsed time was 8.332477595
k was 2. The number of Adaptive Fails is 9999. Elapsed time was 2.586814747
k was 3. The number of Adaptive Fails is 9999. Elapsed time was 4.142193076
k was 4. The number of Adaptive Fails is 9999. Elapsed time was 4.583869417
k was 5. The number of Adaptive Fails is 9999. Elapsed time was 4.014884734
k was 6. The number of Adaptive Fails is 9999. Elapsed time was 1.686423312
k was 7. The number of Adaptive Fails is 9999. Elapsed time was 5.934806418
k was 8. The number of Adaptive Fails is 9999. Elapsed time was 2.646599562

@jitendravjh

Copy link
Copy Markdown
Author

Thanks. I looked into it and the fails are flat across qmax in every configuration I tried, so the section can't determine a qmax as written. Loosening the tolerance or largeFluctuations=false makes it solvable (0 fails), but fails and times stay flat across all 8 qmax. Stiff solvers (ImplicitEM, ImplicitRKMil, STrapezoid) solve it cleanly with times still flat, even at 2^-16.

How do you want to handle it: drop the oval2 qmax section, swap in a problem or solver where qmax actually matters, or change the metric?

@ChrisRackauckas

Copy link
Copy Markdown
Member

It should be in the new controller setup arguments.

The qmax solve keyword is inert for SRIW1 in the current stack: StochasticDiffEqCore's
solve accepts qmax but does not forward it to the integrator, so every qmax value gave
identical results. Set qmax on the step-size controller instead.

Pass controller = PIController(SRIW1(); qmax = q) in both the Oval2 and the other-problems
sweeps. PIController(SRIW1(); qmax = qmax_default(SRIW1())) reproduces SRIW1's default
stepping exactly, so this varies only qmax. Add OrdinaryDiffEqCore to deps for PIController.
@jitendravjh

Copy link
Copy Markdown
Author

Done, routed qmax through the controller in both sweeps.

On the Oval2 test though, it still fails ~100% across all qmax. Should I leave it as-is, or swap it for a solver/tolerance that completes?

@ChrisRackauckas

Copy link
Copy Markdown
Member

Why does it fail? If you remove the try/catch stuff, what is it saying?

@jitendravjh

Copy link
Copy Markdown
Author

No try/catch, just verbose = SciMLLogging.None().
dt(2.220446049250313e-16) <= dtmin(2.220446049250313e-16) at t=0.006961747059462434. Aborting. There is either an error in your model specification or the true solution is unstable.

@ChrisRackauckas

Copy link
Copy Markdown
Member

It shouldn't be failing like that?

@jitendravjh

Copy link
Copy Markdown
Author

Right, it's the solver not the problem. SRIW1 collapses dt to eps on large-fluctuation oval2 at any tolerance (even 0.1), and fixed dt needs dt <= 1/2^16 to stay stable, so it's stability not accuracy. SOSRI and SRA3 solve it fine, and with SOSRI the qmax sweep actually differentiates: 0 fails at qmax=1.03 up to 43/50 at qmax=5.

Oval2 with large fluctuations is a stiff SDE with a tight stability region, so
SRIW1 (not stability-optimized) collapses its step size to eps and fails ~100%
at any tolerance, leaving the qmax sweep with no signal. SOSRI solves it, and
the sweep now differentiates (0 fails at qmax around 1.03, degrading as qmax
grows). Tolerances abstol=2^-13, reltol=2^-7 match the StiffSDE Oval2 benchmarks.
@jitendravjh

Copy link
Copy Markdown
Author

Swapped the Oval2 test to SOSRI, qmax curve is clean now.

@ChrisRackauckas

Copy link
Copy Markdown
Member

There are a bunch of adaptive failures. See an old version to see what you should be getting when it's corrected.

https://github.com/SciML/SciMLBenchmarks.jl/blob/70f4f23bc27fb0408510f565397d624e88cb21d4/pdf/AdaptiveSDE/qmaxDetermination.pdf

Also, the figures of the other one need to transpose the labels to fix the plot legend.

…erance

- AdaptiveEfficiencyTests.jmd: make the RSwM1/2/3 legend a row vector so Plots
  maps each label to the correct curve (fixes the mislabeled plot legend).
- qmaxDetermination.jmd: use the reference abstol=2^-15, reltol=2^-10 for the
  Oval2 qmax sweep (matches the original benchmark).
@jitendravjh

Copy link
Copy Markdown
Author

Transposed the labels on AdaptiveEfficiencyTests, the legend maps correctly now. Moved the Oval2 qmax test to the reference tolerance (2^-15/2^-10), which cuts the failures down a lot but not to zero. From what I can tell this is an upstream regression, SRIW1 solved oval2 with 0 fails in 2019 but fails 100% now, and SOSRI is the closest current solver.
Any idea what changed?

@ChrisRackauckas

Copy link
Copy Markdown
Member

The time stepper is probably very different from before, so it might need to be tuned.

The current adaptive stepper is more aggressive than the 2019 reference, so the
default safety factor (gamma=0.9) overshoots and fails a large fraction of paths
at high qmax. Setting gamma=0.7 in the PIController gives 0 adaptive failures
across the whole qmax sweep (verified at 100 trajectories/qmax), matching the
reference output, with the qmax signal carried by the timing.
@jitendravjh

Copy link
Copy Markdown
Author

That did it. Dropping the controller safety factor to gamma=0.7 gets 0 fails across the whole qmax sweep now, matching the reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix AdaptiveSDE benchmarks

3 participants