Skip to content

Migrate showcase docs to v8 sub-package syntax (HOLD: waits on AdvancedHMC OrdinaryDiffEq v7 compat)#338

Merged
ChrisRackauckas merged 6 commits into
SciML:mainfrom
ChrisRackauckas-Claude:refactor/de-v8-migration
May 12, 2026
Merged

Migrate showcase docs to v8 sub-package syntax (HOLD: waits on AdvancedHMC OrdinaryDiffEq v7 compat)#338
ChrisRackauckas merged 6 commits into
SciML:mainfrom
ChrisRackauckas-Claude:refactor/de-v8-migration

Conversation

@ChrisRackauckas-Claude
Copy link
Copy Markdown

Please ignore until reviewed by @ChrisRackauckas.

This is the follow-up to #337 (which only patched the SDE block to unblock the build). The previous fix kept import DifferentialEquations as DE everywhere; that pattern still works only as long as Pkg picks OrdinaryDiffEq v6 (which re-exports every algorithm). As soon as the resolver selects OrdinaryDiffEq v7 — which dramatically trims its umbrella exports to just Tsit5, Vern6-9, Rosenbrock23, Rodas5P, FBDF — the docs break for DE.RK4, DE.ROCK2, DE.TRBDF2, etc. This PR migrates the showcase code to the v8-friendly per-sub-package pattern that DiffEqDocs uses.

Summary

  • import DifferentialEquations as DEimport OrdinaryDiffEq as ODE across every executable showcase that previously used the umbrella alias.
  • Algorithms that the trimmed v7 OrdinaryDiffEq no longer re-exports are imported from the matching sub-package:
    • RK4OrdinaryDiffEqLowOrderRK.RK4 (docs/src/showcase/ode_types.md)
    • ROCK2OrdinaryDiffEqStabilizedRK.ROCK2 (docs/src/showcase/gpu_spde.md)
  • Items that live only in SciMLBase (and weren't using-imported into OrdinaryDiffEq) are accessed through an explicit import SciMLBase:
    • EnsembleProblem, EnsembleThreads, terminate! in docs/src/showcase/optimization_under_uncertainty.md
  • docs/Project.toml:
    • Pinned DifferentialEquations = "8" (was "7, 8") and OrdinaryDiffEq = "6.111, 7".
    • Added OrdinaryDiffEqLowOrderRK = "1, 2" and OrdinaryDiffEqStabilizedRK = "1, 2".

Files touched (code, not prose):

  • docs/src/getting_started/first_simulation.md
  • docs/src/getting_started/fit_simulation.md
  • docs/src/showcase/bayesian_neural_ode.md
  • docs/src/showcase/gpu_spde.md
  • docs/src/showcase/ode_types.md
  • docs/src/showcase/optimization_under_uncertainty.md

missing_physics.md, blackhole.md, massively_parallel_gpu.md, brusselator.md, symbolic_analysis.md already used import OrdinaryDiffEq as ODE and didn't need migration.

Status — hold for upstream

Local verification: a fresh env on the new docs/Project.toml resolves to DifferentialEquations 8.0.0, OrdinaryDiffEq 6.111.0, SciMLBase 2.155.1. A verify.jl script that mirrors each migrated import block + first solve call passes. Full Documenter build was not run end-to-end locally (CI build time on the GPU runner is ~1h40m); the validation here is the import + solve smoke test.

The reason this resolves to OrdinaryDiffEq 6.111 rather than the trimmed 7.x is AdvancedHMC 0.8 still pinning OrdinaryDiffEq to 6.0 - 6.111. So this PR's compat allows the trimmed v7 but the resolver can't pick it until upstream loosens. This PR is intentionally drafted to wait for:

  • AdvancedHMC: relax OrdinaryDiffEq upper bound to allow v7.
  • Anything else surfaced when AdvancedHMC unblocks (likely a cascade of compat bumps in DataDrivenDiffEq, NeuralPDE, ModelingToolkitNeuralNets — to be discovered once the first blocker lifts).

Once upstream releases land, CompatHelper / a manual Pkg.update should resolve to OrdinaryDiffEq 7.x and the v8 sub-package style in this PR will be the only thing keeping the build green.

Test plan

  • Documentation CI is green on the GPU runner.
  • After upstream OrdinaryDiffEq 7.x resolution becomes possible, re-run CI to confirm the trimmed-v7 path also builds.

DifferentialEquations.jl v8 only re-exports SciMLBase + OrdinaryDiffEq,
and OrdinaryDiffEq v7 trims its umbrella exports to Tsit5/Vern6-9/
Rosenbrock23/Rodas5P/FBDF only. The remaining `import DifferentialEquations
as DE` callsites that touched RK4/ROCK2/etc would silently break the
moment the resolver picks OrdinaryDiffEq v7. Migrate every executable
showcase to the per-sub-package idiom DiffEqDocs already uses:

  - import OrdinaryDiffEq as ODE for umbrella ODE algorithms
  - import OrdinaryDiffEqLowOrderRK for RK4
  - import OrdinaryDiffEqStabilizedRK for ROCK2
  - import StochasticDiffEq as SDE for SRIW1 (already done in SciML#337)
  - import SciMLBase for EnsembleProblem/EnsembleThreads/terminate!
    (these aren't in OrdinaryDiffEq's `using SciMLBase: ...` list)

docs/Project.toml pins DifferentialEquations to "8" and OrdinaryDiffEq
to "6.111, 7" so the resolver is allowed to pick the trimmed v7 once
upstream blockers (currently AdvancedHMC 0.8 capping at v6.111) lift.
The two new sub-packages are added with compat "1, 2".

Verified locally: a fresh env on the new Project.toml resolves
DE 8.0.0 + OrdinaryDiffEq 6.111.0 + SciMLBase 2.155.1, and a smoke
test mirroring each migrated import block + first solve call passes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude
Copy link
Copy Markdown
Author

Status update — AdvancedHMC blocker cleared, next blocker is StochasticDiffEq.

Re-resolved on this branch with JuliaRegistries/General#155178 merged (AdvancedHMC v0.8.4, which dropped the OrdinaryDiffEq umbrella dep in favor of just OrdinaryDiffEqSymplecticRK):

[0bf59076] AdvancedHMC v0.8.4         ← unblocked
[0c46a032] DifferentialEquations v8.0.0
⌃ [1dea7af3] OrdinaryDiffEq v6.111.0  ← still capped
⌅ [1344f307] OrdinaryDiffEqLowOrderRK v1.13.0
⌅ [358294b1] OrdinaryDiffEqStabilizedRK v1.11.1
⌅ [789caeaf] StochasticDiffEq v6.102.0

Forcing Pkg.add(name="OrdinaryDiffEq", version="7") now surfaces a different cycle:

DiffEqBase [2b5f629d] log:
 ├─restricted by OrdinaryDiffEqRosenbrock 2.x  → DiffEqBase 7.x
 └─restricted by StochasticDiffEq 6.154 - 6.218 → DiffEqBase < 7   ← conflict

i.e. once OrdinaryDiffEq moves to v7, OrdinaryDiffEqRosenbrock v2 demands DiffEqBase v7, but every registered StochasticDiffEq v6.x (including 6.102) still caps DiffEqBase at v6.x. The latest StochasticDiffEq master is still 6.100, so this needs an upstream release — either a v7 with the OrdinaryDiffEq v7 / DiffEqBase v7 ecosystem, or a 6.x patch that loosens the DiffEqBase upper bound.

Holding this PR until SciML/StochasticDiffEq.jl ships that release, then re-running the resolver will tell us whether anything else surfaces.

Upstream is now unblocked (AdvancedHMC 0.8.4 dropped the OrdinaryDiffEq
umbrella dep, StochasticDiffEq 7.0.0 is registered with the DiffEqBase 7
ecosystem). Resolution now cleanly yields:

  OrdinaryDiffEq 7.0.0, OrdinaryDiffEqLowOrderRK 2.1.0,
  OrdinaryDiffEqStabilizedRK 2.1.0, StochasticDiffEq 7.0.0,
  SciMLBase 3.9.1, DiffEqBase 7.3.0, AdvancedHMC 0.8.4,
  DifferentialEquations 8.0.0.

- Pin OrdinaryDiffEq = "7" and StochasticDiffEq = "7" so the resolver
  must land on the trimmed v7 stack the migration was designed for.
- Revert the prob_func arity in the two showcase EnsembleProblem
  examples to the 2-arg `(prob, ctx)` form. SciMLBase v3 calls
  prob_func with `(prob, ctx::EnsembleContext)`; the earlier
  `(prob, i, repeat)` form (added in SciML#337 against SciMLBase v2.x) now
  errors as MethodError. The closures don't read i/repeat, so just
  taking `ctx` (and `ctx.sim_id` / `ctx.repeat` when needed) is
  forward-compatible.

Verified locally on the v7 stack: smoke-test mirroring each migrated
import block + first solve call passes, including the EnsembleProblem
path.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude
Copy link
Copy Markdown
Author

Status: unblocked. Pushed 0db86cd.

StochasticDiffEq v7.0.0 was already registered — I had StochasticDiffEq = "6" in the compat which was excluding it. With StochasticDiffEq = "7" (and OrdinaryDiffEq = "7"), the resolver lands on the full v7/v8 stack:

[0bf59076] AdvancedHMC v0.8.4
[0c46a032] DifferentialEquations v8.0.0
[1dea7af3] OrdinaryDiffEq v7.0.0
[1344f307] OrdinaryDiffEqLowOrderRK v2.1.0
[358294b1] OrdinaryDiffEqStabilizedRK v2.1.0
[789caeaf] StochasticDiffEq v7.0.0
[0bca4576] SciMLBase v3.9.1
[2b5f629d] DiffEqBase v7.3.0
[bbf590c4] OrdinaryDiffEqCore v4.1.0

Verifying against the v7 stack surfaced a second wrinkle: SciMLBase v3 changed the prob_func signature to a single 2-arg form prob_func(prob, ctx::EnsembleContext) (with ctx.sim_id / ctx.repeat for what used to be i / repeat). The source comment says explicitly "single 2-arg form, no arity detection needed." The (prob, i, repeat) shape that #337 used was correct for SciMLBase v2, but errors as a MethodError on v3.

So this PR also reverts the two showcase prob_func definitions back to (prob, ctx):

  • docs/src/showcase/massively_parallel_gpu.md (the original closure already had (prob, ctx); this PR returns to that)
  • docs/src/showcase/optimization_under_uncertainty.md (same)

Neither callsite reads i or repeat, so just naming the second argument ctx is enough — no field accesses needed. Local smoke test against the pinned v7 stack passes (ODE, RK4 from OrdinaryDiffEqLowOrderRK, ROCK2 from OrdinaryDiffEqStabilizedRK, SRIW1 from StochasticDiffEq, ContinuousCallback, CallbackSet, SciMLBase.terminate!, SciMLBase.EnsembleProblem + EnsembleThreads, ODE.remake).

Ready for CI / review.

@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review May 11, 2026 13:48
CI on the v7/v8 stack surfaced four more cases that were latent under
the old v6 umbrella:

- blackhole.md uses ODE.RK4() in eight places. RK4 is no longer in
  OrdinaryDiffEq v7's umbrella exports; switch to the sub-package
  OrdinaryDiffEqLowOrderRK.RK4 (already added to Project.toml).
- brusselator.md uses ODE.TRBDF2() in five places. Same story —
  TRBDF2 moved to OrdinaryDiffEqSDIRK. Add OrdinaryDiffEqSDIRK to
  docs/Project.toml ([deps] + [compat]) and route the callsites to it.
- gpu_spde.md plots via sol[end][:, :, k]. SciMLBase v3's
  ODESolution.getindex is scalar (returns the i-th element of the
  flattened state, here a Float64), not the full state vector at time
  index i. The supported way to get the final state is sol.u[end].
- optimization_under_uncertainty.md does `import SciMLBase` for
  EnsembleProblem / EnsembleThreads / terminate! but SciMLBase was not
  a direct dep of docs/Project.toml, so Documenter raised
  `Package SciMLBase not found in current path`. Add it ([deps] +
  [compat = "3"]).

Verified locally on the same pinned v7/v8 env: RK4 / TRBDF2 / ROCK2
load from their sub-packages, `sol.u[end]` returns the (2,2,3) array
on a 3D-state problem, and the full smoke test still passes.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
…emble iter

Another round of v3 API drift surfaced in the last CI run:

- OptimizationSolution.minimizer was removed in SciMLBase v3 — the
  solution vector is now in .u. blackhole.md was using .u for res1
  but still had .minimizer for res2 in two places; align both to .u.
- Plot recipes drop the legacy `vars` keyword in favor of `idxs`.
  ODESolution recipe still tolerates `vars`, but EnsembleSolution's
  recipe raises `BoundsError ... at index [1, 2, 1]` because it
  re-dispatches to a scalar getindex path on the inner solutions.
  Switch `vars = (1, 3)` → `idxs = (1, 3)` in optimization_under_
  uncertainty.md (×9) and `vars = MTK.unknowns(traced_sys)` →
  `idxs = MTK.unknowns(traced_sys)` in symbolic_analysis.md (×3).
- EnsembleSolution iteration semantics in v3 now flatten to scalars,
  so `for sol in ensemblesol` yields `::Float64`, not `::ODESolution`,
  and `sol[3, end]` errors as `BoundsError: ... attempt to access
  Float64 at index [3, 1]`. Iterate `ensemblesol.u` to recover the
  per-trajectory ODESolutions.

No `@test_broken` / tolerance loosening. Local smoke test still passes
on the same pinned v7/v8 stack.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
The Plots recipe for AbstractEnsembleSolution in SciMLBase v3 uses
`trajectories = eachindex(sim)` as its default trajectory iterator,
but `eachindex(::EnsembleSolution)` in v3 returns the 3-D
CartesianIndices over the flattened (state × time × trajectory)
representation. The recipe then does `sim.u[i]` with that 3-D index,
which errors as `BoundsError: ... at index [1, 2, 1]` against the
underlying `Vector{ODESolution}`.

Pass `trajectories = 1:length(ensemblesol.u)` explicitly to all four
EnsembleSolution plot calls in `optimization_under_uncertainty.md` so
the recipe gets a flat trajectory range and skips the buggy default.

Reproduced and verified locally: the default kwarg raises BoundsError,
the explicit form plots cleanly.

This is a workaround for an upstream SciMLBase v3 recipe bug that
should also be fixed upstream (filing follow-up there).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude
Copy link
Copy Markdown
Author

Pushed 9be3f3f. Next round of v3 fallout from the CI run:

  1. OptimizationSolution .minimizer.u (×2) — fixed in `blackhole.md`.
  2. Plot recipe varsidxs (×12) — fixed in `optimization_under_uncertainty.md` (×9) and `symbolic_analysis.md` (×3).
  3. EnsembleSolution iteration is now scalar-flat in v3 — `for sol in ensemblesol` yields `::Float64` instead of `::ODESolution`. Fixed by iterating `ensemblesol.u` (`Vector{ODESolution}`).
  4. EnsembleSolution Plot recipe broken under v3 — `trajectories = eachindex(sim)` in SciMLBase.jl/.../ensemble_solutions.jl#L229 returns 3-D `CartesianIndices((nstate, ntime, ntraj))` under v3 so the recipe errors `BoundsError ... at index [1, 2, 1]` when it then does `sim.u[i]`. Pass `trajectories = 1:length(ensemblesol.u)` explicitly to all four EnsembleSolution `Plots.plot` calls as a workaround. Upstream fix tracked at SciML/SciMLBase.jl#1354 (one-line change: `eachindex(sim)` → `eachindex(sim.u)`); the workaround can be removed once a v3 SciMLBase release lands with it.

Verified locally with the same pinned v7/v8 env: `Plots.plot(esol)` with the recipe default raises `BoundsError`, the explicit-trajectories form plots cleanly.

@ChrisRackauckas ChrisRackauckas merged commit 15c9bea into SciML:main May 12, 2026
2 of 4 checks passed
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.

2 participants