- This repository follows the SciMLStyle and the SciML ColPrac.
- Please run
using JuliaFormatter, OrdinaryDiffEq; format(joinpath(dirname(pathof(OrdinaryDiffEq)), ".."))before committing. - Add tests for any new features.
- Additional help on contributing to the numerical solvers can be found at https://docs.sciml.ai/DiffEqDevDocs/stable/
OrdinaryDiffEq is a very large package and thus it uses a sublibrary approach to keep down the total number of dependencies per solver. As a consequence, it requires a bit of special handling compared to some other Julia packages. When running the full test suite, it's recommended that one has dev'd all of the relevant packages. This can be done via:
using Pkg
pathtolibrary = Pkg.pkgdir(OrdinaryDiffEq)
sublibs = joinpath.(pathtolibrary, "lib", readdir(joinpath(pathtolibrary, "lib")))
Pkg.develop(map(name -> Pkg.PackageSpec.(; path = name), sublibs));and then running Pkg.test("OrdinaryDiffEq") will run the global tests locally. Each of the
per-solver subtests, which includes convergence tests and other per-library handling,
is then ran by using a specific solver set, such as
Pkg.test("OrdinaryDiffEqAdamsBashforthMoulton")
There is a tree dependency structure to the sublibraries of OrdinaryDiffEq. The core stepper lives in OrdinaryDiffEqCore.jl. Explicit methods only require the core. Then on top of the core is OrdinaryDiffEqDifferentiation.jl which defines the utilities used for differentiation and Jacobian construction. This is used directly by methods like Rosenbrock and exponential integrators, which use Jacobians but not implicit solvers. Finally there's OrdinaryDiffEqNonlinearSolve, which is the largest set of dependencies and pulls in the NonlinearSolve.jl stack for handling implicit equations, and is thus the core dependency of the implicit integrators. OrdinaryDiffEqNonlinearSolve relies on OrdinaryDiffEqDifferentiation which relies on OrdinaryDiffEqCore.
Each sublibrary declares its CI jobs through test/test_groups.toml. Groups listed there
(e.g. Core, QA, GPU, ModelingToolkit) become matrix entries dispatched by
.github/scripts/compute_affected_sublibraries.jl. The group name is passed to the
sublibrary's test/runtests.jl via ENV["ODEDIFFEQ_TEST_GROUP"].
By default, when an upstream sublibrary's source changes, every reverse-dependent
sublibrary is added to the matrix and its full set of test groups runs (on Julia 1
only). For groups that are too expensive to justify running on every upstream change —
for example the weak-convergence Monte-Carlo tests in StochasticDiffEqWeak,
StochasticDiffEq, and StochasticDiffEqROCK — set local_only = true in the
group's entry:
[WeakConvergence2]
versions = ["1"]
runner = ["self-hosted", "Linux", "X64", "high-memory"]
timeout = 300
local_only = truelocal_only groups still run whenever any file under this sublibrary's own
lib/<pkg>/ directory is edited (a "direct" trigger). They are skipped only when
the sublibrary lands in the matrix transitively because an upstream dependency
changed. Use this for groups whose value scales with this sublibrary's solvers,
not with upstream behavior.
A group that needs dependencies beyond the sublibrary's main [targets].test list should
use its own isolated environment under test/<group>/Project.toml. test/runtests.jl
activates that environment before running the group's tests:
function activate_qa_env()
Pkg.activate(joinpath(@__DIR__, "qa"))
return Pkg.instantiate()
end
if (TEST_GROUP == "QA" || TEST_GROUP == "ALL") && isempty(VERSION.prerelease)
activate_qa_env()
@time @safetestset "Allocation Tests" include("qa/allocation_tests.jl")
@time @safetestset "JET Tests" include("qa/jet.jl")
@time @safetestset "Aqua" include("qa/qa.jl")
endThis pattern is the standard for the QA (JET + Aqua + AllocCheck) and GPU groups.
Use it for any new group whose dependencies shouldn't leak into the main test env or
into reverse-dependency resolution.
Two conventions that keep this working:
- Heavy test-only deps (JET, Aqua, AllocCheck, CUDA, MTK, …) live only in
test/<group>/Project.toml, not in the sublibrary's[extras]. Do not rely onPkg.addfrom inside a test file. test/<group>/Project.tomluses relative[sources]paths (e.g.path = "../.."for the sublibrary itself,path = "../../../OrdinaryDiffEqCore"for internal deps) so that the isolated env resolves against the in-tree sources.