From 92ad6a84de65ee99da3bdb008ea7c9b192485289 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Thu, 2 May 2024 16:13:48 +0530 Subject: [PATCH 01/25] feat: adjoints through observable functions --- ext/SciMLBaseZygoteExt.jl | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 1d2104cf4..c3b24d458 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -7,7 +7,7 @@ using SciMLBase using SciMLBase: ODESolution, remake, getobserved, build_solution, EnsembleSolution, NonlinearSolution, AbstractTimeseriesSolution -using SymbolicIndexingInterface: symbolic_type, NotSymbolic, variable_index +using SymbolicIndexingInterface: symbolic_type, NotSymbolic, variable_index, is_observed, observed, parameter_values using RecursiveArrayTools # This method resolves the ambiguity with the pullback defined in @@ -109,7 +109,15 @@ end @adjoint function Base.getindex(VA::ODESolution, sym) function ODESolution_getindex_pullback(Δ) i = symbolic_type(sym) != NotSymbolic() ? variable_index(VA, sym) : sym - if i === nothing + if is_observed(VA, sym) + y, back = Zygote.pullback(VA) do sol + f = observed(sol, sym) + p = parameter_values(sol) + f.(sol.u,Ref(p), sol.t) + end + gs = back(Δ) + (gs[1], nothing) + elseif i === nothing throw(error("Zygote AD of purely-symbolic slicing for observed quantities is not yet supported. Work around this by using `A[sym,i]` to access each element sequentially in the function being differentiated.")) else Δ′ = [[i == k ? Δ[j] : zero(x[1]) for k in 1:length(x)] @@ -122,6 +130,7 @@ end @adjoint function Base.getindex(VA::ODESolution{T}, sym::Union{Tuple, AbstractVector}) where T function ODESolution_getindex_pullback(Δ) + @show typeof(Δ) sym = sym isa Tuple ? collect(sym) : sym i = map(x -> symbolic_type(x) != NotSymbolic() ? variable_index(VA, x) : x, sym) if i === nothing @@ -182,15 +191,15 @@ end NonlinearSolution{T, N, uType, R, P, A, O, uType2}(u, args...), NonlinearSolutionAdjoint end -@adjoint function literal_getproperty(sol::AbstractTimeseriesSolution, - ::Val{:u}) - function solu_adjoint(Δ) - zerou = zero(sol.prob.u0) - _Δ = @. ifelse(Δ === nothing, (zerou,), Δ) - (build_solution(sol.prob, sol.alg, sol.t, _Δ),) - end - sol.u, solu_adjoint -end +# @adjoint function literal_getproperty(sol::AbstractTimeseriesSolution, +# ::Val{:u}) +# function solu_adjoint(Δ) +# zerou = zero(sol.prob.u0) +# _Δ = @. ifelse(Δ === nothing, (zerou,), Δ) +# (build_solution(sol.prob, sol.alg, sol.t, _Δ),) +# end +# sol.u, solu_adjoint +# end @adjoint function literal_getproperty(sol::SciMLBase.AbstractNoTimeSolution, ::Val{:u}) From 22dc7ecca9d897864f462b98f6b71edffdcda784 Mon Sep 17 00:00:00 2001 From: Dhairya Gandhi Date: Mon, 6 May 2024 19:33:23 +0530 Subject: [PATCH 02/25] Update ext/SciMLBaseZygoteExt.jl Co-authored-by: Christopher Rackauckas --- ext/SciMLBaseZygoteExt.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index c3b24d458..df2c4df97 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -130,7 +130,6 @@ end @adjoint function Base.getindex(VA::ODESolution{T}, sym::Union{Tuple, AbstractVector}) where T function ODESolution_getindex_pullback(Δ) - @show typeof(Δ) sym = sym isa Tuple ? collect(sym) : sym i = map(x -> symbolic_type(x) != NotSymbolic() ? variable_index(VA, x) : x, sym) if i === nothing From 0c2b69d92ca2baed6120bf38a6517bfe2b9ad256 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 8 May 2024 16:30:10 +0530 Subject: [PATCH 03/25] feat: allow observables in collections --- ext/SciMLBaseZygoteExt.jl | 50 ++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index df2c4df97..04d45baa4 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -128,25 +128,43 @@ end VA[sym], ODESolution_getindex_pullback end -@adjoint function Base.getindex(VA::ODESolution{T}, sym::Union{Tuple, AbstractVector}) where T +function obs_grads(VA, sym, obss_idx, Δ) + y, back = Zygote.pullback(VA) do sol + getindex.(Ref(sol), sym[obss_idx]) + end + Dprime = reduce(hcat, Δ) + Dobss = eachrow(Dprime[obss_idx, :]) + back(Dobss) +end + +function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where T + Δ′ = map(enumerate(VA.u)) do (t_idx, us) + map(enumerate(us)) do (u_idx, u) + if u_idx in i + idx = findfirst(isequal(u_idx), i) + Δ[t_idx][idx] + else + zero(T) + end + end + end + + ((u = Δ′,)) +end + +@adjoint function getindex(VA::ODESolution{T}, sym::Union{Tuple, AbstractVector}) where T function ODESolution_getindex_pullback(Δ) sym = sym isa Tuple ? collect(sym) : sym i = map(x -> symbolic_type(x) != NotSymbolic() ? variable_index(VA, x) : x, sym) - if i === nothing - throw(error("Zygote AD of purely-symbolic slicing for observed quantities is not yet supported. Work around this by using `A[sym,i]` to access each element sequentially in the function being differentiated.")) - else - Δ′ = map(enumerate(VA.u)) do (t_idx, us) - map(enumerate(us)) do (u_idx, u) - if u_idx in i - idx = findfirst(isequal(u_idx), i) - Δ[t_idx][idx] - else - zero(T) - end - end - end - (Δ′, nothing) - end + + obss_idx = findall(s -> is_observed(VA, s), sym) + not_obss_idx = setdiff(1:length(sym), obss_idx) + + gs_obs = obs_grads(VA, sym, obss_idx, Δ) + gs_not_obs = not_obs_grads(VA, sym, not_obss_idx, i, Δ) + + a = Zygote.accum(gs_obs[1], gs_not_obs) + (a, nothing) end VA[sym], ODESolution_getindex_pullback end From c61e08cc7a98b9afbd9d7d2fbdfe0360b179155d Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 8 May 2024 16:35:09 +0530 Subject: [PATCH 04/25] chore: handle no observables in collection --- ext/SciMLBaseZygoteExt.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 04d45baa4..fcea18ea8 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -137,6 +137,10 @@ function obs_grads(VA, sym, obss_idx, Δ) back(Dobss) end +function obs_grads(VA, sym, ::Nothing, Δ) + Zygote.nt_nothing(VA) +end + function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where T Δ′ = map(enumerate(VA.u)) do (t_idx, us) map(enumerate(us)) do (u_idx, u) @@ -149,7 +153,8 @@ function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where T end end - ((u = Δ′,)) + nt = Zygote.nt_nothing(VA) + (Zygote.accum(nt, (u = Δ′,))) end @adjoint function getindex(VA::ODESolution{T}, sym::Union{Tuple, AbstractVector}) where T @@ -160,7 +165,7 @@ end obss_idx = findall(s -> is_observed(VA, s), sym) not_obss_idx = setdiff(1:length(sym), obss_idx) - gs_obs = obs_grads(VA, sym, obss_idx, Δ) + gs_obs = obs_grads(VA, sym, isempty(obss_idx) ? nothing : obss_idx, Δ) gs_not_obs = not_obs_grads(VA, sym, not_obss_idx, i, Δ) a = Zygote.accum(gs_obs[1], gs_not_obs) From 8600a8db77ef9f73b5f3f24edc4564fcc1663401 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 8 May 2024 16:37:17 +0530 Subject: [PATCH 05/25] fix: typo --- ext/SciMLBaseZygoteExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index fcea18ea8..32ce18629 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -154,7 +154,7 @@ function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where T end nt = Zygote.nt_nothing(VA) - (Zygote.accum(nt, (u = Δ′,))) + Zygote.accum(nt, (u = Δ′,)) end @adjoint function getindex(VA::ODESolution{T}, sym::Union{Tuple, AbstractVector}) where T From 785b052f2b0c9934b08d418c33d44a32e1d3caf6 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Sun, 12 May 2024 23:58:04 +0530 Subject: [PATCH 06/25] test: add test for observable functions --- test/downstream/observables_autodiff.jl | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test/downstream/observables_autodiff.jl diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl new file mode 100644 index 000000000..e198bd703 --- /dev/null +++ b/test/downstream/observables_autodiff.jl @@ -0,0 +1,34 @@ +using ModelingToolkit, OrdinaryDiffEq +using Zygote + +@parameters σ ρ β +@variables x(t) y(t) z(t) w(t) + +eqs = [D(D(x)) ~ σ * (y - x), + D(y) ~ x * (ρ - z) - y, + D(z) ~ x * y - β * z, + w ~ x + y + z + 2 * β] + +@mtkbuild sys = ODESystem(eqs, t) + +u0 = [D(x) => 2.0, + x => 1.0, + y => 0.0, + z => 0.0] + +p = [σ => 28.0, + ρ => 10.0, + β => 8 / 3] + +tspan = (0.0, 100.0) +prob = ODEProblem(sys, u0, tspan, p, jac = true) +sol = solve(prob, Tsit5()) + +@testset "AutoDiff Observable Functions" begin + gs, = gradient(sol) do sol + sum(sol[sys.w]) + end + du_ = [0., 1., 1., 1.] + du = [du_ for _ = sol.u] + @test du == gs.u +end From adee4f08d9acd16c0582f5be046202d058574a48 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 13 May 2024 00:00:33 +0530 Subject: [PATCH 07/25] test: add AD testset --- test/runtests.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 5e0bed4c7..f5b3c2d22 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -110,6 +110,9 @@ end @time @safetestset "Partial Functions" begin include("downstream/partial_functions.jl") end + @time @safetestset "Autodiff Observable Functions" begin + include("downstream/observables_autodiff.jl") + end end if !is_APPVEYOR && (GROUP == "Downstream" || GROUP == "SymbolicIndexingInterface") From 2197a30253b3375ccac5895175f2765381593a6b Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Mon, 13 May 2024 06:55:24 -0400 Subject: [PATCH 08/25] Update test/downstream/observables_autodiff.jl --- test/downstream/observables_autodiff.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index e198bd703..5904cbdfc 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -1,5 +1,6 @@ using ModelingToolkit, OrdinaryDiffEq using Zygote +using ModelingToolkit: t_nounits as t, D_nounits as D @parameters σ ρ β @variables x(t) y(t) z(t) w(t) From 917201484b0d4966ce56079e8d0d1bd2494c81a1 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 15 May 2024 17:55:04 +0530 Subject: [PATCH 09/25] test: add a simple DAE example; disable till sensitivities are turned on --- test/downstream/observables_autodiff.jl | 100 ++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index 5904cbdfc..6aa1e1afe 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -33,3 +33,103 @@ sol = solve(prob, Tsit5()) du = [du_ for _ = sol.u] @test du == gs.u end + +# Lorenz + +@parameters σ ρ β +@variables x(t) y(t) z(t) + +eqs = [D(x) ~ σ * (y - x), + D(y) ~ x * (ρ - z) - y, + D(z) ~ x * y - β * z] + +@named lorenz1 = ODESystem(eqs, t) +@named lorenz2 = ODESystem(eqs, t) + +@parameters γ +@variables a(t) α(t) +connections = [0 ~ lorenz1.x + lorenz2.y + a * γ, + α ~ 2lorenz1.x + a * γ] +@mtkbuild sys = ODESystem(connections, t, [a, α], [γ], systems = [lorenz1, lorenz2]) + +u0 = [lorenz1.x => 1.0, + lorenz1.y => 0.0, + lorenz1.z => 0.0, + lorenz2.x => 0.0, + lorenz2.y => 1.0, + lorenz2.z => 0.0, + a => 2.0] + +p = [lorenz1.σ => 10.0, + lorenz1.ρ => 28.0, + lorenz1.β => 8 / 3, + lorenz2.σ => 10.0, + lorenz2.ρ => 28.0, + lorenz2.β => 8 / 3, + γ => 2.0] + +tspan = (0.0, 100.0) +prob = ODEProblem(sys, u0, tspan, p) +integ = init(prob, Rodas4()) +sol = solve(prob, Rodas4()) + +gt = reduce(hcat, sol[[sys.a, sys.α]]) .+ randn.() + +gs, = Zygote.gradient(sol) do sol + mean(abs.(sol[[sys.a, sys.α]] .- gt), dims = 2) +end + +# DAE + +using ModelingToolkit, OrdinaryDiffEq, Zygote +using ModelingToolkitStandardLibrary +import ModelingToolkitStandardLibrary as MSL +using SciMLStructures + +function create_model(; C₁ = 3e-5, C₂ = 1e-6) + @variables t + @named resistor1 = MSL.Electrical.Resistor(R = 5.0) + @named resistor2 = MSL.Electrical.Resistor(R = 2.0) + @named capacitor1 = MSL.Electrical.Capacitor(C = C₁) + @named capacitor2 = MSL.Electrical.Capacitor(C = C₂) + @named source = MSL.Electrical.Voltage() + @named input_signal = MSL.Blocks.Sine(frequency = 100.0) + @named ground = MSL.Electrical.Ground() + @named ampermeter = MSL.Electrical.CurrentSensor() + + eqs = [connect(input_signal.output, source.V) + connect(source.p, capacitor1.n, capacitor2.n) + connect(source.n, resistor1.p, resistor2.p, ground.g) + connect(resistor1.n, capacitor1.p, ampermeter.n) + connect(resistor2.n, capacitor2.p, ampermeter.p)] + + @named circuit_model = ODESystem(eqs, t, + systems = [ + resistor1, resistor2, capacitor1, capacitor2, + source, input_signal, ground, ampermeter, + ]) +end + +model = create_model() +sys = structural_simplify(model) + +prob = ODEProblem(sys, [], (0.0, 1.0)) +sol = solve(prob, Rodas4()) +pf = getp(sol, sys.resistor1.R) +mtkparams = SII.parameter_values(sol) +tunables, _, _ = SS.canonicalize(SS.Tunable(), mtkparams) +p_new = rand(length(tunables)) + +# @testset "Adjoints with DAE" begin +# gs_mtkp, gs_p_new = gradient(mtkparams, p_new) do p, new_tunables +# new_p = SciMLStructures.replace(SciMLStructures.Tunable(), p, new_tunables) +# new_prob = remake(prob, p = new_p) +# sol = solve(new_prob, Rodas4()) +# @show size(sol) +# # mean(abs.(sol[sys.ampermeter.i] .- gt)) +# sum(sol[sys.ampermeter.i]) +# end +# +# @test isnothing(gs_mtkp) +# @test length(gs_p_new) == length(p_new) +# end From 95cf416c0b7ff9f54ce8076d33fbe4ef0a1febb9 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Wed, 15 May 2024 18:14:39 +0530 Subject: [PATCH 10/25] test: add missing imports --- test/downstream/observables_autodiff.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index 6aa1e1afe..bfd96b85f 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -1,6 +1,8 @@ using ModelingToolkit, OrdinaryDiffEq using Zygote using ModelingToolkit: t_nounits as t, D_nounits as D +import SymbolicIndexingInterface as SII +import SciMLStructures as SS @parameters σ ρ β @variables x(t) y(t) z(t) w(t) From 4ce8257cdc4c8e12f0343ea73a434ad0a19e1f1d Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Thu, 16 May 2024 23:21:01 +0530 Subject: [PATCH 11/25] chore: format --- ext/SciMLBaseZygoteExt.jl | 9 +++++---- test/downstream/observables_autodiff.jl | 14 +++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index b8952f910..13eb86d13 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -7,7 +7,8 @@ using SciMLBase using SciMLBase: ODESolution, remake, getobserved, build_solution, EnsembleSolution, NonlinearSolution, AbstractTimeseriesSolution -using SymbolicIndexingInterface: symbolic_type, NotSymbolic, variable_index, is_observed, observed, parameter_values +using SymbolicIndexingInterface: symbolic_type, NotSymbolic, variable_index, is_observed, + observed, parameter_values using RecursiveArrayTools # This method resolves the ambiguity with the pullback defined in @@ -113,7 +114,7 @@ end y, back = Zygote.pullback(VA) do sol f = observed(sol, sym) p = parameter_values(sol) - f.(sol.u,Ref(p), sol.t) + f.(sol.u, Ref(p), sol.t) end gs = back(Δ) (gs[1], nothing) @@ -133,7 +134,7 @@ function obs_grads(VA, sym, obss_idx, Δ) getindex.(Ref(sol), sym[obss_idx]) end Dprime = reduce(hcat, Δ) - Dobss = eachrow(Dprime[obss_idx, :]) + Dobss = eachrow(Dprime[obss_idx, :]) back(Dobss) end @@ -141,7 +142,7 @@ function obs_grads(VA, sym, ::Nothing, Δ) Zygote.nt_nothing(VA) end -function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where T +function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where {T} Δ′ = map(enumerate(VA.u)) do (t_idx, us) map(enumerate(us)) do (u_idx, u) if u_idx in i diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index bfd96b85f..554b6e6f9 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -31,8 +31,8 @@ sol = solve(prob, Tsit5()) gs, = gradient(sol) do sol sum(sol[sys.w]) end - du_ = [0., 1., 1., 1.] - du = [du_ for _ = sol.u] + du_ = [0.0, 1.0, 1.0, 1.0] + du = [du_ for _ in sol.u] @test du == gs.u end @@ -100,15 +100,15 @@ function create_model(; C₁ = 3e-5, C₂ = 1e-6) @named ampermeter = MSL.Electrical.CurrentSensor() eqs = [connect(input_signal.output, source.V) - connect(source.p, capacitor1.n, capacitor2.n) - connect(source.n, resistor1.p, resistor2.p, ground.g) - connect(resistor1.n, capacitor1.p, ampermeter.n) - connect(resistor2.n, capacitor2.p, ampermeter.p)] + connect(source.p, capacitor1.n, capacitor2.n) + connect(source.n, resistor1.p, resistor2.p, ground.g) + connect(resistor1.n, capacitor1.p, ampermeter.n) + connect(resistor2.n, capacitor2.p, ampermeter.p)] @named circuit_model = ODESystem(eqs, t, systems = [ resistor1, resistor2, capacitor1, capacitor2, - source, input_signal, ground, ampermeter, + source, input_signal, ground, ampermeter ]) end From 839bd636afb100afd5a00f7224d88d33c47ad16f Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Thu, 16 May 2024 23:21:49 +0530 Subject: [PATCH 12/25] chore: rm unwanted adjoint --- ext/SciMLBaseZygoteExt.jl | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 13eb86d13..9624a227a 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -215,16 +215,6 @@ end NonlinearSolution{T, N, uType, R, P, A, O, uType2}(u, args...), NonlinearSolutionAdjoint end -# @adjoint function literal_getproperty(sol::AbstractTimeseriesSolution, -# ::Val{:u}) -# function solu_adjoint(Δ) -# zerou = zero(sol.prob.u0) -# _Δ = @. ifelse(Δ === nothing, (zerou,), Δ) -# (build_solution(sol.prob, sol.alg, sol.t, _Δ),) -# end -# sol.u, solu_adjoint -# end - @adjoint function literal_getproperty(sol::SciMLBase.AbstractNoTimeSolution, ::Val{:u}) function solu_adjoint(Δ) From 2474a8d3a1045cf5bf72dc2e6a43a06c3b0a965d Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Sat, 18 May 2024 20:51:22 +0530 Subject: [PATCH 13/25] test: check failures with SciMLSensitivity + SII --- test/runtests.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index f5b3c2d22..0a65e630e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,6 +3,10 @@ using SafeTestsets using Test using SciMLBase +# test with a different SciMLSensitivity branch to see full list of +# failures +Pkg.add(url = "https://github.com/SciML/SciMLSensitivity.jl", rev = "dg/ss") + # https://github.com/JuliaArrays/FillArrays.jl/pull/163 @test_broken isempty(detect_ambiguities(SciMLBase)) From f68cb05b74a1a7f68d499d74bce295fd11f5636b Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Sun, 19 May 2024 00:03:37 +0530 Subject: [PATCH 14/25] ci(SciMLSensitivity): checkout SII branch --- .github/workflows/Downstream.yml | 3 +++ test/runtests.jl | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Downstream.yml b/.github/workflows/Downstream.yml index 4bffe0379..210fb64d0 100644 --- a/.github/workflows/Downstream.yml +++ b/.github/workflows/Downstream.yml @@ -61,6 +61,9 @@ jobs: with: repository: ${{ matrix.package.user }}/${{ matrix.package.repo }} path: downstream + - name: Checkout SII branch if SciMLSensitivity + if: "contains(${{ matrix.package.repo }}, 'SciMLSensitivity.jl')" + run: git checkout dg/ss - name: Load this and run the downstream tests shell: julia --color=yes --project=downstream {0} run: | diff --git a/test/runtests.jl b/test/runtests.jl index 0a65e630e..f5b3c2d22 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,10 +3,6 @@ using SafeTestsets using Test using SciMLBase -# test with a different SciMLSensitivity branch to see full list of -# failures -Pkg.add(url = "https://github.com/SciML/SciMLSensitivity.jl", rev = "dg/ss") - # https://github.com/JuliaArrays/FillArrays.jl/pull/163 @test_broken isempty(detect_ambiguities(SciMLBase)) From 9ab29d940c80ec5f5aaf3be180d9fe66cbeaa63b Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Sun, 19 May 2024 00:12:24 +0530 Subject: [PATCH 15/25] ci(SciMLSensitivity): use correct path --- .github/workflows/Downstream.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Downstream.yml b/.github/workflows/Downstream.yml index 210fb64d0..cdea399e3 100644 --- a/.github/workflows/Downstream.yml +++ b/.github/workflows/Downstream.yml @@ -63,7 +63,7 @@ jobs: path: downstream - name: Checkout SII branch if SciMLSensitivity if: "contains(${{ matrix.package.repo }}, 'SciMLSensitivity.jl')" - run: git checkout dg/ss + run: git -C downstream checkout dg/ss - name: Load this and run the downstream tests shell: julia --color=yes --project=downstream {0} run: | From a417cdd0d565093805ac037ee7e95e132951607e Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Sun, 19 May 2024 00:13:44 +0530 Subject: [PATCH 16/25] ci: revert changes --- .github/workflows/Downstream.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/Downstream.yml b/.github/workflows/Downstream.yml index cdea399e3..4bffe0379 100644 --- a/.github/workflows/Downstream.yml +++ b/.github/workflows/Downstream.yml @@ -61,9 +61,6 @@ jobs: with: repository: ${{ matrix.package.user }}/${{ matrix.package.repo }} path: downstream - - name: Checkout SII branch if SciMLSensitivity - if: "contains(${{ matrix.package.repo }}, 'SciMLSensitivity.jl')" - run: git -C downstream checkout dg/ss - name: Load this and run the downstream tests shell: julia --color=yes --project=downstream {0} run: | From ff9bb2c35c15eeb806c98545c4b0c08060baf8d8 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 01:45:36 +0530 Subject: [PATCH 17/25] chore: revert literal_getproperty adjoint --- ext/SciMLBaseZygoteExt.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 9624a227a..ab25d42df 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -215,6 +215,16 @@ end NonlinearSolution{T, N, uType, R, P, A, O, uType2}(u, args...), NonlinearSolutionAdjoint end +@adjoint function literal_getproperty(sol::AbstractTimeseriesSolution, + ::Val{:u}) + function solu_adjoint(Δ) + zerou = zero(sol.prob.u0) + _Δ = @. ifelse(Δ === nothing, (zerou,), Δ) + (build_solution(sol.prob, sol.alg, sol.t, _Δ),) + end + sol.u, solu_adjoint +end + @adjoint function literal_getproperty(sol::SciMLBase.AbstractNoTimeSolution, ::Val{:u}) function solu_adjoint(Δ) From 032b927d0a050f661704fc1a4068174b321731ca Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 02:22:19 +0530 Subject: [PATCH 18/25] chore: try to avoid returning object --- ext/SciMLBaseZygoteExt.jl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index ab25d42df..47d32905e 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -129,13 +129,13 @@ end VA[sym], ODESolution_getindex_pullback end -function obs_grads(VA, sym, obss_idx, Δ) +function obs_grads(VA, sym, obs_idx, Δ) y, back = Zygote.pullback(VA) do sol - getindex.(Ref(sol), sym[obss_idx]) + getindex.(Ref(sol), sym[obs_idx]) end - Dprime = reduce(hcat, Δ) - Dobss = eachrow(Dprime[obss_idx, :]) - back(Dobss) + Δreduced = reduce(hcat, Δ) + Δobs = eachrow(Δreduced[obs_idx, :]) + back(Δobs) end function obs_grads(VA, sym, ::Nothing, Δ) @@ -164,11 +164,11 @@ end sym = sym isa Tuple ? collect(sym) : sym i = map(x -> symbolic_type(x) != NotSymbolic() ? variable_index(VA, x) : x, sym) - obss_idx = findall(s -> is_observed(VA, s), sym) - not_obss_idx = setdiff(1:length(sym), obss_idx) + obs_idx = findall(s -> is_observed(VA, s), sym) + not_obs_idx = setdiff(1:length(sym), obs_idx) - gs_obs = obs_grads(VA, sym, isempty(obss_idx) ? nothing : obss_idx, Δ) - gs_not_obs = not_obs_grads(VA, sym, not_obss_idx, i, Δ) + gs_obs = obs_grads(VA, sym, isempty(obs_idx) ? nothing : obs_idx, Δ) + gs_not_obs = not_obs_grads(VA, sym, not_obs_idx, i, Δ) a = Zygote.accum(gs_obs[1], gs_not_obs) (a, nothing) @@ -220,7 +220,9 @@ end function solu_adjoint(Δ) zerou = zero(sol.prob.u0) _Δ = @. ifelse(Δ === nothing, (zerou,), Δ) - (build_solution(sol.prob, sol.alg, sol.t, _Δ),) + nt = Zygote.nt_nothing(sol) + gs = Zygote.accum(nt, (u = _Δ,)) + (gs,) end sol.u, solu_adjoint end From 44bfc91acb40821f7f1807952f3ade73a34ccf6b Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 03:17:38 +0530 Subject: [PATCH 19/25] build: add MSL to test deps --- Project.toml | 4 +- ext/SciMLBaseZygoteExt.jl | 4 +- test/downstream/observables_autodiff.jl | 79 +++++++------------------ 3 files changed, 26 insertions(+), 61 deletions(-) diff --git a/Project.toml b/Project.toml index 061bfda7d..f74e73d3d 100644 --- a/Project.toml +++ b/Project.toml @@ -68,6 +68,7 @@ Logging = "1.10" Makie = "0.20" Markdown = "1.10" ModelingToolkit = "8.75, 9" +ModelingToolkitStandardLibrary = "2.7" PartialFunctions = "1.1" PrecompileTools = "1.2" Preferences = "1.3" @@ -96,6 +97,7 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DelayDiffEq = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +ModelingToolkitStandardLibrary = "16a59e39-deab-5bd0-87e4-056b12336739" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" PartialFunctions = "570af359-4316-4cb7-8c74-252c00c2016b" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" @@ -111,4 +113,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [targets] -test = ["Pkg", "Plots", "UnicodePlots", "PyCall", "PythonCall", "SafeTestsets", "Test", "StaticArrays", "StochasticDiffEq", "Aqua", "Zygote", "PartialFunctions", "DataFrames", "ModelingToolkit", "OrdinaryDiffEq", "ForwardDiff"] +test = ["Pkg", "Plots", "UnicodePlots", "PyCall", "PythonCall", "SafeTestsets", "Test", "StaticArrays", "StochasticDiffEq", "Aqua", "Zygote", "PartialFunctions", "DataFrames", "ModelingToolkit", "ModelingToolkitStandardLibrary", "OrdinaryDiffEq", "ForwardDiff"] diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 47d32905e..242500983 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -220,9 +220,7 @@ end function solu_adjoint(Δ) zerou = zero(sol.prob.u0) _Δ = @. ifelse(Δ === nothing, (zerou,), Δ) - nt = Zygote.nt_nothing(sol) - gs = Zygote.accum(nt, (u = _Δ,)) - (gs,) + (build_solution(sol.prob, sol.alg, sol.t, _Δ),) end sol.u, solu_adjoint end diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index 554b6e6f9..ecf38f480 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -3,6 +3,8 @@ using Zygote using ModelingToolkit: t_nounits as t, D_nounits as D import SymbolicIndexingInterface as SII import SciMLStructures as SS +using ModelingToolkitStandardLibrary +import ModelingToolkitStandardLibrary as MSL @parameters σ ρ β @variables x(t) y(t) z(t) w(t) @@ -34,60 +36,18 @@ sol = solve(prob, Tsit5()) du_ = [0.0, 1.0, 1.0, 1.0] du = [du_ for _ in sol.u] @test du == gs.u -end - -# Lorenz - -@parameters σ ρ β -@variables x(t) y(t) z(t) - -eqs = [D(x) ~ σ * (y - x), - D(y) ~ x * (ρ - z) - y, - D(z) ~ x * y - β * z] - -@named lorenz1 = ODESystem(eqs, t) -@named lorenz2 = ODESystem(eqs, t) - -@parameters γ -@variables a(t) α(t) -connections = [0 ~ lorenz1.x + lorenz2.y + a * γ, - α ~ 2lorenz1.x + a * γ] -@mtkbuild sys = ODESystem(connections, t, [a, α], [γ], systems = [lorenz1, lorenz2]) - -u0 = [lorenz1.x => 1.0, - lorenz1.y => 0.0, - lorenz1.z => 0.0, - lorenz2.x => 0.0, - lorenz2.y => 1.0, - lorenz2.z => 0.0, - a => 2.0] - -p = [lorenz1.σ => 10.0, - lorenz1.ρ => 28.0, - lorenz1.β => 8 / 3, - lorenz2.σ => 10.0, - lorenz2.ρ => 28.0, - lorenz2.β => 8 / 3, - γ => 2.0] - -tspan = (0.0, 100.0) -prob = ODEProblem(sys, u0, tspan, p) -integ = init(prob, Rodas4()) -sol = solve(prob, Rodas4()) - -gt = reduce(hcat, sol[[sys.a, sys.α]]) .+ randn.() -gs, = Zygote.gradient(sol) do sol - mean(abs.(sol[[sys.a, sys.α]] .- gt), dims = 2) + # Observable in a vector + gs, = gradient(sol) do sol + sum(sum.(sol[[sys.w, sys.x]])) + end + du_ = [0.0, 1.0, 1.0, 2.0] + du = [du_ for _ in sol.u] + @test du == gs.u end # DAE -using ModelingToolkit, OrdinaryDiffEq, Zygote -using ModelingToolkitStandardLibrary -import ModelingToolkitStandardLibrary as MSL -using SciMLStructures - function create_model(; C₁ = 3e-5, C₂ = 1e-6) @variables t @named resistor1 = MSL.Electrical.Resistor(R = 5.0) @@ -112,15 +72,20 @@ function create_model(; C₁ = 3e-5, C₂ = 1e-6) ]) end -model = create_model() -sys = structural_simplify(model) +@testset "DAE Observable function AD" begin + model = create_model() + sys = structural_simplify(model) + + prob = ODEProblem(sys, [], (0.0, 1.0)) + sol = solve(prob, Rodas4()) -prob = ODEProblem(sys, [], (0.0, 1.0)) -sol = solve(prob, Rodas4()) -pf = getp(sol, sys.resistor1.R) -mtkparams = SII.parameter_values(sol) -tunables, _, _ = SS.canonicalize(SS.Tunable(), mtkparams) -p_new = rand(length(tunables)) + gs, = gradient(sol) do sol + sum(sol[sys.ampermeter.i]) + end + du_ = [0.2, 1.0] + du = [du_ for _ in sol.u] + @test gs.u == du +end # @testset "Adjoints with DAE" begin # gs_mtkp, gs_p_new = gradient(mtkparams, p_new) do p, new_tunables From de2d6cd86649b6b27d2ce3bab914b7c2f5b0268f Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 05:46:31 +0530 Subject: [PATCH 20/25] chore: don't return structural tangent --- ext/SciMLBaseZygoteExt.jl | 20 ++++++++++++-------- test/downstream/observables_autodiff.jl | 6 +++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 242500983..cc09cc9b1 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -6,9 +6,10 @@ import Zygote: literal_getproperty using SciMLBase using SciMLBase: ODESolution, remake, getobserved, build_solution, EnsembleSolution, - NonlinearSolution, AbstractTimeseriesSolution + NonlinearSolution, AbstractTimeseriesSolution, + SciMLStructures using SymbolicIndexingInterface: symbolic_type, NotSymbolic, variable_index, is_observed, - observed, parameter_values + observed, parameter_values, state_values, current_time using RecursiveArrayTools # This method resolves the ambiguity with the pullback defined in @@ -111,10 +112,13 @@ end function ODESolution_getindex_pullback(Δ) i = symbolic_type(sym) != NotSymbolic() ? variable_index(VA, sym) : sym if is_observed(VA, sym) - y, back = Zygote.pullback(VA) do sol - f = observed(sol, sym) - p = parameter_values(sol) - f.(sol.u, Ref(p), sol.t) + f = observed(VA, sym) + p = parameter_values(VA) + tunables, _, _ = SciMLStructures.canonicalize(SciMLStructures.Tunable(), p) + u = state_values(VA) + t = current_time(VA) + y, back = Zygote.pullback(u, tunables) do u, tunables + f.(u, Ref(tunables), t) end gs = back(Δ) (gs[1], nothing) @@ -154,8 +158,7 @@ function not_obs_grads(VA::ODESolution{T}, sym, not_obss_idx, i, Δ) where {T} end end - nt = Zygote.nt_nothing(VA) - Zygote.accum(nt, (u = Δ′,)) + Δ′ end @adjoint function Base.getindex( @@ -171,6 +174,7 @@ end gs_not_obs = not_obs_grads(VA, sym, not_obs_idx, i, Δ) a = Zygote.accum(gs_obs[1], gs_not_obs) + (a, nothing) end VA[sym], ODESolution_getindex_pullback diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index ecf38f480..e03cb7fc6 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -35,7 +35,7 @@ sol = solve(prob, Tsit5()) end du_ = [0.0, 1.0, 1.0, 1.0] du = [du_ for _ in sol.u] - @test du == gs.u + @test du == gs # Observable in a vector gs, = gradient(sol) do sol @@ -43,7 +43,7 @@ sol = solve(prob, Tsit5()) end du_ = [0.0, 1.0, 1.0, 2.0] du = [du_ for _ in sol.u] - @test du == gs.u + @test du == gs end # DAE @@ -84,7 +84,7 @@ end end du_ = [0.2, 1.0] du = [du_ for _ in sol.u] - @test gs.u == du + @test gs == du end # @testset "Adjoints with DAE" begin From c63dfbf3c61883e9a2622c2e75ed74771774644f Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 05:58:49 +0530 Subject: [PATCH 21/25] chore: fix imports --- ext/SciMLBaseZygoteExt.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index cc09cc9b1..7d9ddb084 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -6,11 +6,11 @@ import Zygote: literal_getproperty using SciMLBase using SciMLBase: ODESolution, remake, getobserved, build_solution, EnsembleSolution, - NonlinearSolution, AbstractTimeseriesSolution, - SciMLStructures + NonlinearSolution, AbstractTimeseriesSolution using SymbolicIndexingInterface: symbolic_type, NotSymbolic, variable_index, is_observed, observed, parameter_values, state_values, current_time using RecursiveArrayTools +import SciMLStructures # This method resolves the ambiguity with the pullback defined in # RecursiveArrayToolsZygoteExt From 940ea7820b6108c745bd30aee51a1cd1eb1d7461 Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 12:52:00 +0530 Subject: [PATCH 22/25] test: add MSL to downstream env --- test/downstream/Project.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/downstream/Project.toml b/test/downstream/Project.toml index cf96402b8..146a277eb 100644 --- a/test/downstream/Project.toml +++ b/test/downstream/Project.toml @@ -3,6 +3,7 @@ BoundaryValueDiffEq = "764a87c0-6b3e-53db-9096-fe964310641d" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" JumpProcesses = "ccbc3e58-028d-4f4c-8cd5-9ae44345cda5" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +ModelingToolkitStandardLibrary = "16a59e39-deab-5bd0-87e4-056b12336739" NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" OptimizationMOI = "fd9f6733-72f4-499f-8506-86b2bdd0dea1" @@ -22,6 +23,7 @@ BoundaryValueDiffEq = "5" ForwardDiff = "0.10" JumpProcesses = "9.10" ModelingToolkit = "8.37, 9" +ModelingToolkitStandardLibrary = "2.7" NonlinearSolve = "2, 3" Optimization = "3" OptimizationMOI = "0.4" From 8e48f1c7b178064937fe9050d5c775b91b09a11a Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 18:34:17 +0530 Subject: [PATCH 23/25] test: rm MSL from test env --- Project.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Project.toml b/Project.toml index f74e73d3d..061bfda7d 100644 --- a/Project.toml +++ b/Project.toml @@ -68,7 +68,6 @@ Logging = "1.10" Makie = "0.20" Markdown = "1.10" ModelingToolkit = "8.75, 9" -ModelingToolkitStandardLibrary = "2.7" PartialFunctions = "1.1" PrecompileTools = "1.2" Preferences = "1.3" @@ -97,7 +96,6 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DelayDiffEq = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" -ModelingToolkitStandardLibrary = "16a59e39-deab-5bd0-87e4-056b12336739" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" PartialFunctions = "570af359-4316-4cb7-8c74-252c00c2016b" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" @@ -113,4 +111,4 @@ UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [targets] -test = ["Pkg", "Plots", "UnicodePlots", "PyCall", "PythonCall", "SafeTestsets", "Test", "StaticArrays", "StochasticDiffEq", "Aqua", "Zygote", "PartialFunctions", "DataFrames", "ModelingToolkit", "ModelingToolkitStandardLibrary", "OrdinaryDiffEq", "ForwardDiff"] +test = ["Pkg", "Plots", "UnicodePlots", "PyCall", "PythonCall", "SafeTestsets", "Test", "StaticArrays", "StochasticDiffEq", "Aqua", "Zygote", "PartialFunctions", "DataFrames", "ModelingToolkit", "OrdinaryDiffEq", "ForwardDiff"] From d061ce47f10d99f78850e08b820727c6228b3c8b Mon Sep 17 00:00:00 2001 From: DhairyaLGandhi Date: Mon, 20 May 2024 19:08:02 +0530 Subject: [PATCH 24/25] chore: format --- ext/SciMLBaseZygoteExt.jl | 2 +- test/downstream/observables_autodiff.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/SciMLBaseZygoteExt.jl b/ext/SciMLBaseZygoteExt.jl index 7d9ddb084..4f5ff06b8 100644 --- a/ext/SciMLBaseZygoteExt.jl +++ b/ext/SciMLBaseZygoteExt.jl @@ -174,7 +174,7 @@ end gs_not_obs = not_obs_grads(VA, sym, not_obs_idx, i, Δ) a = Zygote.accum(gs_obs[1], gs_not_obs) - + (a, nothing) end VA[sym], ODESolution_getindex_pullback diff --git a/test/downstream/observables_autodiff.jl b/test/downstream/observables_autodiff.jl index e03cb7fc6..974afa150 100644 --- a/test/downstream/observables_autodiff.jl +++ b/test/downstream/observables_autodiff.jl @@ -75,7 +75,7 @@ end @testset "DAE Observable function AD" begin model = create_model() sys = structural_simplify(model) - + prob = ODEProblem(sys, [], (0.0, 1.0)) sol = solve(prob, Rodas4()) From f817b52acb30b086d8d55fca55bc06e8426fdb8a Mon Sep 17 00:00:00 2001 From: Christopher Rackauckas Date: Fri, 24 May 2024 12:50:20 -0400 Subject: [PATCH 25/25] Update CI.yml --- .github/workflows/CI.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 367257c3c..83c26db8f 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -14,6 +14,7 @@ jobs: test: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: group: - Core @@ -47,4 +48,4 @@ jobs: with: file: lcov.info token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true + fail_ci_if_error: false