Skip to content

Differentiate the PDE solution interface in reverse mode - #698

Draft
utkuyilmaz1903 wants to merge 1 commit into
SciML:masterfrom
utkuyilmaz1903:solution-interface-ad
Draft

utkuyilmaz1903 wants to merge 1 commit into
SciML:masterfrom
utkuyilmaz1903:solution-interface-ad

Conversation

@utkuyilmaz1903

@utkuyilmaz1903 utkuyilmaz1903 commented Sep 13, 2026 •

Copy link
Copy Markdown
Member

Implements the reverse-mode hooks of SciML/SciMLBase.jl#1630 for MOL, in place of the ChainRules rules this PR first added here. Depends on that PR: the SciMLBase compat is bumped to 3.59, so CI resolves once that release is out.

The hooks map a cotangent of sol[u(t, x)] or sol(t, x; dv) back to the solver's solution, for time-dependent and stationary solutions. A grid point that is an unknown takes its share from the state vector by index, and the observed ones, such as eliminated boundary points, go through one observed function of all of them, the way #718 builds the wrapper. On a 21×21 compiled grid that makes a Zygote gradient 4x faster than going through the observed function of the whole field, and Mooncake no longer overflows the stack there. An interpolated value goes to the corners of its cell, and the call hook also returns the coordinate cotangents.

test/SolutionAD (lts, 1) checks fields, slices, repeated indices, interpolation at points and lines, coordinates, a time-last field and parameters in observed boundary values against ForwardDiff:

Zygote Mooncake
DAE path ✓ ✓
compiled ODE path ✓ ✓
stationary ✓ ✓
complex-valued fields error

Under Mooncake, parameters set with setp_oop need SciML/ModelingToolkit.jl#5288. With it the neural network tutorial trains with Mooncake through sol[u(t, x)], so the docs move from Zygote to Mooncake once it is released. Enzyme is blocked by EnzymeAD/Enzyme.jl#3855.

@utkuyilmaz1903
utkuyilmaz1903 marked this pull request as ready for review September 28, 2026 15:14
Comment thread src/interface/solution/chainrules.jl Outdated
Comment on lines +158 to +185
function ChainRulesCore.rrule(
config::ChainRulesCore.RuleConfig{>:ChainRulesCore.HasReverseMode},
A::SciMLBase.PDETimeSeriesSolution{T, N, S, D},
args::Vararg{Union{Num, Number, AbstractArray, Colon}}; dv = nothing
) where {T, N, S, D <: MOLMetadata}
y = A(args...; dv)
Δargs = map(_ -> NoTangent(), args)
function call_pullback(Δ)
Δ = unthunk(Δ)
Δ isa AbstractZero && return (NoTangent(), Δargs...)
Δsol = NoTangent()
if dv === nothing
grid_args = _grid_args(A, args)
for (dvi, Δi) in zip(A.dvs, Δ)
(Δi === nothing || Δi isa AbstractZero) && continue
Δsol = Δsol + interpolation_cotangent(
config, A, dvi, _dv_args(A, dvi, grid_args), Δi
)
end
else
cdv = indexed_dependent_variable(A, dv)
cdv === nothing && throw(not_implemented(dv))
Δsol = interpolation_cotangent(config, A, cdv, _grid_args(A, args, cdv), Δ)
end
return (Tangent{typeof(A)}(; original_sol = Δsol), Δargs...)
end
return y, call_pullback
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is piracy. Also, it hits more pieces. How does this do with NeuralPDE.jl's solution?

@utkuyilmaz1903

Copy link
Copy Markdown
Member Author

Moving the rules up behind a hook as discussed on Slack; will revisit this PR after that lands.

This branch has not been deployed

No deployments
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