diff --git a/Project.toml b/Project.toml index 1712187..7a8c0f7 100644 --- a/Project.toml +++ b/Project.toml @@ -18,8 +18,8 @@ SciMLLogging = "a6db7da4-7206-11f0-1eab-35f2a5dbe1d1" Compat = "4.15" DataStructures = "0.19" DiffEqBase = "7" -ExplicitImports = "1" FunctionWrappers = "1.1.3" +LinearAlgebra = "1" ModelingToolkit = "9, 10, 11" NonlinearSolve = "3, 4" ODEInterface = "0.5" @@ -34,7 +34,6 @@ Test = "1" julia = "1.10" [extras] -ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" @@ -44,4 +43,4 @@ SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["ExplicitImports", "ModelingToolkit", "NonlinearSolve", "SafeTestsets", "SciMLTesting", "SymbolicIndexingInterface", "Test", "ODEProblemLibrary"] +test = ["ModelingToolkit", "NonlinearSolve", "SafeTestsets", "SciMLTesting", "SymbolicIndexingInterface", "Test", "ODEProblemLibrary"] diff --git a/src/algorithms.jl b/src/algorithms.jl index 3acdb2e..c8420fd 100644 --- a/src/algorithms.jl +++ b/src/algorithms.jl @@ -1,6 +1,6 @@ # ODEInterface.jl Algorithms -abstract type ODEInterfaceAlgorithm <: DiffEqBase.AbstractODEAlgorithm end +abstract type ODEInterfaceAlgorithm <: SciMLBase.AbstractODEAlgorithm end abstract type ODEInterfaceImplicitAlgorithm <: ODEInterfaceAlgorithm end abstract type ODEInterfaceExplicitAlgorithm <: ODEInterfaceAlgorithm end """ diff --git a/src/initialize.jl b/src/initialize.jl index f88ffbd..ea85ada 100644 --- a/src/initialize.jl +++ b/src/initialize.jl @@ -11,7 +11,7 @@ export OverrideInit, NoInit, CheckInit, DefaultInit # DefaultInit: OverrideInit → CheckInit pattern (matching Sundials v5) # First run OverrideInit to compute consistent initial conditions, # then run CheckInit to verify the algebraic constraints are satisfied. -function DiffEqBase.initialize_dae!( +function SciMLBase.initialize_dae!( integrator::ODEInterfaceIntegrator, initializealg::DefaultInit ) @@ -19,7 +19,7 @@ function DiffEqBase.initialize_dae!( # First: OverrideInit to compute consistent initial conditions if has_initialization_data(prob.f) - DiffEqBase.initialize_dae!(integrator, OverrideInit()) + SciMLBase.initialize_dae!(integrator, OverrideInit()) # Check if OverrideInit failed if integrator.sol.retcode == ReturnCode.InitialFailure @@ -28,13 +28,13 @@ function DiffEqBase.initialize_dae!( end # Then: CheckInit to verify algebraic constraints are satisfied - DiffEqBase.initialize_dae!(integrator, CheckInit()) + SciMLBase.initialize_dae!(integrator, CheckInit()) return nothing end # NoInit: Do nothing, assume initial conditions are correct -function DiffEqBase.initialize_dae!( +function SciMLBase.initialize_dae!( integrator::ODEInterfaceIntegrator, initializealg::NoInit ) @@ -43,7 +43,7 @@ function DiffEqBase.initialize_dae!( end # CheckInit: Verify that initial conditions satisfy the algebraic constraints -function DiffEqBase.initialize_dae!( +function SciMLBase.initialize_dae!( integrator::ODEInterfaceIntegrator, initializealg::CheckInit ) @@ -69,7 +69,7 @@ function DiffEqBase.initialize_dae!( f(tmp, u0, p, t) # Check residuals of algebraic equations only - abstol = integrator.sol.prob isa DiffEqBase.AbstractODEProblem ? + abstol = integrator.sol.prob isa SciMLBase.AbstractODEProblem ? get(Dict(integrator.opts.callback.discrete_callbacks), :abstol, 1.0e-8) : 1.0e-8 # Try to get abstol from the solve options, fallback to default @@ -100,7 +100,7 @@ function DiffEqBase.initialize_dae!( end # OverrideInit: Use SciMLBase's initialization system (e.g., from ModelingToolkit) -function DiffEqBase.initialize_dae!( +function SciMLBase.initialize_dae!( integrator::ODEInterfaceIntegrator, initializealg::OverrideInit ) diff --git a/src/integrator_types.jl b/src/integrator_types.jl index d61afe9..9b0d2e6 100644 --- a/src/integrator_types.jl +++ b/src/integrator_types.jl @@ -9,7 +9,7 @@ mutable struct ODEInterfaceIntegrator{ F, algType, uType, uPrevType, oType, SType, solType, P, CallbackCacheType, } <: - DiffEqBase.AbstractODEIntegrator{algType, true, uType, Float64} + SciMLBase.AbstractODEIntegrator{algType, true, uType, Float64} f::F u::uType uprev::uPrevType diff --git a/src/solve.jl b/src/solve.jl index a432451..41a3281 100644 --- a/src/solve.jl +++ b/src/solve.jl @@ -1,5 +1,5 @@ -function DiffEqBase.__solve( - prob::DiffEqBase.AbstractODEProblem{uType, tuptType, isinplace}, +function SciMLBase.__solve( + prob::SciMLBase.AbstractODEProblem{uType, tuptType, isinplace}, alg::AlgType, timeseries = [], ts = [], ks = []; saveat = Float64[], @@ -19,8 +19,8 @@ function DiffEqBase.__solve( isstiff = alg isa ODEInterfaceImplicitAlgorithm warned = !isempty(kwargs) && check_keywords(alg, kwargs, warnlist) - if !(prob.f isa DiffEqBase.AbstractParameterizedFunction) && isstiff - if DiffEqBase.has_tgrad(prob.f) + if !(prob.f isa SciMLBase.AbstractParameterizedFunction) && isstiff + if SciMLBase.has_tgrad(prob.f) @SciMLMessage( "Explicit t-gradient given to this stiff solver is ignored.", verbose_spec, :mismatched_input_output_type @@ -34,6 +34,7 @@ function DiffEqBase.__solve( max_len_cb = DiffEqBase.max_vector_callback_length(callbacks_internal) if max_len_cb isa VectorContinuousCallback + uBottomEltype = SciMLBase.recursive_bottom_eltype(prob.u0) callback_cache = DiffEqBase.CallbackCache( max_len_cb.len, uBottomEltype, uBottomEltype @@ -76,7 +77,7 @@ function DiffEqBase.__solve( uprev = similar(u) - sol = DiffEqBase.build_solution( + sol = SciMLBase.build_solution( prob, alg, ts, _timeseries, timeseries_errors = timeseries_errors, calculate_error = false, @@ -111,7 +112,7 @@ function DiffEqBase.__solve( initialize_callbacks!(integrator) # DAE initialization - check/compute consistent initial conditions - DiffEqBase.initialize_dae!(integrator, initializealg) + SciMLBase.initialize_dae!(integrator, initializealg) # Check if initialization failed if integrator.sol.retcode == ReturnCode.InitialFailure @@ -163,7 +164,7 @@ function DiffEqBase.__solve( error("This solver must use full or banded mass matrices.") end end - if DiffEqBase.has_jac(prob.f) + if SciMLBase.has_jac(prob.f) dict[:JACOBIMATRIX] = (t, u, J) -> prob.f.jac(J, u, prob.p, t) end @@ -227,7 +228,7 @@ function DiffEqBase.__solve( f!, tspan[1], tspan[2], vec(integrator.u), opts ) - elseif alg isa ddebdf + else tend, uend, retcode, stats = ODEInterface.ddebdf( @@ -254,13 +255,15 @@ function DiffEqBase.__solve( elseif retcode == -4 @SciMLMessage("Interrupted. Problem is probably stiff.", verbose_spec, :stiff_detection) return_retcode = ReturnCode.Unstable + else + return_retcode = ReturnCode.Failure end else return_retcode = ReturnCode.Success end - if DiffEqBase.has_analytic(prob.f) - DiffEqBase.calculate_solution_errors!( + if SciMLBase.has_analytic(prob.f) + SciMLBase.calculate_solution_errors!( integrator.sol; timeseries_errors = timeseries_errors, dense_errors = dense_errors @@ -279,7 +282,7 @@ function DiffEqBase.__solve( if haskey(stats, "no_lu_decomp") destats.nw = stats["no_lu_decomp"] end - return DiffEqBase.solution_new_retcode(sol, return_retcode) + return SciMLBase.solution_new_retcode(sol, return_retcode) end function save_value!(_timeseries, u, ::Type{T}, sizeu) where {T <: Number} diff --git a/test/explicit_imports.jl b/test/explicit_imports.jl deleted file mode 100644 index a7e8973..0000000 --- a/test/explicit_imports.jl +++ /dev/null @@ -1,8 +0,0 @@ -using ExplicitImports -using ODEInterfaceDiffEq -using Test - -@testset "ExplicitImports" begin - @test check_no_implicit_imports(ODEInterfaceDiffEq) === nothing - @test check_no_stale_explicit_imports(ODEInterfaceDiffEq) === nothing -end diff --git a/test/qa/Project.toml b/test/qa/Project.toml index 793a409..4123806 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -13,6 +13,6 @@ ODEInterfaceDiffEq = { path = "../.." } Aqua = "0.8" JET = "0.9,0.10,0.11" SafeTestsets = "0.0.1, 0.1" -SciMLTesting = "1" +SciMLTesting = "1.7" Test = "1" julia = "1.10" diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 8b63fe6..23eb4ec 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,17 +1,34 @@ -using ODEInterfaceDiffEq, Aqua, JET -using Test +using SciMLTesting, ODEInterfaceDiffEq, Test +using JET -@testset "Aqua" begin - # deps_compat disabled: ODEInterfaceDiffEq does not declare a compat entry - # for the LinearAlgebra stdlib dependency. Tracked in - # https://github.com/SciML/ODEInterfaceDiffEq.jl/issues/105 - Aqua.test_all(ODEInterfaceDiffEq; deps_compat = false) - @test_broken false # Aqua deps compat: missing compat entry for LinearAlgebra dep — tracked in https://github.com/SciML/ODEInterfaceDiffEq.jl/issues/105 -end +# all_qualified_accesses_via_owners: names accessed via SciMLBase that SciMLBase does +# not own. SciMLStructures (the SciMLStructures-owned module) and recursive_bottom_eltype +# (RecursiveArrayTools-owned) are both reached through the SciMLBase reexport. +const QUALIFIED_VIA_OWNERS_IGNORE = ( + :SciMLStructures, :recursive_bottom_eltype, +) -@testset "JET" begin - # JET.test_package reports an undefined-binding error - # (ODEInterfaceDiffEq.uBottomEltype in src/solve.jl). Tracked in - # https://github.com/SciML/ODEInterfaceDiffEq.jl/issues/105 - @test_broken false # JET: `ODEInterfaceDiffEq.uBottomEltype` is not defined (src/solve.jl) — tracked in https://github.com/SciML/ODEInterfaceDiffEq.jl/issues/105 -end +# all_qualified_accesses_are_public: names still non-public in the registered releases. +# - SciMLBase-owned solver-extension internals (SciMLBase 3.28.1 still private). +# - recursive_bottom_eltype (RecursiveArrayTools-owned) / SciMLStructures +# (SciMLStructures-owned), accessed via the SciMLBase reexport: non-public there. +# - DiffEqBase-owned internals (DiffEqBase 7.6.0 still private). +# - ODEInterface C-wrapper solver entry points and constants (ODEInterface 0.5.1, no +# `public` declarations). +const QUALIFIED_ARE_PUBLIC_IGNORE = ( + :OUTPUTFCN_CALL_REASON, :OUTPUTFCN_CALL_STEP, :OUTPUTFCN_DENSE, + :OUTPUTFCN_RET_CONTINUE, :OUTPUTFCN_RET_CONTINUE_XCHANGED, :OUTPUTFCN_WODENSE, + :OptionsODE, :RHS_CALL_INSITU, :SciMLStructures, :Stats, :__solve, + :_process_verbose_param, :calculate_solution_errors!, :ddeabm, :ddebdf, :dop853, + :dopri5, :initialize_dae!, :odex, :radau, :radau5, :recursive_bottom_eltype, + :rodas, :seulex, :solution_new_retcode, +) + +run_qa( + ODEInterfaceDiffEq; + explicit_imports = true, + ei_kwargs = (; + all_qualified_accesses_via_owners = (; ignore = QUALIFIED_VIA_OWNERS_IGNORE), + all_qualified_accesses_are_public = (; ignore = QUALIFIED_ARE_PUBLIC_IGNORE), + ), +)