diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 200127f7ef..ea7336d1a9 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -3,13 +3,6 @@ steps: plugins: - JuliaCI/julia#v1: version: "1" - - staticfloat/metahook: - pre-command: | - julia --project=. -e ' - using Pkg; - Pkg.develop(map(path ->Pkg.PackageSpec.(;path="$(@__DIR__)/lib/$(path)"), readdir("./lib"))); - Pkg.instantiate(); - ' - JuliaCI/julia-test#v1: coverage: false # 1000x slowdown agents: @@ -38,18 +31,11 @@ steps: env: BUILDKITE_PLUGIN_JULIA_VERSION: "{{matrix.version}}" GROUP: "{{matrix.group}}" + JULIA_NUM_THREADS: 2 plugins: - JuliaCI/julia#v1 - - staticfloat/metahook: - pre-command: | - julia --project=. -e ' - using Pkg; - Pkg.develop(map(path ->Pkg.PackageSpec.(;path="$(@__DIR__)/lib/$(path)"), readdir("./lib"))); - Pkg.instantiate(); - ' - JuliaCI/julia-test#v1: coverage: false - julia_args: "--threads=auto" agents: os: "linux" queue: "juliaecosystem" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 700707ced3..ec3b005a0e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,6 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + ignore: + - dependency-name: "crate-ci/typos" + update-types: ["version-update:semver-patch", "version-update:semver-minor"] diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 39932d81d6..d2537df61e 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -21,9 +21,11 @@ jobs: - AlgConvergence_I - AlgConvergence_II - AlgConvergence_III + - ModelingToolkit - Downstream - ODEInterfaceRegression - Multithreading + - QA - OrdinaryDiffEqAdamsBashforthMoulton - OrdinaryDiffEqBDF @@ -41,6 +43,7 @@ jobs: - OrdinaryDiffEqLinear - OrdinaryDiffEqLowOrderRK - OrdinaryDiffEqLowStorageRK + - OrdinaryDiffEqNonlinearSolve - OrdinaryDiffEqNordsieck - OrdinaryDiffEqPDIRK - OrdinaryDiffEqPRK @@ -48,6 +51,7 @@ jobs: - OrdinaryDiffEqRKN - OrdinaryDiffEqRosenbrock - OrdinaryDiffEqSDIRK + - OrdinaryDiffEqSIMDRK - OrdinaryDiffEqSSPRK - OrdinaryDiffEqStabilizedIRK - OrdinaryDiffEqStabilizedRK @@ -55,8 +59,14 @@ jobs: - OrdinaryDiffEqTsit5 - OrdinaryDiffEqVerner + - ImplicitDiscreteSolve + - SimpleImplicitDiscreteSolve + - Enzyme + version: + - 'lts' - '1' + - 'pre' steps: - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v2 @@ -72,15 +82,6 @@ jobs: ${{ runner.os }}-test-${{ env.cache-name }}- ${{ runner.os }}-test- ${{ runner.os }}- - # Explicitly develop the libraries first before running the tests for now. - # This is necessary since the tests are likely to fail otherwise, given that all - # the libs haven't been registered yet. - - name: "Develop the libraries since they haven't been registered yet" - run: | - julia --project=. -e ' - using Pkg; - Pkg.develop(map(path ->Pkg.PackageSpec.(;path="$(@__DIR__)/lib/$(path)"), readdir("./lib"))); - ' - uses: julia-actions/julia-runtest@v1 with: coverage: false @@ -88,8 +89,8 @@ jobs: env: GROUP: ${{ matrix.group }} - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} file: lcov.info - fail_ci_if_error: true + fail_ci_if_error: false diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml index 92c0519266..02b17209f3 100644 --- a/.github/workflows/CompatHelper.yml +++ b/.github/workflows/CompatHelper.yml @@ -2,25 +2,53 @@ name: CompatHelper on: schedule: - - cron: '00 * * * *' - issues: - types: [opened, reopened] + - cron: 0 0 * * * + workflow_dispatch: + +permissions: + contents: write + pull-requests: write jobs: - build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - julia-version: [1] - julia-arch: [x86] - os: [ubuntu-latest] + CompatHelper: + runs-on: ubuntu-latest steps: - - uses: julia-actions/setup-julia@latest + - uses: actions/checkout@v5 + - name: Check if Julia is already available in the PATH + id: julia_in_path + run: which julia + continue-on-error: true + - name: Install Julia, but only if it is not already available in the PATH + uses: julia-actions/setup-julia@v2 with: - version: ${{ matrix.julia-version }} - - name: Pkg.add("CompatHelper") - run: julia -e 'using Pkg; Pkg.add("CompatHelper")' - - name: CompatHelper.main() + version: '1' + arch: ${{ runner.arch }} + if: steps.julia_in_path.outcome != 'success' + - name: "Add the General registry via Git" + run: | + import Pkg + ENV["JULIA_PKG_SERVER"] = "" + Pkg.Registry.add("General") + shell: julia --color=yes {0} + - name: "Install CompatHelper" + run: | + import Pkg + name = "CompatHelper" + uuid = "aa819f21-2bde-4658-8897-bab36330d9b7" + version = "3" + Pkg.add(; name, uuid, version) + shell: julia --color=yes {0} + - name: "Run CompatHelper" + run: | + import CompatHelper + subdirs = ["", "docs", "test/downstream", "test/gpu", "docs"] + for f in readdir("lib"; join=true) + if isdir(f) && isfile(joinpath(f, "Project.toml")) + push!(subdirs, joinpath("lib", basename(f))) + end + end + @info "CompatHelper directories" subdirs + CompatHelper.main(; subdirs) + shell: julia --color=yes {0} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: julia -e 'using CompatHelper; CompatHelper.main(;subdirs=["", "docs", "test/downstream"])' diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 70c5a8e0ac..63863df6f8 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -15,15 +15,6 @@ jobs: - uses: julia-actions/setup-julia@latest with: version: '1' - # Explicitly develop the libraries first before running the tests for now. - # This is necessary since the tests are likely to fail otherwise, given that all - # the libs haven't been registered yet. - - name: "Develop the libraries since they haven't been registered yet" - run: | - julia --project=. -e ' - using Pkg; - Pkg.develop(map(path ->Pkg.PackageSpec.(;path="$(@__DIR__)/lib/$(path)"), readdir("./lib"))); - ' - name: Install dependencies run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' - name: Build and deploy @@ -32,7 +23,7 @@ jobs: DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # For authentication with SSH deploy key run: julia --project=docs/ --code-coverage=user docs/make.jl - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} file: lcov.info diff --git a/.github/workflows/Downgrade.yml b/.github/workflows/Downgrade.yml new file mode 100644 index 0000000000..855cb9c021 --- /dev/null +++ b/.github/workflows/Downgrade.yml @@ -0,0 +1,35 @@ +name: Downgrade +on: + pull_request: + branches: + - master + paths-ignore: + - 'docs/**' + push: + branches: + - master + paths-ignore: + - 'docs/**' +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + downgrade_mode: ['alldeps'] + julia-version: ['1.11'] + group: ['InterfaceI'] + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.julia-version }} + - uses: julia-actions/julia-downgrade-compat@v2 + with: + skip: Pkg,TOML,Statistics,LinearAlgebra,SparseArrays,InteractiveUtils + julia_version: ${{ matrix.julia-version }} + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + with: + ALLOW_RERESOLVE: false + env: + GROUP: ${{ matrix.group }} diff --git a/.github/workflows/DowngradeSublibraries.yml b/.github/workflows/DowngradeSublibraries.yml new file mode 100644 index 0000000000..60117a6215 --- /dev/null +++ b/.github/workflows/DowngradeSublibraries.yml @@ -0,0 +1,71 @@ +name: Downgrade Sublibraries +on: + pull_request: + branches: + - master + paths-ignore: + - 'docs/**' + push: + branches: + - master + paths-ignore: + - 'docs/**' +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + downgrade_mode: ['alldeps'] + julia-version: ['1.11'] + project: + - 'lib/ImplicitDiscreteSolve' + - 'lib/OrdinaryDiffEqAdamsBashforthMoulton' + - 'lib/OrdinaryDiffEqBDF' + - 'lib/OrdinaryDiffEqCore' + - 'lib/OrdinaryDiffEqDefault' + - 'lib/OrdinaryDiffEqDifferentiation' + - 'lib/OrdinaryDiffEqExplicitRK' + - 'lib/OrdinaryDiffEqExponentialRK' + - 'lib/OrdinaryDiffEqExtrapolation' + - 'lib/OrdinaryDiffEqFIRK' + - 'lib/OrdinaryDiffEqFeagin' + - 'lib/OrdinaryDiffEqFunctionMap' + - 'lib/OrdinaryDiffEqHighOrderRK' + - 'lib/OrdinaryDiffEqIMEXMultistep' + - 'lib/OrdinaryDiffEqLinear' + - 'lib/OrdinaryDiffEqLowOrderRK' + - 'lib/OrdinaryDiffEqLowStorageRK' + - 'lib/OrdinaryDiffEqNonlinearSolve' + - 'lib/OrdinaryDiffEqNordsieck' + - 'lib/OrdinaryDiffEqPDIRK' + - 'lib/OrdinaryDiffEqPRK' + - 'lib/OrdinaryDiffEqQPRK' + - 'lib/OrdinaryDiffEqRKN' + - 'lib/OrdinaryDiffEqRosenbrock' + - 'lib/OrdinaryDiffEqSDIRK' + - 'lib/OrdinaryDiffEqSSPRK' + - 'lib/OrdinaryDiffEqStabilizedIRK' + - 'lib/OrdinaryDiffEqStabilizedRK' + - 'lib/OrdinaryDiffEqSymplecticRK' + - 'lib/OrdinaryDiffEqTaylorSeries' + - 'lib/OrdinaryDiffEqTsit5' + - 'lib/OrdinaryDiffEqVerner' + - 'lib/SimpleImplicitDiscreteSolve' + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.julia-version }} + - uses: julia-actions/julia-downgrade-compat@v2 + with: + projects: ${{ matrix.project }} + skip: Pkg,TOML,Statistics,LinearAlgebra,SparseArrays,InteractiveUtils + julia_version: ${{ matrix.julia-version }} + - uses: julia-actions/julia-buildpkg@v1 + with: + project: ${{ matrix.project }} + - uses: julia-actions/julia-runtest@v1 + with: + project: ${{ matrix.project }} + ALLOW_RERESOLVE: false diff --git a/.github/workflows/Downstream.yml b/.github/workflows/Downstream.yml index 8200ba42ba..7d7c4b4cae 100644 --- a/.github/workflows/Downstream.yml +++ b/.github/workflows/Downstream.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - julia-version: [1] + julia-version: ['1.10'] os: [ubuntu-latest] package: - {user: SciML, repo: DelayDiffEq.jl, group: Interface} @@ -30,7 +30,10 @@ jobs: - {user: SciML, repo: SciMLSensitivity.jl, group: Core3} - {user: SciML, repo: SciMLSensitivity.jl, group: Core4} - {user: SciML, repo: SciMLSensitivity.jl, group: Core5} - - {user: SciML, repo: ModelingToolkit.jl, group: All} + - {user: SciML, repo: ModelingToolkit.jl, group: InterfaceI} + - {user: SciML, repo: ModelingToolkit.jl, group: InterfaceII} + - {user: SciML, repo: ModelingToolkit.jl, group: Initialization} + - {user: SciML, repo: ModelingToolkit.jl, group: SymbolicIndexingInterface} - {user: SciML, repo: DiffEqDevTools.jl, group: Core} - {user: nathanaelbosch, repo: ProbNumDiffEq.jl, group: Downstream} - {user: SKopecz, repo: PositiveIntegrators.jl, group: Downstream} @@ -41,15 +44,6 @@ jobs: with: version: ${{ matrix.julia-version }} arch: x64 - # Explicitly develop the libraries first before running the tests for now. - # This is necessary since the tests are likely to fail otherwise, given that all - # the libs haven't been registered yet. - - name: "Develop the libraries since they haven't been registered yet" - run: | - julia --project=. -e ' - using Pkg; - Pkg.develop(map(path ->Pkg.PackageSpec.(;path="$(@__DIR__)/lib/$(path)"), readdir("./lib"))); - ' - name: Clone Downstream uses: actions/checkout@v4 with: @@ -60,10 +54,8 @@ jobs: run: | using Pkg try - # force it to use this PR's version of the package - Pkg.develop(PackageSpec(path=".")) # resolver may fail with main deps - Pkg.update() - Pkg.test(coverage=true) # resolver may fail with test time deps + Pkg.develop(map(path ->Pkg.PackageSpec.(;path="lib/$(path)"), readdir("./lib"))); + Pkg.test(coverage=true) # resolver may fail with test time depsAdd commentMore actions catch err err isa Pkg.Resolve.ResolverError || rethrow() # If we can't resolve that means this is incompatible by SemVer and this is fine @@ -73,8 +65,8 @@ jobs: exit(0) # Exit immediately, as a success end - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v4 + - uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} - file: lcov.info - fail_ci_if_error: true + files: lcov.info + fail_ci_if_error: false diff --git a/.github/workflows/Invalidations.yml b/.github/workflows/Invalidations.yml deleted file mode 100644 index 75c3c7631a..0000000000 --- a/.github/workflows/Invalidations.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Invalidations - -on: - pull_request: - -concurrency: - # Skip intermediate builds: always. - # Cancel intermediate builds: always. - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - evaluate: - # Only run on PRs to the default branch. - # In the PR trigger above branches can be specified only explicitly whereas this check should work for master, main, or any other default branch - if: github.base_ref == github.event.repository.default_branch - runs-on: ubuntu-latest - steps: - - uses: julia-actions/setup-julia@v2 - with: - version: '1' - - uses: actions/checkout@v4 - # Explicitly develop the libraries first before running the tests for now. - # This is necessary since the tests are likely to fail otherwise, given that all - # the libs haven't been registered yet. - - name: "Develop the libraries since they haven't been registered yet" - run: | - julia --project=. -e ' - using Pkg; - Pkg.develop(map(path ->Pkg.PackageSpec.(;path="$(@__DIR__)/lib/$(path)"), readdir("./lib"))); - ' - - uses: julia-actions/julia-invalidations@v1 - id: invs_pr - - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.repository.default_branch }} - - uses: julia-actions/julia-buildpkg@v1 - - uses: julia-actions/julia-invalidations@v1 - id: invs_default - - - name: Report invalidation counts - run: | - echo "Invalidations on default branch: ${{ steps.invs_default.outputs.total }} (${{ steps.invs_default.outputs.deps }} via deps)" >> $GITHUB_STEP_SUMMARY - echo "This branch: ${{ steps.invs_pr.outputs.total }} (${{ steps.invs_pr.outputs.deps }} via deps)" >> $GITHUB_STEP_SUMMARY - - name: Check if the PR does increase number of invalidations - if: steps.invs_pr.outputs.total > steps.invs_default.outputs.total - run: exit 1 diff --git a/.github/workflows/SpellCheck.yml b/.github/workflows/SpellCheck.yml new file mode 100644 index 0000000000..ed4fe17798 --- /dev/null +++ b/.github/workflows/SpellCheck.yml @@ -0,0 +1,13 @@ +name: Spell Check + +on: [pull_request] + +jobs: + typos-check: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - name: Checkout Actions Repository + uses: actions/checkout@v4 + - name: Check spelling + uses: crate-ci/typos@v1.18.0 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000000..d194038a86 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,25 @@ +name: Benchmark + +on: + pull_request: + branches: [master] + paths-ignore: ['docs/**', '*.md'] + +permissions: + pull-requests: write + contents: read + +jobs: + benchmark: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + version: ["1", "lts"] + steps: + - uses: MilesCranmer/AirspeedVelocity.jl@action-v1 + with: + julia_version: ${{ matrix.version }} + script: "benchmark/benchmarks.jl" + annotate_pr: true + extra-pkgs: "StableRNGs,StaticArrays,LinearAlgebra,SparseArrays,DiffEqBase" \ No newline at end of file diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 0000000000..f4b94ed0eb --- /dev/null +++ b/.typos.toml @@ -0,0 +1,83 @@ +[default.extend-words] +# Julia-specific functions +indexin = "indexin" +findfirst = "findfirst" +findlast = "findlast" +eachindex = "eachindex" +setp = "setp" +getp = "getp" +setu = "setu" +getu = "getu" + +# Mathematical/scientific terms +jacobian = "jacobian" +hessian = "hessian" +eigenvalue = "eigenvalue" +eigenvector = "eigenvector" +discretization = "discretization" +linearization = "linearization" +parameterized = "parameterized" +discretized = "discretized" +vectorized = "vectorized" +extrapolant = "extrapolant" +# Person names in citations - these are correct spellings +Sigal = "Sigal" # Sigal Gottlieb is a real person/author + +# Common journal abbreviations +Numer = "Numer" # As in "P. Numer. Math." (Periodica Numerica Mathematica) + +# Technical variable names +dorder = "dorder" # Parameter for delta order / order change + + +# Common variable patterns in Julia/SciML +ists = "ists" +ispcs = "ispcs" +osys = "osys" +rsys = "rsys" +usys = "usys" +fsys = "fsys" +eqs = "eqs" +rhs = "rhs" +lhs = "lhs" +ode = "ode" +pde = "pde" +sde = "sde" +dde = "dde" +bvp = "bvp" +ivp = "ivp" + +# Common abbreviations +tol = "tol" +rtol = "rtol" +atol = "atol" +idx = "idx" +jdx = "jdx" +prev = "prev" +curr = "curr" +init = "init" +tmp = "tmp" +vec = "vec" +arr = "arr" +dt = "dt" +du = "du" +dx = "dx" +dy = "dy" +dz = "dz" + +# Algorithm/type suffixes +alg = "alg" +prob = "prob" +sol = "sol" +cb = "cb" +opts = "opts" +args = "args" +kwargs = "kwargs" + +# Scientific abbreviations +ND = "ND" +nd = "nd" +MTK = "MTK" +ODE = "ODE" +PDE = "PDE" +SDE = "SDE" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5005a1864f..9cb4b2885e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,8 +11,9 @@ handling compared to some other Julia packages. When running the full test suite recommended that one has dev'd all of the relevant packages. This can be done via: ```julia +using Pkg pathtolibrary = Pkg.pkgdir(OrdinaryDiffEq) -sublibs = string.((pathtolibrary,), readdir(pathtolibrary)) +sublibs = joinpath.(pathtolibrary, "lib", readdir(joinpath(pathtolibrary, "lib"))) Pkg.develop(map(name -> Pkg.PackageSpec.(; path = name), sublibs)); ``` diff --git a/Project.toml b/Project.toml index 2ac3331b5e..b3e9ccfc70 100644 --- a/Project.toml +++ b/Project.toml @@ -1,12 +1,13 @@ name = "OrdinaryDiffEq" uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" authors = ["Chris Rackauckas ", "Yingbo Ma "] -version = "6.89.0" +version = "6.102.1" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" +CommonSolve = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" @@ -68,107 +69,142 @@ SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7" SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +[sources] +OrdinaryDiffEqAdamsBashforthMoulton = {path = "lib/OrdinaryDiffEqAdamsBashforthMoulton"} +OrdinaryDiffEqBDF = {path = "lib/OrdinaryDiffEqBDF"} +OrdinaryDiffEqCore = {path = "lib/OrdinaryDiffEqCore"} +OrdinaryDiffEqDefault = {path = "lib/OrdinaryDiffEqDefault"} +OrdinaryDiffEqDifferentiation = {path = "lib/OrdinaryDiffEqDifferentiation"} +OrdinaryDiffEqExplicitRK = {path = "lib/OrdinaryDiffEqExplicitRK"} +OrdinaryDiffEqExponentialRK = {path = "lib/OrdinaryDiffEqExponentialRK"} +OrdinaryDiffEqExtrapolation = {path = "lib/OrdinaryDiffEqExtrapolation"} +OrdinaryDiffEqFIRK = {path = "lib/OrdinaryDiffEqFIRK"} +OrdinaryDiffEqFeagin = {path = "lib/OrdinaryDiffEqFeagin"} +OrdinaryDiffEqFunctionMap = {path = "lib/OrdinaryDiffEqFunctionMap"} +OrdinaryDiffEqHighOrderRK = {path = "lib/OrdinaryDiffEqHighOrderRK"} +OrdinaryDiffEqIMEXMultistep = {path = "lib/OrdinaryDiffEqIMEXMultistep"} +OrdinaryDiffEqLinear = {path = "lib/OrdinaryDiffEqLinear"} +OrdinaryDiffEqLowOrderRK = {path = "lib/OrdinaryDiffEqLowOrderRK"} +OrdinaryDiffEqLowStorageRK = {path = "lib/OrdinaryDiffEqLowStorageRK"} +OrdinaryDiffEqNonlinearSolve = {path = "lib/OrdinaryDiffEqNonlinearSolve"} +OrdinaryDiffEqNordsieck = {path = "lib/OrdinaryDiffEqNordsieck"} +OrdinaryDiffEqPDIRK = {path = "lib/OrdinaryDiffEqPDIRK"} +OrdinaryDiffEqPRK = {path = "lib/OrdinaryDiffEqPRK"} +OrdinaryDiffEqQPRK = {path = "lib/OrdinaryDiffEqQPRK"} +OrdinaryDiffEqRKN = {path = "lib/OrdinaryDiffEqRKN"} +OrdinaryDiffEqRosenbrock = {path = "lib/OrdinaryDiffEqRosenbrock"} +OrdinaryDiffEqSDIRK = {path = "lib/OrdinaryDiffEqSDIRK"} +OrdinaryDiffEqSSPRK = {path = "lib/OrdinaryDiffEqSSPRK"} +OrdinaryDiffEqStabilizedIRK = {path = "lib/OrdinaryDiffEqStabilizedIRK"} +OrdinaryDiffEqStabilizedRK = {path = "lib/OrdinaryDiffEqStabilizedRK"} +OrdinaryDiffEqSymplecticRK = {path = "lib/OrdinaryDiffEqSymplecticRK"} +OrdinaryDiffEqTsit5 = {path = "lib/OrdinaryDiffEqTsit5"} +OrdinaryDiffEqVerner = {path = "lib/OrdinaryDiffEqVerner"} + [compat] -ADTypes = "0.2, 1" -Adapt = "3.0, 4" -ArrayInterface = "7" -DataStructures = "0.18" -DiffEqBase = "6.154" -DocStringExtensions = "0.9" -EnumX = "1" -ExponentialUtilities = "1" -FastBroadcast = "0.2, 0.3" -FastClosures = "0.3" -FillArrays = "1.9" -FiniteDiff = "2" -ForwardDiff = "0.10" -FunctionWrappersWrappers = "0.1" +ADTypes = "1.16" +Adapt = "4.3" +ArrayInterface = "7.19" +CommonSolve = "0.2.4" +DataStructures = "0.18.22, 0.19" +DiffEqBase = "6.190.2" +DocStringExtensions = "0.9.5" +EnumX = "1.0.5" +ExplicitImports = "1.13.1" +ExponentialUtilities = "1.27" +FastBroadcast = "0.3.5" +FastClosures = "0.3.2" +FillArrays = "1.13" +FiniteDiff = "2.27" +ForwardDiff = "0.10.38, 1" +FunctionWrappersWrappers = "0.1.3" InteractiveUtils = "1.9" -LineSearches = "7" +JLArrays = "0.2" +LineSearches = "7.4" LinearAlgebra = "1.9" -LinearSolve = "2" +LinearSolve = "3.27" Logging = "1.9" -MacroTools = "0.5" -MuladdMacro = "0.2.1" -NonlinearSolve = "3" -OrdinaryDiffEqAdamsBashforthMoulton = "1" -OrdinaryDiffEqBDF = "1" -OrdinaryDiffEqCore = "1" -OrdinaryDiffEqDefault = "1" -OrdinaryDiffEqDifferentiation = "1" -OrdinaryDiffEqExplicitRK = "1" -OrdinaryDiffEqExponentialRK = "1" -OrdinaryDiffEqExtrapolation = "1" -OrdinaryDiffEqFIRK = "1" -OrdinaryDiffEqFeagin = "1" -OrdinaryDiffEqFunctionMap = "1" -OrdinaryDiffEqHighOrderRK = "1" -OrdinaryDiffEqIMEXMultistep = "1" -OrdinaryDiffEqLinear = "1" -OrdinaryDiffEqLowOrderRK = "1" -OrdinaryDiffEqLowStorageRK = "1" -OrdinaryDiffEqNonlinearSolve = "1" -OrdinaryDiffEqNordsieck = "1" -OrdinaryDiffEqPDIRK = "1" -OrdinaryDiffEqPRK = "1" -OrdinaryDiffEqQPRK = "1" -OrdinaryDiffEqRKN = "1" -OrdinaryDiffEqRosenbrock = "1" -OrdinaryDiffEqSDIRK = "1" -OrdinaryDiffEqStabilizedIRK = "1" -OrdinaryDiffEqSSPRK = "1" -OrdinaryDiffEqStabilizedRK = "1" -OrdinaryDiffEqSymplecticRK = "1" -OrdinaryDiffEqTsit5 = "1" -OrdinaryDiffEqVerner = "1" -Polyester = "0.7" -PreallocationTools = "0.4" -PrecompileTools = "1" -Preferences = "1.3" -RecursiveArrayTools = "2.36, 3" -Reexport = "1.0" -SciMLBase = "2.53.2" -SciMLOperators = "0.3" -SciMLStructures = "1" -SimpleNonlinearSolve = "1" -SimpleUnPack = "1" -SparseDiffTools = "2" -Static = "0.8, 1" -StaticArrayInterface = "1.2" -StaticArrays = "1.0" -TruncatedStacktraces = "1.2" +MacroTools = "0.5.16" +MuladdMacro = "0.2.4" +NonlinearSolve = "4.10" +OrdinaryDiffEqAdamsBashforthMoulton = "1.4.0" +OrdinaryDiffEqBDF = "1.9.0" +OrdinaryDiffEqCore = "1.29.0" +OrdinaryDiffEqDefault = "1.7.0" +OrdinaryDiffEqDifferentiation = "1.12.0" +OrdinaryDiffEqExplicitRK = "1.3.0" +OrdinaryDiffEqExponentialRK = "1.7.0" +OrdinaryDiffEqExtrapolation = "1.7.0" +OrdinaryDiffEqFIRK = "1.15.0" +OrdinaryDiffEqFeagin = "1.3.0" +OrdinaryDiffEqFunctionMap = "1.4.0" +OrdinaryDiffEqHighOrderRK = "1.4.0" +OrdinaryDiffEqIMEXMultistep = "1.6.0" +OrdinaryDiffEqLinear = "1.5.0" +OrdinaryDiffEqLowOrderRK = "1.5.0" +OrdinaryDiffEqLowStorageRK = "1.5.0" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +OrdinaryDiffEqNordsieck = "1.3.0" +OrdinaryDiffEqPDIRK = "1.5.0" +OrdinaryDiffEqPRK = "1.3.0" +OrdinaryDiffEqQPRK = "1.3.0" +OrdinaryDiffEqRKN = "1.4.0" +OrdinaryDiffEqRosenbrock = "1.15.1" +OrdinaryDiffEqSDIRK = "1.6.0" +OrdinaryDiffEqSSPRK = "1.5.0" +OrdinaryDiffEqStabilizedIRK = "1.5.0" +OrdinaryDiffEqStabilizedRK = "1.4.0" +OrdinaryDiffEqSymplecticRK = "1.6.0" +OrdinaryDiffEqTsit5 = "1.4.0" +OrdinaryDiffEqVerner = "1.5.0" +Polyester = "0.7.18" +PreallocationTools = "0.4.30" +PrecompileTools = "1.2.1" +Preferences = "1.4.3" +RecursiveArrayTools = "3.36" +Reexport = "1.2.2" +SciMLBase = "2.115" +SciMLOperators = "1.4" +SciMLStructures = "1.7" +SimpleNonlinearSolve = "2.7" +SimpleUnPack = "1.1" +Static = "1.2" +StaticArrayInterface = "1.8" +StaticArrays = "1.9.14" +StructArrays = "0.6, 0.7" +TruncatedStacktraces = "1.4" julia = "1.10" [extras] AlgebraicMultigrid = "2169fc97-5a83-5252-b627-83903c6c433c" -Calculus = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" ElasticArrays = "fdbdab4c-e67f-52f5-8c3f-e7b388dad3d4" +ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895" -InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +JLArrays = "27aeb0d3-9eb9-45fb-866b-73c2ecf80fcb" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -ParameterizedFunctions = "65888b18-ceab-5e60-b2b9-181511a3b968" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PoissonRandom = "e409e4f3-bfea-5376-8464-e040bb5c01ab" -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" +RecursiveFactorization = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +SparseConnectivityTracer = "9f842d2f-2579-4b1d-911e-f412cf18a3f5" +SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" [targets] -test = ["Calculus", "ComponentArrays", "Symbolics", "AlgebraicMultigrid", "IncompleteLU", "DiffEqCallbacks", "DiffEqDevTools", "ODEProblemLibrary", "ElasticArrays", "InteractiveUtils", "ParameterizedFunctions", "PoissonRandom", "Printf", "Random", "ReverseDiff", "SafeTestsets", "SparseArrays", "Statistics", "Test", "Unitful", "ModelingToolkit", "Pkg", "NLsolve"] +test = ["ComponentArrays", "AlgebraicMultigrid", "IncompleteLU", "DiffEqCallbacks", "DifferentiationInterface", "DiffEqDevTools", "ExplicitImports", "ODEProblemLibrary", "ElasticArrays", "JLArrays", "Random", "SafeTestsets", "StructArrays", "Test", "Unitful", "Pkg", "NLsolve", "RecursiveFactorization", "SparseConnectivityTracer", "SparseMatrixColorings", "Statistics"] diff --git a/benchmark/benchmarks.jl b/benchmark/benchmarks.jl new file mode 100644 index 0000000000..2396c761b5 --- /dev/null +++ b/benchmark/benchmarks.jl @@ -0,0 +1,358 @@ +using OrdinaryDiffEq, BenchmarkTools, DiffEqBase +using LinearAlgebra, SparseArrays, StaticArrays, StableRNGs + +const SUITE = BenchmarkGroup() + +# ============================================================================= +# Non-Stiff ODE Problems +# ============================================================================= + +SUITE["nonstiff"] = BenchmarkGroup() + +# Lotka-Volterra (Predator-Prey) Problem +function lotka_volterra!(du, u, p, t) + α, β, γ, δ = p + x, y = u + du[1] = α*x - β*x*y # dx/dt + du[2] = δ*x*y - γ*y # dy/dt + nothing +end + +function lotka_volterra_prob() + p = (1.5, 1.0, 3.0, 1.0) # α, β, γ, δ + u0 = [1.0, 1.0] + tspan = (0.0, 10.0) + ODEProblem(lotka_volterra!, u0, tspan, p) +end + +# Pleiades Problem (7-body celestial mechanics) +function pleiades!(du, u, p, t) + # u[1:7] = x positions, u[8:14] = y positions + # u[15:21] = x velocities, u[22:28] = y velocities + x = @view u[1:7] + y = @view u[8:14] + vx = @view u[15:21] + vy = @view u[22:28] + + # Copy velocities to position derivatives + du[1:7] .= vx + du[8:14] .= vy + + # Calculate accelerations + fill!(du[15:21], 0.0) + fill!(du[22:28], 0.0) + + for i in 1:7 + for j in 1:7 + if i != j + dx = x[j] - x[i] + dy = y[j] - y[i] + r = sqrt(dx^2 + dy^2) + r3 = r^3 + du[14 + i] += j * dx / r3 # mass j = j + du[21 + i] += j * dy / r3 + end + end + end + nothing +end + +function pleiades_prob() + # Initial conditions from literature + u0 = [3.0, 3.0, -1.0, -3.0, 2.0, -2.0, 2.0, 3.0, -3.0, 2.0, 0, 0, -4.0, 4.0, + 0, 0, 0, 0, 0, 1.75, -1.5, 0, 0, 0, -1.25, 1, 0, 0] + tspan = (0.0, 3.0) + ODEProblem(pleiades!, u0, tspan) +end + +# FitzHugh-Nagumo Model +function fitzhugh_nagumo!(du, u, p, t) + a, b, c = p + v, w = u + du[1] = c * (v - v^3/3 + w) # dv/dt + du[2] = -(v - a + b*w) / c # dw/dt + nothing +end + +function fitzhugh_nagumo_prob() + p = (0.7, 0.8, 12.5) + u0 = [-1.0, 1.0] + tspan = (0.0, 20.0) + ODEProblem(fitzhugh_nagumo!, u0, tspan, p) +end + +# ============================================================================= +# Stiff ODE Problems +# ============================================================================= + +SUITE["stiff"] = BenchmarkGroup() + +# ROBER Problem (Robertson chemical kinetics) +function rober!(du, u, p, t) + k1, k2, k3 = p + y1, y2, y3 = u + du[1] = -k1*y1 + k3*y2*y3 # dy1/dt + du[2] = k1*y1 - k2*y2^2 - k3*y2*y3 # dy2/dt + du[3] = k2*y2^2 # dy3/dt + nothing +end + +function rober_prob() + p = (0.04, 3e7, 1e4) # k1, k2, k3 + u0 = [1.0, 0.0, 0.0] + tspan = (0.0, 1e5) + ODEProblem(rober!, u0, tspan, p) +end + +# Van der Pol Oscillator (stiff) +function van_der_pol!(du, u, p, t) + μ = p[1] + x, y = u + du[1] = y # dx/dt + du[2] = μ * ((1 - x^2)*y - x) # dy/dt + nothing +end + +function van_der_pol_prob() + p = [1e6] # very stiff + u0 = [1.0, 1.0] + tspan = (0.0, 6.3) + ODEProblem(van_der_pol!, u0, tspan, p) +end + +# Pollution Problem (atmospheric chemistry, 20D stiff system) +const k1=.35e0 +const k2=.266e2 +const k3=.123e5 +const k4=.86e-3 +const k5=.82e-3 +const k6=.15e5 +const k7=.13e-3 +const k8=.24e5 +const k9=.165e5 +const k10=.9e4 +const k11=.22e-1 +const k12=.12e5 +const k13=.188e1 +const k14=.163e5 +const k15=.48e7 +const k16=.35e-3 +const k17=.175e-1 +const k18=.1e9 +const k19=.444e12 +const k20=.124e4 +const k21=.21e1 +const k22=.578e1 +const k23=.474e-1 +const k24=.178e4 +const k25=.312e1 + +function pollution!(dy, y, p, t) + r1 = k1 * y[1] + r2 = k2 * y[2] * y[4] + r3 = k3 * y[5] * y[2] + r4 = k4 * y[7] + r5 = k5 * y[7] + r6 = k6 * y[7] * y[6] + r7 = k7 * y[9] + r8 = k8 * y[9] * y[6] + r9 = k9 * y[11] * y[2] + r10 = k10*y[11]*y[1] + r11 = k11*y[13] + r12 = k12*y[10]*y[2] + r13 = k13*y[14] + r14 = k14*y[1]*y[6] + r15 = k15*y[3] + r16 = k16*y[4] + r17 = k17*y[4] + r18 = k18*y[16] + r19 = k19*y[16] + r20 = k20*y[17]*y[6] + r21 = k21*y[19] + r22 = k22*y[19] + r23 = k23*y[1]*y[4] + r24 = k24*y[19]*y[1] + r25 = k25*y[20] + + dy[1] = -r1-r10-r14-r23-r24 + r2 + r3 + r9 + r11 + r12 + r22 + r25 + dy[2] = -r2-r3-r9-r12+r1+r21 + dy[3] = -r15+r1+r17+r19+r22 + dy[4] = -r2-r16-r17-r23+r15 + dy[5] = -r3+r4+r4+r6+r7+r13+r20 + dy[6] = -r6-r8-r14-r20+r3+r18+r18 + dy[7] = -r4-r5-r6+r13 + dy[8] = r4+r5+r6+r7 + dy[9] = -r7-r8 + dy[10] = -r12+r7+r9 + dy[11] = -r9-r10+r8+r11 + dy[12] = r9 + dy[13] = -r11+r10 + dy[14] = -r13+r12 + dy[15] = r14 + dy[16] = -r18-r19+r16 + dy[17] = -r20 + dy[18] = r20 + dy[19] = -r21-r22-r24+r23+r25 + dy[20] = -r25+r24 + nothing +end + +function pollution_prob() + u0 = zeros(20) + u0[2] = 0.2 + u0[4] = 0.04 + u0[7] = 0.1 + u0[8] = 0.3 + u0[9] = 0.01 + u0[17] = 0.007 + tspan = (0.0, 60.0) + ODEProblem(pollution!, u0, tspan) +end + +# ============================================================================= +# Scaling Problems (different dimensions) +# ============================================================================= + +SUITE["scaling"] = BenchmarkGroup() + +# Linear ODE with varying dimensions +function linear_ode!(du, u, p, t) + A = p + mul!(du, A, u) + nothing +end + +function create_linear_prob(N::Int) + rng = StableRNG(123) # Fixed seed for reproducibility + A = randn(rng, N, N) + A = A - A' # Make skew-symmetric for bounded solutions + u0 = randn(rng, N) + tspan = (0.0, 1.0) + ODEProblem(linear_ode!, u0, tspan, A) +end + +# Brusselator PDE (2D reaction-diffusion from advanced ODE example) +# Forcing function - creates a localized disturbance +brusselator_f(x, y, t) = (((x - 0.3)^2 + (y - 0.6)^2) <= 0.1^2) * (t >= 1.1) * 5.0 + +# Periodic boundary condition helper +limit(a, N) = a == N + 1 ? 1 : a == 0 ? N : a + +function brusselator_2d!(du, u, p, t) + A, B, α, dx, N = p + α = α / dx^2 + + # Create coordinate arrays for this N + xyd = range(0, stop = 1, length = N) + + @inbounds for I in CartesianIndices((N, N)) + i, j = Tuple(I) + x, y = xyd[i], xyd[j] + ip1, im1, jp1, + jm1 = limit(i + 1, N), limit(i - 1, N), limit(j + 1, N), limit(j - 1, N) + + # u equation: ∂u/∂t = 1 + u²v - 4.4u + α∇²u + f(x,y,t) + du[i, j, 1] = α * (u[im1, j, 1] + u[ip1, j, 1] + u[i, jp1, 1] + u[i, jm1, 1] - 4*u[i, j, 1]) + B + u[i, j, 1]^2 * u[i, j, 2] - (A + 1) * u[i, j, 1] + brusselator_f(x, y, t) + + # v equation: ∂v/∂t = 3.4u - u²v + α∇²v + du[i, j, 2] = α * (u[im1, j, 2] + u[ip1, j, 2] + u[i, jp1, 2] + u[i, jm1, 2] - 4*u[i, j, 2]) + A * u[i, j, 1] - u[i, j, 1]^2 * u[i, j, 2] + end + nothing +end + +function init_brusselator_2d(N::Int) + xyd = range(0, stop = 1, length = N) + u = zeros(N, N, 2) + for I in CartesianIndices((N, N)) + x = xyd[I[1]] + y = xyd[I[2]] + u[I, 1] = 22 * (y * (1 - y))^(3/2) # u initial condition + u[I, 2] = 27 * (x * (1 - x))^(3/2) # v initial condition + end + u +end + +function create_brusselator_2d_prob(N::Int) + A, B, α = 3.4, 1.0, 10.0 + xyd = range(0, stop = 1, length = N) + dx = step(xyd) + u0 = init_brusselator_2d(N) + tspan = (0.0, 11.5) + ODEProblem(brusselator_2d!, u0, tspan, (A, B, α, dx, N)) +end + +# ============================================================================= +# Benchmark Definitions +# ============================================================================= + +# Non-stiff benchmarks with different solvers +lv_prob = lotka_volterra_prob() +pl_prob = pleiades_prob() +fn_prob = fitzhugh_nagumo_prob() + +# Explicit RK methods for non-stiff problems +explicit_solvers = [Tsit5(), Vern6(), Vern7(), DP5(), BS3()] + +SUITE["nonstiff"]["lotka_volterra"] = BenchmarkGroup() +SUITE["nonstiff"]["pleiades"] = BenchmarkGroup() +SUITE["nonstiff"]["fitzhugh_nagumo"] = BenchmarkGroup() + +for solver in explicit_solvers + solver_name = string(typeof(solver).name.name) + SUITE["nonstiff"]["lotka_volterra"][solver_name] = @benchmarkable solve( + $lv_prob, $solver, reltol = 1e-6, abstol = 1e-8) + SUITE["nonstiff"]["pleiades"][solver_name] = @benchmarkable solve( + $pl_prob, $solver, reltol = 1e-6, abstol = 1e-8) + SUITE["nonstiff"]["fitzhugh_nagumo"][solver_name] = @benchmarkable solve( + $fn_prob, $solver, reltol = 1e-6, abstol = 1e-8) +end + +# Stiff benchmarks with different solvers +rober_prob_instance = rober_prob() +vdp_prob = van_der_pol_prob() +pollution_prob_instance = pollution_prob() + +# Stiff solvers +stiff_solvers = [Rosenbrock23(), Rodas4(), TRBDF2(), KenCarp4(), FBDF()] + +SUITE["stiff"]["rober"] = BenchmarkGroup() +SUITE["stiff"]["van_der_pol"] = BenchmarkGroup() +SUITE["stiff"]["pollution"] = BenchmarkGroup() + +for solver in stiff_solvers + solver_name = string(typeof(solver).name.name) + SUITE["stiff"]["rober"][solver_name] = @benchmarkable solve( + $rober_prob_instance, $solver, reltol = 1e-6, abstol = 1e-8) + SUITE["stiff"]["van_der_pol"][solver_name] = @benchmarkable solve( + $vdp_prob, $solver, reltol = 1e-6, abstol = 1e-8) + SUITE["stiff"]["pollution"][solver_name] = @benchmarkable solve( + $pollution_prob_instance, $solver, reltol = 1e-6, abstol = 1e-8) +end + +# Scaling benchmarks +SUITE["scaling"]["linear"] = BenchmarkGroup() +SUITE["scaling"]["brusselator_2d"] = BenchmarkGroup() + +# Linear ODE scaling (different problem sizes) +for N in [10, 50, 100] + prob = create_linear_prob(N) + SUITE["scaling"]["linear"]["N$N"] = @benchmarkable solve($prob, Tsit5(), reltol = 1e-6, abstol = 1e-8) +end + +# Brusselator 2D scaling (different grid sizes) +for N in [8, 16, 32] + prob = create_brusselator_2d_prob(N) + SUITE["scaling"]["brusselator_2d"]["$(N)x$(N)"] = @benchmarkable solve($prob, TRBDF2(), + reltol = 1e-4, abstol = 1e-6, maxiters = 1000) +end + +# ============================================================================= +# Problem Construction Benchmarks +# ============================================================================= + +SUITE["construction"] = BenchmarkGroup() + +# Test problem construction overhead +SUITE["construction"]["lotka_volterra"] = @benchmarkable lotka_volterra_prob() +SUITE["construction"]["rober"] = @benchmarkable rober_prob() +SUITE["construction"]["linear_N50"] = @benchmarkable create_linear_prob(50) diff --git a/docs/make.jl b/docs/make.jl index 59d6df25d4..595a11eb93 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -3,6 +3,9 @@ using Documenter, OrdinaryDiffEq cp("./docs/Manifest.toml", "./docs/src/assets/Manifest.toml", force = true) cp("./docs/Project.toml", "./docs/src/assets/Project.toml", force = true) +# Keep pages.jl separate for the DiffEqDocs.jl build +include("pages.jl") + makedocs(sitename = "OrdinaryDiffEq.jl", authors = "Chris Rackauckas et al.", clean = true, @@ -41,59 +44,7 @@ makedocs(sitename = "OrdinaryDiffEq.jl", canonical = "https://ordinarydiffeq.sciml.ai/stable/", size_threshold_ignore = [joinpath("semiimplicit", "Rosenbrock.md"), joinpath("massmatrixdae", "Rosenbrock.md")]), - pages = [ - "OrdinaryDiffEq.jl: ODE solvers and utilities" => "index.md", - "Usage" => "usage.md", - "Explicit Solvers" => [ - "explicit/Tsit5.md", - "explicit/Verner.md", - "explicit/AdamsBashforthMoulton.md", - "explicit/LowStorageRK.md", - "explicit/SSPRK.md", - "explicit/LowOrderRK.md", - "explicit/HighOrderRK.md", - "explicit/Feagin.md", - "explicit/PRK.md", - "explicit/QPRK.md", - "explicit/Extrapolation.md" - ], - "Semi-Implicit Solvers" => [ - "semiimplicit/Rosenbrock.md", - "semiimplicit/StabalizedRK.md", - "semiimplicit/ExponentialRK.md" - ], - "Implicit Solvers" => [ - "implicit/SDIRK.md", - "implicit/FIRK.md", - "implicit/BDF.md", - "implicit/Extrapolation.md", - "implicit/PDIRK.md", - "implicit/Nordsieck.md" - ], - "IMEX Solvers" => [ - "imex/IMEXMultistep.md", - "imex/StabalizedIRK.md", - "imex/IMEXBDF.md" - ], - "Dynamical ODE Explicit Solvers" => [ - "dynamicalodeexplicit/RKN.md", - "dynamicalodeexplicit/SymplecticRK.md" - ], - "Semilinear ODE Solvers" => [ - "semilinear/ExponentialRK.md", - "semilinear/Linear.md" - ], - "Mass Matrix DAE Solvers" => [ - "massmatrixdae/Rosenbrock.md", - "massmatrixdae/BDF.md" - ], - "Fully Implicit DAE Solvers" => [ - "fullyimplicitdae/BDF.md" - ], - "Misc Solvers" => [ - "misc.md" - ] - ]) + pages = pages) deploydocs(repo = "github.com/SciML/OrdinaryDiffEq.jl"; push_preview = true) diff --git a/docs/pages.jl b/docs/pages.jl new file mode 100644 index 0000000000..8be27c064d --- /dev/null +++ b/docs/pages.jl @@ -0,0 +1,54 @@ +pages = [ + "OrdinaryDiffEq.jl: ODE solvers and utilities" => "index.md", + "Usage" => "usage.md", + "Explicit Solvers" => [ + "explicit/Tsit5.md", + "explicit/Verner.md", + "explicit/AdamsBashforthMoulton.md", + "explicit/LowStorageRK.md", + "explicit/SSPRK.md", + "explicit/LowOrderRK.md", + "explicit/HighOrderRK.md", + "explicit/Feagin.md", + "explicit/PRK.md", + "explicit/QPRK.md", + "explicit/TaylorSeries.md", + "explicit/Extrapolation.md" + ], + "Semi-Implicit Solvers" => [ + "semiimplicit/Rosenbrock.md", + "semiimplicit/StabilizedRK.md", + "semiimplicit/ExponentialRK.md" + ], + "Implicit Solvers" => [ + "implicit/SDIRK.md", + "implicit/FIRK.md", + "implicit/BDF.md", + "implicit/Extrapolation.md", + "implicit/PDIRK.md", + "implicit/Nordsieck.md" + ], + "IMEX Solvers" => [ + "imex/IMEXMultistep.md", + "imex/StabilizedIRK.md", + "imex/IMEXBDF.md" + ], + "Dynamical ODE Explicit Solvers" => [ + "dynamicalodeexplicit/RKN.md", + "dynamicalodeexplicit/SymplecticRK.md" + ], + "Semilinear ODE Solvers" => [ + "semilinear/ExponentialRK.md", + "semilinear/Linear.md" + ], + "Mass Matrix DAE Solvers" => [ + "massmatrixdae/Rosenbrock.md", + "massmatrixdae/BDF.md" + ], + "Fully Implicit DAE Solvers" => [ + "fullyimplicitdae/BDF.md" + ], + "Misc Solvers" => [ + "misc.md" + ] +] diff --git a/docs/src/dynamicalodeexplicit/RKN.md b/docs/src/dynamicalodeexplicit/RKN.md index ff8f20bcf8..8f0d437f80 100644 --- a/docs/src/dynamicalodeexplicit/RKN.md +++ b/docs/src/dynamicalodeexplicit/RKN.md @@ -4,7 +4,87 @@ CollapsedDocStrings = true # OrdinaryDiffEqRKN -Second order solvers. +Runge-Kutta-Nyström (RKN) methods for solving second-order differential equations of the form `d²u/dt² = f(u, du/dt, t)`. These methods are specifically designed for second-order ODEs and can be more efficient than converting to first-order systems when the problem has this natural structure. + +## Key Properties + +RKN methods provide: + + - **Direct integration** of second-order ODEs without conversion to first-order systems + - **Efficient handling** of problems where velocity dependence is minimal or absent + - **Specialized variants** for different types of second-order problems + - **High-order accuracy** with methods up to 12th order available + - **Trigonometrically-fitted variants** for oscillatory problems + - **Improved efficiency** for second-order problems compared to first-order conversions + +## When to Use RKN Methods + +These methods are recommended for: + + - **Second-order differential equations** with natural `d²u/dt² = f(u, du/dt, t)` structure + - **Classical mechanics problems** (Newton's equations of motion) + - **Oscillatory second-order systems** (springs, pendulums, wave equations) + - **Problems where velocity dependence is weak** or absent + - **Celestial mechanics** and orbital dynamics + - **Vibration analysis** and structural dynamics + - **Wave propagation** problems in their natural second-order form + +## Problem Types + +### Velocity-independent problems: `d²u/dt² = f(u, t)` + +When the acceleration depends only on position (and possibly time): + + - **More efficient specialized methods** available + - **Classical examples**: gravitational problems, springs with `F = -kx` + +### Velocity-dependent problems: `d²u/dt² = f(u, du/dt, t)` + +When acceleration depends on both position and velocity: + + - **General RKN methods** handle the full dependence + - **Examples**: damped oscillators, air resistance problems + +## Solver Selection Guide + +### General-purpose RKN methods + + - **`Nystrom4`**: Fourth-order method for general second-order ODEs + - **`IRKN3`**, **`IRKN4`**: Improved Runge-Kutta-Nyström methods + +### Velocity-independent specialized methods + + - **`Nystrom4VelocityIndependent`**: Fourth-order for `d²u/dt² = f(u, t)` + - **`Nystrom5VelocityIndependent`**: Fifth-order for `d²u/dt² = f(u, t)` + +### Velocity-dependent methods + + - **`FineRKN4`**: Fourth-order allowing velocity dependence + - **`FineRKN5`**: Fifth-order allowing velocity dependence + +### High-order Dormand-Prince variants + + - **`DPRKN4`**: Fourth-order Dormand-Prince RKN + - **`DPRKN5`**: Fifth-order Dormand-Prince RKN + - **`DPRKN6`**: Sixth-order with free interpolant + - **`DPRKN6FM`**: Sixth-order with optimized error coefficients + - **`DPRKN8`**: Eighth-order for high accuracy + - **`DPRKN12`**: Twelfth-order for extreme precision + +### Trigonometrically-fitted methods for oscillatory problems + + - **`ERKN4`**: Embedded 4(3) pair for periodic problems + - **`ERKN5`**: Embedded 5(4) pair for periodic problems + - **`ERKN7`**: Higher-order embedded pair for oscillatory systems + +### Specialized methods + + - **`RKN4`**: Fourth-order for linear inhomogeneous second-order IVPs + +## Advantages Over First-Order Conversion + + - **Natural problem structure**: Preserves the physical meaning of the equations + - **Specialized optimizations**: Methods can exploit second-order structure To be able to access the solvers in `OrdinaryDiffEqRKN`, you must first install them use the Julia package manager: diff --git a/docs/src/dynamicalodeexplicit/SymplecticRK.md b/docs/src/dynamicalodeexplicit/SymplecticRK.md index cd35b08e1b..c72a2293b5 100644 --- a/docs/src/dynamicalodeexplicit/SymplecticRK.md +++ b/docs/src/dynamicalodeexplicit/SymplecticRK.md @@ -4,12 +4,81 @@ CollapsedDocStrings = true # OrdinaryDiffEqSymplecticRK -A symplectic integrator is an integrator whose solution resides on a symplectic manifold. -Because of discretization error, when it is solving a Hamiltonian system it doesn't get exactly the correct trajectory on the manifold. -Instead, that trajectory itself is perturbed `O(Δtn)` for the order n from the true trajectory. -Then there's a linear drift due to numerical error of this trajectory over time -Normal integrators tend to have a quadratic (or more) drift, and do not have any good global guarantees about this phase space path (just local). -What means is that symplectic integrators tend to capture the long-time patterns better than normal integrators because of this lack of drift and this almost guarantee of periodicity. +Symplectic integrators are specialized methods for solving Hamiltonian systems and second-order differential equations that preserve important geometric properties of the phase space. These methods are essential for long-time integration of conservative mechanical systems. + +## Key Properties + +Symplectic integrators provide: + + - **Exact conservation of symplectic structure** in phase space + - **Bounded energy error** over long time periods + - **Excellent long-time stability** without secular drift + - **Preservation of periodic orbits** and other geometric structures + - **Linear energy drift** instead of quadratic (much better than standard methods) + +## When to Use Symplectic Methods + +Symplectic integrators are essential for: + + - **Hamiltonian systems** and conservative mechanical problems + - **Molecular dynamics** and N-body simulations + - **Celestial mechanics** and orbital computations + - **Plasma physics** and charged particle dynamics + - **Long-time integration** where energy conservation is critical + - **Oscillatory problems** requiring preservation of periodic structure + - **Classical mechanics problems** with known analytical properties + +## Mathematical Background + +For a Hamiltonian system with energy `H(p,q)`, symplectic integrators preserve the symplectic structure `dp ∧ dq`. While standard integrators have energy error growing quadratically over time, symplectic methods maintain bounded energy with only linear drift, making them superior for long-time integration. + +## Solver Selection Guide + +### First-order methods + + - **`SymplecticEuler`**: First-order, simplest symplectic method. Only recommended when the dynamics function `f` is not differentiable. + +### Second-order methods + + - **`McAte2`**: Optimized second-order McLachlan-Atela method, **recommended for most applications** + - **`VelocityVerlet`**: Second-order, common choice for molecular dynamics but less efficient in terms of accuracy than McAte2 + - **`VerletLeapfrog`**: Second-order, kick-drift-kick formulation + - **`LeapfrogDriftKickDrift`**: Alternative second-order leapfrog + - **`PseudoVerletLeapfrog`**: Modified Verlet scheme + +### Third-order methods + + - **`Ruth3`**: Third-order method + - **`McAte3`**: Optimized third-order McLachlan-Atela method + +### Fourth-order methods + + - **`CandyRoz4`**: Fourth-order method + - **`McAte4`**: Fourth-order McLachlan-Atela (requires quadratic kinetic energy) + - **`CalvoSanz4`**: Optimized fourth-order method + - **`McAte42`**: Alternative fourth-order method (BROKEN) + +### Higher-order methods + + - **`McAte5`**: Fifth-order McLachlan-Atela method + - **`Yoshida6`**: Sixth-order method + - **`KahanLi6`**: Optimized sixth-order method + - **`McAte8`**: Eighth-order McLachlan-Atela method + - **`KahanLi8`**: Optimized eighth-order method + - **`SofSpa10`**: Tenth-order method for highest precision + +## Method Selection Guidelines + + - **For most applications**: `McAte2` (second-order, optimal efficiency) + - **For molecular dynamics (common choice)**: `VelocityVerlet` (less efficient than McAte2 but widely used) + - **For non-differentiable dynamics**: `SymplecticEuler` (first-order, only when necessary) + - **For computational efficiency**: `McAte2` or `McAte3` + +### Important Note on Chaotic Systems + +Most N-body problems (molecular dynamics, astrophysics) are chaotic systems where solutions diverge onto shadow trajectories. In such cases, **higher-order methods provide no practical advantage** because the true error remains O(1) for sufficiently long integrations - exactly the scenarios where symplectic methods are most needed. The geometric properties preserved by symplectic integrators are more important than high-order accuracy for chaotic systems. + +For more information on chaos and accuracy in numerical integration, see: [How Chaotic is Chaos? How Some AI for Science (SciML) Papers are Overstating Accuracy Claims](https://www.stochasticlifestyle.com/how-chaotic-is-chaos-how-some-ai-for-science-sciml-papers-are-overstating-accuracy-claims/) ## Installation @@ -47,6 +116,7 @@ sol = solve(prob, KahanLi8(), dt = 1 / 10) SymplecticEuler VelocityVerlet VerletLeapfrog +LeapfrogDriftKickDrift PseudoVerletLeapfrog McAte2 Ruth3 diff --git a/docs/src/explicit/AdamsBashforthMoulton.md b/docs/src/explicit/AdamsBashforthMoulton.md index bef0173cde..9f1bd31d5c 100644 --- a/docs/src/explicit/AdamsBashforthMoulton.md +++ b/docs/src/explicit/AdamsBashforthMoulton.md @@ -4,7 +4,84 @@ CollapsedDocStrings = true # OrdinaryDiffEqAdamsBashforthMoulton -Multistep methods, useful for integrating a very expensive to evaluate non-stiff system of differential equations. +Adams-Bashforth and Adams-Moulton multistep methods for non-stiff differential equations. **Note that Runge-Kutta methods generally come out as more efficient in benchmarks, except when the ODE function `f` is expensive to evaluate or the problem is very smooth.** These methods can achieve high accuracy with fewer function evaluations per step than Runge-Kutta methods in those specific cases. + +## Key Properties + +Adams-Bashforth-Moulton methods provide: + + - **Reduced function evaluations** compared to Runge-Kutta methods + - **High efficiency** for expensive-to-evaluate functions + - **Multistep structure** using information from previous timesteps + - **Variable step and order** capabilities for adaptive integration + - **Predictor-corrector variants** for enhanced accuracy and stability + - **Good stability properties** for non-stiff problems + +## When to Use Adams-Bashforth-Moulton Methods + +These methods are recommended for: + + - **Expensive function evaluations** where minimizing calls to `f` is critical + - **Non-stiff smooth problems** with regular solution behavior + - **Long-time integration** where efficiency over many steps matters + - **Problems with expensive Jacobian computations** that cannot use implicit methods efficiently + - **Scientific computing applications** with computationally intensive right-hand sides + - **Systems where startup cost** of multistep methods is amortized over long integration + +## Method Types + +### Explicit Adams-Bashforth (AB) + +Pure explicit multistep methods using only past information: + + - **Lower computational cost** per step + - **Less stability** than predictor-corrector variants + - **Good for mildly stiff** problems + +### Predictor-Corrector Adams-Bashforth-Moulton (ABM) + +Implicit corrector step for enhanced accuracy: + + - **Better accuracy** than pure explicit methods + - **Improved stability** properties + - **Slightly higher cost** but often worth it + +## Solver Selection Guide + +### Primary recommendation + + - **`VCABM`**: **Main recommendation** - adaptive order variable-step Adams-Bashforth-Moulton, best overall choice for Adams methods + +### Variable-step predictor-corrector methods + + - **`VCABM3`**: Third-order variable-step Adams-Bashforth-Moulton + - **`VCABM4`**: Fourth-order variable-step Adams-Bashforth-Moulton + - **`VCABM5`**: Fifth-order variable-step Adams-Bashforth-Moulton + +### Variable-step Adams-Bashforth methods + + - **`VCAB3`**: Third-order variable-step Adams-Bashforth + - **`VCAB4`**: Fourth-order variable-step Adams-Bashforth + - **`VCAB5`**: Fifth-order variable-step Adams-Bashforth + +### Fixed-step predictor-corrector methods + + - **`ABM32`**: Third-order Adams-Bashforth-Moulton + - **`ABM43`**: Fourth-order Adams-Bashforth-Moulton + - **`ABM54`**: Fifth-order Adams-Bashforth-Moulton + +### Fixed-step explicit methods + + - **`AB3`**: Third-order Adams-Bashforth + - **`AB4`**: Fourth-order Adams-Bashforth + - **`AB5`**: Fifth-order Adams-Bashforth + +## Performance Considerations + + - **Most efficient** when function evaluation dominates computational cost + - **Startup phase** requires initial steps from single-step method + - **Memory efficient** compared to high-order Runge-Kutta methods + - **Best for smooth problems** - avoid for problems with discontinuities ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/Extrapolation.md b/docs/src/explicit/Extrapolation.md index 5d80afc833..fb27c27f84 100644 --- a/docs/src/explicit/Extrapolation.md +++ b/docs/src/explicit/Extrapolation.md @@ -4,11 +4,67 @@ CollapsedDocStrings = true # OrdinaryDiffEqExtrapolation -Solvers based on within method parallelism, allowing multithreading of the solution across -different values of `f`. -The explicit extrapolation solvers are generally outclassed by other explicit methods. -However, some [stiff extrapolation](@ref StiffExtrapolation) methods perform very well if -the problem is sufficiently stiff. +Explicit extrapolation methods that achieve high accuracy through Richardson extrapolation of basic integration schemes. These methods provide adaptive order capabilities and natural parallelism, though they are generally outclassed by modern Runge-Kutta methods for most non-stiff problems. + +## Key Properties + +Extrapolation methods provide: + + - **Adaptive order capability** allowing arbitrarily high orders + - **Natural parallelism** across different substep sequences + - **High accuracy potential** for very smooth problems + - **Richardson extrapolation** to eliminate lower-order error terms + - **Automatic stepsize and order control** + - **Theoretical appeal** but often practical limitations + +## When to Use Extrapolation Methods + +These methods are recommended for: + + - **Very smooth problems** where high-order accuracy is beneficial + - **Extremely low tolerance requirements** where adaptive order helps + - **Parallel computing environments** that can exploit the natural parallelism + - **Research applications** exploring adaptive order techniques + - **Problems where other high-order methods struggle** with accuracy + +## Important Limitations + + - **Generally outclassed** by modern explicit RK methods (Tsit5, Verner methods) + - **Higher computational overhead** compared to optimized RK methods + - **Best suited for very smooth functions** - poor performance on non-smooth problems + - **Parallel efficiency gains** often don't compensate for increased work + +## Mathematical Background + +Extrapolation methods use sequences of basic integrators (like Euler or midpoint) with different stepsizes, then apply Richardson extrapolation to achieve higher-order accuracy. The adaptive order capability comes from using longer extrapolation sequences. + +## Solver Selection Guide + +### Explicit extrapolation methods + + - **`AitkenNeville`**: Euler extrapolation using Aitken-Neville algorithm + - **`ExtrapolationMidpointDeuflhard`**: Midpoint extrapolation with barycentric coordinates + - **`ExtrapolationMidpointHairerWanner`**: Midpoint extrapolation following ODEX algorithm + +### When to consider these methods + + - **Very low tolerances** (< 1e-12) where adaptive order might help + - **Extremely smooth problems** with analytic solutions + - **Parallel computing** scenarios with many available cores + - **Comparison studies** with other high-order methods + +### Better alternatives for most problems + + - **For high accuracy**: Use Verner methods (Vern7, Vern8, Vern9) + - **For general problems**: Use Tsit5 or appropriate RK method + - **For stiff problems**: Consider [implicit extrapolation methods](@ref StiffExtrapolation) + +## Performance Notes + + - **Consider stiff extrapolation** methods which can perform very well for sufficiently stiff problems + - **Test against Verner methods** before choosing extrapolation for high accuracy + - **Parallelism benefits** are problem and hardware dependent + - **Most effective** on very smooth, well-behaved problems ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/Feagin.md b/docs/src/explicit/Feagin.md index c2f66d9727..d0857bbf38 100644 --- a/docs/src/explicit/Feagin.md +++ b/docs/src/explicit/Feagin.md @@ -4,13 +4,62 @@ CollapsedDocStrings = true # OrdinaryDiffEqFeagin -Preferred solvers for non-stiff problems at very low tolerance, `<1e-30`. -Best combined with preciser than `Float64` number types for the state, such as the `BigFloat` number type. -Note that the Feagin methods have a less robust error estimator than the Verner methods, and thus even for -very low tolerance problems the Verner methods (`Vern9`) may still be more efficient. In addition, at extremely -low tolerances the explicit extrapolation methods allow for arbitrarily high variable order stepping which will -also outperform the Feagin methods. As such, the Feagin methods may be useful in the Float128 precision range -but should be tested against other algorithms. +Ultra-high-order explicit Runge-Kutta methods for non-stiff problems at extremely low tolerances (< 1e-30). These methods are designed for applications requiring extreme precision, typically used with higher-precision number types like `BigFloat`. + +## Key Properties + +Feagin methods provide: + + - **Ultra-high-order accuracy** (10th, 12th, and 14th order) + - **Extreme precision capabilities** for very low tolerance requirements + - **Compatibility with arbitrary precision** arithmetic (`BigFloat`, `Float128`) + - **Specialized for very demanding applications** requiring maximum accuracy + +## When to Use Feagin Methods + +These methods are recommended for: + + - **Extremely low tolerance problems** (< 1e-30) + - **Arbitrary precision arithmetic** applications using `BigFloat` or `Float128` + - **Ultra-high precision requirements** where standard methods are insufficient + - **Research applications** requiring maximum possible accuracy + - **Long-time integration** where error accumulation must be minimized to extreme levels + +## Important Limitations + +### Theoretical vs Practical Performance + + - **Very good theoretical efficiency** due to high order and optimized coefficients + - **Poor practical performance** in benchmarks due to bad error estimators and adaptivity issues + - **Generally recommend `Vern9` instead** as it tends to be more efficient in practice despite lower theoretical order + +### Performance Considerations + + - **May be less efficient** than `Vern9` even for very low tolerance problems + - **Outperformed by extrapolation methods** at extremely low tolerances due to adaptive order + - **Potential efficiency for >128-bit numbers** but no practical cases found yet where this is actually true + - **Should always be tested** against `Vern9` and extrapolation methods + +## Solver Selection Guide + +### Extreme precision (< 1e-30) + + - **`Feagin14`**: 14th-order method for maximum accuracy + - **`Feagin12`**: 12th-order method, balance of accuracy and efficiency + - **`Feagin10`**: 10th-order method for moderate extreme precision + +### Strongly recommended alternatives + + - **For most very low tolerance problems**: Use `Vern9` first (more efficient in practice despite lower theoretical order) + - **For extremely low tolerances**: Consider extrapolation methods for adaptive order + - **For >128-bit precision**: These methods may be more efficient, but no practical cases found yet + - **Always benchmark**: Compare performance with `Vern9` and extrapolation methods before choosing Feagin methods + +## Usage Guidelines + + - **Best with `BigFloat`** or `Float128` number types + - **Useful in Float128 precision range** but test against other algorithms + - **Consider problem-specific characteristics** when choosing order level ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/HighOrderRK.md b/docs/src/explicit/HighOrderRK.md index 0f7648354f..9b68fe9a68 100644 --- a/docs/src/explicit/HighOrderRK.md +++ b/docs/src/explicit/HighOrderRK.md @@ -4,8 +4,44 @@ CollapsedDocStrings = true # OrdinaryDiffEqHighOrderRK -Solvers for non-stiff problems at low tolerance. -However, the solvers in [`OrdinaryDiffEqVerner`](@ref OrdinaryDiffEqVerner) generally perform better at low tolerances. +High-order explicit Runge-Kutta methods for non-stiff differential equations requiring high accuracy. These methods provide alternatives to the Verner methods, though **[`OrdinaryDiffEqVerner`](@ref OrdinaryDiffEqVerner) methods generally perform better at low tolerances** and should be preferred in most cases. + +## Key Properties + +High-order RK methods provide: + + - **High-order accuracy** (7th and 8th order) for precise integration + - **Specialized coefficients** for specific problem types + - **Dense output capabilities** for some methods + - **Alternative approaches** to the more commonly used Verner methods + +## When to Use High-Order RK Methods + +These methods are recommended when: + + - **Verner methods are not suitable** for specific problem characteristics + - **Specialized properties** are needed (e.g., phase-fitted methods for oscillatory problems) + - **Research or comparison purposes** require different high-order method families + - **Specific applications** benefit from particular method properties + +## Solver Selection Guide + +### General high-order integration + + - **Use [`Vern7`](@ref OrdinaryDiffEqVerner) or [`Vern8`](@ref OrdinaryDiffEqVerner) instead** - they are generally more efficient + +### Specialized cases where these methods may be preferred + + - **`TanYam7`**: Seventh-order Tanaka-Yamashita method + - **`TsitPap8`**: Eighth-order Tsitouras-Papakostas method + - **`DP8`**: Eighth-order Dormand-Prince method (Hairer's 8/5/3 implementation) + - **`PFRK87`**: Phase-fitted eighth-order method for oscillatory problems + +## Performance Notes + + - **Verner methods are generally more efficient** for most high-accuracy applications + - **These methods are provided** for specialized use cases and research purposes + - **Consider problem-specific properties** when choosing between different high-order families ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/LowOrderRK.md b/docs/src/explicit/LowOrderRK.md index 662b67fda3..7ebc09caa9 100644 --- a/docs/src/explicit/LowOrderRK.md +++ b/docs/src/explicit/LowOrderRK.md @@ -4,13 +4,74 @@ CollapsedDocStrings = true # OrdinaryDiffEqLowOrderRK -If [`OrdinaryDiffEqTsit5`](@ref OrdinaryDiffEqTsit5) is not working well for your non-stiff problem at default and higher tolerance, -it can be worthwhile to explore the options in this package. -In particular, when more robust error control is required, [`BS5`](@ref) is a good choice. -If at moderate tolerances and the interpolation error is very important, -consider the [`OwrenZen5`](@ref) method. -For fast solving at higher tolerances, we recommend [`BS3`](@ref), -or [`OwrenZen3`](@ref)if the interpolation error is important. +Low-order explicit Runge-Kutta methods for non-stiff differential equations. **Most of the time, you should use [`Tsit5`](@ref OrdinaryDiffEqTsit5)**, which is the most common and efficient low-order RK method. The alternative methods provided here are for special circumstances where Tsit5 is not suitable. + +## Key Properties + +Low-order explicit RK methods offer: + + - **Computational efficiency** at higher tolerances (>1e-6) + - **Robust error control** for difficult non-stiff problems + - **Specialized interpolation properties** for applications requiring dense output + - **Lower-order derivatives** requirements for non-smooth functions + - **Good performance** for specific problem types + +## When to Use Alternative Low-Order RK Methods + +Choose these methods instead of Tsit5 when: + + - **ODE function `f` is not differentiable to 5th order** - use lower-order methods (the more discontinuous, the lower the order needed) + - **Heavy use of interpolations** - OwrenZen methods have superior interpolation convergence + - **Delay differential equations** - OwrenZen methods are most efficient (see SciMLBenchmarks) + - **Very high tolerances** (>1e-3) - BS3 is more efficient than Tsit5 + - **Quadratic polynomial ODEs** - SIR54 is optimized for these systems + - **Educational purposes** - simpler methods for understanding algorithms + +## Solver Selection Guide + +### Primary recommendation + +**For most problems, use [`Tsit5`](@ref OrdinaryDiffEqTsit5) instead of these methods.** + +### High tolerances (>1e-3) + + - **`BS3`**: Third-order Bogacki-Shampine method, most efficient for very high tolerances + +### Superior interpolation needs + + - **`OwrenZen3`**: Third-order with excellent interpolation convergence + - **`OwrenZen5`**: Fifth-order with excellent interpolation, **optimal for DDEs** + - **`OwrenZen4`**: Fourth-order interpolation-optimized method + +### Non-smooth or discontinuous ODEs + + - **`BS3`**: Third-order for mildly non-smooth functions + - **`Heun`**: Second-order for more discontinuous functions (not generally recommended) + - **`Euler`**: First-order for highly discontinuous problems + +### Robust error control alternatives + + - **`BS5`**: Fifth-order with very robust error estimation + - **`DP5`**: Fifth-order Dormand-Prince method, classical alternative to Tsit5 + +### Specialized applications + + - **`RK4`**: Fourth-order with special residual error control, good for DDEs. **Note**: Uses adaptive timestepping by default - set `adaptive=false` in `solve()` for traditional fixed-step RK4 + - **`SIR54`**: Fifth-order optimized for ODEs defined by quadratic polynomials (e.g., SIR-type epidemiological models) + - **`Stepanov5`**: Fifth-order method with enhanced stability properties and optimized error constants + - **`Ralston`**: Second-order with optimized error constants + +### Periodic and oscillatory problems + + - **`Anas5`**: Fifth-order optimized for periodic problems with minimal phase error + - **`FRK65`**: Sixth-order zero dissipation method for oscillatory problems + +### Advanced specialized methods + + - **`RKO65`**: Sixth-order optimized method + - **`MSRK5`**, **`MSRK6`**: Multi-stage methods for specific applications + - **`PSRK4p7q6`**, **`PSRK3p5q4`**, **`PSRK3p6q5`**: Pseudo-symplectic methods + - **`Alshina2`**, **`Alshina3`**, **`Alshina6`**: Methods with optimized parameters ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/LowStorageRK.md b/docs/src/explicit/LowStorageRK.md index 563c134554..2d14f1a0b1 100644 --- a/docs/src/explicit/LowStorageRK.md +++ b/docs/src/explicit/LowStorageRK.md @@ -4,11 +4,73 @@ CollapsedDocStrings = true # OrdinaryDiffEqLowStorageRK -These methods are designed to have reduced register requirements, allowing for larger sets of ODEs to more -easily fit into RAM. For example, while the 5th order Tsit5 requires around 9 concurrent instantiations of the -ODE state `u`, `RDPK3Sp510` can achieve 5th order with 3 registers, effectively requiring 1/3 of the memory. -However, there are some efficiency trade-offs used in the design of the low-storage RK methods, and thus they -are generally only recommended in situations which are RAM bound, like large-scale PDE discretizations. +Low-storage Runge-Kutta methods are specialized explicit schemes designed to minimize memory requirements while maintaining high-order accuracy. These methods are essential for large-scale computational fluid dynamics and wave propagation problems where memory constraints are critical. + +## Key Properties + +Low-storage RK methods provide: + + - **Drastically reduced memory usage** (typically 2-4 registers vs 7-10 for standard RK) + - **High-order accuracy** comparable to standard RK methods + - **Preservation of important stability properties** (low dissipation/dispersion) + - **Scalability** to very large PDE discretizations + +## When to Use Low-Storage RK Methods + +These methods are recommended for: + + - **Large-scale PDE discretizations** where memory is the limiting factor + - **Computational fluid dynamics** and wave propagation simulations + - **High-performance computing** applications with memory constraints + - **GPU computations** where memory bandwidth is critical + - **Compressible flow simulations** and aerodynamics + - **Seismic wave propagation** and acoustic simulations + - **Problems with millions or billions of unknowns** + +## Memory Efficiency Comparison + +**Registers** refer to the number of copies of the `u0` vector that must be stored in memory during integration: + + - **Standard Tsit5**: ~9 registers (copies of the state vector) + - **Low-storage methods**: 2-4 registers (copies of the state vector) + - **Practical example**: If `u0` is from a PDE semi-discretization requiring 2 GB, then Tsit5 needs 18 GB of working memory, while a 2-register method only needs 4 GB and can achieve the same order + - **Trade-off**: These methods achieve memory reduction by being less computationally efficient, trading compute performance for lower memory requirements + +## Solver Selection Guide + +### General-purpose low-storage + + - **`CarpenterKennedy2N54`**: Fourth-order, 5-stage, excellent general choice + - **`RDPK3Sp510`**: Fifth-order with only 3 registers, very memory efficient + +### Wave propagation optimized + + - **`ORK256`**: Second-order, 5-stage, optimized for wave equations + - **`CFRLDDRK64`**: Low-dissipation and low-dispersion variant + - **`TSLDDRK74`**: Seventh-order for high accuracy wave propagation + +### Discontinuous Galerkin optimized + + - **`DGLDDRK73_C`**: Optimized for DG discretizations (constrained) + - **`DGLDDRK84_C`**, **`DGLDDRK84_F`**: Fourth-order DG variants + +### Specialized high-order + + - **`NDBLSRK124`**, **`NDBLSRK144`**: Multi-stage fourth-order methods + - **`SHLDDRK64`**: Low dissipation and dispersion properties + - **`RK46NL`**: Six-stage fourth-order method + +### Computational fluid dynamics + + - **Carpenter-Kennedy-Lewis series** (`CKLLSRK*`): Optimized for Navier-Stokes equations + - **Parsani-Ketcheson-Deconinck series** (`ParsaniKetcheson*`): CFD-optimized variants + - **Ranocha-Dalcin-Parsani-Ketcheson series** (`RDPK*`): Modern CFD methods + +## Performance Considerations + + - **Use only when memory-bound**: Standard RK methods are often more efficient when memory is not limiting + - **Best for large systems**: Most beneficial for problems with >10⁶ unknowns + - **GPU acceleration**: Particularly effective on memory-bandwidth limited hardware ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/PRK.md b/docs/src/explicit/PRK.md index f1cf3ed72e..c866052058 100644 --- a/docs/src/explicit/PRK.md +++ b/docs/src/explicit/PRK.md @@ -4,7 +4,81 @@ CollapsedDocStrings = true # OrdinaryDiffEqPRK -Explicit solvers optimized for a certain number of parallel calls of the system of ordinary differential equations `f`. +Parallel Runge-Kutta (PRK) methods are explicit solvers specifically designed to exploit parallelism by making multiple independent evaluations of the ODE function `f` simultaneously. These methods are optimized for parallel computing environments where function evaluations can be distributed across multiple processors. + +!!! warning "Research and Development" + + These methods are currently in research and development and not intended for general use. + +## Key Properties + +PRK methods provide: + + - **Explicit parallelism** in function evaluations within each timestep + - **Fixed processor count optimization** for specific parallel architectures + - **Independent stage evaluations** that can run simultaneously + - **Maintained accuracy** while achieving parallel speedup + - **Specialized tableaus** designed for parallel efficiency + +## When to Use PRK Methods + +These methods are recommended for: + + - **Parallel computing environments** with multiple processors available + - **Expensive function evaluations** that benefit from parallelization + - **Systems where function evaluation dominates** computational cost + - **Applications with fixed parallel architecture** (e.g., exactly 2 or 5 processors) + - **Problems where parallel speedup** outweighs method overhead + +## Important Considerations + +### Parallel Requirements + + - **Requires multiple processors** to achieve benefits + - **Function evaluations must be parallelizable** (no data dependencies) + - **Parallel overhead** must be less than speedup gains + - **Fixed processor count** optimization may not match available hardware + +### When NOT to Use + + - **Sequential computing** environments + - **Cheap function evaluations** where parallel overhead dominates + - **Memory-bound problems** where parallelism doesn't help + - **Variable processor availability** scenarios + - **Large systems** where LU factorization of implicit steps parallelizes efficiently (around 200×200 matrices and larger on modern processors) + +## Mathematical Background + +PRK methods rearrange traditional Runge-Kutta tableaus to allow stage evaluations to be computed independently and simultaneously. The specific processor count determines the tableau structure and achievable parallelism. + +## Solver Selection Guide + +### Available methods + + - **`KuttaPRK2p5`**: Fifth-order method optimized for 2 processors + +### Usage considerations + + - **Best with exactly 2 processors** for KuttaPRK2p5 + - **Function evaluation must support** parallel execution + - **Test parallel efficiency** against sequential high-order methods + - **Consider problem-specific** parallel architecture + +## Performance Guidelines + + - **Measure actual speedup** vs sequential methods on target hardware + - **Account for parallel overhead** in performance comparisons + - **Consider memory bandwidth** limitations in parallel environments + - **Compare against** other parallelization strategies (e.g., spatial domain decomposition) + +## Alternative Parallelization Approaches + +For most problems, consider these alternatives: + + - **Spatial domain decomposition** for PDE problems + - **Multiple trajectory parallelism** for Monte Carlo simulations + - **Vectorized operations** within function evaluations + - **High-order sequential methods** with better single-thread performance ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/QPRK.md b/docs/src/explicit/QPRK.md index 507f30de38..3c6008e832 100644 --- a/docs/src/explicit/QPRK.md +++ b/docs/src/explicit/QPRK.md @@ -4,8 +4,85 @@ CollapsedDocStrings = true # OrdinaryDiffEqQPRK -Explicit solvers optimized for a certain number of parallel calls of the system of ordinary differential equations `f`. -Particularly good at low tolerances, when using quad-precision arithmetic, `Float128`. +Quadruple-precision parallel Runge-Kutta (QPRK) methods are high-order explicit solvers specifically designed for ultra-high precision computations using quad-precision arithmetic (`Float128`). These methods combine parallel evaluation capabilities with coefficients optimized for extended precision arithmetic. **Note: These methods are still under-benchmarked and need more research.** + +## Key Properties + +QPRK methods provide: + + - **Ultra-high-order accuracy** (9th order) for maximum precision + - **Quadruple-precision optimization** specifically designed for `Float128` + - **Parallel function evaluations** for computational efficiency + - **Extreme precision capabilities** for very demanding applications + - **Optimized coefficients** for extended precision arithmetic + +## When to Use QPRK Methods + +These methods are recommended for: + + - **Ultra-high precision requirements** demanding `Float128` arithmetic + - **Extremely low tolerances** (< 1e-20) where standard precision fails + - **Scientific applications** requiring maximum possible accuracy + - **Parallel computing environments** with quad-precision support + - **Research applications** exploring limits of numerical precision + - **Long-time integration** where error accumulation must be minimized to extreme levels + +## Important Requirements + +### Precision Requirements + + - **Must use `Float128`** or higher precision number types + - **All problem components** should support extended precision + - **Tolerances should match** the precision capabilities (< 1e-20) + +### Computational Considerations + + - **Slower** than standard precision methods due to extended precision arithmetic + - **Higher memory usage** due to extended precision + - **Limited hardware support** for quad-precision operations + +## Mathematical Background + +QPRK methods use tableaus with coefficients computed in extended precision to maintain accuracy throughout the ultra-high precision computation. The parallel structure allows independent function evaluations to be computed simultaneously. + +## Solver Selection Guide + +### Available methods + + - **`QPRK98`**: Ninth-order method optimized for quad-precision arithmetic with parallel evaluation + +### Usage guidelines + + - **Essential to use `Float128`** for the state vector and parameters + - **Consider [MultiFloats.jl](https://github.com/dzhang314/MultiFloats.jl)** for higher precision number types + - **Set very low tolerances** (e.g., 1e-25) to utilize full precision + - **Test against alternatives** like Feagin methods with `BigFloat` + +## Performance Considerations + + - **Slower** than standard precision methods due to extended precision arithmetic + - **Memory intensive** due to extended precision storage + - **Hardware dependent** - some architectures lack efficient quad-precision support + +## Alternative High-Precision Methods + +For ultra-high precision, also consider: + + - **Feagin methods** with `BigFloat` for arbitrary precision + - **Arbitrary precision extrapolation** methods + - **Verner methods** with `BigFloat` for slightly lower but efficient precision + - **Taylor series methods** with automatic differentiation for extreme precision + +## Usage Example + +```julia +using OrdinaryDiffEqQPRK +# Ensure using Float128 for ultra-high precision +u0 = Float128[1.0, 0.0] +tspan = (Float128(0.0), Float128(10.0)) +prob = ODEProblem(f, u0, tspan) +sol = solve(prob, QPRK98(), abstol = 1e-25, reltol = 1e-25) +``` ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/SSPRK.md b/docs/src/explicit/SSPRK.md index d0fd732d05..b928f3a62b 100644 --- a/docs/src/explicit/SSPRK.md +++ b/docs/src/explicit/SSPRK.md @@ -4,13 +4,67 @@ CollapsedDocStrings = true # OrdinaryDiffEqSSPRK -SSPRK methods are Runge-Kutta methods which support the "strongly preserving property" (SSP). -They are designed for the use in discretizations of hyperbolic partial differential equations and conservation laws -as they have extra stability properties ( e.g., stability with respect to total variation, the maximum norm, or other convex functionals) -when step-size restrictions are respected. -In particular, these properties are granted if the step-size is kept to a level where the CFL coefficients are less than the SSP coefficient. +Strong Stability Preserving Runge-Kutta (SSPRK) methods are specialized explicit Runge-Kutta methods designed to preserve important stability properties of the underlying spatial discretization when applied to hyperbolic partial differential equations and conservation laws. -Note that for SSPRK methods, a algorithm utility `OrdinaryDiffEqCore.ssp_coefficient(alg)` exists that allows for querying the SSP coefficient for use in step size calculations. +## Key Properties + +SSPRK methods provide: + + - **Strong stability preservation** for convex functionals (total variation, maximum norm, entropy) + - **Optimal SSP coefficients** allowing larger stable timesteps + - **Non-oscillatory behavior** crucial for hyperbolic PDEs and conservation laws + - **High-order accuracy** while maintaining monotonicity properties + - **Specialized variants** for different orders and storage requirements + +## When to Use SSPRK Methods + +SSPRK methods are essential for: + + - **Hyperbolic partial differential equations** (Euler equations, shallow water, etc.) + - **Conservation laws** where preserving physical bounds is critical + - **Discontinuous Galerkin methods** and other high-order spatial discretizations + - **Problems requiring monotonicity preservation** or total variation stability + - **Shock-capturing schemes** where spurious oscillations must be avoided + - **Astrophysical simulations** and computational fluid dynamics + +## SSP Coefficient and CFL Conditions + +The SSP coefficient determines the maximum allowable timestep for stability preservation. Use `OrdinaryDiffEqCore.ssp_coefficient(alg)` to query this value for step size calculations. The timestep must satisfy `dt ≤ CFL * dx / max_wavespeed` where CFL ≤ SSP coefficient. + +## Solver Selection Guide + +### Second-order methods + + - **`SSPRK22`**: Two-stage, second-order (SSP coefficient = 1) + - **`SSPRKMSVS32`**: Three-step multistep variant + +### Third-order methods + + - **`SSPRK33`**: Three-stage, third-order, optimal (SSP coefficient = 1) + - **`SSPRK53`**: Five-stage, third-order, higher SSP coefficient + - **`SSPRK63`**, **`SSPRK73`**, **`SSPRK83`**: More stages for larger SSP coefficients + - **`SSPRK43`**: Four-stage with embedded error estimation + - **`SSPRK432`**: Low-storage variant + +### Fourth-order methods + + - **`SSPRK54`**: Five-stage, fourth-order + - **`SSPRK104`**: Ten-stage, fourth-order, large SSP coefficient + +### Low-storage variants + + - **`SSPRK53_2N1`**, **`SSPRK53_2N2`**, **`SSPRK53_H`**: Two-register storage schemes + +### Discontinuous Galerkin optimized + + - **`KYKSSPRK42`**: Optimized for DG spatial discretizations + - **`KYK2014DGSSPRK_3S2`**: Specialized DG method + +### Adaptive methods + + - **`SSPRK432`**: Third-order with error control + - **`SSPRK932`**: High-stage adaptive method + - **`SSPRKMSVS43`**: Multistep adaptive variant ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/TaylorSeries.md b/docs/src/explicit/TaylorSeries.md new file mode 100644 index 0000000000..6e6b6cc7ee --- /dev/null +++ b/docs/src/explicit/TaylorSeries.md @@ -0,0 +1,134 @@ +```@meta +CollapsedDocStrings = true +``` + +# OrdinaryDiffEqTaylorSeries + +Taylor series methods for ordinary differential equations using automatic differentiation. These methods achieve very high-order accuracy by computing Taylor expansions of the solution using automatic differentiation techniques through TaylorDiff.jl. + +!!! warn "Development Status" + + These methods are still in development and may not be fully optimized or reliable for production use. + +## Key Properties + +Taylor series methods provide: + + - **Very high-order accuracy** with arbitrary order capability + - **Automatic differentiation** for derivative computation + - **Step size control** through Taylor series truncation + - **Natural error estimation** from higher-order terms + - **Excellent accuracy** for smooth problems + - **Single-step methods** without requiring history + +## When to Use Taylor Series Methods + +These methods are recommended for: + + - **Ultra-high precision problems** where maximum accuracy is needed + - **Smooth problems** with well-behaved derivatives + - **Scientific computing** requiring very low error tolerances + - **Problems with expensive function evaluations** where high-order methods reduce total steps + +## Mathematical Background + +Taylor series methods compute the solution using Taylor expansions: +`u(t + h) = u(t) + h*u'(t) + h²/2!*u''(t) + h³/3!*u'''(t) + ...` + +The derivatives are computed automatically using automatic differentiation, allowing arbitrary-order methods without manual derivative computation. + +## Solver Selection Guide + +### Available Methods + + - **`ExplicitTaylor2`**: Second-order Taylor series method for moderate accuracy + - **`ExplicitTaylor`**: Arbitrary-order Taylor series method (specify order with `order = Val{p}()`) + +### Usage considerations + + - **Smooth problems only**: Methods assume the function has many continuous derivatives + - **Computational cost**: Higher orders require more automatic differentiation computations + - **Memory requirements**: Higher orders store more derivative information + +## Performance Guidelines + +### When Taylor series methods excel + + - **Very smooth problems** where high-order derivatives exist and are well-behaved + - **High precision requirements** beyond standard double precision + - **Long-time integration** where accumulated error matters + - **Problems where function evaluations dominate** computational cost + +### Problem characteristics + + - **Polynomial and analytic functions** work extremely well + - **Smooth ODEs** from physics simulations + - **Problems requiring** very low tolerances (< 1e-12) + +## Limitations and Considerations + +### Method limitations + + - **Requires smooth functions** - non-smooth problems may cause issues + - **Memory overhead** for storing multiple derivatives + - **Limited to problems** where high-order derivatives are meaningful + - **Automatic differentiation compatibility** - requires functions compatible with TaylorDiff.jl and Symbolics.jl tracing + - **Long compile times** due to automatic differentiation and symbolic processing overhead + +### When to consider alternatives + + - **Non-smooth problems**: Use adaptive Runge-Kutta methods instead + - **Stiff problems**: Taylor methods are explicit and may be inefficient + - **Large systems**: Automatic differentiation cost may become prohibitive + - **Standard accuracy needs**: Lower-order methods are often sufficient + +## Alternative Approaches + +Consider these alternatives: + + - **High-order Runge-Kutta** methods (Feagin, Verner) for good accuracy with less overhead + - **Extrapolation methods** for high accuracy with standard function evaluations + - **Adaptive methods** for problems with varying smoothness + - **Implicit methods** for stiff problems requiring high accuracy + +## Installation and Usage + +Taylor series methods require explicit installation of the specialized library: + +```julia +using Pkg +Pkg.add("OrdinaryDiffEqTaylorSeries") +``` + +Then use the methods with: + +```julia +using OrdinaryDiffEqTaylorSeries + +# Example: Second-order Taylor method +function f(u, p, t) + σ, ρ, β = p + du1 = σ * (u[2] - u[1]) + du2 = u[1] * (ρ - u[3]) - u[2] + du3 = u[1] * u[2] - β * u[3] + [du1, du2, du3] +end + +u0 = [1.0, 0.0, 0.0] +tspan = (0.0, 10.0) +p = [10.0, 28.0, 8/3] +prob = ODEProblem(f, u0, tspan, p) + +# Second-order Taylor method +sol = solve(prob, ExplicitTaylor2()) + +# Arbitrary-order Taylor method (e.g., 8th order) +sol = solve(prob, ExplicitTaylor(order = Val{8}())) +``` + +## Full list of solvers + +```@docs +ExplicitTaylor2 +ExplicitTaylor +``` diff --git a/docs/src/explicit/Tsit5.md b/docs/src/explicit/Tsit5.md index 921427d667..6eea21d6aa 100644 --- a/docs/src/explicit/Tsit5.md +++ b/docs/src/explicit/Tsit5.md @@ -4,7 +4,49 @@ CollapsedDocStrings = true # [OrdinaryDiffEqTsit5](@id OrdinaryDiffEqTsit5) -Recommended solver for most non-stiff problems at default and higher tolerance. +The Tsitouras 5/4 method is the **recommended default solver** for most non-stiff differential equation problems. This method provides an excellent balance of efficiency, reliability, and accuracy. + +## Key Properties + +Tsit5 offers: + + - **Fifth-order accuracy** with embedded fourth-order error estimation + - **Excellent efficiency** at default tolerances (1e-6 to 1e-3) + - **FSAL (First Same As Last)** property for computational efficiency + - **High-quality interpolation** for dense output + - **Robust performance** across a wide range of problem types + - **Optimized coefficients** for minimal error in practical applications + +## When to Use Tsit5 + +Tsit5 is recommended for: + + - **Most non-stiff problems** as the first choice solver + - **Default and higher tolerances** (1e-3 to 1e-6) + - **General-purpose integration** when problem characteristics are unknown + - **Educational and research applications** as a reliable baseline + - **Real-time applications** requiring predictable performance + - **Problems where simplicity and reliability** are preferred over maximum efficiency + +## Solver Selection Guide + +### Primary recommendation + + - **`Tsit5`**: Use as the default choice for non-stiff problems at standard tolerances + +### Automatic switching + + - **`AutoTsit5`**: Automatically switches to a stiff solver when stiffness is detected, making it robust for problems of unknown character + +## When to Consider Alternatives + +Consider other solvers when: + + - **Higher accuracy needed**: Use Verner methods (Vern6, Vern7, Vern8, Vern9) for tolerances below 1e-6 + - **Higher tolerances**: Use BS3 or OwrenZen3 for tolerances above 1e-3 + - **Robust error control needed**: Use BS5 when Tsit5 struggles with error estimation + - **Equation is stiff**: Use implicit methods (SDIRK, BDF) or semi-implicit methods (Rosenbrock) for stiff problems + - **Special properties required**: Use specialized methods (SSP, symplectic, etc.) for specific problem types ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/explicit/Verner.md b/docs/src/explicit/Verner.md index 51b1dac276..afb1877cd7 100644 --- a/docs/src/explicit/Verner.md +++ b/docs/src/explicit/Verner.md @@ -4,10 +4,54 @@ CollapsedDocStrings = true # [OrdinaryDiffEqVerner](@id OrdinaryDiffEqVerner) -Preferred solvers for non-stiff problems at low tolerance. -`Vern6`, `Vern7`, or `Vern8` are good methods for tolerances between `~1e-8-1e-12`, -and using `Float64` numbers for the state of the differential equation. -For even lower tolerances,`Vern9` should be used, combined with the more precise `BigFloat` number type. +Verner methods are high-order explicit Runge-Kutta methods designed for high-accuracy integration of non-stiff differential equations. These are the preferred solvers when very low tolerances are required. + +## Key Properties + +Verner methods provide: + + - **High-order accuracy** (6th through 9th order) for precise integration + - **Excellent efficiency** at low tolerances (1e-8 to 1e-15) + - **Robust error estimation** with embedded error control + - **Dense output capability** with high-quality interpolation + +## When to Use Verner Methods + +Verner methods are recommended for: + + - **High-accuracy requirements** with tolerances between 1e-8 and 1e-15 + - **Smooth non-stiff problems** where high precision is critical + - **Long-time integration** where error accumulation must be minimized + - **Problems requiring dense output** with high interpolation accuracy + - **Orbit computation, molecular dynamics,** and other precision-critical applications + +## Solver Selection Guide + +### Medium-low tolerance (1e-6 to 1e-8) + + - **`Vern6`**: Sixth-order method, good balance of efficiency and accuracy + - **`AutoVern6`**: Automatic switching version for mixed stiffness + +### Low tolerance (1e-8 to 1e-12) with Float64 + + - **`Vern7`**: Seventh-order method, excellent for most high-precision needs + - **`Vern8`**: Eighth-order method, best efficiency at very low tolerances + - **`AutoVern7`**, **`AutoVern8`**: Automatic switching versions + +### Very low tolerance (<1e-12) + + - **`Vern9`**: Ninth-order method for extreme precision requirements + - **Recommended with `BigFloat`** for tolerances below 1e-15 + - **`AutoVern9`**: Automatic switching version for mixed problems + +## Performance Notes + + - **Vern6**: Most efficient for tolerances around 1e-6 to 1e-8 + - **Vern7**: Sweet spot for tolerances around 1e-8 to 1e-10 + - **Vern8**: Best for tolerances around 1e-10 to 1e-12 + - **Vern9**: For tolerances below 1e-12, especially with arbitrary precision + +The `Auto*` variants automatically switch to stiff solvers when stiffness is detected, making them robust for problems of unknown character. ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/fullyimplicitdae/BDF.md b/docs/src/fullyimplicitdae/BDF.md index 5f0c6ae38d..e028eb198f 100644 --- a/docs/src/fullyimplicitdae/BDF.md +++ b/docs/src/fullyimplicitdae/BDF.md @@ -4,11 +4,45 @@ CollapsedDocStrings = true # OrdinaryDiffEqBDF -Multistep BDF methods, good for large stiff systems. +BDF (Backward Differentiation Formula) methods for fully implicit differential-algebraic equations (DAEs) in the form F(du/dt, u, t) = 0. These methods provide robust integration for index-1 DAE systems with fully implicit formulations. -```@eval -using OrdinaryDiffEqBDF +!!! warn "Performance Consideration" + + DFBDF and family have not been made fully efficient yet, and thus Sundials.jl IDA is recommended for production use. + +## Key Properties + +Fully implicit DAE BDF methods provide: + + - **General DAE capability** for F(du/dt, u, t) = 0 formulations + - **Index-1 DAE support** for properly formulated DAE systems + - **Robust nonlinear solver integration** for implicit equation systems + - **High-order accuracy** with excellent stability properties + - **Large stiff system capability** with efficient linear algebra + +## When to Use Fully Implicit DAE BDF Methods + +These methods are recommended for: + + - **Fully implicit DAE systems** where F(du/dt, u, t) = 0 cannot be easily rearranged + - **Index-1 DAE problems** that cannot be easily rearranged to semi-explicit form + - **Multibody dynamics** with complex kinematic constraints + - **Electrical circuits** with ideal components and algebraic loops + - **Chemical engineering** with equilibrium and conservation constraints + - **Large-scale DAE systems** requiring robust implicit integration + +## Mathematical Background + +Fully implicit DAEs have the general form: +F(du/dt, u, t) = 0 +Unlike semi-explicit forms, these cannot be written as du/dt = f(u,t) even after constraint elimination. BDF methods discretize the time derivative using backward differences and solve the resulting nonlinear system at each timestep. + +## Problem Formulation + +Use `DAEProblem` with implicit function specification: + +```julia function f2(out, du, u, p, t) out[1] = -0.04u[1] + 1e4 * u[2] * u[3] - du[1] out[2] = +0.04u[1] - 3e7 * u[2]^2 - 1e4 * u[2] * u[3] - du[2] @@ -22,6 +56,64 @@ prob = DAEProblem(f2, du₀, u₀, tspan, differential_vars = differential_vars) sol = solve(prob, DFBDF()) ``` +## Solver Selection Guide + +### Recommended DAE Methods + + - **`DFBDF`**: **Recommended** - Variable-order BDF for general DAE systems + - **`DImplicitEuler`**: For non-smooth problems with discontinuities + +### Method characteristics + + - **`DFBDF`**: Most robust and efficient for general smooth DAE problems + - **`DImplicitEuler`**: Best choice for problems with discontinuities, events, or non-smooth behavior + +## Performance Guidelines + +### When fully implicit DAE BDF methods excel + + - **Index-1 DAE systems** with complex implicit structure + - **Complex constraint structures** with multiple algebraic relationships + - **Large-scale problems** where specialized DAE methods are essential + - **Multiphysics simulations** with mixed differential-algebraic structure + - **Problems where semi-explicit formulation is impractical** + +### Index considerations + + - **Index-1 formulation required**: Problems should be written in index-1 form + - **Compare with mass matrix methods**: For some index-1 problems, mass matrix formulation may be more efficient + - **Higher-index problems**: Should be reduced to index-1 form before using these methods + +## Important DAE Requirements + +### Initial conditions + + - **Both u₀ and du₀** must be provided and consistent with constraints + - **differential_vars** specification helps identify algebraic variables + - **Consistent initialization** is crucial for index-1 DAE problems + +### Function specification + + - **Residual form**: F(du/dt, u, t) = 0 with F returning zero for satisfied equations + - **Proper scaling**: Ensure equations are well-conditioned numerically + - **Jacobian availability**: Analytical Jacobians improve performance when available + +## Alternative Approaches + +Consider these alternatives: + + - **Mass matrix DAE methods** for index-1 problems with M du/dt = f(u,t) structure + - **Index reduction techniques** using [ModelingToolkit.jl](https://docs.sciml.ai/ModelingToolkit/stable/) to convert problems to index-1 form if needed + - **Constraint stabilization** methods for drift control + - **Projection methods** for manifold preservation + +For more details on DAE formulations and alternative approaches, see [this blog post on Neural DAEs](https://www.stochasticlifestyle.com/machine-learning-with-hard-constraints-neural-differential-algebraic-equations-daes-as-a-general-formalism/). + +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqBDF", "DFBDF") +``` + ## Full list of solvers ### DAE diff --git a/docs/src/imex/IMEXBDF.md b/docs/src/imex/IMEXBDF.md index 62a37aef67..27e83e5c6d 100644 --- a/docs/src/imex/IMEXBDF.md +++ b/docs/src/imex/IMEXBDF.md @@ -4,32 +4,101 @@ CollapsedDocStrings = true # OrdinaryDiffEqBDF -Solvers if your system of ordinary differential equations can be split up into the sum of a -stiff and non-stiff part. These are IMEX extensions of common BDF schemes. +IMEX BDF (Implicit-Explicit Backward Differentiation Formula) methods for stiff differential equations that can be split into stiff and non-stiff components. These methods apply implicit BDF schemes to the stiff part while treating the non-stiff part explicitly, providing efficient handling of problems with mixed stiffness characteristics. -## Installation +## Key Properties -To be able to access the solvers in `OrdinaryDiffEqBDF`, you must first install them use the Julia package manager: +IMEX BDF methods provide: -```julia -using Pkg -Pkg.add("OrdinaryDiffEqBDF") -``` + - **Implicit-explicit splitting** for mixed stiffness problems + - **BDF stability** for the stiff component with A-stable and L-stable behavior + - **Explicit treatment** of non-stiff terms avoiding unnecessary computational cost + - **High-order accuracy** up to 4th order for both components + - **Efficient for large systems** where full implicit treatment is expensive + - **Natural for operator splitting** problems + +## When to Use IMEX BDF Methods + +These methods are recommended for: + + - **Reaction-diffusion systems** where reaction terms are stiff and diffusion is moderate + - **Convection-diffusion problems** with stiff source terms and explicit convection + - **Parabolic PDEs** where diffusion operators are naturally split from other terms + - **Problems with natural stiffness separation** where some terms require implicit treatment + - **Large-scale systems** where full implicit methods are computationally prohibitive + - **Applications requiring operator splitting** methodology + +## Mathematical Background + +IMEX BDF methods split the ODE system `du/dt = f(u,t)` into: +`du/dt = f₁(u,t) + f₂(u,t)` + +where: + + - `f₁(u,t)` contains stiff terms (treated implicitly with BDF) + - `f₂(u,t)` contains non-stiff terms (treated explicitly) + +This splitting must be chosen carefully to ensure both stability and efficiency. + +## Problem Splitting Requirements + +These methods require a `SplitODEProblem` formulation where: + + - **First function** `f₁` should contain stiff, implicit terms + - **Second function** `f₂` should contain non-stiff, explicit terms + - **Splitting strategy** significantly affects method performance + - **Stiffness characteristics** should align with implicit/explicit treatment + +## Solver Selection Guide + +### IMEX Multistep Methods + + - **`SBDF2`**: **Recommended** - Second-order IMEX BDF method, good balance of accuracy and stability + - **`SBDF3`**: Third-order method for higher accuracy requirements + - **`SBDF4`**: Fourth-order method for maximum accuracy in IMEX BDF family + - **`SBDF`**: Adaptive order method (experimental) + +### IMEX SDIRK Methods + + - **`IMEXEuler`**: First-order method for simple problems or debugging + - **`IMEXEulerARK`**: Alternative first-order formulation + +## Performance Guidelines + +### When IMEX BDF methods excel + + - **Natural stiffness separation** where splitting is obvious + - **Large systems** where full implicit treatment is expensive + - **Parabolic PDEs** with natural operator splitting + - **Reaction-diffusion problems** with well-separated timescales + - **Problems where implicit component** has efficient linear algebra + +### Splitting strategy considerations + + - **Identify stiff vs non-stiff terms** based on eigenvalue analysis + - **Linear stiff terms** work well in implicit component + - **Nonlinear non-stiff terms** are suitable for explicit treatment + - **Test different splittings** to optimize performance + +## Alternative Approaches + +Consider these alternatives: + + - **Full implicit methods** (BDF, SDIRK) if splitting is unclear or ineffective + - **Standard IMEX Runge-Kutta** methods for different accuracy/efficiency trade-offs + - **Exponential integrators** for linear stiff problems with nonlinear non-stiff terms + - **Rosenbrock methods** for moderately stiff problems without natural splitting -This will only install the solvers listed at the bottom of this page. -If you want to explore other solvers for your problem, -you will need to install some of the other libraries listed in the navigation bar on the left. +## Usage Considerations -## Example usage + - **Careful splitting design** is crucial for method effectiveness + - **Stability analysis** should verify that explicit treatment doesn't introduce instabilities + - **Timestep restrictions** may apply to the explicit component + - **Linear algebra efficiency** in the implicit component affects overall performance -```julia -using OrdinaryDiffEqBDF -f1 = (u, p, t) -> 2u -f2 = (u, p, t) -> 2u -u0 = 1.0 -tspan = (0.0, 1.0) -prob = SplitODEProblem(f1, f2, u0, tspan) -sol = solve(prob, SBDF2(), dt = 1 / 10) +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqBDF", "SBDF2") ``` ## Full list of solvers diff --git a/docs/src/imex/IMEXMultistep.md b/docs/src/imex/IMEXMultistep.md index 5fd4803a1b..a7de728ae2 100644 --- a/docs/src/imex/IMEXMultistep.md +++ b/docs/src/imex/IMEXMultistep.md @@ -4,33 +4,117 @@ CollapsedDocStrings = true # OrdinaryDiffEqIMEXMultistep -Solvers if your system of ordinary differential equations can be split up into the sum of a stiff and non-stiff part. -These are "standard" low order IMEX methods common in many naive partial differential -equation applications. +Standard low-order IMEX (Implicit-Explicit) multistep methods for problems that can be split into stiff and non-stiff components. These are widely used classical methods in partial differential equation applications, providing simple and reliable IMEX integration with moderate accuracy requirements. -## Installation +## Key Properties -To be able to access the solvers in `OrdinaryDiffEqIMEXMultistep`, you must first install them use the Julia package manager: +IMEX Multistep methods provide: -```julia -using Pkg -Pkg.add("OrdinaryDiffEqIMEXMultistep") -``` + - **Standard IMEX formulations** commonly used in PDE applications + - **Low-order accuracy** (typically 2nd order) with good stability + - **Simple implementation** and well-understood behavior + - **Explicit treatment** of non-stiff terms with implicit handling of stiff components + - **Fixed timestep requirements** due to multistep nature + - **Efficient for large-scale problems** where splitting is natural + +## When to Use IMEX Multistep Methods + +These methods are recommended for: + + - **Classical PDE applications** where standard IMEX methods are established + - **Reaction-diffusion systems** with natural explicit/implicit splitting + - **Convection-diffusion problems** where convection is explicit and diffusion implicit + - **Large-scale spatial discretizations** where simple, efficient methods are preferred + - **Applications prioritizing robustness** over high-order accuracy + - **Problems with natural operator splitting** methodology + +## Mathematical Background + +IMEX multistep methods treat the split system: +`du/dt = f₁(u,t) + f₂(u,t)` + +using: + + - **Implicit multistep schemes** (like Crank-Nicolson) for stiff terms f₁ + - **Explicit multistep schemes** (like Adams-Bashforth) for non-stiff terms f₂ + +This combination provides stability for stiff components while maintaining efficiency for non-stiff parts. + +## Problem Splitting Requirements + +These methods require a `SplitODEProblem` where: + + - **First function** `f₁` contains stiff terms requiring implicit treatment + - **Second function** `f₂` contains non-stiff terms suitable for explicit treatment + - **Splitting should align** with the natural time scale separation + - **Linear stiff terms** work particularly well with these methods + +## Solver Selection Guide + +### Available Methods + + - **`CNAB2`**: **Recommended** - Crank-Nicolson Adams-Bashforth 2nd order method + - **`CNLF2`**: Crank-Nicolson Leap-Frog 2nd order method + +### Method characteristics + + - **`CNAB2`**: Most commonly used, good stability and accuracy balance + - **`CNLF2`**: Alternative formulation, may have different stability properties + +## Performance Guidelines + +### When IMEX Multistep methods excel + + - **PDE problems** with established IMEX splitting practices + - **Large spatial discretizations** where method efficiency matters more than high accuracy + - **Problems with linear stiff terms** that are efficiently handled implicitly + - **Applications requiring consistent timesteps** (no adaptive timestepping) + - **Well-conditioned problems** where simple methods suffice + +### Splitting strategy considerations + + - **Linear diffusion terms** → implicit component (f₁) + - **Nonlinear convection/reaction** → explicit component (f₂) if not too stiff + - **Source terms** → choose based on stiffness characteristics + - **Boundary conditions** → often naturally handled in implicit component + +## Limitations and Considerations + +### Method limitations + + - **Fixed timestep required** - no adaptive timestepping capabilities + - **Low order only** - maximum 2nd order accuracy + - **Startup procedures** needed for multistep methods + - **Limited stability analysis** compared to modern IMEX-RK methods + +### When to consider alternatives + + - **Higher accuracy needs**: Use IMEX-RK or higher-order IMEX methods + - **Adaptive timestepping**: Use IMEX-RK or ARK methods + - **Complex stability requirements**: Use more sophisticated IMEX schemes + - **Very stiff problems**: Consider fully implicit methods + +## Alternative Approaches + +Consider these alternatives: + + - **IMEX Runge-Kutta** methods for adaptive timestepping and higher order + - **IMEX BDF methods** for better stability properties and higher accuracy + - **Fully implicit methods** if splitting is not beneficial + - **Exponential integrators** for linear stiff problems + +## Classical Applications -This will only install the solvers listed at the bottom of this page. -If you want to explore other solvers for your problem, -you will need to install some of the other libraries listed in the navigation bar on the left. +These methods are standard in: -## Example usage + - **Computational fluid dynamics** for incompressible Navier-Stokes equations + - **Atmospheric modeling** for advection-diffusion-reaction systems + - **Ocean modeling** for transport equations with diffusion + - **Astrophysical simulations** for multiphysics problems -```julia -using OrdinaryDiffEqIMEXMultistep -f1 = (u, p, t) -> 2u -f2 = (u, p, t) -> 2u -u0 = 1.0 -tspan = (0.0, 1.0) -prob = SplitODEProblem(f1, f2, u0, tspan) -sol = solve(prob, CNAB2(), dt = 1 / 10) +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqIMEXMultistep", "CNAB2") ``` ## Full list of solvers diff --git a/docs/src/imex/StabalizedIRK.md b/docs/src/imex/StabalizedIRK.md deleted file mode 100644 index 5707ef8cac..0000000000 --- a/docs/src/imex/StabalizedIRK.md +++ /dev/null @@ -1,57 +0,0 @@ -```@meta -CollapsedDocStrings = true -``` - -# OrdinaryDiffEqStabalizedIRK - -Stabilized Explicit Runge-Kutta methods, -like Runge-Kutta-Chebyshev methods and ROCK methods -are explicit methods which chain together many stages in a specific way to get large stability regions. -they are made in such a way to converge to a large stability region, -and thus suitable to stiff equations. -However, they converge to having a large stability region in the direction of the negative real axis, -and thus are only stable on a subset of stiff equations which are not dominated by large complex eigenvalues in the Jacobian. - -Stabilized implicit methods try to mitigate this problem by being an IMEX type scheme, -requiring a SplitODEProblem where the splitting is designed to treat the large complex eigenvalues implicitly -while treating the large real eigenvalues using a fast explicit stabilized RK type of method. - -These methods utilize an upper bound on the spectral radius of the Jacobian. -Users can supply an upper bound by specifying the keyword argument `eigen_est`, for example - -```julia -`eigen_est = (integrator) -> integrator.eigen_est = upper_bound` -``` - -## Installation - -To be able to access the solvers in `OrdinaryDiffEqStabalizedIRK`, you must first install them use the Julia package manager: - -```julia -using Pkg -Pkg.add("OrdinaryDiffEqStabalizedIRK") -``` - -This will only install the solvers listed at the bottom of this page. -If you want to explore other solvers for your problem, -you will need to install some of the other libraries listed in the navigation bar on the left. - -## Example usage - -```julia -using OrdinaryDiffEqStabilizedIRK -A = randn(20, 20) -B = randn(20, 20) -f1 = (u, p, t) -> A * u -f2 = (u, p, t) -> B * u -u0 = randn(20, 1) -tspan = (0.0, 1.0) -prob = SplitODEProblem(f1, f2, u0, tspan) -sol = solve(prob, IRKC()) -``` - -## Full list of solvers - -```@docs -IRKC -``` diff --git a/docs/src/imex/StabilizedIRK.md b/docs/src/imex/StabilizedIRK.md new file mode 100644 index 0000000000..6a3c843486 --- /dev/null +++ b/docs/src/imex/StabilizedIRK.md @@ -0,0 +1,100 @@ +```@meta +CollapsedDocStrings = true +``` + +# OrdinaryDiffEqStabilizedIRK + +Stabilized Implicit Runge-Kutta (IMEX) methods combine the benefits of stabilized explicit methods with implicit treatment of problematic eigenvalues. These IMEX schemes are designed for problems where the Jacobian has both large real eigenvalues (suitable for explicit stabilized methods) and large complex eigenvalues (requiring implicit treatment). + +## Key Properties + +Stabilized IRK methods provide: + + - **IMEX formulation** treating different stiffness components appropriately + - **Large stability regions** for real eigenvalues via explicit stabilized schemes + - **Implicit treatment** of complex eigenvalues for unconditional stability + - **Efficient handling** of mixed stiffness characteristics + - **Splitting-based approach** requiring `SplitODEProblem` formulation + +## When to Use Stabilized IRK Methods + +These methods are recommended for: + + - **Mixed stiffness problems** with both real and complex eigenvalues + - **Parabolic PDEs with convection** where diffusion and advection have different scales + - **Reaction-diffusion systems** with stiff reactions and moderate diffusion + - **Problems where pure explicit stabilized methods fail** due to complex eigenvalues + - **Large-scale systems** where full implicit methods are too expensive + +## Mathematical Background + +Standard stabilized explicit methods (like RKC, ROCK) achieve large stability regions along the negative real axis but struggle with complex eigenvalues. Stabilized IRK methods address this by: + + 1. **Explicit stabilized treatment** for large real eigenvalues + 2. **Implicit treatment** for complex eigenvalues + 3. **IMEX coupling** to maintain overall stability and accuracy + +## Problem Splitting Requirements + +These methods require a `SplitODEProblem` where: + + - **First component** contains terms with large real eigenvalues (explicit treatment) + - **Second component** contains terms with complex eigenvalues (implicit treatment) + - **Splitting design** is crucial for method performance + +## Spectral Radius Estimation + +Users can supply an upper bound on the spectral radius: + +```julia +eigen_est = (integrator) -> integrator.eigen_est = upper_bound +``` + +This bound applies to the explicit component of the split problem. + +## Solver Selection Guide + +### Available methods + + - **`IRKC`**: Implicit Runge-Kutta-Chebyshev method for mixed stiffness problems + +### Usage considerations + + - **Requires careful splitting** of the problem components + - **Spectral radius estimation** needed for explicit component + - **Test splitting strategies** for optimal performance + - **Compare with pure implicit** or explicit stabilized alternatives + +## Performance Guidelines + +### When IMEX stabilized methods excel + + - **Mixed eigenvalue distribution** (both real and complex) + - **Moderate to large systems** where splitting is natural + - **Problems where neither pure explicit nor implicit** methods are ideal + +### Splitting strategy considerations + + - **Identify dominant eigenvalue types** in different terms + - **Real-dominated terms** → explicit component + - **Complex-dominated terms** → implicit component + - **Test different splittings** for best performance + +## Alternative Approaches + +Consider these alternatives: + + - **Pure implicit methods** (BDF, SDIRK, Rosenbrock) for highly stiff problems + - **Explicit stabilized methods** (ROCK, RKC) if complex eigenvalues are small + - **Standard IMEX methods** for natural explicit/implicit splitting + +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqStabilizedIRK", "IRKC") +``` + +## Full list of solvers + +```@docs +IRKC +``` diff --git a/docs/src/implicit/BDF.md b/docs/src/implicit/BDF.md index 5dd0c64edb..ef10f23580 100644 --- a/docs/src/implicit/BDF.md +++ b/docs/src/implicit/BDF.md @@ -4,7 +4,57 @@ CollapsedDocStrings = true # OrdinaryDiffEqBDF -Multistep methods, good for large stiff systems. +Backward Differentiation Formula (BDF) methods are multistep implicit methods specifically designed for solving large stiff systems of differential equations. They are the preferred choice for very large systems (>1000 equations) where other implicit methods become computationally expensive. + +## Key Properties + +BDF methods offer: + + - **Excellent efficiency for large systems** (>1000 ODEs) + - **L-stable behavior** for orders 1 and 2 only + - **Adaptive order and stepsize** control for optimal performance + - **Alpha-stability** for higher orders (but less stable than L-stable methods for problems with large complex eigenvalues) + +## When to Use BDF Methods + +BDF methods are recommended for: + + - **Large stiff systems** with more than 1000 equations + - **Very stiff problems** where other implicit methods struggle + - **Long-time integration** of stiff systems + - **Parabolic PDEs** after spatial discretization + - **Reaction-diffusion systems** and chemical kinetics + - **Circuit simulation** and other engineering applications with large stiff systems + +## Solver Selection Guide + +### Recommended methods + + - **`QNDF`**: Adaptive order quasi-constant timestep BDF, best general choice for large systems + - **`FBDF`**: Fixed-leading coefficient BDF, often more efficient than QNDF + +## Performance Characteristics + + - **Most efficient for systems with >1000 equations** + - **Outperform Runge-Kutta methods** on very large stiff systems + - **Memory efficient** due to multistep structure + - **Excel at very low tolerances** (1e-9 and below) + - **Particularly effective** for problems arising from PDE discretizations + +## Comparison with Other Methods + +Choose BDF methods over: + + - **Rosenbrock methods**: When system size > 1000 equations + - **SDIRK methods**: For very large stiff systems where RK methods become expensive + - **Explicit methods**: For any stiff problem + +Choose other methods over BDF when: + + - **System size < 100**: Rosenbrock or SDIRK methods often more efficient + - **Problems with large complex eigenvalues**: Rosenbrock and L-stable SDIRK methods are more stable due to BDF methods only being alpha-stable + - **Moderate stiffness**: SDIRK methods may be more robust + - **Non-stiff problems**: Use explicit methods like Tsit5 ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/implicit/FIRK.md b/docs/src/implicit/FIRK.md index 535c265c4d..5344c68ea5 100644 --- a/docs/src/implicit/FIRK.md +++ b/docs/src/implicit/FIRK.md @@ -4,27 +4,70 @@ CollapsedDocStrings = true # OrdinaryDiffEqFIRK -FIRK methods are fully implicit Runge-Kutta methods. -They can have special properties, like be symplectic integrators, and can achieve higher order for the same number of stage in comparison to diagonal methods. -However, the fully implicit methods have a larger implicit system to solve and thus have a higher linear algebra cost. -This can be useful in some contexts to promote more parallelism, -but also since the size of the factorization is cubic and the dominant cost for large equations, -multiplying `O(n^3)` operations to `O((sn)^3)` can be a considerable cost increase for FIRK tableaus, -where `s`, the number of stages, is particularly large. -That said, the restriction to diagonal implicitness imposes order restrictions, -such as SDIRK methods having a maximum order of 5, which can restrict the problems best suited for SDIRK methods. - -The most common FIRK method in production are those based on RadauIIA tableaus, -which is an ODE representation of Gaussian collocation. -Like Gaussian collocation, it achieves higher order convergence than its stages, namely order 2s+1 for s stages. -Thus RadauIIA FIRK methods tend to be some of the highest order methods (excluding extrapolation methods). -This means that high order RadauIIA methods are recommended in the same scenarios that high-order explicit Runge-Kutta methods are recommended simply with the restriction of being a stiff equation. -Such scenarios include cases like very low tolerances: RadauIIA methods can be the best performing methods for scenarios where tolerances are `1e-9` and below. -Additionally, for ODE systems of size less than 200, the increased size of the Jacobian is mitigated by improved multithreading, -since BLAS implementations are only good at multithreading LU factorizations after a certain matrix size. -For this reason, RadauIIA methods tend to be recommended in cases where ODE size is small to intermediate and very accurate solutions are required. - -They should be tested against the parallel implicit extrapolation which also specialize in this regime. +Fully Implicit Runge-Kutta (FIRK) methods for stiff differential equations requiring very high accuracy. These methods solve a fully coupled implicit system at each timestep, providing superior accuracy and stability compared to diagonally implicit methods. + +!!! warning "Real Numbers Only" + + FIRK methods should only be used for problems defined on real numbers, not complex numbers. + +## Key Properties + +FIRK methods provide: + + - **Highest-order implicit methods** (excluding extrapolation) + - **Superior accuracy** for very low tolerance requirements (≤ 1e-9) + - **A-stable and L-stable** behavior for stiff problems + - **Higher order per stage** than SDIRK methods (order 2s+1 for s stages) + - **Special geometric properties** (some methods are symplectic) + - **Excellent for small to medium systems** with high accuracy requirements + +## When to Use FIRK Methods + +These methods are recommended for: + + - **Very low tolerance problems** (1e-9 and below) where accuracy is paramount + - **Small to medium stiff systems** (< 200 equations) + - **Problems requiring highest possible accuracy** for implicit methods + - **Stiff problems** where SDIRK order limitations (max order 5) are insufficient + - **Applications where computational cost is acceptable** for maximum accuracy + +## Mathematical Background + +RadauIIA methods are based on Gaussian collocation and achieve order 2s+1 for s stages, making them among the highest-order implicit methods available. They represent the ODE analog of Gaussian quadrature. For more details on recent advances in FIRK methods, see our paper: [High-Order Adaptive Time Stepping for the Incompressible Navier-Stokes Equations](https://arxiv.org/abs/2412.14362). + +## Computational Considerations + +### Advantages + + - **Higher accuracy per stage** than diagonal methods + - **Better multithreading** for small systems due to larger linear algebra operations + - **No order restrictions** like SDIRK methods (which max out at order 5) + +### Disadvantages + + - **Limited to real-valued problems** - cannot be used for complex number systems + - **Higher implementation complexity** compared to SDIRK methods + +## Solver Selection Guide + +### High accuracy requirements + + - **`AdaptiveRadau`**: **Recommended** - adaptive order method that automatically selects optimal order + - **`RadauIIA5`**: 5th-order method, good balance of accuracy and efficiency + - **`RadauIIA9`**: 9th-order method for extremely high accuracy requirements + - **`RadauIIA3`**: 3rd-order method for moderate accuracy needs + +### System size considerations + + - **Systems < 200**: FIRK methods are competitive due to better multithreading + - **Systems > 200**: Consider SDIRK or BDF methods instead + +## Performance Guidelines + + - **Best for tolerances ≤ 1e-9** where high accuracy justifies the cost + - **Most efficient on small to medium systems** where linear algebra cost is manageable + - **Should be tested against** parallel implicit extrapolation methods which specialize in similar regimes + - **Compare with** high-order SDIRK methods for borderline cases ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/implicit/Nordsieck.md b/docs/src/implicit/Nordsieck.md index 2ec56f837a..d34093cb33 100644 --- a/docs/src/implicit/Nordsieck.md +++ b/docs/src/implicit/Nordsieck.md @@ -4,16 +4,83 @@ CollapsedDocStrings = true # OrdinaryDiffEqNordsieck -The Nordsieck form is an alternative representation of multistep methods which, -instead of representing and saving past step values in a history vector, -it uses a derivative list (like a Taylor expansion) for the computation of the next point. -The Nordsieck form was pioneered by early implementations of BDF methods such LSODE, VODE, and finally CVODE. -It can have some advantages in terms of restartability as the full Nordsieck vector can be instantiated given only the information of f and its derivatives after discontinuities, -but the higher derivative representations can also introduce numerical instabilities of their own. - -The Nordsieck implementations here are considered experimental implementations of the LSODE non-fixed leading coefficient form -and are generally considered inferior to the fixed-leading history-based BDF implementation of FBDF, and thus for all standard usage we recommend FBDF. -However, this algorithm is kept for experimental research and development purposes with the possibility of one day becoming a more discontinuity-aware BDF implementation. +Nordsieck form multistep methods represent an alternative approach to traditional multistep algorithms. Instead of storing past solution values, these methods maintain a vector of scaled derivatives (similar to Taylor series coefficients) to advance the solution. This representation was pioneered in classic codes like LSODE, VODE, and CVODE. + +!!! warning "Research and Development" + + These methods are currently in research and development and not intended for general use. + +## Key Properties + +Nordsieck methods provide: + + - **Derivative-based representation** instead of solution history + - **Improved restartability** after discontinuities using derivative information + - **Variable order and stepsize** capabilities + - **Alternative to history-based** multistep methods + - **Research and experimental** implementations + +## When to Use Nordsieck Methods + +These methods are recommended for: + + - **Research applications** exploring alternative multistep representations + - **Problems with discontinuities** where restartability is important + - **Experimental comparisons** with traditional multistep methods + - **Development of discontinuity-aware** algorithms + +## Important Limitations + +### Experimental Status + + - **Considered experimental** and inferior to modern BDF implementations + - **Generally recommend FBDF instead** for production use + - **Maintained for research purposes** and future development + - **Numerical instabilities** can arise from higher derivative representations + +### Performance Considerations + + - **Less robust** than fixed-leading coefficient BDF methods + - **Higher computational overhead** for derivative maintenance + - **Potential stability issues** with derivative representations + +## Mathematical Background + +The Nordsieck form represents the solution using scaled derivatives: +`y_n = [y, h*y', h²*y''/2!, h³*y'''/3!, ...]` + +This representation allows reconstruction of the solution and its derivatives, enabling restarts after discontinuities without losing accuracy. + +## Solver Selection Guide + +### Nordsieck implementations + + - **`AN5`**: Fifth-order Adams method with fixed leading coefficient + - **`JVODE`**: Variable order Adams/BDF method (experimental LSODE-style) + - **`JVODE_Adams`**: JVODE configured for Adams methods + - **`JVODE_BDF`**: JVODE configured for BDF methods + +### Recommended alternatives + + - **For most applications**: Use `QNDF` or `FBDF` instead + - **For stiff problems**: Prefer modern BDF implementations + - **For research**: These methods are appropriate for experimental work + +## Research and Development + +These implementations serve as: + + - **Experimental testbed** for Nordsieck form algorithms + - **Research platform** for discontinuity-aware methods + - **Development basis** for future improved BDF implementations + - **Educational examples** of alternative multistep representations + +## Usage Guidelines + + - **Not recommended** for production applications + - **Use FBDF or QNDF** for reliable multistep integration + - **Consider these methods** only for research or experimental purposes + - **Expect potentially lower performance** compared to modern alternatives ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/implicit/SDIRK.md b/docs/src/implicit/SDIRK.md index 4d04f1041e..53e84e91cb 100644 --- a/docs/src/implicit/SDIRK.md +++ b/docs/src/implicit/SDIRK.md @@ -4,11 +4,53 @@ CollapsedDocStrings = true # OrdinaryDiffEqSDIRK -This article is a stub. +Singly Diagonally Implicit Runge-Kutta (SDIRK) methods are a family of implicit Runge-Kutta methods designed for solving stiff ordinary differential equations. These methods are particularly effective for problems where explicit methods become unstable due to stiffness. + +## Key Properties + +SDIRK methods have several important characteristics: + + - **A-stable and L-stable**: Can handle highly stiff problems without numerical instability + - **Stiffly accurate**: Many SDIRK methods provide additional numerical stability for stiff problems + - **Diagonally implicit structure**: The implicit system only requires solving a sequence of nonlinear equations rather than a large coupled system + - **Good for moderate to large systems**: More efficient than fully implicit RK methods for many problems + +## When to Use SDIRK Methods + +SDIRK methods are recommended for: + + - **Stiff differential equations** where explicit methods fail or require very small timesteps + - **Problems requiring good stability properties** at moderate to high tolerances + - **Systems where Rosenbrock methods** (which require Jacobians) are not suitable or available + - **IMEX problems** using the KenCarp family, which can split stiff and non-stiff terms + +## Solver Selection Guide + +### High tolerance (>1e-2) + + - **`TRBDF2`**: Second-order A-B-L-S-stable method, good for oscillatory problems + +### Medium tolerance (1e-8 to 1e-2) + + - **`KenCarp4`**: Fourth-order method with excellent stability, good all-around choice + - **`KenCarp47`**: Seventh-stage fourth-order method, enhanced stability + - **`Kvaerno4`** or **`Kvaerno5`**: High-order stiffly accurate methods + +### Low tolerance (<1e-8) + + - **`Kvaerno5`**: Fifth-order stiffly accurate method for high accuracy + - **`KenCarp5`**: Fifth-order method with splitting capabilities + +### Special Cases + + - **`ImplicitEuler`**: First-order method, only recommended for problems with discontinuities or when `f` is not differentiable + - **`Trapezoid`**: Second-order symmetric method, reversible but not symplectic. Good for eliminating damping often seen with L-stable methods + - **`ImplicitMidpoint`**: Second-order A-stable symplectic method for energy-preserving systems + - **`SSPSDIRK2`**: Strong stability preserving variant for problems requiring monotonicity preservation ```@eval first_steps = evalfile("./common_first_steps.jl") -first_steps("OrdinaryDiffEqSDIRK", "PDIRK44") +first_steps("OrdinaryDiffEqSDIRK", "KenCarp4") ``` ## Full list of solvers diff --git a/docs/src/index.md b/docs/src/index.md index b2647f8898..0b6616e99a 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,9 +1,9 @@ # OrdinaryDiffEq.jl -OrdinaryDiffEq.jl is a component package in the DifferentialEquations ecosystem. It holds the -ordinary differential equation solvers and utilities. While completely independent -and usable on its own, users interested in using this -functionality should check out [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl). +OrdinaryDiffEq.jl is a component package in the DifferentialEquations ecosystem. +It holds the core ordinary differential equation solvers and utilities. While completely independent and usable on its own, users interested in using this +functionality should check out +[DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl). ## Installation @@ -14,61 +14,3 @@ OrdinaryDiffEq.jl in the standard way: import Pkg; Pkg.add("OrdinaryDiffEq"); ``` - -## Reproducibility - -```@raw html -
The documentation of this SciML package was built using these direct dependencies, -``` - -```@example -using Pkg # hide -Pkg.status() # hide -``` - -```@raw html -
-``` - -```@raw html -
and using this machine and Julia version. -``` - -```@example -using InteractiveUtils # hide -versioninfo() # hide -``` - -```@raw html -
-``` - -```@raw html -
A more complete overview of all dependencies and their versions is also provided. -``` - -```@example -using Pkg # hide -Pkg.status(; mode = PKGMODE_MANIFEST) # hide -``` - -```@raw html -
-``` - -```@eval -using TOML -using Markdown -version = TOML.parse(read("../../Project.toml", String))["version"] -name = TOML.parse(read("../../Project.toml", String))["name"] -link_manifest = "https://github.com/SciML/" * name * ".jl/tree/gh-pages/v" * version * - "/assets/Manifest.toml" -link_project = "https://github.com/SciML/" * name * ".jl/tree/gh-pages/v" * version * - "/assets/Project.toml" -Markdown.parse("""You can also download the -[manifest]($link_manifest) -file and the -[project]($link_project) -file. -""") -``` diff --git a/docs/src/massmatrixdae/BDF.md b/docs/src/massmatrixdae/BDF.md index d6d9f600df..51313920af 100644 --- a/docs/src/massmatrixdae/BDF.md +++ b/docs/src/massmatrixdae/BDF.md @@ -4,9 +4,43 @@ CollapsedDocStrings = true # OrdinaryDiffEqBDF -Multistep BDF methods, good for large stiff systems. +BDF (Backward Differentiation Formula) methods for mass matrix differential-algebraic equations (DAEs) and stiff ODEs with singular mass matrices. These methods provide robust, high-order integration for systems with algebraic constraints and mixed differential-algebraic structure. + +## Key Properties + +Mass matrix BDF methods provide: + + - **DAE capability** for index-1 differential-algebraic equations + - **Mass matrix support** for singular and non-diagonal mass matrices + - **High-order accuracy** up to 5th order with good stability + - **L-stable behavior** for stiff problems with excellent damping + - **Automatic differentiation** for efficient Jacobian computation + - **Variable order and stepsize** adaptation for efficiency + +## When to Use Mass Matrix BDF Methods + +These methods are recommended for: + + - **Differential-algebraic equations (DAEs)** with index-1 structure + - **Constrained mechanical systems** with holonomic constraints + - **Electrical circuit simulation** with algebraic loop equations + - **Chemical reaction networks** with conservation constraints + - **Multibody dynamics** with kinematic constraints + - **Semi-explicit DAEs** arising from spatial discretizations + +## Mathematical Background + +Mass matrix DAEs have the form: +`M du/dt = f(u,t)` + +where M is a potentially singular mass matrix. When M is singular, some equations become algebraic constraints rather than differential equations, leading to a DAE system. + +## Problem Formulation + +Use `ODEFunction` with a `mass_matrix`: ```julia +using LinearAlgebra: Diagonal function rober(du, u, p, t) y₁, y₂, y₃ = u k₁, k₂, k₃ = p @@ -15,14 +49,74 @@ function rober(du, u, p, t) du[3] = y₁ + y₂ + y₃ - 1 nothing end -M = [1.0 0 0 - 0 1.0 0 - 0 0 0] +M = Diagonal([1.0, 1.0, 0]) # Singular mass matrix f = ODEFunction(rober, mass_matrix = M) prob_mm = ODEProblem(f, [1.0, 0.0, 0.0], (0.0, 1e5), (0.04, 3e7, 1e4)) sol = solve(prob_mm, FBDF(), reltol = 1e-8, abstol = 1e-8) ``` +## Solver Selection Guide + +### Recommended Methods + + - **`FBDF`**: **Recommended** - Fixed leading coefficient BDF with excellent stability + - **`QNDF`**: Quasi-constant stepsize Nordsieck BDF with good efficiency + - **`QBDF`**: Alternative quasi-constant stepsize BDF formulation + +### Specific order methods + + - **`QNDF1`**: First-order method for simple problems + - **`QNDF2`**: Second-order method balancing accuracy and stability + - **`QBDF1`**, **`QBDF2`**: Alternative second-order formulations + - **`ABDF2`**: Adams-type BDF for specific applications + - **`MEBDF2`**: Modified extended BDF for enhanced stability + +## Performance Guidelines + +### When mass matrix BDF methods excel + + - **Index-1 DAE systems** with well-separated differential and algebraic variables + - **Large stiff systems** with algebraic constraints + - **Problems with conservation laws** naturally expressed as constraints + - **Multiphysics simulations** combining differential and algebraic equations + - **Systems where constraints are essential** to the physics + +### Mass matrix considerations + + - **Singular mass matrices** require consistent initial conditions + - **Index determination** affects solver performance and stability + - **Constraint violations** may accumulate and require projection + - **Well-conditioned problems** generally perform better + +## Important Considerations + +### Initial conditions + + - **Must be consistent** with algebraic constraints + - **Use initialization procedures** if constraints are not satisfied initially + - **Index-1 assumption** requires that constraints uniquely determine algebraic variables + +### Numerical challenges + + - **Constraint drift** may occur over long integrations + - **Index higher than 1** not directly supported + - **Ill-conditioned mass matrices** can cause numerical difficulties + - **Discontinuities** in constraints require special handling + +## Alternative Approaches + +Consider these alternatives: + + - **Implicit Runge-Kutta methods** for higher accuracy requirements + - **Rosenbrock methods** for moderately stiff DAEs + - **Projection methods** for constraint preservation + - **Index reduction techniques** for higher-index DAEs + +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqBDF", "FBDF") +``` + ## Full list of solvers ```@docs; canonical=false diff --git a/docs/src/massmatrixdae/Rosenbrock.md b/docs/src/massmatrixdae/Rosenbrock.md index aadbf41b66..3bdff45b47 100644 --- a/docs/src/massmatrixdae/Rosenbrock.md +++ b/docs/src/massmatrixdae/Rosenbrock.md @@ -4,11 +4,29 @@ CollapsedDocStrings = true # OrdinaryDiffEqRosenbrock -Methods for small and medium sized stiff systems of differential equations. -At high tolerances, `>1e-2`, `Rosenbrock23` is a good choice. -At medium tolerances `>1e-8` it is recommended you use `Rodas5P` or `Rodas4P`, -the former is more efficient, but the latter is more reliable. -For larger systems look at multistep methods. +Rosenbrock methods for mass matrix differential-algebraic equations (DAEs) and stiff ODEs with singular mass matrices. These methods provide efficient integration for moderately stiff systems with algebraic constraints, offering excellent performance for small to medium-sized DAE problems. + +## Key Properties + +Mass matrix Rosenbrock methods provide: + + - **DAE capability** for index-1 differential-algebraic equations + - **W-method efficiency** using approximate Jacobians for computational savings + - **Mass matrix support** for singular and non-diagonal mass matrices + - **Moderate to high order accuracy** (2nd to 6th order available) + - **Good stability properties** with stiffly accurate behavior + - **Embedded error estimation** for adaptive timestepping + +## When to Use Mass Matrix Rosenbrock Methods + +These methods are recommended for: + + - **Index-1 DAE systems** with moderate stiffness + - **Small to medium constrained systems** (< 1000 equations) + - **Semi-explicit DAEs** arising from discretized PDEs + - **Problems requiring good accuracy** with moderate computational cost + - **DAEs with moderate nonlinearity** where W-methods are efficient + - **Electrical circuits** and **mechanical systems** with constraints !!! warn @@ -17,9 +35,74 @@ For larger systems look at multistep methods. `using OrdinaryDiffEqNonlinearSolve` is required or you must pass an `initializealg` with a valid `nlsolve` choice. -## Example usage +## Mathematical Background + +Mass matrix DAEs have the form: +`M du/dt = f(u,t)` + +Rosenbrock methods linearize around the current solution and solve linear systems of the form: +`(M/γh - J) k_i = ...` + +where J is the Jacobian of f and γ is a method parameter. + +## Solver Selection Guide + +### Recommended Methods by Tolerance + + - **High tolerances** (>1e-2): **`Rosenbrock23`** - efficient low-order method + - **Medium tolerances** (1e-8 to 1e-2): **`Rodas5P`** - most efficient choice, or **`Rodas4P`** for higher reliability + - **Low tolerances** (<1e-8): **`Rodas5Pe`** or higher-order alternatives + +### Method families + + - **`Rodas5P`**: **Recommended** - Most efficient 5th-order method for general use + - **`Rodas4P`**: More reliable 4th-order alternative + - **`Rosenbrock23`**: Good for high tolerance problems + - **`Rodas5`**: Standard 5th-order method without embedded pair optimization + +## Performance Guidelines + +### When mass matrix Rosenbrock methods excel + + - **Small to medium DAE systems** (< 1000 equations) + - **Moderately stiff problems** where full BDF methods are overkill + - **Problems with efficient Jacobian computation** or finite difference approximation + - **Index-1 DAEs with well-conditioned mass matrices** + - **Semi-explicit index-1 problems** from spatial discretizations + +### System size considerations + + - **Small systems** (< 100): Rosenbrock methods often outperform multistep methods + - **Medium systems** (100-1000): Good performance with proper linear algebra + - **Large systems** (> 1000): Consider BDF methods instead + +## Important DAE Considerations + +### Initial conditions + + - **Must be consistent** with algebraic constraints + - **Consistent initialization** may require nonlinear solver + - **Index-1 assumption** for reliable performance + +### Mass matrix requirements + + - **Index-1 DAE structure** for optimal performance + - **Non-singular leading submatrix** for differential variables + - **Well-conditioned constraint equations** + +## Alternative Approaches + +Consider these alternatives: + + - **Mass matrix BDF methods** for larger or highly stiff DAE systems + - **Implicit Runge-Kutta methods** for higher accuracy requirements + - **Standard Rosenbrock methods** for regular ODEs without constraints + - **IMEX methods** if natural explicit/implicit splitting exists + +## Example Usage ```julia +using LinearAlgebra: Diagonal function rober(du, u, p, t) y₁, y₂, y₃ = u k₁, k₂, k₃ = p @@ -28,14 +111,17 @@ function rober(du, u, p, t) du[3] = y₁ + y₂ + y₃ - 1 nothing end -M = [1.0 0 0 - 0 1.0 0 - 0 0 0] +M = Diagonal([1.0, 1.0, 0]) # Singular mass matrix f = ODEFunction(rober, mass_matrix = M) prob_mm = ODEProblem(f, [1.0, 0.0, 0.0], (0.0, 1e5), (0.04, 3e7, 1e4)) sol = solve(prob_mm, Rodas5(), reltol = 1e-8, abstol = 1e-8) ``` +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqRosenbrock", "Rodas5P") +``` + ## Full list of solvers ```@docs; canonical=false diff --git a/docs/src/misc.md b/docs/src/misc.md index bbf99e06f7..d831b94663 100644 --- a/docs/src/misc.md +++ b/docs/src/misc.md @@ -1,4 +1,11 @@ +# Miscellaneous Solvers + +These are solvers that do not fall clearly into any of the major categories. + ```@docs SplitEuler CompositeAlgorithm +FunctionMap +ExplicitRK +IDSolve ``` diff --git a/docs/src/semiimplicit/ExponentialRK.md b/docs/src/semiimplicit/ExponentialRK.md index e1f5a788f1..99950b2319 100644 --- a/docs/src/semiimplicit/ExponentialRK.md +++ b/docs/src/semiimplicit/ExponentialRK.md @@ -4,7 +4,78 @@ CollapsedDocStrings = true # OrdinaryDiffEqExponentialRK -Methods for semi-linear differential equations. +Exponential Runge-Kutta methods are specialized integrators for semi-linear differential equations of the form `du/dt = Au + f(u,t)`, where `A` is a linear operator (often representing diffusion or dispersion) and `f` represents nonlinear terms. These methods are particularly effective for stiff linear parts combined with non-stiff nonlinear terms. **Important**: The nonlinear term `f(u,t)` must be non-stiff for these methods to be effective. + +## Key Properties + +Exponential RK methods provide: + + - **Exact treatment of linear parts** using matrix exponential functions + - **High-order accuracy** for both linear and nonlinear components + - **Excellent stability properties** for problems with stiff linear operators + - **Efficient handling of semi-linear PDEs** after spatial discretization + - **Reduced timestep restrictions** compared to traditional explicit methods + - **Preservation of qualitative behavior** for many physical systems + +## When to Use Exponential RK Methods + +These methods are recommended for: + + - **Semi-linear PDEs** with stiff diffusion/dispersion and moderate **non-stiff** nonlinearity + - **Reaction-diffusion systems** with fast diffusion and slower **non-stiff** reactions + - **Nonlinear Schrödinger equations** and other dispersive wave equations with **non-stiff** nonlinear terms + - **Pattern formation problems** (Turing patterns, phase field models) where nonlinearity is **non-stiff** + - **Quantum dynamics** with linear Hamiltonian and **non-stiff** nonlinear interactions + - **Problems with strong linear damping** or oscillatory linear parts combined with **non-stiff** nonlinear terms + - **Spatially discretized PDEs** where the linear part dominates stiffness but the nonlinear part remains **non-stiff** + +## Mathematical Background + +For problems `du/dt = Au + f(u,t)`, exponential methods compute the exact solution of the linear part `Au` using `exp(A*dt)` and treat the nonlinear part `f(u,t)` with Runge-Kutta-like stages. This approach is particularly effective when `A` represents well-understood physics (diffusion, dispersion, linear oscillations). + +## Solver Selection Guide + +### Basic exponential time differencing (ETD) + + - **`LawsonEuler`**: First-order exponential Euler method + - **`NorsettEuler`** / **`ETD1`**: Alternative first-order scheme + - **`ETDRK2`**: Second-order exponential RK + - **`ETDRK3`**: Third-order exponential RK + - **`ETDRK4`**: Fourth-order exponential RK, popular choice + - **`ETD2`**: Second-order exponential time differencing (in development) + +### High-order specialized methods + + - **`HochOst4`**: Fourth-order exponential RK with enhanced stability + - **`Exp4`**: Fourth-order EPIRK scheme + +### Adaptive exponential Rosenbrock + + - **`Exprb32`**: Third-order adaptive method with error control + - **`Exprb43`**: Fourth-order adaptive method + +### EPIRK (Exponential Propagation Iterative RK) methods + + - **`EPIRK4s3A`**: Fourth-order with stiff order 4 + - **`EPIRK4s3B`**: Alternative fourth-order variant + - **`EPIRK5s3`**: Fifth-order method (note: marked as broken) + - **`EXPRB53s3`**: Fifth-order with stiff order 5 + - **`EPIRK5P1`**, **`EPIRK5P2`**: Fifth-order variants + +## Performance Recommendations + + - **For most semi-linear problems**: `ETDRK4` + - **For adaptive stepsize**: `Exprb43` + - **For high stiffness in linear part**: `EPIRK4s3A` or `EPIRK4s3B` + - **For maximum accuracy**: `EXPRB53s3` + +## Implementation Requirements + +These methods require: + + - **Computation of matrix exponentials** `exp(A*dt)` and related functions + - **Krylov subspace methods** for large systems (automatic in most cases) + - **Proper problem formulation** with identified linear and nonlinear parts ## Installation diff --git a/docs/src/semiimplicit/Rosenbrock.md b/docs/src/semiimplicit/Rosenbrock.md index 782ba30793..ab3fa8ccf3 100644 --- a/docs/src/semiimplicit/Rosenbrock.md +++ b/docs/src/semiimplicit/Rosenbrock.md @@ -4,11 +4,61 @@ CollapsedDocStrings = true # OrdinaryDiffEqRosenbrock -Methods for small and medium sized stiff systems of differential equations. -At high tolerances, `>1e-2`, `Rosenbrock23` is a good choice. -At medium tolerances `>1e-8` it is recommended you use `Rodas5P` or `Rodas4P`, -the former is more efficient, but the latter is more reliable. -For larger systems look at multistep methods. +Rosenbrock methods are semi-implicit Runge-Kutta methods designed for small to medium-sized stiff systems of differential equations. These methods combine the stability properties of implicit methods with computational efficiency by using approximate Jacobians. They work particularly well for strict tolerance requirements. + +## Key Properties + +Rosenbrock methods provide: + + - **Excellent efficiency for small to medium systems** (<1000 ODEs) + - **L-stable and A-stable variants** for stiff problems + - **W-method structure** making them robust to inaccurate Jacobians + - **Automatic differentiation compatibility** for Jacobian computation + - **High-order accuracy** with embedded error estimation + - **Excellent performance for strict tolerance requirements** + - **Stiffly accurate variants** for enhanced stability + +## When to Use Rosenbrock Methods + +Rosenbrock methods are recommended for: + + - **Small to medium stiff systems** (10 to 1000 equations) + - **Problems where Jacobians are available** or can be computed efficiently + - **Medium tolerance requirements** (1e-8 to 1e-2) + - **Stiff ODEs arising from reaction kinetics** and chemical systems + - **Moderately stiff PDEs** after spatial discretization + - **Problems requiring reliable error control** for stiff systems + +## Solver Selection Guide + +### Low tolerance (>1e-2) + + - **`Rosenbrock23`**: Second/third-order method, recommended for low tolerance requirements + +### Medium tolerance (1e-8 to 1e-2) + + - **`Rodas5P`**: Fifth-order method, most efficient for many problems + - **`Rodas4P`**: Fourth-order method, more reliable than Rodas5P + - **`Rodas5Pe`**: Enhanced fifth-order variant with stiffly accurate embedded estimate for better adaptivity on highly stiff equations + - **`Rodas5Pr`**: Fifth-order variant with residual test for robust error estimation that guarantees accuracy on interpolation + +## Performance Guidelines + + - **Rodas5P**: Best overall efficiency at medium tolerances + - **Rodas4P**: Most reliable when Rodas5P fails + - **Rosenbrock23**: Fastest at high tolerances (>1e-2) + +## When to Choose Alternatives + +Consider other methods when: + + - **System size > 1000**: Use BDF methods (QNDF, FBDF) + - **Matrix-free methods**: If using Krylov solvers for the linear solver (matrix-free methods), SDIRK or BDF methods are preferred + +## Advantages of Rosenbrock Methods + + - **Very low tolerances**: Rosenbrock23 performs well even at very low tolerances + - **Very high stiffness**: Rosenbrock methods are often more stable than SDIRK or BDF methods because other methods can diverge due to bad initial guesses for the Newton method (leading to nonlinear solver divergence) ```@eval first_steps = evalfile("./common_first_steps.jl") diff --git a/docs/src/semiimplicit/StabalizedRK.md b/docs/src/semiimplicit/StabalizedRK.md deleted file mode 100644 index 43851e49ea..0000000000 --- a/docs/src/semiimplicit/StabalizedRK.md +++ /dev/null @@ -1,28 +0,0 @@ -```@meta -CollapsedDocStrings = true -``` - -# OrdinaryDiffEqStabalizedRK - -Explicit stabilized methods utilize an upper bound on the spectral radius of the Jacobian. -Users can supply an upper bound by specifying the keyword argument `eigen_est`, for example - -```julia -`eigen_est = (integrator) -> integrator.eigen_est = upper_bound` -``` - -```@eval -first_steps = evalfile("./common_first_steps.jl") -first_steps("OrdinaryDiffEqStabalizedRK", "ROCK4") -``` - -## Full list of solvers - -```@docs -ROCK2 -ROCK4 -RKC -SERK2 -ESERK4 -ESERK5 -``` diff --git a/docs/src/semiimplicit/StabilizedRK.md b/docs/src/semiimplicit/StabilizedRK.md new file mode 100644 index 0000000000..e82cbb5cea --- /dev/null +++ b/docs/src/semiimplicit/StabilizedRK.md @@ -0,0 +1,89 @@ +```@meta +CollapsedDocStrings = true +``` + +# OrdinaryDiffEqStabilizedRK + +Stabilized Runge-Kutta methods are explicit schemes designed to handle moderately stiff problems by extending the stability region through careful tableau construction. These methods use an upper bound on the spectral radius of the Jacobian to achieve much larger stable timesteps than conventional explicit methods. **These methods are good for large real eigenvalue problems, but not for problems where the complex eigenvalues are large.** + +## Key Properties + +Stabilized RK methods provide: + + - **Extended stability regions** for moderately stiff problems + - **Explicit formulation** avoiding nonlinear solvers + - **Large stable timestep sizes** compared to standard explicit methods + - **Automatic spectral radius estimation** or user-supplied bounds + - **Efficient for parabolic PDEs** with moderate stiffness + - **Good performance** on problems with well-separated timescales + +## When to Use Stabilized RK Methods + +These methods are recommended for: + + - **Moderately stiff problems** where implicit methods are overkill + - **Parabolic PDEs** with diffusion-dominated behavior + - **Problems with large spatial grids** where implicit methods become expensive + - **Systems with well-separated timescales** but not extreme stiffness + - **Cases where explicit is preferred** but standard methods are unstable + - **Large-scale problems** where linear algebra cost of implicit methods is prohibitive + +## Mathematical Background + +Stabilized methods achieve extended stability by constructing tableaus with enlarged stability regions, often using Chebyshev polynomials or orthogonal polynomial techniques. The stable timestep is determined by the spectral radius bound rather than the CFL condition. **Important**: These methods extend stability primarily along the negative real axis, making them effective for large real eigenvalues but ineffective when complex eigenvalues dominate the stiffness. + +## Spectral Radius Estimation + +Users can supply an upper bound on the spectral radius using: + +```julia +eigen_est = (integrator) -> integrator.eigen_est = upper_bound +``` + +If not provided, the methods include automatic estimation procedures. + +## Solver Selection Guide + +### Recommended stabilized methods + + - **`ROCK2`**: Second-order ROW-type stabilized method with extended stability + - **`ROCK4`**: Fourth-order stabilized method for higher accuracy requirements + +## Performance Guidelines + +### When stabilized methods excel + + - **Large real eigenvalue problems** where stiffness comes from real eigenvalues + - **Moderate stiffness ratio** (10³ to 10⁶) dominated by real eigenvalues + - **Large spatial discretizations** where implicit solver cost is high + - **Very large systems** where stabilized RK methods are more efficient than BDF methods due to no linear algebra requirements + - **Parabolic PDEs** with diffusion-dominated (real eigenvalue) stiffness + - **Problems where spectral radius** can be estimated reliably + +### When to use alternatives + + - **Complex eigenvalue dominated problems**: Use implicit methods (BDF, SDIRK, Rosenbrock) + - **Non-stiff problems**: Use standard explicit methods (Tsit5, Verner) + +## Usage Considerations + + - **Spectral radius estimation** is crucial for performance + - **Method efficiency** depends on stiffness ratio + - **Test against implicit methods** for highly stiff problems + - **Consider adaptive spectral radius** estimation for varying stiffness + +```@eval +first_steps = evalfile("./common_first_steps.jl") +first_steps("OrdinaryDiffEqStabilizedRK", "ROCK4") +``` + +## Full list of solvers + +```@docs +ROCK2 +ROCK4 +RKC +SERK2 +ESERK4 +ESERK5 +``` diff --git a/docs/src/semilinear/Linear.md b/docs/src/semilinear/Linear.md index e797ba1d68..617fc6f29b 100644 --- a/docs/src/semilinear/Linear.md +++ b/docs/src/semilinear/Linear.md @@ -4,7 +4,84 @@ CollapsedDocStrings = true # OrdinaryDiffEqLinear -Methods for semi-linear differential equations. +Specialized methods for linear and semi-linear differential equations where the system can be written in matrix form `du/dt = A(t,u) * u` or `du/dt = A(t) * u`. These methods exploit the linear structure to provide exact solutions or highly accurate integration. + +## Key Properties + +Linear ODE methods provide: + + - **Exact solutions** for time-independent linear systems + - **Geometric integration** preserving Lie group structure + - **High-order Magnus expansions** for time-dependent linear systems + - **Lie group methods** for matrix differential equations + - **Excellent stability** for a wide range of linear systems + - **Specialized algorithms** for different types of linear operators + +## When to Use Linear Methods + +These methods are essential for: + + - **Linear systems** `du/dt = A * u` with constant or time-dependent matrices + - **Matrix differential equations** on Lie groups (rotation matrices, etc.) + - **Quantum dynamics** with Hamiltonian evolution + - **Linear oscillators** and harmonic systems + - **Time-dependent linear systems** with periodic or smooth coefficients + - **Geometric mechanics** requiring preservation of group structure + +## Mathematical Background + +For linear systems `du/dt = A(t) * u`, the exact solution is `u(t) = exp(∫A(s)ds) * u₀`. Linear methods approximate this matrix exponential using various mathematical techniques like Magnus expansions, Lie group integrators, and specialized exponential methods. + +## Solver Selection Guide + +### Time and state-independent (constant A) + + - **`LinearExponential`**: Exact solution for `du/dt = A * u` with constant matrix A + +### Time-dependent, state-independent (A(t)) + + - **`MagnusMidpoint`**: Second-order Magnus method + - **`MagnusLeapfrog`**: Second-order Magnus leapfrog scheme + - **`MagnusGauss4`**: Fourth-order with Gauss quadrature + - **`MagnusGL4`**: Fourth-order Gauss-Legendre Magnus method + - **`MagnusGL6`**: Sixth-order Gauss-Legendre Magnus method + - **`MagnusGL8`**: Eighth-order Gauss-Legendre Magnus method + - **`MagnusNC6`**: Sixth-order Newton-Cotes Magnus method + - **`MagnusNC8`**: Eighth-order Newton-Cotes Magnus method + +### State-dependent (A(u)) + + - **`LieEuler`**: First-order Lie group method + - **`RKMK2`**: Second-order Runge-Kutta-Munthe-Kaas method + - **`RKMK4`**: Fourth-order Runge-Kutta-Munthe-Kaas method + - **`LieRK4`**: Fourth-order Lie Runge-Kutta method + - **`CG2`**: Second-order Crouch-Grossman method + - **`CG4a`**: Fourth-order Crouch-Grossman method + - **`CayleyEuler`**: First-order method using Cayley transformations + +### Adaptive methods + + - **`MagnusAdapt4`**: Fourth-order adaptive Magnus method + +### Time and state-dependent (A(t,u)) + + - **`CG3`**: Third-order Crouch-Grossman method for most general case + +## Method Selection Guidelines + + - **For constant linear systems**: `LinearExponential` (exact) + - **For time-dependent systems**: Magnus methods based on desired order + - **For matrix Lie groups**: Lie group methods (RKMK, LieRK4, CG) + - **For high accuracy**: Higher-order Magnus methods (GL6, GL8) + - **For adaptive integration**: `MagnusAdapt4` + +## Special Considerations + +These methods require: + + - **Proper problem formulation** with identified linear structure + - **Matrix operator interface** for operator-based problems + - **Understanding of Lie group structure** for geometric problems ## Installation @@ -23,14 +100,14 @@ you will need to install some of the other libraries listed in the navigation ba ```julia using OrdinaryDiffEqLinear, SciMLOperators -function update_func(A, u, p, t) +function update_func!(A, u, p, t) A[1, 1] = 0 A[2, 1] = sin(u[1]) A[1, 2] = -1 A[2, 2] = 0 end A0 = ones(2, 2) -A = DiffEqArrayOperator(A0, update_func = update_func) +A = MatrixOperator(A0, update_func! = update_func!) u0 = ones(2) tspan = (0.0, 30.0) prob = ODEProblem(A, u0, tspan) diff --git a/lib/ImplicitDiscreteSolve/LICENSE.md b/lib/ImplicitDiscreteSolve/LICENSE.md new file mode 100644 index 0000000000..4a7df96ac5 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/LICENSE.md @@ -0,0 +1,24 @@ +The OrdinaryDiffEq.jl package is licensed under the MIT "Expat" License: + +> Copyright (c) 2016-2020: ChrisRackauckas, Yingbo Ma, Julia Computing Inc, and +> other contributors: +> +> https://github.com/SciML/OrdinaryDiffEq.jl/graphs/contributors +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. diff --git a/lib/ImplicitDiscreteSolve/Project.toml b/lib/ImplicitDiscreteSolve/Project.toml new file mode 100644 index 0000000000..d25e9f75d1 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/Project.toml @@ -0,0 +1,41 @@ +name = "ImplicitDiscreteSolve" +uuid = "3263718b-31ed-49cf-8a0f-35a466e8af96" +authors = ["vyudu "] +version = "1.2.0" + +[deps] +SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7" +SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5" +UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" + +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" + +[compat] +Test = "1.10.0" +OrdinaryDiffEqSDIRK = "1.6.0" +SciMLBase = "2.99" +SimpleNonlinearSolve = "2.7" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +SymbolicIndexingInterface = "0.3.38" +julia = "1.10" +JET = "0.9.18, 0.10.4" +UnPack = "1.0.2" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" + +[targets] +test = ["OrdinaryDiffEqSDIRK", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/ImplicitDiscreteSolve/src/ImplicitDiscreteSolve.jl b/lib/ImplicitDiscreteSolve/src/ImplicitDiscreteSolve.jl new file mode 100644 index 0000000000..b52829f5ed --- /dev/null +++ b/lib/ImplicitDiscreteSolve/src/ImplicitDiscreteSolve.jl @@ -0,0 +1,29 @@ +module ImplicitDiscreteSolve + +using SciMLBase +using SimpleNonlinearSolve +using UnPack +using SymbolicIndexingInterface: parameter_symbols +import OrdinaryDiffEqCore: OrdinaryDiffEqAlgorithm, alg_cache, OrdinaryDiffEqMutableCache, + OrdinaryDiffEqConstantCache, get_fsalfirstlast, isfsal, + initialize!, perform_step!, isdiscretecache, isdiscretealg, + alg_order, beta2_default, beta1_default, dt_required, + _initialize_dae!, DefaultInit, BrownFullBasicInit, OverrideInit + +using Reexport +@reexport using SciMLBase + +""" + IDSolve() + +Simple solver for `ImplicitDiscreteSystems`. Uses `SimpleNewtonRaphson` to solve for the next state at every timestep. +""" +struct IDSolve <: OrdinaryDiffEqAlgorithm end + +include("cache.jl") +include("solve.jl") +include("alg_utils.jl") + +export IDSolve + +end diff --git a/lib/ImplicitDiscreteSolve/src/alg_utils.jl b/lib/ImplicitDiscreteSolve/src/alg_utils.jl new file mode 100644 index 0000000000..5c25c2c217 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/src/alg_utils.jl @@ -0,0 +1,19 @@ +function SciMLBase.isautodifferentiable(alg::IDSolve) + true +end +function SciMLBase.allows_arbitrary_number_types(alg::IDSolve) + true +end +function SciMLBase.allowscomplex(alg::IDSolve) + true +end + +SciMLBase.isdiscrete(alg::IDSolve) = true + +isfsal(alg::IDSolve) = false +alg_order(alg::IDSolve) = 0 +beta2_default(alg::IDSolve) = 0 +beta1_default(alg::IDSolve, beta2) = 0 + +dt_required(alg::IDSolve) = false +isdiscretealg(alg::IDSolve) = true diff --git a/lib/ImplicitDiscreteSolve/src/cache.jl b/lib/ImplicitDiscreteSolve/src/cache.jl new file mode 100644 index 0000000000..f9c7835d82 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/src/cache.jl @@ -0,0 +1,36 @@ +mutable struct ImplicitDiscreteState{uType, pType, tType} + u::uType + p::pType + t_next::tType +end + +mutable struct IDSolveCache{uType} <: OrdinaryDiffEqMutableCache + u::uType + uprev::uType + state::ImplicitDiscreteState + prob::Union{Nothing, SciMLBase.AbstractNonlinearProblem} +end + +function alg_cache(alg::IDSolve, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + state = ImplicitDiscreteState(isnothing(u) ? nothing : zero(u), p, t) + IDSolveCache(u, uprev, state, nothing) +end + +isdiscretecache(cache::IDSolveCache) = true + +struct IDSolveConstantCache <: OrdinaryDiffEqConstantCache + prob::Union{Nothing, SciMLBase.AbstractNonlinearProblem} +end + +function alg_cache(alg::IDSolve, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + state = ImplicitDiscreteState(isnothing(u) ? nothing : zero(u), p, t) + IDSolveCache(u, uprev, state, nothing) +end + +get_fsalfirstlast(cache::IDSolveCache, rate_prototype) = (nothing, nothing) diff --git a/lib/ImplicitDiscreteSolve/src/solve.jl b/lib/ImplicitDiscreteSolve/src/solve.jl new file mode 100644 index 0000000000..e0580799d8 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/src/solve.jl @@ -0,0 +1,70 @@ +# Remake the nonlinear problem, then update +function perform_step!(integrator, cache::IDSolveCache, repeat_step = false) + @unpack alg, u, uprev, dt, t, f, p = integrator + @unpack state, prob = cache + state.u .= uprev + state.t_next = t + prob = remake(prob, p = state) + + u = solve(prob, SimpleNewtonRaphson()) + integrator.sol = SciMLBase.solution_new_retcode(integrator.sol, u.retcode) + integrator.u = u +end + +function initialize!(integrator, cache::IDSolveCache) + integrator.u isa AbstractVector && (cache.state.u .= integrator.u) + cache.state.p = integrator.p + cache.state.t_next = integrator.t + f = integrator.f + + _f = if isinplace(f) + (resid, u_next, p) -> f(resid, u_next, p.u, p.p, p.t_next) + else + (u_next, p) -> f(u_next, p.u, p.p, p.t_next) + end + u_len = isnothing(integrator.u) ? 0 : length(integrator.u) + nlls = !isnothing(f.resid_prototype) && (length(f.resid_prototype) != u_len) + + prob = if nlls + NonlinearLeastSquaresProblem{isinplace(f)}( + NonlinearFunction(_f; resid_prototype = f.resid_prototype), + cache.state.u, cache.state) + else + NonlinearProblem{isinplace(f)}(_f, cache.state.u, cache.state) + end + cache.prob = prob +end + +function _initialize_dae!(integrator, prob::ImplicitDiscreteProblem, + alg::DefaultInit, x::Union{Val{true}, Val{false}}) + isnothing(prob.u0) && return + atol = one(eltype(prob.u0)) * 1e-12 + if SciMLBase.has_initializeprob(prob.f) + _initialize_dae!(integrator, prob, + OverrideInit(atol), x) + else + @unpack u, p, t, f = integrator + initstate = ImplicitDiscreteState(u, p, t) + + _f = if isinplace(f) + (resid, u_next, p) -> f(resid, u_next, p.u, p.p, p.t_next) + else + (u_next, p) -> f(u_next, p.u, p.p, p.t_next) + end + + nlls = !isnothing(f.resid_prototype) && + (length(f.resid_prototype) != length(integrator.u)) + prob = if nlls + NonlinearLeastSquaresProblem{isinplace(f)}( + NonlinearFunction(_f; resid_prototype = f.resid_prototype), u, initstate) + else + NonlinearProblem{isinplace(f)}(_f, u, initstate) + end + sol = solve(prob, SimpleNewtonRaphson()) + if sol.retcode == ReturnCode.Success + integrator.u = sol + else + integrator.sol = SciMLBase.solution_new_retcode(integrator.sol, ReturnCode.InitialFailure) + end + end +end diff --git a/lib/ImplicitDiscreteSolve/test/qa.jl b/lib/ImplicitDiscreteSolve/test/qa.jl new file mode 100644 index 0000000000..cc4d2e2ba1 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/test/qa.jl @@ -0,0 +1,9 @@ +using ImplicitDiscreteSolve +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + ImplicitDiscreteSolve; + piracies = false + ) +end diff --git a/lib/ImplicitDiscreteSolve/test/runtests.jl b/lib/ImplicitDiscreteSolve/test/runtests.jl new file mode 100644 index 0000000000..4c94621302 --- /dev/null +++ b/lib/ImplicitDiscreteSolve/test/runtests.jl @@ -0,0 +1,133 @@ +#runtests +using Test +using ImplicitDiscreteSolve +using OrdinaryDiffEqCore +using OrdinaryDiffEqSDIRK +using SciMLBase +using JET + +# Test implicit Euler using ImplicitDiscreteProblem +@testset "Implicit Euler" begin + function lotkavolterra(u, p, t) + [1.5*u[1] - u[1]*u[2], -3.0*u[2] + u[1]*u[2]] + end + + function f!(resid, u_next, u, p, t) + lv = lotkavolterra(u_next, p, t) + resid[1] = u_next[1] - u[1] - 0.01*lv[1] + resid[2] = u_next[2] - u[2] - 0.01*lv[2] + nothing + end + u0 = [1.0, 1.0] + tspan = (0.0, 0.5) + + idprob = ImplicitDiscreteProblem(f!, u0, tspan, []; dt = 0.01) + idsol = solve(idprob, IDSolve()) + + oprob = ODEProblem(lotkavolterra, u0, tspan) + osol = solve(oprob, ImplicitEuler()) + + @test isapprox(idsol[end], osol[end], atol = 0.1) + + ### free-fall + # y, dy + function ff(u, p, t) + [u[2], -9.8] + end + + function g!(resid, u_next, u, p, t) + f = ff(u_next, p, t) + resid[1] = u_next[1] - u[1] - 0.01*f[1] + resid[2] = u_next[2] - u[2] - 0.01*f[2] + nothing + end + u0 = [10.0, 0.0] + tspan = (0, 0.2) + + idprob = ImplicitDiscreteProblem(g!, u0, tspan, []; dt = 0.01) + idsol = solve(idprob, IDSolve()) + + oprob = ODEProblem(ff, u0, tspan) + osol = solve(oprob, ImplicitEuler()) + + @test isapprox(idsol[end], osol[end], atol = 0.1) +end + +@testset "Solver initializes" begin + function periodic!(resid, u_next, u, p, t) + resid[1] = u_next[1] - u[1] - sin(t*π/4) + resid[2] = 16 - u_next[2]^2 - u_next[1]^2 + end + + tsteps = 15 + u0 = [1.0, 3.0] + idprob = ImplicitDiscreteProblem(periodic!, u0, (0, tsteps), []) + integ = init(idprob, IDSolve()) + @test integ.u[1]^2 + integ.u[2]^2 ≈ 16 + + for ts in 1:tsteps + step!(integ) + @test integ.u[1]^2 + integ.u[2]^2 ≈ 16 + end +end + +@testset "Handle nothing in u0" begin + function empty(u_next, u, p, t) + nothing + end + + tsteps = 5 + u0 = nothing + idprob = ImplicitDiscreteProblem(empty, u0, (0, tsteps), []) + @test_nowarn integ = init(idprob, IDSolve()) +end + +@testset "Create NonlinearLeastSquaresProblem" begin + function over(u_next, u, p, t) + [u_next[1] - 1, u_next[2] - 1, u_next[1] - u_next[2]] + end + + tsteps = 5 + u0 = [1.0, 1.0] + idprob = ImplicitDiscreteProblem( + ImplicitDiscreteFunction(over, resid_prototype = zeros(3)), u0, (0, tsteps), []) + integ = init(idprob, IDSolve()) + @test integ.cache.prob isa NonlinearLeastSquaresProblem + + function under(u_next, u, p, t) + [u_next[1] - u_next[2] - 1] + end + idprob = ImplicitDiscreteProblem( + ImplicitDiscreteFunction(under; resid_prototype = zeros(1)), u0, (0, tsteps), []) + integ = init(idprob, IDSolve()) + @test integ.cache.prob isa NonlinearLeastSquaresProblem + + function full(u_next, u, p, t) + [u_next[1]^2 - 3, u_next[2] - u[1]] + end + idprob = ImplicitDiscreteProblem( + ImplicitDiscreteFunction(full; resid_prototype = zeros(2)), u0, (0, tsteps), []) + integ = init(idprob, IDSolve()) + @test integ.cache.prob isa NonlinearProblem +end + +@testset "InitialFailure thrown" begin + function bad(u_next, u, p, t) + [u_next[1] - u_next[2], u_next[1] - 3, u_next[2] - 4] + end + + u0 = [3.0, 4.0] + idprob = ImplicitDiscreteProblem(bad, u0, (0, 0), []) + integ = init(idprob, IDSolve()) + @test check_error(integ) == ReturnCode.InitialFailure + sol = solve(idprob, IDSolve()) + @test length(sol.u) == 1 + @test !SciMLBase.successful_retcode(sol) +end + +@testset "JET Tests" begin + test_package( + ImplicitDiscreteSolve, target_defined_modules = true, mode = :typo) +end + +include("qa.jl") diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/Project.toml b/lib/OrdinaryDiffEqAdamsBashforthMoulton/Project.toml index 1c1e832dab..4971a132c4 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/Project.toml +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/Project.toml @@ -1,45 +1,56 @@ name = "OrdinaryDiffEqAdamsBashforthMoulton" uuid = "89bda076-bce5-4f1c-845f-551c83cdda9a" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.5.0" [deps] -ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" OrdinaryDiffEqLowOrderRK = "1344f307-1e59-4825-a18e-ace9aa3fa4c6" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -ADTypes = "1.7.1" -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqLowOrderRK = "<0.0.1, 1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" [extras] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +Polyester = "0.7" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +OrdinaryDiffEqLowOrderRK = "1.5.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "ODEProblemLibrary", "Random", "SafeTestsets", "Test", "DiffEqBase"] +test = ["DiffEqDevTools", "ODEProblemLibrary", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqLowOrderRK] +path = "../OrdinaryDiffEqLowOrderRK" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/OrdinaryDiffEqAdamsBashforthMoulton.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/OrdinaryDiffEqAdamsBashforthMoulton.jl index 070524d8a3..fda67f03d6 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/OrdinaryDiffEqAdamsBashforthMoulton.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/OrdinaryDiffEqAdamsBashforthMoulton.jl @@ -9,16 +9,16 @@ import OrdinaryDiffEqCore: OrdinaryDiffEqMutableCache, OrdinaryDiffEqConstantCac constvalue, calculate_residuals, calculate_residuals!, trivial_limiter!, get_fsalfirstlast, generic_solver_docstring, - full_cache + full_cache, + _bool_to_ADType import OrdinaryDiffEqLowOrderRK: BS3ConstantCache, BS3Cache, RK4ConstantCache, RK4Cache import RecursiveArrayTools: recursivefill! using MuladdMacro, FastBroadcast import Static: False -import ADTypes: AutoForwardDiff import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_caches.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_caches.jl index d417f9cdad..283b4b6b18 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_caches.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_caches.jl @@ -4,7 +4,7 @@ get_fsalfirstlast(cache::ABMMutableCache, u) = (cache.fsalfirst, cache.k) function get_fsalfirstlast(cache::ABMVariableCoefficientMutableCache, u) (cache.fsalfirst, cache.k4) end -@cache mutable struct AB3Cache{uType, rateType} <: ABMMutableCache +@cache mutable struct AB3Cache{uType, rateType, Thread} <: ABMMutableCache u::uType uprev::uType fsalfirst::rateType @@ -14,6 +14,7 @@ end k::rateType tmp::uType step::Int + thread::Thread end @cache mutable struct AB3ConstantCache{rateType} <: OrdinaryDiffEqConstantCache @@ -32,7 +33,7 @@ function alg_cache(alg::AB3, u, rate_prototype, ::Type{uEltypeNoUnits}, ralk2 = zero(rate_prototype) k = zero(rate_prototype) tmp = zero(u) - AB3Cache(u, uprev, fsalfirst, k2, k3, ralk2, k, tmp, 1) + AB3Cache(u, uprev, fsalfirst, k2, k3, ralk2, k, tmp, 1, alg.thread) end function alg_cache(alg::AB3, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -44,7 +45,7 @@ function alg_cache(alg::AB3, u, rate_prototype, ::Type{uEltypeNoUnits}, AB3ConstantCache(k2, k3, 1) end -@cache mutable struct ABM32Cache{uType, rateType} <: ABMMutableCache +@cache mutable struct ABM32Cache{uType, rateType, Thread} <: ABMMutableCache u::uType uprev::uType fsalfirst::rateType @@ -54,6 +55,7 @@ end k::rateType tmp::uType step::Int + thread::Thread end @cache mutable struct ABM32ConstantCache{rateType} <: OrdinaryDiffEqConstantCache @@ -72,7 +74,7 @@ function alg_cache(alg::ABM32, u, rate_prototype, ::Type{uEltypeNoUnits}, ralk2 = zero(rate_prototype) k = zero(rate_prototype) tmp = zero(u) - ABM32Cache(u, uprev, fsalfirst, k2, k3, ralk2, k, tmp, 1) + ABM32Cache(u, uprev, fsalfirst, k2, k3, ralk2, k, tmp, 1, alg.thread) end function alg_cache(alg::ABM32, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -84,7 +86,7 @@ function alg_cache(alg::ABM32, u, rate_prototype, ::Type{uEltypeNoUnits}, ABM32ConstantCache(k2, k3, 1) end -@cache mutable struct AB4Cache{uType, rateType} <: ABMMutableCache +@cache mutable struct AB4Cache{uType, rateType, Thread} <: ABMMutableCache u::uType uprev::uType fsalfirst::rateType @@ -98,6 +100,7 @@ end t3::rateType t4::rateType step::Int + thread::Thread end @cache mutable struct AB4ConstantCache{rateType} <: OrdinaryDiffEqConstantCache @@ -121,7 +124,7 @@ function alg_cache(alg::AB4, u, rate_prototype, ::Type{uEltypeNoUnits}, t2 = zero(rate_prototype) t3 = zero(rate_prototype) t4 = zero(rate_prototype) - AB4Cache(u, uprev, fsalfirst, k2, k3, k4, ralk2, k, tmp, t2, t3, t4, 1) + AB4Cache(u, uprev, fsalfirst, k2, k3, k4, ralk2, k, tmp, t2, t3, t4, 1, alg.thread) end function alg_cache(alg::AB4, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -134,7 +137,7 @@ function alg_cache(alg::AB4, u, rate_prototype, ::Type{uEltypeNoUnits}, AB4ConstantCache(k2, k3, k4, 1) end -@cache mutable struct ABM43Cache{uType, rateType} <: ABMMutableCache +@cache mutable struct ABM43Cache{uType, rateType, Thread} <: ABMMutableCache u::uType uprev::uType fsalfirst::rateType @@ -151,6 +154,7 @@ end t6::rateType t7::rateType step::Int + thread::Thread end @cache mutable struct ABM43ConstantCache{rateType} <: OrdinaryDiffEqConstantCache @@ -177,7 +181,8 @@ function alg_cache(alg::ABM43, u, rate_prototype, ::Type{uEltypeNoUnits}, t5 = zero(rate_prototype) t6 = zero(rate_prototype) t7 = zero(rate_prototype) - ABM43Cache(u, uprev, fsalfirst, k2, k3, k4, ralk2, k, tmp, t2, t3, t4, t5, t6, t7, 1) + ABM43Cache(u, uprev, fsalfirst, k2, k3, k4, ralk2, k, + tmp, t2, t3, t4, t5, t6, t7, 1, alg.thread) end function alg_cache(alg::ABM43, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -190,7 +195,7 @@ function alg_cache(alg::ABM43, u, rate_prototype, ::Type{uEltypeNoUnits}, ABM43ConstantCache(k2, k3, k4, 1) end -@cache mutable struct AB5Cache{uType, rateType} <: ABMMutableCache +@cache mutable struct AB5Cache{uType, rateType, Thread} <: ABMMutableCache u::uType uprev::uType fsalfirst::rateType @@ -204,6 +209,7 @@ end t3::rateType t4::rateType step::Int + thread::Thread end @cache mutable struct AB5ConstantCache{rateType} <: OrdinaryDiffEqConstantCache @@ -228,7 +234,7 @@ function alg_cache(alg::AB5, u, rate_prototype, ::Type{uEltypeNoUnits}, t2 = zero(rate_prototype) t3 = zero(rate_prototype) t4 = zero(rate_prototype) - AB5Cache(u, uprev, fsalfirst, k2, k3, k4, k5, k, tmp, t2, t3, t4, 1) + AB5Cache(u, uprev, fsalfirst, k2, k3, k4, k5, k, tmp, t2, t3, t4, 1, alg.thread) end function alg_cache(alg::AB5, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -242,7 +248,7 @@ function alg_cache(alg::AB5, u, rate_prototype, ::Type{uEltypeNoUnits}, AB5ConstantCache(k2, k3, k4, k5, 1) end -@cache mutable struct ABM54Cache{uType, rateType} <: ABMMutableCache +@cache mutable struct ABM54Cache{uType, rateType, Thread} <: ABMMutableCache u::uType uprev::uType fsalfirst::rateType @@ -260,6 +266,7 @@ end t7::rateType t8::rateType step::Int + thread::Thread end @cache mutable struct ABM54ConstantCache{rateType} <: OrdinaryDiffEqConstantCache @@ -288,7 +295,8 @@ function alg_cache(alg::ABM54, u, rate_prototype, ::Type{uEltypeNoUnits}, t6 = zero(rate_prototype) t7 = zero(rate_prototype) t8 = zero(rate_prototype) - ABM54Cache(u, uprev, fsalfirst, k2, k3, k4, k5, k, tmp, t2, t3, t4, t5, t6, t7, t8, 1) + ABM54Cache(u, uprev, fsalfirst, k2, k3, k4, k5, k, tmp, + t2, t3, t4, t5, t6, t7, t8, 1, alg.thread) end function alg_cache(alg::ABM54, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -317,7 +325,7 @@ end end @cache mutable struct VCAB3Cache{uType, rateType, TabType, bs3Type, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -337,6 +345,7 @@ end utilde::uType tab::TabType step::Int + thread::Thread end function alg_cache(alg::VCAB3, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -395,7 +404,7 @@ function alg_cache(alg::VCAB3, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp = zero(u) utilde = zero(u) VCAB3Cache(u, uprev, fsalfirst, bs3cache, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕstar_n, β, - order, atmp, tmp, utilde, tab, 1) + order, atmp, tmp, utilde, tab, 1, alg.thread) end @cache mutable struct VCAB4ConstantCache{rk4constcache, tArrayType, rArrayType, cArrayType, @@ -413,7 +422,7 @@ end end @cache mutable struct VCAB4Cache{uType, rateType, rk4cacheType, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -432,6 +441,7 @@ end tmp::uType utilde::uType step::Int + thread::Thread end function alg_cache(alg::VCAB4, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -489,7 +499,7 @@ function alg_cache(alg::VCAB4, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp = zero(u) utilde = zero(u) VCAB4Cache(u, uprev, fsalfirst, rk4cache, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕstar_n, β, - order, atmp, tmp, utilde, 1) + order, atmp, tmp, utilde, 1, alg.thread) end # VCAB5 @@ -509,7 +519,7 @@ end end @cache mutable struct VCAB5Cache{uType, rateType, rk4cacheType, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -528,6 +538,7 @@ end tmp::uType utilde::uType step::Int + thread::Thread end function alg_cache(alg::VCAB5, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -585,7 +596,7 @@ function alg_cache(alg::VCAB5, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp = zero(u) utilde = zero(u) VCAB5Cache(u, uprev, fsalfirst, rk4cache, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕstar_n, β, - order, atmp, tmp, utilde, 1) + order, atmp, tmp, utilde, 1, alg.thread) end # VCABM3 @@ -607,7 +618,7 @@ end @cache mutable struct VCABM3Cache{ uType, rateType, TabType, bs3Type, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -628,6 +639,7 @@ end utilde::uType tab::TabType step::Int + thread::Thread end function alg_cache(alg::VCABM3, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -691,7 +703,7 @@ function alg_cache(alg::VCABM3, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp = zero(u) utilde = zero(u) VCABM3Cache(u, uprev, fsalfirst, bs3cache, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕ_np1, - ϕstar_n, β, order, atmp, tmp, utilde, tab, 1) + ϕstar_n, β, order, atmp, tmp, utilde, tab, 1, alg.thread) end # VCABM4 @@ -713,7 +725,7 @@ end end @cache mutable struct VCABM4Cache{uType, rateType, rk4cacheType, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -733,6 +745,7 @@ end tmp::uType utilde::uType step::Int + thread::Thread end function alg_cache(alg::VCABM4, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -796,7 +809,7 @@ function alg_cache(alg::VCABM4, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp = zero(u) utilde = zero(u) VCABM4Cache(u, uprev, fsalfirst, rk4cache, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕ_np1, - ϕstar_n, β, order, atmp, tmp, utilde, 1) + ϕstar_n, β, order, atmp, tmp, utilde, 1, alg.thread) end # VCABM5 @@ -818,7 +831,7 @@ end end @cache mutable struct VCABM5Cache{uType, rateType, rk4cacheType, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -838,6 +851,7 @@ end tmp::uType utilde::uType step::Int + thread::Thread end function alg_cache(alg::VCABM5, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -901,7 +915,7 @@ function alg_cache(alg::VCABM5, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp = zero(u) utilde = zero(u) VCABM5Cache(u, uprev, fsalfirst, rk4cache, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕ_np1, - ϕstar_n, β, order, atmp, tmp, utilde, 1) + ϕstar_n, β, order, atmp, tmp, utilde, 1, alg.thread) end # VCABM @@ -924,7 +938,7 @@ end end @cache mutable struct VCABMCache{uType, rateType, dtType, tArrayType, cArrayType, - uNoUnitsType, coefType, dtArrayType} <: + uNoUnitsType, coefType, dtArrayType, Thread} <: ABMVariableCoefficientMutableCache u::uType uprev::uType @@ -952,6 +966,7 @@ end atmpm2::uNoUnitsType atmpp1::uNoUnitsType step::Int + thread::Thread end function alg_cache(alg::VCABM, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -1023,5 +1038,5 @@ function alg_cache(alg::VCABM, u, rate_prototype, ::Type{uEltypeNoUnits}, VCABMCache( u, uprev, fsalfirst, k4, ϕstar_nm1, dts, c, g, ϕ_n, ϕ_np1, ϕstar_n, β, order, max_order, atmp, tmp, ξ, ξ0, utilde, utildem1, utildem2, utildep1, atmpm1, - atmpm2, atmpp1, 1) + atmpm2, atmpp1, 1, alg.thread) end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_perform_step.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_perform_step.jl index 077fdfb4ec..1af821146a 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_perform_step.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_bashforth_moulton_perform_step.jl @@ -68,7 +68,7 @@ end @muladd function perform_step!(integrator, cache::AB3Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack tmp, fsalfirst, k2, k3, ralk2, k = cache + @unpack tmp, fsalfirst, k2, k3, ralk2, k, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -77,17 +77,17 @@ end if cache.step <= 2 cache.step += 1 ttmp = t + (2 / 3) * dt - @.. broadcast=false tmp=uprev + (2 / 3) * dt * k1 + @.. broadcast=false thread=thread tmp=uprev+(2/3)*dt*k1 f(ralk2, tmp, p, ttmp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false u=uprev + (dt / 4) * (k1 + 3 * ralk2) #Ralston Method + @.. broadcast=false thread=thread u=uprev+(dt/4)*(k1+3*ralk2) #Ralston Method if cnt == 1 cache.k3 .= k1 else cache.k2 .= k1 end else - @.. broadcast=false u=uprev + (dt / 12) * (23 * k1 - 16 * k2 + 5 * k3) + @.. broadcast=false thread=thread u=uprev+(dt/12)*(23*k1-16*k2+5*k3) cache.k2, cache.k3 = k3, k2 cache.k2 .= k1 end @@ -128,7 +128,7 @@ end @muladd function perform_step!(integrator, cache::ABM32Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack tmp, fsalfirst, k2, k3, ralk2, k = cache + @unpack tmp, fsalfirst, k2, k3, ralk2, k, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -137,21 +137,21 @@ end if cache.step == 1 cache.step += 1 ttmp = t + (2 / 3) * dt - @.. broadcast=false tmp=uprev + (2 / 3) * dt * k1 + @.. broadcast=false thread=thread tmp=uprev+(2/3)*dt*k1 f(ralk2, tmp, p, ttmp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false u=uprev + (dt / 4) * (k1 + 3 * ralk2) #Ralston Method + @.. broadcast=false thread=thread u=uprev+(dt/4)*(k1+3*ralk2) #Ralston Method cache.k2 .= k1 else if cnt == 2 perform_step!(integrator, - AB3Cache(u, uprev, fsalfirst, copy(k2), k3, ralk2, k, tmp, cnt)) #Here passing copy of k2, otherwise it will change in AB3() + AB3Cache(u, uprev, fsalfirst, copy(k2), k3, ralk2, k, tmp, cnt, thread)) #Here passing copy of k2, otherwise it will change in AB3() else perform_step!(integrator, - AB3Cache(u, uprev, fsalfirst, k2, k3, ralk2, k, tmp, cnt)) + AB3Cache(u, uprev, fsalfirst, k2, k3, ralk2, k, tmp, cnt, thread)) end k = integrator.fsallast - @.. broadcast=false u=uprev + (dt / 12) * (5 * k + 8 * k1 - k2) + @.. broadcast=false thread=thread u=uprev+(dt/12)*(5*k+8*k1-k2) cache.k2, cache.k3 = k3, k2 cache.k2 .= k1 end @@ -198,7 +198,7 @@ end @muladd function perform_step!(integrator, cache::AB4Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack tmp, fsalfirst, k2, k3, k4, ralk2, k, t2, t3, t4 = cache + @unpack tmp, fsalfirst, k2, k3, k4, ralk2, k, t2, t3, t4, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -208,14 +208,14 @@ end cache.step += 1 halfdt = dt / 2 ttmp = t + halfdt - @.. broadcast=false tmp=uprev + halfdt * k1 + @.. broadcast=false thread=thread tmp=uprev+halfdt*k1 f(t2, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + halfdt * t2 + @.. broadcast=false thread=thread tmp=uprev+halfdt*t2 f(t3, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + dt * t3 + @.. broadcast=false thread=thread tmp=uprev+dt*t3 f(t4, tmp, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) - @.. broadcast=false u=uprev + (dt / 6) * (2 * (t2 + t3) + (k1 + t4)) #RK4 + @.. broadcast=false thread=thread u=uprev+(dt/6)*(2*(t2+t3)+(k1+t4)) #RK4 if cnt == 1 cache.k4 .= k1 elseif cnt == 2 @@ -224,7 +224,9 @@ end cache.k2 .= k1 end else - @.. broadcast=false u=uprev + (dt / 24) * (55 * k1 - 59 * k2 + 37 * k3 - 9 * k4) + @.. broadcast=false thread=thread u=uprev+ + (dt/24)* + (55*k1-59*k2+37*k3-9*k4) cache.k4, cache.k3 = k3, k4 cache.k3 .= k2 cache.k2 .= k1 @@ -272,7 +274,7 @@ end @muladd function perform_step!(integrator, cache::ABM43Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack tmp, fsalfirst, k2, k3, k4, ralk2, k, t2, t3, t4, t5, t6, t7 = cache + @unpack tmp, fsalfirst, k2, k3, k4, ralk2, k, t2, t3, t4, t5, t6, t7, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -282,14 +284,14 @@ end cache.step += 1 halfdt = dt / 2 ttmp = t + halfdt - @.. broadcast=false tmp=uprev + halfdt * k1 + @.. broadcast=false thread=thread tmp=uprev+halfdt*k1 f(t2, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + halfdt * t2 + @.. broadcast=false thread=thread tmp=uprev+halfdt*t2 f(t3, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + dt * t3 + @.. broadcast=false thread=thread tmp=uprev+dt*t3 f(t4, tmp, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) - @.. broadcast=false u=uprev + (dt / 6) * (2 * (t2 + t3) + (k1 + t4)) #RK4 + @.. broadcast=false thread=thread u=uprev+(dt/6)*(2*(t2+t3)+(k1+t4)) #RK4 if cnt == 1 cache.k3 .= k1 else @@ -301,9 +303,10 @@ end t4 .= k4 perform_step!(integrator, AB4Cache(u, uprev, fsalfirst, t2, t3, t4, ralk2, k, tmp, t5, t6, t7, - cnt)) + cnt, thread)) k = integrator.fsallast - @.. broadcast=false u=uprev + (dt / 24) * (9 * k + 19 * k1 - 5 * k2 + k3) + @.. broadcast=false thread=thread u=uprev+ + (dt/24)*(9*k+19*k1-5*k2+k3) cache.k4, cache.k3 = k3, k4 cache.k3 .= k2 cache.k2 .= k1 @@ -354,7 +357,7 @@ end @muladd function perform_step!(integrator, cache::AB5Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack tmp, fsalfirst, k2, k3, k4, k5, k, t2, t3, t4 = cache + @unpack tmp, fsalfirst, k2, k3, k4, k5, k, t2, t3, t4, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -364,14 +367,14 @@ end cache.step += 1 halfdt = dt / 2 ttmp = t + halfdt - @.. broadcast=false tmp=uprev + halfdt * k1 + @.. broadcast=false thread=thread tmp=uprev+halfdt*k1 f(t2, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + halfdt * t2 + @.. broadcast=false thread=thread tmp=uprev+halfdt*t2 f(t3, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + dt * t3 + @.. broadcast=false thread=thread tmp=uprev+dt*t3 f(t4, tmp, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false u=uprev + (dt / 6) * (2 * (t2 + t3) + (k1 + t4)) #RK4 + @.. broadcast=false thread=thread u=uprev+(dt/6)*(2*(t2+t3)+(k1+t4)) #RK4 if cnt == 1 cache.k5 .= k1 elseif cnt == 2 @@ -382,9 +385,10 @@ end cache.k2 .= k1 end else - @.. broadcast=false u=uprev + - (dt / 720) * - (1901 * k1 - 2774 * k2 + 2616 * k3 - 1274 * k4 + 251 * k5) + @.. broadcast=false thread=thread u=uprev+ + (dt/720)* + (1901*k1-2774*k2+2616*k3-1274*k4+ + 251*k5) cache.k5, cache.k4 = k4, k5 cache.k4 .= k3 cache.k3 .= k2 @@ -436,7 +440,7 @@ end @muladd function perform_step!(integrator, cache::ABM54Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack tmp, fsalfirst, k2, k3, k4, k5, k, t2, t3, t4, t5, t6, t7, t8 = cache + @unpack tmp, fsalfirst, k2, k3, k4, k5, k, t2, t3, t4, t5, t6, t7, t8, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -446,13 +450,13 @@ end cache.step += 1 halfdt = dt / 2 ttmp = t + halfdt - @.. broadcast=false tmp=uprev + halfdt * k1 + @.. broadcast=false thread=thread tmp=uprev+halfdt*k1 f(t2, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + halfdt * t2 + @.. broadcast=false thread=thread tmp=uprev+halfdt*t2 f(t3, tmp, p, ttmp) - @.. broadcast=false tmp=uprev + dt * t3 + @.. broadcast=false thread=thread tmp=uprev+dt*t3 f(t4, tmp, p, t + dt) - @.. broadcast=false u=uprev + (dt / 6) * (2 * (t2 + t3) + (k1 + t4)) #RK4 + @.. broadcast=false thread=thread u=uprev+(dt/6)*(2*(t2+t3)+(k1+t4)) #RK4 OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) if cnt == 1 cache.k4 .= k1 @@ -468,11 +472,12 @@ end t5 .= k5 perform_step!(integrator, AB5Cache(u, uprev, fsalfirst, t2, t3, t4, t5, k, tmp, t6, t7, t8, - cnt)) + cnt, thread)) k = integrator.fsallast - @.. broadcast=false u=uprev + - (dt / 720) * - (251 * k + 646 * k1 - 264 * k2 + 106 * k3 - 19 * k4) + @.. broadcast=false thread=thread u=uprev+ + (dt/720)* + (251*k+646*k1-264*k2+106*k3- + 19*k4) cache.k5, cache.k4 = k4, k5 cache.k4 .= k3 cache.k3 .= k2 @@ -561,7 +566,7 @@ end @muladd function perform_step!(integrator, cache::VCAB3Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕstar_n, ϕstar_nm1, order, atmp, utilde, bs3cache = cache + @unpack k4, dts, g, ϕstar_n, ϕstar_nm1, order, atmp, utilde, bs3cache, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -587,12 +592,12 @@ end integrator.fsallast .= k4 else g_coefs!(cache, k) - @.. broadcast=false u=uprev + @.. broadcast=false thread=thread u=uprev for i in 1:k - @.. broadcast=false u+=g[i] * ϕstar_n[i] + @.. broadcast=false thread=thread u+=g[i]*ϕstar_n[i] end if integrator.opts.adaptive - @.. broadcast=false utilde=g[k] * ϕstar_n[k] # Using lower order AB from subset of coefficients + @.. broadcast=false thread=thread utilde=g[k]*ϕstar_n[k] # Using lower order AB from subset of coefficients calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -694,7 +699,8 @@ end @muladd function perform_step!(integrator, cache::VCAB4Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕ_n, ϕstar_n, ϕstar_nm1, order, atmp, utilde, rk4cache = cache + @unpack k4, dts, g, ϕ_n, ϕstar_n, ϕstar_nm1, order, atmp, utilde, rk4cache, + thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -726,12 +732,12 @@ end integrator.fsallast .= rk4cache.k else g_coefs!(cache, k) - @.. broadcast=false u=uprev + @.. broadcast=false thread=thread u=uprev for i in 1:k - @.. broadcast=false u+=g[i] * ϕstar_n[i] + @.. broadcast=false thread=thread u+=g[i]*ϕstar_n[i] end if integrator.opts.adaptive - @.. broadcast=false utilde=g[k] * ϕstar_n[k] + @.. broadcast=false thread=thread utilde=g[k]*ϕstar_n[k] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -842,7 +848,8 @@ end @muladd function perform_step!(integrator, cache::VCAB5Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕ_n, ϕstar_n, ϕstar_nm1, order, atmp, utilde, rk4cache = cache + @unpack k4, dts, g, ϕ_n, ϕstar_n, ϕstar_nm1, order, atmp, utilde, rk4cache, + thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -881,12 +888,12 @@ end integrator.fsallast .= rk4cache.k else g_coefs!(cache, k) - @.. broadcast=false u=uprev + @.. broadcast=false thread=thread u=uprev for i in 1:k - @.. broadcast=false u+=g[i] * ϕstar_n[i] + @.. broadcast=false thread=thread u+=g[i]*ϕstar_n[i] end if integrator.opts.adaptive - @.. broadcast=false utilde=g[k] * ϕstar_n[k] + @.. broadcast=false thread=thread utilde=g[k]*ϕstar_n[k] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -988,7 +995,8 @@ end @muladd function perform_step!(integrator, cache::VCABM3Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕstar_n, ϕ_np1, ϕstar_nm1, order, atmp, utilde, bs3cache = cache + @unpack k4, dts, g, ϕstar_n, ϕ_np1, ϕstar_nm1, order, atmp, utilde, bs3cache, + thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -1014,16 +1022,16 @@ end integrator.fsallast .= k4 else g_coefs!(cache, k + 1) - @.. broadcast=false u=uprev + @.. broadcast=false thread=thread u=uprev for i in 1:(k - 1) - @.. broadcast=false u+=g[i] * ϕstar_n[i] + @.. broadcast=false thread=thread u+=g[i]*ϕstar_n[i] end f(k4, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) ϕ_np1!(cache, k4, k + 1) - @.. broadcast=false u+=g[end - 1] * ϕ_np1[end - 1] + @.. broadcast=false thread=thread u+=g[end - 1]*ϕ_np1[end - 1] if integrator.opts.adaptive - @.. broadcast=false utilde=(g[end] - g[end - 1]) * ϕ_np1[end] + @.. broadcast=false thread=thread utilde=(g[end]-g[end - 1])*ϕ_np1[end] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -1131,7 +1139,8 @@ end @muladd function perform_step!(integrator, cache::VCABM4Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕstar_n, ϕ_np1, ϕstar_nm1, order, atmp, utilde, rk4cache = cache + @unpack k4, dts, g, ϕstar_n, ϕ_np1, ϕstar_nm1, order, atmp, utilde, rk4cache, + thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -1163,16 +1172,16 @@ end integrator.fsallast .= rk4cache.k else g_coefs!(cache, k + 1) - @.. broadcast=false u=uprev + @.. broadcast=false thread=thread u=uprev for i in 1:(k - 1) - @.. broadcast=false u+=g[i] * ϕstar_n[i] + @.. broadcast=false thread=thread u+=g[i]*ϕstar_n[i] end f(k4, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) ϕ_np1!(cache, k4, k + 1) - @.. broadcast=false u+=g[end - 1] * ϕ_np1[end - 1] + @.. broadcast=false thread=thread u+=g[end - 1]*ϕ_np1[end - 1] if integrator.opts.adaptive - @.. broadcast=false utilde=(g[end] - g[end - 1]) * ϕ_np1[end] + @.. broadcast=false thread=thread utilde=(g[end]-g[end - 1])*ϕ_np1[end] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -1288,7 +1297,8 @@ end @muladd function perform_step!(integrator, cache::VCABM5Cache, repeat_step = false) @inbounds begin @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕ_n, ϕ_np1, ϕstar_n, ϕstar_nm1, order, atmp, utilde, rk4cache = cache + @unpack k4, dts, g, ϕ_n, ϕ_np1, ϕstar_n, ϕstar_nm1, + order, atmp, utilde, rk4cache, thread = cache k1 = integrator.fsalfirst if integrator.u_modified cache.step = 1 @@ -1327,16 +1337,16 @@ end integrator.fsallast .= rk4cache.k else g_coefs!(cache, 6) - @.. broadcast=false u=muladd(g[1], ϕstar_n[1], uprev) - @.. broadcast=false u=muladd(g[2], ϕstar_n[2], u) - @.. broadcast=false u=muladd(g[3], ϕstar_n[3], u) - @.. broadcast=false u=muladd(g[4], ϕstar_n[4], u) + @.. broadcast=false thread=thread u=muladd(g[1], ϕstar_n[1], uprev) + @.. broadcast=false thread=thread u=muladd(g[2], ϕstar_n[2], u) + @.. broadcast=false thread=thread u=muladd(g[3], ϕstar_n[3], u) + @.. broadcast=false thread=thread u=muladd(g[4], ϕstar_n[4], u) f(k4, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) ϕ_np1!(cache, k4, 6) - @.. broadcast=false u=muladd(g[6 - 1], ϕ_np1[6 - 1], u) + @.. broadcast=false thread=thread u=muladd(g[6 - 1], ϕ_np1[6 - 1], u) if integrator.opts.adaptive - @.. broadcast=false utilde=(g[6] - g[6 - 1]) * ϕ_np1[end] + @.. broadcast=false thread=thread utilde=(g[6]-g[6 - 1])*ϕ_np1[end] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) @@ -1464,7 +1474,8 @@ end @muladd function perform_step!(integrator, cache::VCABMCache, repeat_step = false) @inbounds begin @unpack t, dt, uprev, u, f, p = integrator - @unpack k4, dts, g, ϕ_n, ϕ_np1, ϕstar_n, ϕstar_nm1, order, max_order, utilde, utildem2, utildem1, utildep1, atmp, atmpm1, atmpm2, atmpp1 = cache + @unpack k4, dts, g, ϕ_n, ϕ_np1, ϕstar_n, ϕstar_nm1, order, max_order, utilde, + utildem2, utildem1, utildep1, atmp, atmpm1, atmpm2, atmpp1, thread = cache k1 = integrator.fsalfirst step = integrator.iter k = order @@ -1476,16 +1487,16 @@ end ϕ_and_ϕstar!(cache, k1, k) g_coefs!(cache, k + 1) # unroll the predictor once - @.. broadcast=false u=muladd(g[1], ϕstar_n[1], uprev) + @.. broadcast=false thread=thread u=muladd(g[1], ϕstar_n[1], uprev) for i in 2:(k - 1) - @.. broadcast=false u=muladd(g[i], ϕstar_n[i], u) + @.. broadcast=false thread=thread u=muladd(g[i], ϕstar_n[i], u) end f(k4, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) ϕ_np1!(cache, k4, k + 1) - @.. broadcast=false u=muladd(g[k], ϕ_np1[k], u) + @.. broadcast=false thread=thread u=muladd(g[k], ϕ_np1[k], u) if integrator.opts.adaptive - @.. broadcast=false utilde=(g[k + 1] - g[k]) * ϕ_np1[k + 1] + @.. broadcast=false thread=thread utilde=(g[k + 1]-g[k])*ϕ_np1[k + 1] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -1501,13 +1512,15 @@ end if step <= 4 || order < 3 cache.order = min(order + 1, 3) else - # @.. broadcast=false utildem2 = dt * γstar[(k-2)+1] * ϕ_np1[k-1] - @.. broadcast=false utildem2=(g[k - 1] - g[k - 2]) * ϕ_np1[k - 1] - # @.. broadcast=false utildem1 = dt * γstar[(k-1)+1] * ϕ_np1[k] - @.. broadcast=false utildem1=(g[k] - g[k - 1]) * ϕ_np1[k] + # @.. broadcast=false thread=thread utildem2 = dt * γstar[(k-2)+1] * ϕ_np1[k-1] + @.. broadcast=false thread=thread utildem2=(g[k - 1]-g[k - 2])* + ϕ_np1[k - 1] + # @.. broadcast=false thread=thread utildem1 = dt * γstar[(k-1)+1] * ϕ_np1[k] + @.. broadcast=false thread=thread utildem1=(g[k]-g[k - 1])*ϕ_np1[k] expand_ϕ_and_ϕstar!(cache, k + 1) ϕ_np1!(cache, k4, k + 2) - @.. broadcast=false utildep1=dt * γstar[(k + 1) + 1] * ϕ_np1[k + 2] + @.. broadcast=false thread=thread utildep1=dt*γstar[(k + 1) + 1]* + ϕ_np1[k + 2] calculate_residuals!(atmpm2, utildem2, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_utils.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_utils.jl index 274a7b3b5b..9daf45c21e 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_utils.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/adams_utils.jl @@ -19,8 +19,8 @@ function ϕ_and_ϕstar!(cache, du, k) β[i] = β[i - 1] * ξ / ξ0 ξ += dts[i] if cache isa OrdinaryDiffEqMutableCache - @.. broadcast=false ϕ_n[i]=ϕ_n[i - 1] - ϕstar_nm1[i - 1] - @.. broadcast=false ϕstar_n[i]=β[i] * ϕ_n[i] + @.. broadcast=false ϕ_n[i]=ϕ_n[i - 1]-ϕstar_nm1[i - 1] + @.. broadcast=false ϕstar_n[i]=β[i]*ϕ_n[i] else ϕ_n[i] = ϕ_n[i - 1] - ϕstar_nm1[i - 1] ϕstar_n[i] = β[i] * ϕ_n[i] @@ -47,8 +47,8 @@ function ϕ_and_ϕstar!(cache::Union{VCABMConstantCache, VCABMCache}, du, k) β[i] = β[i - 1] * ξ / ξ0 ξ += dts[i] if cache isa OrdinaryDiffEqMutableCache - @.. broadcast=false ϕ_n[i]=ϕ_n[i - 1] - ϕstar_nm1[i - 1] - @.. broadcast=false ϕstar_n[i]=β[i] * ϕ_n[i] + @.. broadcast=false ϕ_n[i]=ϕ_n[i - 1]-ϕstar_nm1[i - 1] + @.. broadcast=false ϕstar_n[i]=β[i]*ϕ_n[i] else ϕ_n[i] = ϕ_n[i - 1] - ϕstar_nm1[i - 1] ϕstar_n[i] = β[i] * ϕ_n[i] @@ -64,8 +64,8 @@ function expand_ϕ_and_ϕstar!(cache, i) ξ0 += dts[i] β[i] = β[i - 1] * ξ / ξ0 if cache isa OrdinaryDiffEqMutableCache - @.. broadcast=false ϕ_n[i]=ϕ_n[i - 1] - ϕstar_nm1[i - 1] - @.. broadcast=false ϕstar_n[i]=β[i] * ϕ_n[i] + @.. broadcast=false ϕ_n[i]=ϕ_n[i - 1]-ϕstar_nm1[i - 1] + @.. broadcast=false ϕstar_n[i]=β[i]*ϕ_n[i] else ϕ_n[i] = ϕ_n[i - 1] - ϕstar_nm1[i - 1] ϕstar_n[i] = β[i] * ϕ_n[i] @@ -78,7 +78,7 @@ function ϕ_np1!(cache, du_np1, k) for i in 1:k if i != 1 if cache isa OrdinaryDiffEqMutableCache - @.. broadcast=false ϕ_np1[i]=ϕ_np1[i - 1] - ϕstar_n[i - 1] + @.. broadcast=false ϕ_np1[i]=ϕ_np1[i - 1]-ϕstar_n[i - 1] else ϕ_np1[i] = ϕ_np1[i - 1] - ϕstar_n[i - 1] end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/algorithms.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/algorithms.jl index af35c61140..8adf8dbd43 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/algorithms.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/src/algorithms.jl @@ -3,31 +3,46 @@ reference = """E. Hairer, S. P. Norsett, G. Wanner, Solving Ordinary Differentia Problems. Computational Mathematics (2nd revised ed.), Springer (1996) doi: https://doi.org/10.1007/978-3-540-78862-1""" +keyword_default_description = """ +- `thread`: determines whether internal broadcasting on appropriate CPU arrays should be serial (`thread = OrdinaryDiffEq.False()`) or use multiple threads (`thread = OrdinaryDiffEq.True()`) when Julia is started with multiple threads. +""" + +keyword_default = """ +thread = OrdinaryDiffEq.False(), +""" + @doc generic_solver_docstring("The 3-step third order multistep method. Ralston's Second Order Method is used to calculate starting values.", "AB3", "Adams-Bashforth Explicit Method", reference, - "", - "") -struct AB3 <: OrdinaryDiffEqAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct AB3{Thread} <: OrdinaryDiffEqAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("The 4-step fourth order multistep method. Runge-Kutta method of order 4 is used to calculate starting values.", "AB4", "Adams-Bashforth Explicit Method", reference, - "", - "") -struct AB4 <: OrdinaryDiffEqAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct AB4{Thread} <: OrdinaryDiffEqAlgorithm + thread::Thread = False() +end + @doc generic_solver_docstring("The 5-step fifth order multistep method. Ralston's 3rd order Runge-Kutta method is used to calculate starting values.", "AB5", "Adams-Bashforth Explicit Method", reference, - "", - "") -struct AB5 <: OrdinaryDiffEqAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct AB5{Thread} <: OrdinaryDiffEqAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("It is third order method. In ABM32, AB3 works as predictor and Adams Moulton 2-steps method works as Corrector. @@ -35,9 +50,11 @@ struct AB5 <: OrdinaryDiffEqAlgorithm end "ABM32", "Adams-Bashforth Explicit Method", reference, - "", - "") -struct ABM32 <: OrdinaryDiffEqAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct ABM32{Thread} <: OrdinaryDiffEqAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("It is fourth order method. In ABM43, AB4 works as predictor and Adams Moulton 3-steps method works as Corrector. @@ -45,9 +62,11 @@ struct ABM32 <: OrdinaryDiffEqAlgorithm end "ABM43", "Adams-Bashforth Explicit Method", reference, - "", - "") -struct ABM43 <: OrdinaryDiffEqAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct ABM43{Thread} <: OrdinaryDiffEqAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("It is fifth order method. In ABM54, AB5 works as predictor and Adams Moulton 4-steps method works as Corrector. @@ -55,9 +74,11 @@ struct ABM43 <: OrdinaryDiffEqAlgorithm end "ABM54", "Adams-Bashforth Explicit Method", reference, - "", - "") -struct ABM54 <: OrdinaryDiffEqAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct ABM54{Thread} <: OrdinaryDiffEqAlgorithm + thread::Thread = False() +end # Variable Step Size Adams methods @@ -66,54 +87,66 @@ struct ABM54 <: OrdinaryDiffEqAlgorithm end "VCAB3", "Adams explicit Method", reference, - "", - "") -struct VCAB3 <: OrdinaryDiffEqAdaptiveAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCAB3{Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("The 4th order Adams method. Runge-Kutta 4 is used to calculate starting values.", "VCAB4", "Adams explicit Method", reference, - "", - "") -struct VCAB4 <: OrdinaryDiffEqAdaptiveAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCAB4{Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("The 5th order Adams method. Runge-Kutta 4 is used to calculate starting values.", "VCAB5", "Adams explicit Method", reference, - "", - "") -struct VCAB5 <: OrdinaryDiffEqAdaptiveAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCAB5{Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("The 3rd order Adams-Moulton method. Bogacki-Shampine 3/2 method is used to calculate starting values.", "VCABM3", "Adams explicit Method", reference, - "", - "") -struct VCABM3 <: OrdinaryDiffEqAdaptiveAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCABM3{Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("The 4th order Adams-Moulton method. Runge-Kutta 4 is used to calculate starting values.", "VCABM4", "Adams explicit Method", reference, - "", - "") -struct VCABM4 <: OrdinaryDiffEqAdaptiveAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCABM4{Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + thread::Thread = False() +end @doc generic_solver_docstring("The 5th order Adams-Moulton method. Runge-Kutta 4 is used to calculate starting values.", "VCABM5", "Adams explicit Method", reference, - "", - "") -struct VCABM5 <: OrdinaryDiffEqAdaptiveAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCABM5{Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + thread::Thread = False() +end # Variable Order and Variable Step Size Adams methods @@ -122,6 +155,8 @@ struct VCABM5 <: OrdinaryDiffEqAdaptiveAlgorithm end "VCABM", "adaptive order Adams explicit Method", reference, - "", - "") -struct VCABM <: OrdinaryDiffEqAdamsVarOrderVarStepAlgorithm end + keyword_default_description, + keyword_default) +Base.@kwdef struct VCABM{Thread} <: OrdinaryDiffEqAdamsVarOrderVarStepAlgorithm + thread::Thread = False() +end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/abm_convergence_tests.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/abm_convergence_tests.jl index ccebddd73e..4abfe350c8 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/abm_convergence_tests.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/abm_convergence_tests.jl @@ -8,7 +8,9 @@ dts1 = 1 .// 2 .^ (9:-1:5) dts = 1 .// 2 .^ (8:-1:4) testTol = 0.2 -@testset "Explicit Solver Convergence Tests ($(["out-of-place", "in-place"][i]))" for i in 1:2 +@testset "Explicit Solver Convergence Tests ($(["out-of-place", "in-place"][i]))" for i in + 1:2 + prob = (ODEProblemLibrary.prob_ode_linear, ODEProblemLibrary.prob_ode_2Dlinear)[i] @@ -37,3 +39,23 @@ testTol = 0.2 sim106 = test_convergence(dts, prob, VCABM5()) @test sim106.𝒪est[:l2]≈5 atol=testTol end + +@testset "Explicit Solver Convergence Tests ($(["out-of-place", "in-place"][i])) - threaded " for i in + 1:2 + + prob = (ODEProblemLibrary.prob_ode_linear, + ODEProblemLibrary.prob_ode_2Dlinear)[i] + + sim5 = test_convergence(dts, prob, AB3(true)) + @test sim5.𝒪est[:l2]≈3 atol=testTol + sim7 = test_convergence(dts, prob, AB4(true)) + @test sim7.𝒪est[:l2]≈4 atol=testTol + sim9 = test_convergence(dts, prob, AB5(true)) + @test sim9.𝒪est[:l2]≈5 atol=testTol + sim101 = test_convergence(dts, prob, VCAB3(true)) + @test sim101.𝒪est[:l2]≈3 atol=testTol + sim103 = test_convergence(dts, prob, VCAB5(true)) + @test sim103.𝒪est[:l2]≈5 atol=testTol + sim105 = test_convergence(dts, prob, VCABM4(true)) + @test sim105.𝒪est[:l2]≈4 atol=testTol +end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/jet.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/jet.jl new file mode 100644 index 0000000000..d5687e7cea --- /dev/null +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqAdamsBashforthMoulton +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqAdamsBashforthMoulton, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/qa.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/qa.jl new file mode 100644 index 0000000000..5a1ce46d44 --- /dev/null +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqAdamsBashforthMoulton +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqAdamsBashforthMoulton + ) +end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/regression_test_threading.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/regression_test_threading.jl new file mode 100644 index 0000000000..b70a6b11cb --- /dev/null +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/regression_test_threading.jl @@ -0,0 +1,22 @@ +using OrdinaryDiffEqAdamsBashforthMoulton, ODEProblemLibrary +import OrdinaryDiffEqCore: OrdinaryDiffEqAdaptiveAlgorithm +using Test +using Static + +algorithms = [ + AB3, AB4, AB5, ABM32, ABM43, ABM54, VCAB3, VCAB4, VCAB5, VCABM3, VCABM4, VCABM5, VCABM] + +problem = ODEProblemLibrary.prob_ode_linear + +@testset "Regression test for threading versions vs non threading versions" begin + @testset "$ALG" for ALG in algorithms + if ALG isa OrdinaryDiffEqAdaptiveAlgorithm + sol_thread = solve(problem, ALG(Static.True())) + sol_nothread = solve(problem, ALG(Static.False())) + else + sol_thread = solve(problem, ALG(Static.True()), dt = 1 // 2^9) + sol_nothread = solve(problem, ALG(Static.False()), dt = 1 // 2^9) + end + @test all(sol_nothread .== sol_thread) + end +end diff --git a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/runtests.jl b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/runtests.jl index a0518e6f70..45c90bac04 100644 --- a/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/runtests.jl +++ b/lib/OrdinaryDiffEqAdamsBashforthMoulton/test/runtests.jl @@ -2,3 +2,6 @@ using SafeTestsets @time @safetestset "ABM Convergence Tests" include("abm_convergence_tests.jl") @time @safetestset "Adams Variable Coefficients Tests" include("adams_tests.jl") +@time @safetestset "Regression test for threading versions vs non threading versions" include("regression_test_threading.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqBDF/Project.toml b/lib/OrdinaryDiffEqBDF/Project.toml index b5f182aff6..b7f57e4e9e 100644 --- a/lib/OrdinaryDiffEqBDF/Project.toml +++ b/lib/OrdinaryDiffEqBDF/Project.toml @@ -1,59 +1,86 @@ name = "OrdinaryDiffEqBDF" uuid = "6ad6398a-0878-4a85-9266-38940aa047c8" authors = ["ParamThakkar123 "] -version = "1.1.2" +version = "1.10.0" [deps] -ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" -OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" -PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" Preferences = "21216c6a-2e73-6563-6e65-726566657250" +MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" - -[compat] -ArrayInterface = "7.15.0" -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -ForwardDiff = "0.10.36" -LinearAlgebra = "<0.0.1, 1" -MacroTools = "0.5.13" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqNonlinearSolve = "<0.0.1, 1" -OrdinaryDiffEqSDIRK = "<0.0.1, 1" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -TruncatedStacktraces = "1.4.0" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +NonlinearSolve = "4.10" +ForwardDiff = "0.10.38, 1" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearSolve = "3.26" +PrecompileTools = "1.2" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +OrdinaryDiffEqSDIRK = "1.6.0" +TruncatedStacktraces = "1.4" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +ArrayInterface = "7.19" +Enzyme = "0.13" +Preferences = "1.4" +MacroTools = "0.5" +JET = "0.9.18, 0.10.4" +StaticArrays = "1.9" +julia = "1.10" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "ForwardDiff", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "StaticArrays"] +test = ["DiffEqDevTools", "ForwardDiff", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "NonlinearSolve", "Enzyme", "LinearSolve", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqSDIRK] +path = "../OrdinaryDiffEqSDIRK" + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqNonlinearSolve] +path = "../OrdinaryDiffEqNonlinearSolve" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqBDF/src/OrdinaryDiffEqBDF.jl b/lib/OrdinaryDiffEqBDF/src/OrdinaryDiffEqBDF.jl index 5a2981219b..fb7ab3d305 100644 --- a/lib/OrdinaryDiffEqBDF/src/OrdinaryDiffEqBDF.jl +++ b/lib/OrdinaryDiffEqBDF/src/OrdinaryDiffEqBDF.jl @@ -20,21 +20,29 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, step_accept_controller!, step_reject_controller!, post_newton_controller!, u_modified!, DAEAlgorithm, _unwrap_val, DummyController, - get_fsalfirstlast, generic_solver_docstring + get_fsalfirstlast, generic_solver_docstring, _bool_to_ADType, + _process_AD_choice using OrdinaryDiffEqSDIRK: ImplicitEulerConstantCache, ImplicitEulerCache -using TruncatedStacktraces, MuladdMacro, MacroTools, FastBroadcast, RecursiveArrayTools +using TruncatedStacktraces: @truncate_stacktrace +using MuladdMacro: @muladd +using MacroTools: @capture +using FastBroadcast: @.. +using RecursiveArrayTools: recursivefill! import StaticArrays: SArray, MVector, SVector, @SVector, StaticArray, MMatrix, SA using LinearAlgebra: mul!, I -using ArrayInterface +import ArrayInterface +using ArrayInterface: ismutable import OrdinaryDiffEqCore using OrdinaryDiffEqDifferentiation: UJacobianWrapper using OrdinaryDiffEqNonlinearSolve: NLNewton, du_alias_or_new, build_nlsolver, nlsolve!, nlsolvefail, isnewton, markfirststage!, - set_new_W!, DIRK, compute_step!, COEFFICIENT_MULTISTEP + set_new_W!, DIRK, compute_step!, COEFFICIENT_MULTISTEP, + NonlinearSolveAlg +import ADTypes: AutoForwardDiff, AutoFiniteDiff, AbstractADType using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") @@ -85,6 +93,7 @@ PrecompileTools.@compile_workload begin end for prob in prob_list, solver in solver_list + solve(prob, solver)(5.0) end diff --git a/lib/OrdinaryDiffEqBDF/src/algorithms.jl b/lib/OrdinaryDiffEqBDF/src/algorithms.jl index 494bbcfa8a..147cace806 100644 --- a/lib/OrdinaryDiffEqBDF/src/algorithms.jl +++ b/lib/OrdinaryDiffEqBDF/src/algorithms.jl @@ -5,21 +5,22 @@ function BDF_docstring(description::String, extra_keyword_default::String = "") keyword_default = """ chunk_size = Val{0}(), - autodiff = true, + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS, """ * "\n" * extra_keyword_default keyword_default_description = """ - - `chunk_size`: The chunk size used with ForwardDiff.jl. Defaults to `Val{0}()` - and thus uses the internal ForwardDiff.jl algorithm for the choice. - - `autodiff`: Specifies whether to use automatic differentiation via + - `autodiff`: Uses [ADTypes.jl](https://sciml.github.io/ADTypes.jl/stable/) + to specify whether to use automatic differentiation via [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) or finite - differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). - Defaults to `Val{true}()` for automatic differentiation. + differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). + Defaults to `AutoForwardDiff()` for automatic differentiation, which by default uses + `chunksize = 0`, and thus uses the internal ForwardDiff.jl algorithm for the choice. + To use `FiniteDiff.jl`, the `AutoFiniteDiff()` ADType can be used, which has a keyword argument + `fdtype` with default value `Val{:forward}()`, and alternatives `Val{:central}()` and `Val{:complex}()`. - `standardtag`: Specifies whether to use package-specific tags instead of the ForwardDiff default function-specific tags. For more information, see [this blog post](https://www.stochasticlifestyle.com/improved-forwarddiff-jl-stacktraces-with-package-tags/). @@ -27,9 +28,6 @@ function BDF_docstring(description::String, - `concrete_jac`: Specifies whether a Jacobian should be constructed. Defaults to `nothing`, which means it will be chosen true/false depending on circumstances of the solver, such as whether a Krylov subspace method is used for `linsolve`. - - `diff_type`: The type of differentiation used in FiniteDiff.jl if `autodiff=false`. - Defaults to `Val{:forward}`, with alternatives of `Val{:central}` and - `Val{:complex}`. - `linsolve`: Any [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl) compatible linear solver. For example, to use [KLU.jl](https://github.com/JuliaSparse/KLU.jl), specify `$name(linsolve = KLUFactorization()`). @@ -112,18 +110,22 @@ struct ABDF2{CS, AD, F, F2, P, FDT, ST, CJ, K, T, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function ABDF2(; chunk_size = Val{0}(), autodiff = true, standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function ABDF2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), κ = nothing, tol = nothing, linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :Standard, step_limiter! = trivial_limiter!) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + ABDF2{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol), typeof(step_limiter!)}(linsolve, nlsolve, precs, κ, tol, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end @doc BDF_docstring( @@ -167,14 +169,17 @@ struct SBDF{CS, AD, F, F2, P, FDT, ST, CJ, K, T} <: extrapolant::Symbol order::Int ark::Bool + autodiff::AD end -function SBDF(order; chunk_size = Val{0}(), autodiff = Val{true}(), - standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, +function SBDF(order; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), + standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, ark = false) - SBDF{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SBDF{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol)}(linsolve, nlsolve, @@ -183,17 +188,21 @@ function SBDF(order; chunk_size = Val{0}(), autodiff = Val{true}(), tol, extrapolant, order, - ark) + ark, + AD_choice) end # All keyword form needed for remake -function SBDF(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function SBDF(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, order, ark = false) - SBDF{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SBDF{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol)}(linsolve, nlsolve, @@ -202,7 +211,8 @@ function SBDF(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val tol, extrapolant, order, - ark) + ark, + AD_choice) end """ @@ -251,8 +261,7 @@ See also `SBDF`. SBDF4(; kwargs...) = SBDF(4; kwargs...) @doc BDF_docstring( - "An adaptive order 1 quasi-constant timestep L-stable numerical differentiation function (NDF) method. -Optional parameter kappa defaults to Shampine's accuracy-optimal -0.1850.", + "An adaptive order 1 quasi-constant timestep L-stable numerical differentiation function method.", "QNDF1", references = """@article{shampine1997matlab, title={The matlab ode suite}, @@ -287,15 +296,19 @@ struct QNDF1{CS, AD, F, F2, P, FDT, ST, CJ, κType, StepLimiter} <: kappa::κType controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function QNDF1(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function QNDF1(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, kappa = -37 // 200, controller = :Standard, step_limiter! = trivial_limiter!) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + QNDF1{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(kappa), typeof(step_limiter!)}(linsolve, nlsolve, @@ -303,7 +316,8 @@ function QNDF1(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Va extrapolant, kappa, controller, - step_limiter!) + step_limiter!, + AD_choice) end @doc BDF_docstring( @@ -342,15 +356,19 @@ struct QNDF2{CS, AD, F, F2, P, FDT, ST, CJ, κType, StepLimiter} <: kappa::κType controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function QNDF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function QNDF2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, kappa = -1 // 9, controller = :Standard, step_limiter! = trivial_limiter!) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + QNDF2{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(kappa), typeof(step_limiter!)}(linsolve, nlsolve, @@ -358,12 +376,12 @@ function QNDF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Va extrapolant, kappa, controller, - step_limiter!) + step_limiter!, + AD_choice) end @doc BDF_docstring( - "An adaptive order quasi-constant timestep NDF method. -Utilizes Shampine's accuracy-optimal kappa values as defaults (has a keyword argument for a tuple of kappa coefficients).", + "An adaptive order quasi-constant timestep NDF method. Similar to MATLAB's ode15s. Uses Shampine's accuracy-optimal coefficients. Performance improves with larger, more complex ODEs. Good for medium to highly stiff problems. Recommended for large systems (>1000 ODEs).", "QNDF", references = """@article{shampine1997matlab, title={The matlab ode suite}, @@ -405,25 +423,28 @@ struct QNDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T, κType, StepLimiter} <: kappa::κType controller::Symbol step_limiter!::StepLimiter + autodiff::AD end function QNDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), - autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, kappa = ( -37 // 200, -1 // 9, -823 // 10000, -83 // 2000, 0 // 1), controller = :Standard, step_limiter! = trivial_limiter!) where {MO} - QNDF{MO, _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + QNDF{MO, _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol), typeof(kappa), typeof(step_limiter!)}( max_order, linsolve, nlsolve, precs, κ, tol, - extrapolant, kappa, controller, step_limiter!) + extrapolant, kappa, controller, step_limiter!, AD_choice) end -TruncatedStacktraces.@truncate_stacktrace QNDF +@truncate_stacktrace QNDF @doc BDF_docstring("The second order Modified Extended BDF method, which has improved stability properties over the standard BDF. @@ -452,17 +473,22 @@ struct MEBDF2{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function MEBDF2(; chunk_size = Val{0}(), autodiff = true, standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function MEBDF2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :constant) - MEBDF2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + MEBDF2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc BDF_docstring( @@ -504,23 +530,26 @@ struct FBDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end function FBDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), - autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, controller = :Standard, step_limiter! = trivial_limiter!) where {MO} - FBDF{MO, _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + FBDF{MO, _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol), typeof(step_limiter!)}( max_order, linsolve, nlsolve, precs, κ, tol, extrapolant, - controller, step_limiter!) + controller, step_limiter!, AD_choice) end -TruncatedStacktraces.@truncate_stacktrace FBDF +@truncate_stacktrace FBDF """ QBDF1: Multistep Method @@ -601,7 +630,7 @@ See also `SBDF`, `IMEXEuler`. IMEXEulerARK(; kwargs...) = SBDF(1; ark = true, kwargs...) @doc BDF_docstring( - "Implicit Euler for implicit DAE form. + "1st order A-L and stiffly stable adaptive implicit Euler. Implicit Euler for implicit DAE form. It uses an apriori error estimator for adaptivity based on a finite differencing approximation from SPICE.", "DImplicitEuler", extra_keyword_description = """ @@ -620,20 +649,24 @@ struct DImplicitEuler{CS, AD, F, F2, P, FDT, ST, CJ} <: DAEAlgorithm{CS, AD, FDT precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end function DImplicitEuler(; - chunk_size = Val{0}(), autodiff = true, standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :constant, controller = :Standard) - DImplicitEuler{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + DImplicitEuler{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, - nlsolve, precs, extrapolant, controller) + nlsolve, precs, extrapolant, controller, AD_choice) end -@doc BDF_docstring("Fully implicit implementation of BDF2.", +@doc BDF_docstring( + "2nd order A-L stable adaptive BDF method. Fully implicit implementation of BDF2.", "DABDF2", references = """@article{celaya2014implementation, title={Implementation of an Adaptive BDF2 Formula and Comparison with the MATLAB Ode15s}, @@ -659,16 +692,20 @@ struct DABDF2{CS, AD, F, F2, P, FDT, ST, CJ} <: DAEAlgorithm{CS, AD, FDT, ST, CJ precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end -function DABDF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function DABDF2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :constant, controller = :Standard) - DABDF2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + DABDF2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, - nlsolve, precs, extrapolant, controller) + nlsolve, precs, extrapolant, controller, AD_choice) end #= @@ -685,7 +722,8 @@ DBDF(;chunk_size=Val{0}(),autodiff=Val{true}(), standardtag = Val{true}(), concr linsolve,nlsolve,precs,extrapolant) =# -@doc BDF_docstring("Fully implicit implementation of FBDF based on Shampine's", +@doc BDF_docstring( + "Fixed-leading coefficient adaptive-order adaptive-time BDF method. Fully implicit implementation of FBDF based on Shampine's", "DFBDF", references = """@article{shampine2002solving, title={Solving 0= F (t, y (t), y′(t)) in Matlab}, @@ -718,18 +756,21 @@ struct DFBDF{MO, CS, AD, F, F2, P, FDT, ST, CJ, K, T} <: DAEAlgorithm{CS, AD, FD tol::T extrapolant::Symbol controller::Symbol + autodiff::AD end function DFBDF(; max_order::Val{MO} = Val{5}(), chunk_size = Val{0}(), - autodiff = Val{true}(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, controller = :Standard) where {MO} - DFBDF{MO, _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + DFBDF{MO, _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol)}(max_order, linsolve, nlsolve, precs, κ, tol, extrapolant, - controller) + controller, AD_choice) end -TruncatedStacktraces.@truncate_stacktrace DFBDF +@truncate_stacktrace DFBDF diff --git a/lib/OrdinaryDiffEqBDF/src/bdf_caches.jl b/lib/OrdinaryDiffEqBDF/src/bdf_caches.jl index 00c6875cef..9917964992 100644 --- a/lib/OrdinaryDiffEqBDF/src/bdf_caches.jl +++ b/lib/OrdinaryDiffEqBDF/src/bdf_caches.jl @@ -15,7 +15,7 @@ function alg_cache(alg::ABDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = 2 // 3, 1 + γ, c = Int64(2) // 3, 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) eulercache = ImplicitEulerConstantCache(nlsolver) @@ -45,7 +45,7 @@ function alg_cache(alg::ABDF2, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = 2 // 3, 1 + γ, c = Int64(2) // 3, 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) fsalfirst = zero(rate_prototype) @@ -104,7 +104,7 @@ function alg_cache(alg::SBDF, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = 1 // 1, 1 + γ, c = Int64(1) // 1, 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) @@ -127,7 +127,7 @@ function alg_cache(alg::SBDF, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = 1 // 1, 1 + γ, c = Int64(1) // 1, 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) fsalfirst = zero(rate_prototype) @@ -360,7 +360,7 @@ function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits } where {MO} max_order = MO - γ, c = one(uEltypeNoUnits), 1 + γ, c = Int64(1)//1, 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) dtprev = one(dt) @@ -380,7 +380,7 @@ function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, end U = SArray(U) - γₖ = SVector(ntuple(k -> sum(tTypeNoUnits(1 // j) for j in 1:k), Val(max_order))) + γₖ = SVector(ntuple(k -> sum(tTypeNoUnits(Int64(1) // j) for j in 1:k), Val(max_order))) QNDFConstantCache(nlsolver, U, D, prevD, 1, 1, Val(max_order), dtprev, 0, 0, EEst1, EEst2, γₖ) @@ -418,7 +418,7 @@ end step_limiter!::StepLimiter end -TruncatedStacktraces.@truncate_stacktrace QNDFCache 1 +@truncate_stacktrace QNDFCache 1 function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, @@ -426,7 +426,7 @@ function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits } where {MO} max_order = MO - γ, c = one(eltype(alg.kappa)), 1 + γ, c = Int64(1)//1, 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) fsalfirst = zero(rate_prototype) @@ -459,7 +459,7 @@ function alg_cache(alg::QNDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, U = SArray(U) RU = Matrix(U) - γₖ = SVector(ntuple(k -> sum(tTypeNoUnits(1 // j) for j in 1:k), Val(max_order))) + γₖ = SVector(ntuple(k -> sum(tTypeNoUnits(Int64(1) // j) for j in 1:k), Val(max_order))) QNDFCache(fsalfirst, dd, utilde, utildem1, utildep1, ϕ, u₀, nlsolver, U, RU, D, Dtmp, tmp2, prevD, 1, 1, Val(max_order), dtprev, 0, 0, EEst1, EEst2, γₖ, atmp, @@ -541,15 +541,15 @@ function alg_cache(alg::FBDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits } where {MO} - γ, c = one(uEltypeNoUnits), 1 + γ, c = Int64(1)//1, 1 max_order = MO nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) bdf_coeffs = SA[1 -1 0 0 0 0; - 3//2 -2 1//2 0 0 0; - 11//6 -3 3//2 -1//3 0 0; - 25//12 -4 3 -4//3 1//4 0; - 137//60 -5 5 -10//3 5//4 -1//5] + Int64(3)//2 -2 Int64(1)//2 0 0 0; + Int64(11)//6 -3 Int64(3)//2 -Int64(1)//3 0 0; + Int64(25)//12 -4 3 -Int64(4)//3 Int64(1)//4 0; + Int64(137)//60 -5 5 -Int64(10)//3 Int64(5)//4 -Int64(1)//5] ts = zero(Vector{typeof(t)}(undef, max_order + 2)) #ts is the successful past points, it will be updated after successful step ts_tmp = similar(ts) @@ -609,23 +609,23 @@ end step_limiter!::StepLimiter end -TruncatedStacktraces.@truncate_stacktrace FBDFCache 1 +@truncate_stacktrace FBDFCache 1 function alg_cache(alg::FBDF{MO}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {MO, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = one(uEltypeNoUnits), 1 + γ, c = Int64(1)//1, 1 fsalfirst = zero(rate_prototype) max_order = MO nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(true)) bdf_coeffs = SA[1 -1 0 0 0 0; - 3//2 -2 1//2 0 0 0; - 11//6 -3 3//2 -1//3 0 0; - 25//12 -4 3 -4//3 1//4 0; - 137//60 -5 5 -10//3 5//4 -1//5] + Int64(3)//2 -2 Int64(1)//2 0 0 0; + Int64(11)//6 -3 Int64(3)//2 -Int64(1)//3 0 0; + Int64(25)//12 -4 3 -Int64(4)//3 Int64(1)//4 0; + Int64(137)//60 -5 5 -Int64(10)//3 Int64(5)//4 -Int64(1)//5] ts = Vector{typeof(t)}(undef, max_order + 2) #ts is the successful past points, it will be updated after successful step u_history = Matrix{eltype(u)}(undef, length(u), max_order + 2) order = 1 diff --git a/lib/OrdinaryDiffEqBDF/src/bdf_perform_step.jl b/lib/OrdinaryDiffEqBDF/src/bdf_perform_step.jl index bca93c4d01..b421a987dd 100644 --- a/lib/OrdinaryDiffEqBDF/src/bdf_perform_step.jl +++ b/lib/OrdinaryDiffEqBDF/src/bdf_perform_step.jl @@ -27,7 +27,7 @@ end fₙ₋₁ = integrator.fsalfirst ρ = dtₙ / dtₙ₋₁ - β₀ = 2 // 3 + β₀ = Int64(2) // 3 β₁ = -(ρ - 1) / 3 α₀ = 1 α̂ = ρ^2 / 3 @@ -113,7 +113,7 @@ end fₙ₋₁ = integrator.fsalfirst ρ = dtₙ / dtₙ₋₁ - β₀ = 2 // 3 + β₀ = Int64(2) // 3 β₁ = -(ρ - 1) / 3 α₀ = 1 α̂ = ρ^2 / 3 @@ -124,7 +124,7 @@ end # initial guess if alg.extrapolant == :linear - @.. broadcast=false z=uₙ₋₁ + dtₙ * fₙ₋₁ + @.. broadcast=false z=uₙ₋₁+dtₙ*fₙ₋₁ else # :constant @.. broadcast=false z=uₙ₋₁ end @@ -132,12 +132,12 @@ end mass_matrix = f.mass_matrix if mass_matrix === I - @.. broadcast=false tmp=((dtₙ * β₁) * fₙ₋₁ + (α₁ * uₙ₋₁ + α₂ * uₙ₋₂)) / (dtₙ * β₀) + @.. broadcast=false tmp=((dtₙ*β₁)*fₙ₋₁+(α₁*uₙ₋₁+α₂*uₙ₋₂))/(dtₙ*β₀) else dz = nlsolver.cache.dz - @.. broadcast=false dz=α₁ * uₙ₋₁ + α₂ * uₙ₋₂ + @.. broadcast=false dz=α₁*uₙ₋₁+α₂*uₙ₋₂ mul!(ztmp, mass_matrix, dz) - @.. broadcast=false tmp=((dtₙ * β₁) * fₙ₋₁ + ztmp) / (dtₙ * β₀) + @.. broadcast=false tmp=((dtₙ*β₁)*fₙ₋₁+ztmp)/(dtₙ*β₀) end nlsolver.γ = β₀ nlsolver.α = α₀ @@ -152,12 +152,12 @@ end f(integrator.fsallast, uₙ, p, t + dtₙ) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) if integrator.opts.adaptive - btilde0 = (dtₙ₋₁ + dtₙ) * 1 // 6 + btilde0 = (dtₙ₋₁ + dtₙ) * Int64(1) // 6 btilde1 = 1 + dtₙ / dtₙ₋₁ btilde2 = dtₙ / dtₙ₋₁ - @.. broadcast=false tmp=btilde0 * - (integrator.fsallast - btilde1 * integrator.fsalfirst + - btilde2 * cache.fsalfirstprev) + @.. broadcast=false tmp=btilde0* + (integrator.fsallast-btilde1*integrator.fsalfirst+ + btilde2*cache.fsalfirstprev) calculate_residuals!(atmp, tmp, uₙ₋₁, uₙ, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -207,12 +207,12 @@ function perform_step!(integrator, cache::SBDFConstantCache, repeat_step = false if cnt == 1 tmp = uprev + dt * du₂ elseif cnt == 2 - tmp = γ * (2 * uprev - 1 // 2 * uprev2 + dt * (2 * du₂ - k₁)) + tmp = γ * (2 * uprev - Int64(1) // 2 * uprev2 + dt * (2 * du₂ - k₁)) elseif cnt == 3 tmp = γ * - (3 * uprev - 3 // 2 * uprev2 + 1 // 3 * uprev3 + dt * (3 * (du₂ - k₁) + k₂)) + (3 * uprev - Int64(3) // 2 * uprev2 + Int64(1) // 3 * uprev3 + dt * (3 * (du₂ - k₁) + k₂)) else - tmp = γ * (4 * uprev - 3 * uprev2 + 4 // 3 * uprev3 - 1 // 4 * uprev4 + + tmp = γ * (4 * uprev - 3 * uprev2 + Int64(4) // 3 * uprev3 - Int64(1) // 4 * uprev4 + dt * (4 * du₂ - 6 * k₁ + 4 * k₂ - k₃)) end nlsolver.tmp = tmp @@ -235,11 +235,11 @@ function perform_step!(integrator, cache::SBDFConstantCache, repeat_step = false u = nlsolver.tmp + γ * z cnt == 4 && (cache.uprev4 = uprev3; - cache.k₃ = k₂) + cache.k₃ = k₂) cnt >= 3 && (cache.uprev3 = uprev2; - cache.k₂ = k₁) + cache.k₂ = k₁) (cache.uprev2 = uprev; - cache.k₁ = du₂) + cache.k₁ = du₂) cache.du₁ = f1(u, p, t + dt) cache.du₂ = f2(u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -262,7 +262,7 @@ function initialize!(integrator, cache::SBDFCache) f2(cache.du₂, uprev, p, t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 - @.. broadcast=false integrator.fsalfirst=cache.du₁ + cache.du₂ + @.. broadcast=false integrator.fsalfirst=cache.du₁+cache.du₂ end function perform_step!(integrator, cache::SBDFCache, repeat_step = false) @@ -281,15 +281,15 @@ function perform_step!(integrator, cache::SBDFCache, repeat_step = false) integrator.stats.nf2 += 1 end if cnt == 1 - @.. broadcast=false tmp=uprev + dt * du₂ + @.. broadcast=false tmp=uprev+dt*du₂ elseif cnt == 2 - @.. broadcast=false tmp=γ * (2 * uprev - 1 // 2 * uprev2 + dt * (2 * du₂ - k₁)) + @.. broadcast=false tmp=γ*(2*uprev-1//2*uprev2+dt*(2*du₂-k₁)) elseif cnt == 3 - @.. broadcast=false tmp=γ * (3 * uprev - 3 // 2 * uprev2 + 1 // 3 * uprev3 + - dt * (3 * (du₂ - k₁) + k₂)) + @.. broadcast=false tmp=γ*(3*uprev-3//2*uprev2+1//3*uprev3+ + dt*(3*(du₂-k₁)+k₂)) else - @.. broadcast=false tmp=γ * (4 * uprev - 3 * uprev2 + 4 // 3 * uprev3 - - 1 // 4 * uprev4 + dt * (4 * du₂ - 6 * k₁ + 4 * k₂ - k₃)) + @.. broadcast=false tmp=γ*(4*uprev-3*uprev2+4//3*uprev3- + 1//4*uprev4+dt*(4*du₂-6*k₁+4*k₂-k₃)) end # Implicit part # precalculations @@ -298,26 +298,26 @@ function perform_step!(integrator, cache::SBDFCache, repeat_step = false) # initial guess if alg.extrapolant == :linear - @.. broadcast=false z=dt * du₁ + @.. broadcast=false z=dt*du₁ else # :constant @.. broadcast=false z=zero(eltype(u)) end z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false u=tmp + γ * z + @.. broadcast=false u=tmp+γ*z cnt == 4 && (cache.uprev4 .= uprev3; - cache.k₃ .= k₂) + cache.k₃ .= k₂) cnt >= 3 && (cache.uprev3 .= uprev2; - cache.k₂ .= k₁) + cache.k₂ .= k₁) (cache.uprev2 .= uprev; - cache.k₁ .= du₂) + cache.k₁ .= du₂) f1(du₁, u, p, t + dt) f2(du₂, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 - @.. broadcast=false integrator.fsallast=du₁ + du₂ + @.. broadcast=false integrator.fsallast=du₁+du₂ end # QNDF1 @@ -428,11 +428,11 @@ function perform_step!(integrator, cache::QNDF1Cache, repeat_step = false) k = 1 if cnt > 1 ρ = dt / dtₙ₋₁ - @.. broadcast=false D[1]=uprev - uprev2 # backward diff + @.. broadcast=false D[1]=uprev-uprev2 # backward diff if ρ != 1 R!(k, ρ, cache) R .= R * U - @.. broadcast=false D[1]=D[1] * R[1, 1] + @.. broadcast=false D[1]=D[1]*R[1, 1] end else κ = zero(alg.kappa) @@ -454,12 +454,12 @@ function perform_step!(integrator, cache::QNDF1Cache, repeat_step = false) mass_matrix = f.mass_matrix if mass_matrix === I - @.. broadcast=false tmp=(α₁ * uprev + α₂ * uprev2) / (dt * β₀) + @.. broadcast=false tmp=(α₁*uprev+α₂*uprev2)/(dt*β₀) else dz = nlsolver.cache.dz - @.. broadcast=false dz=α₁ * uprev + α₂ * uprev2 + @.. broadcast=false dz=α₁*uprev+α₂*uprev2 mul!(ztmp, mass_matrix, dz) - @.. broadcast=false tmp=ztmp / (dt * β₀) + @.. broadcast=false tmp=ztmp/(dt*β₀) end nlsolver.γ = β₀ @@ -475,9 +475,9 @@ function perform_step!(integrator, cache::QNDF1Cache, repeat_step = false) if integrator.success_iter == 0 integrator.EEst = one(integrator.EEst) else - @.. broadcast=false D2[1]=u - uprev - @.. broadcast=false D2[2]=D2[1] - D[1] - @.. broadcast=false utilde=(κ + inv(k + 1)) * D2[2] + @.. broadcast=false D2[1]=u-uprev + @.. broadcast=false D2[2]=D2[1]-D[1] + @.. broadcast=false utilde=(κ+inv(k+1))*D2[2] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -513,12 +513,12 @@ function perform_step!(integrator, cache::QNDF2ConstantCache, repeat_step = fals k = 2 if cnt == 1 || cnt == 2 κ = zero(alg.kappa) - γ₁ = 1 // 1 - γ₂ = 1 // 1 + γ₁ = Int64(1) // 1 + γ₂ = Int64(1) // 1 elseif dtₙ₋₁ != dtₙ₋₂ κ = alg.kappa - γ₁ = 1 // 1 - γ₂ = 1 // 1 + 1 // 2 + γ₁ = Int64(1) // 1 + γ₂ = Int64(1) // 1 + Int64(1) // 2 ρ₁ = dt / dtₙ₋₁ ρ₂ = dt / dtₙ₋₂ D[1] = uprev - uprev2 @@ -526,8 +526,8 @@ function perform_step!(integrator, cache::QNDF2ConstantCache, repeat_step = fals D[2] = D[1] - ((uprev2 - uprev3) * ρ₂) else κ = alg.kappa - γ₁ = 1 // 1 - γ₂ = 1 // 1 + 1 // 2 + γ₁ = Int64(1) // 1 + γ₂ = Int64(1) // 1 + Int64(1) // 2 ρ = dt / dtₙ₋₁ # backward diff D[1] = uprev - uprev2 @@ -615,37 +615,38 @@ end function perform_step!(integrator, cache::QNDF2Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator - @unpack uprev2, uprev3, dtₙ₋₁, dtₙ₋₂, D, D2, R, U, utilde, atmp, nlsolver, step_limiter! = cache + @unpack uprev2, uprev3, dtₙ₋₁, dtₙ₋₂, D, D2, R, U, utilde, atmp, nlsolver, + step_limiter! = cache @unpack z, tmp, ztmp = nlsolver alg = unwrap_alg(integrator, true) cnt = integrator.iter k = 2 if cnt == 1 || cnt == 2 κ = zero(alg.kappa) - γ₁ = 1 // 1 - γ₂ = 1 // 1 + γ₁ = Int64(1) // 1 + γ₂ = Int64(1) // 1 elseif dtₙ₋₁ != dtₙ₋₂ κ = alg.kappa - γ₁ = 1 // 1 - γ₂ = 1 // 1 + 1 // 2 + γ₁ = Int64(1) // 1 + γ₂ = Int64(1) // 1 + Int64(1) // 2 ρ₁ = dt / dtₙ₋₁ ρ₂ = dt / dtₙ₋₂ - @.. broadcast=false D[1]=uprev - uprev2 - @.. broadcast=false D[1]=D[1] * ρ₁ - @.. broadcast=false D[2]=D[1] - ((uprev2 - uprev3) * ρ₂) + @.. broadcast=false D[1]=uprev-uprev2 + @.. broadcast=false D[1]=D[1]*ρ₁ + @.. broadcast=false D[2]=D[1]-((uprev2-uprev3)*ρ₂) else κ = alg.kappa - γ₁ = 1 // 1 - γ₂ = 1 // 1 + 1 // 2 + γ₁ = Int64(1) // 1 + γ₂ = Int64(1) // 1 + Int64(1) // 2 ρ = dt / dtₙ₋₁ # backward diff - @.. broadcast=false D[1]=uprev - uprev2 - @.. broadcast=false D[2]=D[1] - (uprev2 - uprev3) + @.. broadcast=false D[1]=uprev-uprev2 + @.. broadcast=false D[2]=D[1]-(uprev2-uprev3) if ρ != 1 R!(k, ρ, cache) R .= R * U - @.. broadcast=false D[1]=D[1] * R[1, 1] + D[2] * R[2, 1] - @.. broadcast=false D[2]=D[1] * R[1, 2] + D[2] * R[2, 2] + @.. broadcast=false D[1]=D[1]*R[1, 1]+D[2]*R[2, 1] + @.. broadcast=false D[2]=D[1]*R[1, 2]+D[2]*R[2, 2] end end @@ -663,12 +664,12 @@ function perform_step!(integrator, cache::QNDF2Cache, repeat_step = false) mass_matrix = f.mass_matrix if mass_matrix === I - @.. broadcast=false tmp=(u₀ - ϕ) / (dt * β₀) + @.. broadcast=false tmp=(u₀-ϕ)/(dt*β₀) else dz = nlsolver.cache.dz - @.. broadcast=false dz=u₀ - ϕ + @.. broadcast=false dz=u₀-ϕ mul!(ztmp, mass_matrix, dz) - @.. broadcast=false tmp=ztmp / (dt * β₀) + @.. broadcast=false tmp=ztmp/(dt*β₀) end nlsolver.γ = β₀ @@ -685,15 +686,15 @@ function perform_step!(integrator, cache::QNDF2Cache, repeat_step = false) if integrator.success_iter == 0 integrator.EEst = one(integrator.EEst) elseif integrator.success_iter == 1 - @.. broadcast=false utilde=(u - uprev) - ((uprev - uprev2) * dt / dtₙ₋₁) + @.. broadcast=false utilde=(u-uprev)-((uprev-uprev2)*dt/dtₙ₋₁) calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) else - @.. broadcast=false D2[1]=u - uprev - @.. broadcast=false D2[2]=D2[1] - D[1] - @.. broadcast=false D2[3]=D2[2] - D[2] - @.. broadcast=false utilde=(κ * γ₂ + inv(k + 1)) * D2[3] + @.. broadcast=false D2[1]=u-uprev + @.. broadcast=false D2[2]=D2[1]-D[1] + @.. broadcast=false D2[3]=D2[2]-D[2] + @.. broadcast=false utilde=(κ*γ₂+inv(k+1))*D2[3] calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -841,7 +842,8 @@ end function perform_step!(integrator, cache::QNDFCache{max_order}, repeat_step = false) where {max_order} @unpack t, dt, uprev, u, f, p = integrator - @unpack dtprev, order, D, nlsolver, γₖ, dd, atmp, atmpm1, atmpp1, utilde, utildem1, utildep1, ϕ, u₀, step_limiter! = cache + @unpack dtprev, order, D, nlsolver, γₖ, dd, atmp, atmpm1, atmpp1, + utilde, utildem1, utildep1, ϕ, u₀, step_limiter! = cache alg = unwrap_alg(integrator, true) if integrator.u_modified @@ -894,10 +896,10 @@ function perform_step!(integrator, cache::QNDFCache{max_order}, mass_matrix = f.mass_matrix if mass_matrix === I - @.. broadcast=false nlsolver.tmp=(u₀ / β₀ - ϕ) / dt + @.. broadcast=false nlsolver.tmp=(u₀/β₀-ϕ)/dt else @unpack tmp2 = cache - @.. broadcast=false tmp2=(u₀ / β₀ - ϕ) / dt + @.. broadcast=false tmp2=(u₀/β₀-ϕ)/dt mul!(nlsolver.tmp, mass_matrix, tmp2) end @@ -908,7 +910,7 @@ function perform_step!(integrator, cache::QNDFCache{max_order}, z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return @.. broadcast=false u=z - @.. broadcast=false dd=u - u₀ + @.. broadcast=false dd=u-u₀ update_D!(D, dd, k) step_limiter!(u, integrator, p, t + dt) @@ -1024,7 +1026,7 @@ end # initial guess if alg.extrapolant == :linear - @.. broadcast=false z=dt * integrator.fsalfirst + @.. broadcast=false z=dt*integrator.fsalfirst else # :constant z .= zero(eltype(u)) end @@ -1033,23 +1035,23 @@ end nlsolver.tmp = uprev z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false z₁=uprev + z + @.. broadcast=false z₁=uprev+z ### STEP 2 nlsolver.tmp = z₁ nlsolver.c = 2 isnewton(nlsolver) && set_new_W!(nlsolver, false) z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false z₂=z₁ + z + @.. broadcast=false z₂=z₁+z ### STEP 3 # z .= zero(eltype(u)) - @.. broadcast=false tmp2=0.5uprev + z₁ - 0.5z₂ + @.. broadcast=false tmp2=0.5uprev+z₁-0.5z₂ nlsolver.tmp = tmp2 nlsolver.c = 1 isnewton(nlsolver) && set_new_W!(nlsolver, false) z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false u=tmp2 + z + @.. broadcast=false u=tmp2+z ### finalize f(integrator.fsallast, u, p, t + dt) @@ -1066,11 +1068,17 @@ function initialize!(integrator, cache::FBDFConstantCache) integrator.fsallast = zero(integrator.fsalfirst) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + + u_modified = integrator.u_modified + integrator.u_modified = true + reinitFBDF!(integrator, cache) + integrator.u_modified = u_modified end function perform_step!(integrator, cache::FBDFConstantCache{max_order}, repeat_step = false) where {max_order} - @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, ts_tmp, iters_from_event, nconsteps = cache + @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, + weights, ts_tmp, iters_from_event, nconsteps = cache @unpack t, dt, u, f, p, uprev = integrator tdt = t + dt @@ -1222,11 +1230,17 @@ function initialize!(integrator, cache::FBDFCache) integrator.k[2] = integrator.fsallast integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + + u_modified = integrator.u_modified + integrator.u_modified = true + reinitFBDF!(integrator, cache) + integrator.u_modified = u_modified end function perform_step!(integrator, cache::FBDFCache{max_order}, repeat_step = false) where {max_order} - @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, terk_tmp, terkp1_tmp, atmp, tmp, equi_ts, u₀, ts_tmp, step_limiter! = cache + @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, terk_tmp, + terkp1_tmp, atmp, tmp, equi_ts, u₀, ts_tmp, step_limiter! = cache @unpack t, dt, u, f, p, uprev = integrator reinitFBDF!(integrator, cache) @@ -1251,7 +1265,7 @@ function perform_step!(integrator, cache::FBDFCache{max_order}, @views calc_Lagrange_interp!(k, weights, equi_ts[i], ts, u_history, u_corrector[:, i]) end - @.. broadcast=false tmp=-uprev * bdf_coeffs[k, 2] + @.. broadcast=false tmp=-uprev*bdf_coeffs[k, 2] vc = _vec(tmp) for i in 1:(k - 1) @.. broadcast=false @views vc -= u_corrector[:, i] * bdf_coeffs[k, i + 2] @@ -1259,9 +1273,9 @@ function perform_step!(integrator, cache::FBDFCache{max_order}, invdt = inv(dt) if mass_matrix === I - @.. broadcast=false nlsolver.tmp=tmp * invdt + @.. broadcast=false nlsolver.tmp=tmp*invdt else - @.. broadcast=false terkp1_tmp=tmp * invdt + @.. broadcast=false terkp1_tmp=tmp*invdt mul!(nlsolver.tmp, mass_matrix, terkp1_tmp) end @@ -1285,7 +1299,7 @@ function perform_step!(integrator, cache::FBDFCache{max_order}, end #for terkp1, we could use corrector and predictor to make an estimation. - @.. broadcast=false terkp1_tmp=(u - u₀) + @.. broadcast=false terkp1_tmp=(u-u₀) for j in 1:(k + 1) @.. broadcast=false terkp1_tmp*=j * dt / (tdt - ts[j]) end @@ -1294,7 +1308,7 @@ function perform_step!(integrator, cache::FBDFCache{max_order}, for j in 2:k lte -= bdf_coeffs[k, j] * r[j] end - @.. broadcast=false terk_tmp=lte * terkp1_tmp + @.. broadcast=false terk_tmp=lte*terkp1_tmp if integrator.opts.adaptive @unpack abstol, reltol, internalnorm = integrator.opts for i in 1:(k + 1) diff --git a/lib/OrdinaryDiffEqBDF/src/bdf_utils.jl b/lib/OrdinaryDiffEqBDF/src/bdf_utils.jl index 30c09d6bd4..32941dc82c 100644 --- a/lib/OrdinaryDiffEqBDF/src/bdf_utils.jl +++ b/lib/OrdinaryDiffEqBDF/src/bdf_utils.jl @@ -26,7 +26,7 @@ function backward_diff!(cache::OrdinaryDiffEqMutableCache, D, D2, k, flag = true flag && copyto!(D[1], D2[1, 1]) for i in 2:k for j in 1:(k - i + 1) - @.. broadcast=false D2[i, j]=D2[i - 1, j] - D2[i - 1, j + 1] + @.. broadcast=false D2[i, j]=D2[i - 1, j]-D2[i - 1, j + 1] end flag && copyto!(D[i], D2[i, 1]) end @@ -82,15 +82,15 @@ end function update_D!(D, dd, k) dd = _vec(dd) - @views @.. broadcast=false D[:, k + 2]=dd - D[:, k + 1] + @views @.. broadcast=false D[:, k + 2]=dd-D[:, k + 1] @views @.. broadcast=false D[:, k + 1]=dd for i in k:-1:1 - @views @.. broadcast=false D[:, i]=D[:, i] + D[:, i + 1] + @views @.. broadcast=false D[:, i]=D[:, i]+D[:, i + 1] end return nothing end -const γₖ = @SVector[sum(1 // j for j in 1:k) for k in 1:6] +const γₖ = @SVector[sum(Int64(1) // j for j in 1:k) for k in 1:6] function error_constant(integrator, alg::QNDF, k) @unpack γₖ = integrator.cache @@ -195,7 +195,8 @@ end function reinitFBDF!(integrator, cache) # This function is used for initialize weights and arrays that store past history information. It will be used in the first-time step advancing and event handling. - @unpack weights, consfailcnt, ts, u_history, u_corrector, iters_from_event, order = cache + @unpack weights, consfailcnt, ts, u_history, u_corrector, iters_from_event, + order = cache @unpack t, dt, uprev = integrator if integrator.u_modified @@ -237,7 +238,7 @@ function estimate_terk!(integrator, cache, k, ::Val{max_order}) where {max_order @unpack ts_tmp, terk_tmp, u_history = cache @unpack t, dt, u = integrator fd_weights = calc_finite_difference_weights(ts_tmp, t + dt, k - 1, Val(max_order)) - @.. broadcast=false terk_tmp=fd_weights[1, k] * u + @.. broadcast=false terk_tmp=fd_weights[1, k]*u vc = _vec(terk_tmp) for i in 2:k @.. broadcast=false @views vc += fd_weights[i, k] * u_history[:, i - 1] diff --git a/lib/OrdinaryDiffEqBDF/src/dae_caches.jl b/lib/OrdinaryDiffEqBDF/src/dae_caches.jl index aa03fc0f25..1c7383dc08 100644 --- a/lib/OrdinaryDiffEqBDF/src/dae_caches.jl +++ b/lib/OrdinaryDiffEqBDF/src/dae_caches.jl @@ -63,8 +63,8 @@ function alg_cache(alg::DABDF2, du, u, res_prototype, rate_prototype, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = 1 // 1, 1 - α = 1 // 1 + γ, c = Int64(1) // 1, 1 + α = Int64(1) // 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, res_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, α, Val(false)) eulercache = DImplicitEulerConstantCache(nlsolver) @@ -92,8 +92,8 @@ function alg_cache(alg::DABDF2, du, u, res_prototype, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - γ, c = 1 // 1, 1 - α = 1 // 1 + γ, c = Int64(1) // 1, 1 + α = Int64(1) // 1 nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, res_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, α, Val(true)) fsalfirst = zero(rate_prototype) @@ -146,10 +146,10 @@ function alg_cache(alg::DFBDF{MO}, du, u, res_prototype, rate_prototype, uEltype nlsolver = build_nlsolver(alg, u, uprev, p, t, dt, f, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, Val(false)) bdf_coeffs = SA[1 -1 0 0 0 0; - 2//3 -4//3 1//3 0 0 0; - 6//11 -18//11 9//11 -2//11 0 0; - 12//25 -48//25 36//25 -16//25 3//25 0; - 60//137 -300//137 300//137 -200//137 75//137 -12//137] + Int64(2)//3 -Int64(4)//3 Int64(1)//3 0 0 0; + Int64(6)//11 -Int64(18)//11 Int64(9)//11 -Int64(2)//11 0 0; + Int64(12)//25 -Int64(48)//25 Int64(36)//25 -Int64(16)//25 Int64(3)//25 0; + Int64(60)//137 -Int64(300)//137 Int64(300)//137 -Int64(200)//137 Int64(75)//137 -Int64(12)//137] ts = zero(Vector{typeof(t)}(undef, max_order + 2)) #ts is the successful past points, it will be updated after successful step ts_tmp = similar(ts) @@ -223,10 +223,10 @@ function alg_cache(alg::DFBDF{MO}, du, u, res_prototype, rate_prototype, uEltype 25//12 -4 3 -4//3 1//4 0 ; 137//60 -5 5 -10//3 5//4 -1//5]=# bdf_coeffs = SA[1 -1 0 0 0 0; - 2//3 -4//3 1//3 0 0 0; - 6//11 -18//11 9//11 -2//11 0 0; - 12//25 -48//25 36//25 -16//25 3//25 0; - 60//137 -300//137 300//137 -200//137 75//137 -12//137] + Int64(2)//3 -Int64(4)//3 Int64(1)//3 0 0 0; + Int64(6)//11 -Int64(18)//11 Int64(9)//11 -Int64(2)//11 0 0; + Int64(12)//25 -Int64(48)//25 Int64(36)//25 -Int64(16)//25 Int64(3)//25 0; + Int64(60)//137 -Int64(300)//137 Int64(300)//137 -Int64(200)//137 Int64(75)//137 -Int64(12)//137] ts = Vector{typeof(t)}(undef, max_order + 2) #ts is the successful past points, it will be updated after successful step u_history = Matrix{eltype(u)}(undef, length(u), max_order + 2) order = 1 diff --git a/lib/OrdinaryDiffEqBDF/src/dae_perform_step.jl b/lib/OrdinaryDiffEqBDF/src/dae_perform_step.jl index d372a89a5e..211cde7752 100644 --- a/lib/OrdinaryDiffEqBDF/src/dae_perform_step.jl +++ b/lib/OrdinaryDiffEqBDF/src/dae_perform_step.jl @@ -66,8 +66,8 @@ end nlsolver.γ = 1 z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false u=uprev + z - @.. broadcast=false du=z * inv(dt) + @.. broadcast=false u=uprev+z + @.. broadcast=false du=z*inv(dt) if integrator.opts.adaptive && integrator.success_iter > 0 # local truncation error (LTE) bound by dt^2/2*max|y''(t)| @@ -82,9 +82,9 @@ end c = 7 / 12 # default correction factor in SPICE (LTE overestimated by DD) r = c * dt^2 # by mean value theorem 2nd DD equals y''(s)/2 for some s - @.. broadcast=false tmp=r * integrator.opts.internalnorm( - (u - uprev) / dt1 - - (uprev - uprev2) / dt2, t) + @.. broadcast=false tmp=r*integrator.opts.internalnorm( + (u-uprev)/dt1- + (uprev-uprev2)/dt2, t) calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -122,7 +122,7 @@ end c1 = ρ^2 / (1 + 2ρ) nlsolver.γ = (1 + ρ) / (1 + 2ρ) - nlsolver.α = 1 // 1 + nlsolver.α = Int64(1) // 1 nlsolver.z = zero(uₙ) @@ -177,7 +177,7 @@ end if integrator.iter == 1 && !integrator.u_modified cache.dtₙ₋₁ = dtₙ perform_step!(integrator, cache.eulercache, repeat_step) - @.. broadcast=false integrator.fsalfirst=(uₙ - uₙ₋₁) / dt + @.. broadcast=false integrator.fsalfirst=(uₙ-uₙ₋₁)/dt cache.fsalfirstprev .= integrator.fsalfirst return end @@ -187,24 +187,24 @@ end c1 = ρ^2 / (1 + 2ρ) nlsolver.γ = (1 + ρ) / (1 + 2ρ) - nlsolver.α = 1 // 1 - @.. broadcast=false nlsolver.tmp=-c1 * uₙ₋₁ + c1 * uₙ₋₂ + nlsolver.α = Int64(1) // 1 + @.. broadcast=false nlsolver.tmp=-c1*uₙ₋₁+c1*uₙ₋₂ nlsolver.z .= zero(eltype(z)) z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false uₙ=uₙ₋₁ + z - @.. broadcast=false du=(nlsolver.α * z + nlsolver.tmp) * inv(nlsolver.γ * dt) + @.. broadcast=false uₙ=uₙ₋₁+z + @.. broadcast=false du=(nlsolver.α*z+nlsolver.tmp)*inv(nlsolver.γ*dt) @.. broadcast=false integrator.fsallast=du OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) if integrator.opts.adaptive - btilde0 = (dtₙ₋₁ + dtₙ) * 1 // 6 + btilde0 = (dtₙ₋₁ + dtₙ) * Int64(1) // 6 btilde1 = 1 + ρ btilde2 = ρ - @.. broadcast=false tmp=btilde0 * - (integrator.fsallast - btilde1 * integrator.fsalfirst + - btilde2 * cache.fsalfirstprev) + @.. broadcast=false tmp=btilde0* + (integrator.fsallast-btilde1*integrator.fsalfirst+ + btilde2*cache.fsalfirstprev) calculate_residuals!(atmp, tmp, uₙ₋₁, uₙ, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) @@ -229,11 +229,17 @@ function initialize!(integrator, cache::DFBDFConstantCache) integrator.fsallast = zero(integrator.fsalfirst) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + + u_modified = integrator.u_modified + integrator.u_modified = true + reinitFBDF!(integrator, cache) + integrator.u_modified = u_modified end function perform_step!(integrator, cache::DFBDFConstantCache{max_order}, repeat_step = false) where {max_order} - @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, ts_tmp, iters_from_event, nconsteps = cache + @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, + weights, ts_tmp, iters_from_event, nconsteps = cache @unpack t, dt, u, f, p, uprev = integrator k = order @@ -268,7 +274,7 @@ function perform_step!(integrator, cache::DFBDFConstantCache{max_order}, ts, u_history, u_corrector[:, - i]) + i]) end tmp = uprev * bdf_coeffs[k, 2] vc = _vec(tmp) @@ -281,7 +287,7 @@ function perform_step!(integrator, cache::DFBDFConstantCache{max_order}, nlsolver.tmp = tmp + cache.u₀ nlsolver.z = zero(nlsolver.z) nlsolver.γ = bdf_coeffs[k, 1] - nlsolver.α = 1 // 1 + nlsolver.α = Int64(1) // 1 z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return u = z + cache.u₀ @@ -355,11 +361,17 @@ function initialize!(integrator, cache::DFBDFCache) integrator.k[2] = integrator.fsallast #integrator.f(integrator.fsalfirst, integrator.du, integrator.uprev, integrator.p, integrator.t) # For the interpolation, needs k at the updated point #OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + + u_modified = integrator.u_modified + integrator.u_modified = true + reinitFBDF!(integrator, cache) + integrator.u_modified = u_modified end function perform_step!(integrator, cache::DFBDFCache{max_order}, repeat_step = false) where {max_order} - @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, terk_tmp, terkp1_tmp, atmp, tmp, equi_ts, u₀, ts_tmp = cache + @unpack ts, u_history, order, u_corrector, bdf_coeffs, r, nlsolver, weights, + terk_tmp, terkp1_tmp, atmp, tmp, equi_ts, u₀, ts_tmp = cache @unpack t, dt, u, f, p, uprev = integrator reinitFBDF!(integrator, cache) @@ -382,19 +394,19 @@ function perform_step!(integrator, cache::DFBDFCache{max_order}, u_corrector[:, i]) end - @.. broadcast=false tmp=uprev * bdf_coeffs[k, 2] + @.. broadcast=false tmp=uprev*bdf_coeffs[k, 2] vc = _vec(tmp) for i in 1:(k - 1) @.. broadcast=false @views vc += u_corrector[:, i] * bdf_coeffs[k, i + 2] end - @.. broadcast=false nlsolver.tmp=tmp + u₀ + @.. broadcast=false nlsolver.tmp=tmp+u₀ @.. broadcast=false nlsolver.z=zero(eltype(nlsolver.z)) nlsolver.γ = bdf_coeffs[k, 1] - nlsolver.α = 1 // 1 + nlsolver.α = Int64(1) // 1 z = nlsolve!(nlsolver, integrator, cache, repeat_step) nlsolvefail(nlsolver) && return - @.. broadcast=false u=z + u₀ + @.. broadcast=false u=z+u₀ for j in 2:k r[j] = (1 - j) @@ -412,7 +424,7 @@ function perform_step!(integrator, cache::DFBDFCache{max_order}, for j in 2:k lte -= (bdf_coeffs[k, j] // bdf_coeffs[k, 1]) * r[j] end - @.. broadcast=false terk_tmp=lte * terkp1_tmp + @.. broadcast=false terk_tmp=lte*terkp1_tmp if integrator.opts.adaptive @unpack abstol, reltol, internalnorm = integrator.opts for i in 1:(k + 1) @@ -450,7 +462,7 @@ function perform_step!(integrator, cache::DFBDFCache{max_order}, cache.terkp1 = zero(cache.terkp1) end end - @.. broadcast=false integrator.fsallast=integrator.du = (nlsolver.α * z + - nlsolver.tmp) * - inv(nlsolver.γ * dt) #TODO Lorenz plot seems not smooth + @.. broadcast=false integrator.fsallast=integrator.du=(nlsolver.α*z+ + nlsolver.tmp)* + inv(nlsolver.γ*dt) #TODO Lorenz plot seems not smooth end diff --git a/lib/OrdinaryDiffEqBDF/test/allocation_tests.jl b/lib/OrdinaryDiffEqBDF/test/allocation_tests.jl new file mode 100644 index 0000000000..3d5851649b --- /dev/null +++ b/lib/OrdinaryDiffEqBDF/test/allocation_tests.jl @@ -0,0 +1,124 @@ +using OrdinaryDiffEqBDF +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqBDF solvers using AllocCheck.jl. +These tests verify that the step! operation should not allocate during stepping. +Currently, many BDF solvers are allocating and marked with @test_broken. +""" + +@testset "BDF Allocation Tests" begin + # Test problem for standard ODE BDF methods + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Split problem for IMEX methods + function f1!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = 0.0 + end + function f2!(du, u, p, t) + du[1] = 0.0 + du[2] = -1.5 * u[2] + end + split_prob = SplitODEProblem(f1!, f2!, [1.0, 1.0], (0.0, 1.0)) + + # DAE problem for DAE solvers + function dae_f!(resid, du, u, p, t) + resid[1] = -0.5 * u[1] + u[2] - du[1] + resid[2] = u[1] - u[2] - du[2] + end + du0 = zeros(2) + differential_vars = [true, false] + dae_prob = DAEProblem(dae_f!, du0, [1.0, 1.0], (0.0, 1.0), differential_vars=differential_vars) + + # Test all exported BDF solvers for allocation-free behavior + # Standard ODE BDF methods + bdf_solvers = [ABDF2(), QNDF1(), QBDF1(), QNDF2(), QBDF2(), QNDF(), QBDF(), FBDF(), MEBDF2()] + + # IMEX/Split methods need SplitODEProblem + imex_solvers = [SBDF(order=2), SBDF2(), SBDF3(), SBDF4(), IMEXEuler(), IMEXEulerARK()] + + # DAE methods need DAEProblem + dae_solvers = [DABDF2(), DImplicitEuler(), DFBDF()] + + @testset "BDF Solver Allocation Analysis" begin + for solver in bdf_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test length(allocs) == 0 broken=true + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end + + @testset "IMEX Solver Allocation Analysis" begin + for solver in imex_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(split_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test length(allocs) == 0 broken=true + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end + + @testset "DAE Solver Allocation Analysis" begin + for solver in dae_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(dae_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test length(allocs) == 0 broken=true + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqBDF/test/bdf_convergence_tests.jl b/lib/OrdinaryDiffEqBDF/test/bdf_convergence_tests.jl index ef6a1d533a..926f12ca37 100644 --- a/lib/OrdinaryDiffEqBDF/test/bdf_convergence_tests.jl +++ b/lib/OrdinaryDiffEqBDF/test/bdf_convergence_tests.jl @@ -1,11 +1,20 @@ # This definitely needs cleaning -using OrdinaryDiffEqBDF, ODEProblemLibrary, DiffEqDevTools +using OrdinaryDiffEqBDF, ODEProblemLibrary, DiffEqDevTools, ADTypes, LinearSolve +using OrdinaryDiffEqNonlinearSolve: NLFunctional, NLAnderson, NonlinearSolveAlg using Test, Random Random.seed!(100) testTol = 0.2 +dts = 1 .// 2 .^ (9:-1:5) +dts3 = 1 .// 2 .^ (12:-1:7) + +if isempty(VERSION.prerelease) + using Enzyme +end + +@testset "Implicit Solver Convergence Tests ($(["out-of-place", "in-place"][i]))" for i in + 1:2 -@testset "Implicit Solver Convergence Tests ($(["out-of-place", "in-place"][i]))" for i in 1:2 prob = (ODEProblemLibrary.prob_ode_linear, ODEProblemLibrary.prob_ode_2Dlinear)[i] @@ -36,6 +45,31 @@ testTol = 0.2 @test sim.𝒪est[:l2]≈1 atol=testTol @test sim.𝒪est[:l∞]≈1 atol=testTol + sim = test_convergence(dts, prob, QNDF1(autodiff = AutoFiniteDiff())) + @test sim.𝒪est[:final]≈1 atol=testTol + @test sim.𝒪est[:l2]≈1 atol=testTol + @test sim.𝒪est[:l∞]≈1 atol=testTol + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, + prob, + QNDF1(autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), + function_annotation = Enzyme.Const))) + @test sim.𝒪est[:final]≈1 atol=testTol + @test sim.𝒪est[:l2]≈1 atol=testTol + @test sim.𝒪est[:l∞]≈1 atol=testTol + + sim = test_convergence(dts, + prob, + QNDF1( + autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), + function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test sim.𝒪est[:final]≈1 atol=testTol + @test sim.𝒪est[:l2]≈1 atol=testTol + @test sim.𝒪est[:l∞]≈1 atol=testTol + end + sim = test_convergence(dts3, prob, QNDF2()) @test sim.𝒪est[:final]≈2 atol=testTol @test sim.𝒪est[:l2]≈2 atol=testTol diff --git a/lib/OrdinaryDiffEqBDF/test/bdf_regression_tests.jl b/lib/OrdinaryDiffEqBDF/test/bdf_regression_tests.jl new file mode 100644 index 0000000000..5a4a82fe98 --- /dev/null +++ b/lib/OrdinaryDiffEqBDF/test/bdf_regression_tests.jl @@ -0,0 +1,36 @@ +using OrdinaryDiffEqBDF, ForwardDiff, Test + +foop = (u, p, t) -> u * p +proboop = ODEProblem(foop, ones(2), (0.0, 1000.0), 1.0) + +fiip = (du, u, p, t) -> du .= u .* p +probiip = ODEProblem(fiip, ones(2), (0.0, 1000.0), 1.0) + +@testset "FBDF reinit" begin + for prob in [proboop, probiip] + integ = init(prob, FBDF(), verbose = false) #suppress warning to clean up CI + solve!(integ) + @test integ.sol.retcode != ReturnCode.Success + @test integ.sol.t[end] >= 700 + reinit!(integ, prob.u0) + solve!(integ) + @test integ.sol.retcode != ReturnCode.Success + @test integ.sol.t[end] >= 700 + end +end + +function ad_helper(alg, prob) + function costoop(p) + _oprob = remake(prob; p) + sol = solve(_oprob, alg, saveat = 1:10) + return sum(sol) + end +end + +@testset "parameter autodiff" begin + for prob in [proboop, probiip] + for alg in [FBDF(), QNDF()] + ForwardDiff.derivative(ad_helper(alg, prob), 1.0) + end + end +end diff --git a/lib/OrdinaryDiffEqBDF/test/dae_ad_tests.jl b/lib/OrdinaryDiffEqBDF/test/dae_ad_tests.jl index ede33c5bbe..cdb037f45e 100644 --- a/lib/OrdinaryDiffEqBDF/test/dae_ad_tests.jl +++ b/lib/OrdinaryDiffEqBDF/test/dae_ad_tests.jl @@ -1,5 +1,8 @@ using OrdinaryDiffEqBDF, LinearAlgebra, ForwardDiff, Test using OrdinaryDiffEqNonlinearSolve: BrownFullBasicInit, ShampineCollocationInit +using ADTypes: AutoForwardDiff, AutoFiniteDiff + +afd_cs3 = AutoForwardDiff(chunksize = 3) function f(out, du, u, p, t) out[1] = -p[1] * u[1] + p[3] * u[2] * u[3] - du[1] @@ -11,22 +14,44 @@ function f(du, u, p, t) +p[1] * u[1] - p[2] * u[2]^2 - p[3] * u[2] * u[3] - du[2], u[1] + u[2] + u[3] - 1.0] end +function f_ode(du, u, p, t) + du .= [-p[1] * u[1] + p[3] * u[2] * u[3], + +p[1] * u[1] - p[2] * u[2]^2 - p[3] * u[2] * u[3], + u[1] + u[2] + u[3] - 1.0] +end +function f_ode(u, p, t) + [-p[1] * u[1] + p[3] * u[2] * u[3], + +p[1] * u[1] - p[2] * u[2]^2 - p[3] * u[2] * u[3], + u[1] + u[2] + u[3] - 1.0] +end p = [0.04, 3e7, 1e4] u₀ = [1.0, 0, 0] du₀ = [-0.04, 0.04, 0.0] tspan = (0.0, 100000.0) differential_vars = [true, true, false] +M = Diagonal([1.0, 1.0, 0.0]) prob = DAEProblem(f, du₀, u₀, tspan, p, differential_vars = differential_vars) prob_oop = DAEProblem{false}(f, du₀, u₀, tspan, p, differential_vars = differential_vars) -sol1 = solve(prob, DFBDF(), dt = 1e-5, abstol = 1e-8, reltol = 1e-8) +f_mm = ODEFunction{true}(f_ode, mass_matrix = M) +prob_mm = ODEProblem(f_mm, u₀, tspan, p) +f_mm_oop = ODEFunction{false}(f_ode, mass_matrix = M) +prob_mm_oop = ODEProblem(f_mm_oop, u₀, tspan, p) +@test_broken sol1 = @inferred solve( + prob, DFBDF(autodiff = afd_cs3), dt = 1e-5, abstol = 1e-8, reltol = 1e-8) +@test_broken sol2 = @inferred solve( + prob_oop, DFBDF(autodiff = afd_cs3), dt = 1e-5, abstol = 1e-8, reltol = 1e-8) +@test_broken sol3 = @inferred solve( + prob_mm, FBDF(autodiff = afd_cs3), dt = 1e-5, abstol = 1e-8, reltol = 1e-8) # These tests flex differentiation of the solver and through the initialization # To only test the solver part and isolate potential issues, set the initialization to consistent -@testset "Inplace: $(isinplace(_prob)), DAEProblem: $(_prob isa DAEProblem), BrownBasic: $(initalg isa BrownFullBasicInit), Autodiff: $autodiff" for _prob in [ - prob, prob_oop], - initalg in [BrownFullBasicInit(), ShampineCollocationInit()], autodiff in [true, false] +@testset "Inplace: $(isinplace(_prob)), DAEProblem: $(_prob isa DAEProblem), BrownBasic: $(initalg isa BrownFullBasicInit), Autodiff: $autodiff" for _prob in + [ + prob, prob_oop, prob_mm, prob_mm_oop], + initalg in [BrownFullBasicInit(), ShampineCollocationInit()], + autodiff in [afd_cs3, AutoFiniteDiff()] - alg = DFBDF(; autodiff) + alg = (_prob isa DAEProblem) ? DFBDF(; autodiff) : FBDF(; autodiff) function f(p) sol = solve(remake(_prob, p = p), alg, abstol = 1e-14, reltol = 1e-14, initializealg = initalg) diff --git a/lib/OrdinaryDiffEqBDF/test/dae_convergence_tests.jl b/lib/OrdinaryDiffEqBDF/test/dae_convergence_tests.jl index bd0d5891c4..1829c679a0 100644 --- a/lib/OrdinaryDiffEqBDF/test/dae_convergence_tests.jl +++ b/lib/OrdinaryDiffEqBDF/test/dae_convergence_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEqBDF, DiffEqDevTools +using OrdinaryDiffEqBDF, DiffEqDevTools, ADTypes using Test, Random Random.seed!(100) @@ -22,13 +22,13 @@ prob_dae_linear_iip = DAEProblem( sim11 = test_convergence(dts, prob, DImplicitEuler()) @test sim11.𝒪est[:final]≈1 atol=testTol - sim12 = test_convergence(dts, prob, DImplicitEuler(; autodiff = false)) + sim12 = test_convergence(dts, prob, DImplicitEuler(; autodiff = AutoFiniteDiff())) @test sim12.𝒪est[:final]≈1 atol=testTol sim13 = test_convergence(dts, prob, DABDF2()) @test sim13.𝒪est[:final]≈2 atol=testTol - sim14 = test_convergence(dts, prob, DABDF2(; autodiff = false)) + sim14 = test_convergence(dts, prob, DABDF2(; autodiff = AutoFiniteDiff())) @test sim14.𝒪est[:final]≈2 atol=testTol @test_nowarn solve(prob, DFBDF()) @@ -46,13 +46,13 @@ prob_dae_linear_iip_jac = DAEProblem( sim11 = test_convergence(dts, prob, DImplicitEuler()) @test sim11.𝒪est[:final]≈1 atol=testTol - sim12 = test_convergence(dts, prob, DImplicitEuler(; autodiff = false)) + sim12 = test_convergence(dts, prob, DImplicitEuler(; autodiff = AutoFiniteDiff())) @test sim12.𝒪est[:final]≈1 atol=testTol sim13 = test_convergence(dts, prob, DABDF2()) @test sim13.𝒪est[:final]≈2 atol=testTol - sim14 = test_convergence(dts, prob, DABDF2(; autodiff = false)) + sim14 = test_convergence(dts, prob, DABDF2(; autodiff = AutoFiniteDiff())) @test sim14.𝒪est[:final]≈2 atol=testTol @test_nowarn solve(prob, DFBDF()) @@ -76,13 +76,13 @@ prob_dae_linear_oop = DAEProblem( sim21 = test_convergence(dts, prob, DImplicitEuler()) @test sim21.𝒪est[:final]≈1 atol=testTol - sim22 = test_convergence(dts, prob, DImplicitEuler(; autodiff = false)) + sim22 = test_convergence(dts, prob, DImplicitEuler(; autodiff = AutoFiniteDiff())) @test sim22.𝒪est[:final]≈1 atol=testTol sim23 = test_convergence(dts, prob, DABDF2()) @test sim23.𝒪est[:final]≈2 atol=testTol - sim24 = test_convergence(dts, prob, DABDF2(; autodiff = false)) + sim24 = test_convergence(dts, prob, DABDF2(; autodiff = AutoFiniteDiff())) @test sim24.𝒪est[:final]≈2 atol=testTol @test_nowarn solve(prob, DFBDF()) @@ -100,13 +100,13 @@ prob_dae_linear_oop = DAEProblem( sim21 = test_convergence(dts, prob, DImplicitEuler()) @test sim21.𝒪est[:final]≈1 atol=testTol - sim22 = test_convergence(dts, prob, DImplicitEuler(; autodiff = false)) + sim22 = test_convergence(dts, prob, DImplicitEuler(; autodiff = AutoFiniteDiff())) @test sim22.𝒪est[:final]≈1 atol=testTol sim23 = test_convergence(dts, prob, DABDF2()) @test sim23.𝒪est[:final]≈2 atol=testTol - sim24 = test_convergence(dts, prob, DABDF2(; autodiff = false)) + sim24 = test_convergence(dts, prob, DABDF2(; autodiff = AutoFiniteDiff())) @test sim24.𝒪est[:final]≈2 atol=testTol @test_nowarn solve(prob, DFBDF()) diff --git a/lib/OrdinaryDiffEqBDF/test/dae_initialization_tests.jl b/lib/OrdinaryDiffEqBDF/test/dae_initialization_tests.jl index cc8d574fd1..154f499c07 100644 --- a/lib/OrdinaryDiffEqBDF/test/dae_initialization_tests.jl +++ b/lib/OrdinaryDiffEqBDF/test/dae_initialization_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEqBDF, StaticArrays, LinearAlgebra, Test +using OrdinaryDiffEqBDF, StaticArrays, LinearAlgebra, Test, ADTypes using OrdinaryDiffEqNonlinearSolve f = function (du, u, p, t) @@ -56,7 +56,7 @@ tspan = (0.0, 100000.0) differential_vars = [true, true, false] prob = DAEProblem(f, du₀, u₀, tspan, differential_vars = differential_vars) integrator = init(prob, DABDF2()) -integrator2 = init(prob, DABDF2(autodiff = false)) +integrator2 = init(prob, DABDF2(autodiff = AutoFiniteDiff())) @test integrator.du[1]≈-0.04 atol=1e-9 @test integrator.du[2]≈0.04 atol=1e-9 diff --git a/lib/OrdinaryDiffEqBDF/test/inference_tests.jl b/lib/OrdinaryDiffEqBDF/test/inference_tests.jl new file mode 100644 index 0000000000..58ac2bba75 --- /dev/null +++ b/lib/OrdinaryDiffEqBDF/test/inference_tests.jl @@ -0,0 +1,18 @@ +using OrdinaryDiffEqBDF, ADTypes, Test +using NonlinearSolve: TrustRegion + +prob = ODEProblem((du, u, p, t) -> du .= u, zeros(1), (0.0, 1.0)) +nlalg = FBDF(autodiff = false, + nlsolve = OrdinaryDiffEqBDF.NonlinearSolveAlg(TrustRegion(autodiff = AutoFiniteDiff()))) +basicalg = FBDF(autodiff = false) +basicalgad = FBDF() + +nlsolver = @inferred OrdinaryDiffEqBDF.build_nlsolver( + basicalg, prob.u0, prob.u0, prob.p, 0.0, 0.0, prob.f, prob.u0, Float64, + Float64, Float64, 0.0, 0.0, Val(true)) +nlsolver = @inferred OrdinaryDiffEqBDF.build_nlsolver( + nlalg, prob.u0, prob.u0, prob.p, 0.0, 0.0, prob.f, prob.u0, Float64, + Float64, Float64, 0.0, 0.0, Val(true)) +nlsolver = @test_throws Any @inferred OrdinaryDiffEqBDF.build_nlsolver( + basicalgad, prob.u0, prob.u0, prob.p, 0.0, 0.0, prob.f, prob.u0, Float64, + Float64, Float64, 0.0, 0.0, Val(true)) diff --git a/lib/OrdinaryDiffEqBDF/test/jet.jl b/lib/OrdinaryDiffEqBDF/test/jet.jl new file mode 100644 index 0000000000..42cd320a0e --- /dev/null +++ b/lib/OrdinaryDiffEqBDF/test/jet.jl @@ -0,0 +1,78 @@ +import OrdinaryDiffEqBDF +using OrdinaryDiffEqBDF +using OrdinaryDiffEqCore +using DiffEqBase: SplitODEProblem, DAEProblem +using JET +using Test + +@testset "JET Tests" begin + # Test package for typos - now passing + test_package( + OrdinaryDiffEqBDF, target_defined_modules = true, mode = :typo) + + # Test individual solver type stability + @testset "Solver Type Stability Tests" begin + # Test problem - use a simple linear problem for stiff solvers + linear_prob = ODEProblem((u, p, t) -> -u, 1.0, (0.0, 1.0)) + + # Split problem for SBDF solvers (which require SplitODEProblem) + split_prob = SplitODEProblem((u, p, t) -> -u, (u, p, t) -> 0.0, 1.0, (0.0, 1.0)) + + # DAE problem for DAE solvers + function simple_dae!(resid, du, u, p, t) + resid[1] = -u[1] - du[1] + end + u0 = [1.0] + du0 = [-1.0] + dae_prob = DAEProblem(simple_dae!, du0, u0, (0.0, 1.0)) + + # Regular BDF solvers (ODEProblem) + regular_bdf_solvers = [ABDF2(), QNDF1(), QBDF1(), QNDF2(), QBDF2(), QNDF(), QBDF(), FBDF(), + MEBDF2(), IMEXEuler(), IMEXEulerARK()] + + # DAE solvers (DAEProblem) + dae_solvers = [DABDF2(), DImplicitEuler(), DFBDF()] + + # Test SBDF solvers separately with required order parameter and SplitODEProblem + sbdf_solvers = [SBDF(order=2), SBDF(order=3), SBDF(order=4), SBDF2(), SBDF3(), SBDF4()] + + for solver in regular_bdf_solvers + @testset "$(typeof(solver)) type stability" begin + try + @test_opt broken=true init(linear_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(linear_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + + for solver in dae_solvers + @testset "$(typeof(solver)) DAE type stability" begin + try + @test_opt broken=true init(dae_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(dae_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + + for solver in sbdf_solvers + @testset "$(typeof(solver)) type stability" begin + try + @test_opt broken=true init(split_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(split_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + end +end diff --git a/lib/OrdinaryDiffEqBDF/test/qa.jl b/lib/OrdinaryDiffEqBDF/test/qa.jl new file mode 100644 index 0000000000..4898e74998 --- /dev/null +++ b/lib/OrdinaryDiffEqBDF/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqBDF +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqBDF; + ) +end diff --git a/lib/OrdinaryDiffEqBDF/test/runtests.jl b/lib/OrdinaryDiffEqBDF/test/runtests.jl index ef964c7f1a..a52df2b4a2 100644 --- a/lib/OrdinaryDiffEqBDF/test/runtests.jl +++ b/lib/OrdinaryDiffEqBDF/test/runtests.jl @@ -4,3 +4,14 @@ using SafeTestsets @time @safetestset "DAE AD Tests" include("dae_ad_tests.jl") @time @safetestset "DAE Event Tests" include("dae_event.jl") @time @safetestset "DAE Initialization Tests" include("dae_initialization_tests.jl") + +@time @safetestset "BDF Inference Tests" include("inference_tests.jl") +@time @safetestset "BDF Convergence Tests" include("bdf_convergence_tests.jl") +@time @safetestset "BDF Regression Tests" include("bdf_regression_tests.jl") + +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqCore/Project.toml b/lib/OrdinaryDiffEqCore/Project.toml index 274351cdde..0cd0099661 100644 --- a/lib/OrdinaryDiffEqCore/Project.toml +++ b/lib/OrdinaryDiffEqCore/Project.toml @@ -1,86 +1,102 @@ name = "OrdinaryDiffEqCore" uuid = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" authors = ["ParamThakkar123 "] -version = "1.6.1" +version = "1.34.0" [deps] -ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56" -FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" -FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" +SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" FunctionWrappersWrappers = "77dc65aa-8811-40c2-897b-53d922fa7daf" -InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" Preferences = "21216c6a-2e73-6563-6e65-726566657250" +SymbolicIndexingInterface = "2efcf032-c050-4f8e-a9bb-153293bab1f5" +MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" +FastPower = "a4df4552-cc26-4903-aec0-212e50a0e84b" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" -SimpleUnPack = "ce78b400-467f-4804-87d8-8f486da07d0a" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718" -StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" -TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" - -[weakdeps] -EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" +Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" -[extensions] -OrdinaryDiffEqCoreEnzymeCoreExt = "EnzymeCore" +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" [compat] -ADTypes = "0.2, 1" -Adapt = "3.0, 4" -ArrayInterface = "7" -DataStructures = "0.18" -DiffEqBase = "6.147" -DiffEqDevTools = "2.44.4" -DocStringExtensions = "0.9" -EnumX = "1" -FastBroadcast = "0.2, 0.3" -FastClosures = "0.3" -FillArrays = "1.9" +SafeTestsets = "0.1.0" +SciMLOperators = "1.4" +Accessors = "0.1.36" +StaticArraysCore = "1.4.3" +SciMLStructures = "1.7" FunctionWrappersWrappers = "0.1" -InteractiveUtils = "1.9" -LinearAlgebra = "1.9" -Logging = "1.9" -MacroTools = "0.5" -MuladdMacro = "0.2.1" -Polyester = "0.7" -PrecompileTools = "1" -Preferences = "1.3" +FastBroadcast = "0.3" Random = "<0.0.1, 1" -RecursiveArrayTools = "2.36, 3" -Reexport = "1.0" -SafeTestsets = "0.1.0" -SciMLBase = "2.50.4" -SciMLOperators = "0.3" -SciMLStructures = "1" -SimpleUnPack = "1" -Static = "0.8, 1" -StaticArrayInterface = "1.2" -StaticArraysCore = "1.0" +DiffEqDevTools = "2.44.4" Test = "<0.0.1, 1" -TruncatedStacktraces = "1.2" +StaticArrayInterface = "1.8" +EnzymeCore = "0.7, 0.8" +MuladdMacro = "0.2" +PrecompileTools = "1.2" +EnumX = "1.0" +Polyester = "0.7" +LinearAlgebra = "1.10" +TruncatedStacktraces = "1.4" +SimpleUnPack = "1.1" +SciMLBase = "2.115" +FastClosures = "0.3" +DataStructures = "0.18.22, 0.19" +Static = "1.2" +Aqua = "0.8.11" +DocStringExtensions = "0.9" +ArrayInterface = "7.19" +Preferences = "1.4" +SymbolicIndexingInterface = "0.3.31" +MacroTools = "0.5" julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +InteractiveUtils = "1.10" +RecursiveArrayTools = "3.36" +FastPower = "1.1" +Logging = "1.10" +Mooncake = "0.4" +AllocCheck = "0.2" +DiffEqBase = "6.190.2" +FillArrays = "1.13" +Adapt = "4.3" +Reexport = "1.2" -[extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[weakdeps] +Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" +EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[extensions] +OrdinaryDiffEqCoreEnzymeCoreExt = "EnzymeCore" +OrdinaryDiffEqCoreMooncakeExt = "Mooncake" diff --git a/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreEnzymeCoreExt.jl b/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreEnzymeCoreExt.jl index b8bc336b57..20537ea033 100644 --- a/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreEnzymeCoreExt.jl +++ b/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreEnzymeCoreExt.jl @@ -1,20 +1,39 @@ module OrdinaryDiffEqCoreEnzymeCoreExt import OrdinaryDiffEqCore, EnzymeCore -EnzymeCore.EnzymeRules.inactive(::typeof(OrdinaryDiffEqCore.increment_nf!), args...) = true -function EnzymeCore.EnzymeRules.inactive( +function EnzymeCore.EnzymeRules.inactive_noinl( + ::typeof(OrdinaryDiffEqCore.increment_nf!), args...) + true +end +function EnzymeCore.EnzymeRules.inactive_noinl( ::typeof(OrdinaryDiffEqCore.fixed_t_for_floatingpoint_error!), args...) true end -function EnzymeCore.EnzymeRules.inactive( +function EnzymeCore.EnzymeRules.inactive_noinl( ::typeof(OrdinaryDiffEqCore.increment_accept!), args...) true end -function EnzymeCore.EnzymeRules.inactive( +function EnzymeCore.EnzymeRules.inactive_noinl( ::typeof(OrdinaryDiffEqCore.increment_reject!), args...) true end -EnzymeCore.EnzymeRules.inactive(::typeof(OrdinaryDiffEqCore.check_error!), args...) = true -EnzymeCore.EnzymeRules.inactive(::typeof(OrdinaryDiffEqCore.log_step!), args...) = true +function EnzymeCore.EnzymeRules.inactive_noinl( + ::typeof(OrdinaryDiffEqCore.check_error!), args...) + true +end +function EnzymeCore.EnzymeRules.inactive_noinl( + ::typeof(OrdinaryDiffEqCore.log_step!), args...) + true +end + +function EnzymeCore.EnzymeRules.inactive_noinl( + ::typeof(OrdinaryDiffEqCore.final_progress), args...) + true +end + +function EnzymeCore.EnzymeRules.inactive_noinl( + ::typeof(OrdinaryDiffEqCore.ode_determine_initdt), args...) + true +end end diff --git a/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreMooncakeExt.jl b/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreMooncakeExt.jl new file mode 100644 index 0000000000..d328f9516d --- /dev/null +++ b/lib/OrdinaryDiffEqCore/ext/OrdinaryDiffEqCoreMooncakeExt.jl @@ -0,0 +1,15 @@ +module OrdinaryDiffEqCoreMooncakeExt + +using OrdinaryDiffEqCore, Mooncake +using Mooncake: @zero_adjoint, MinimalCtx +Mooncake.@zero_adjoint Mooncake.MinimalCtx Tuple{ + typeof(OrdinaryDiffEqCore.ode_determine_initdt), + Any, Any, Any, Any, Any, Any, Any, Any, Any} +Mooncake.@zero_adjoint Mooncake.MinimalCtx Tuple{ + typeof(OrdinaryDiffEqCore.SciMLBase.check_error), Any} +Mooncake.@zero_adjoint Mooncake.MinimalCtx Tuple{ + typeof(OrdinaryDiffEqCore.fixed_t_for_floatingpoint_error!), Any, Any} +Mooncake.@zero_adjoint Mooncake.MinimalCtx Tuple{ + typeof(OrdinaryDiffEqCore.final_progress), Any} + +end diff --git a/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl b/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl index d3ae689ec0..53e3383b49 100644 --- a/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl +++ b/lib/OrdinaryDiffEqCore/src/OrdinaryDiffEqCore.jl @@ -5,22 +5,30 @@ if isdefined(Base, :Experimental) && @eval Base.Experimental.@max_methods 1 end -using DocStringExtensions -using Reexport -@reexport using DiffEqBase +import DocStringExtensions +import Reexport: @reexport +using Reexport: @reexport +@reexport using SciMLBase +import DiffEqBase -using Logging +import Logging: @logmsg, LogLevel -using MuladdMacro, FastClosures +using MuladdMacro: @muladd -using LinearAlgebra +using LinearAlgebra: opnorm, I, UniformScaling, diag, rank, isdiag -using PrecompileTools +import PrecompileTools import FillArrays: Trues, Falses +import FastPower: fastpower + # Interfaces -import DiffEqBase: solve!, step!, initialize!, isadaptive +import SciMLBase: solve!, step!, isadaptive +import DiffEqBase: initialize! + +# DAE Initialization algorithms +import DiffEqBase: DefaultInit, ShampineCollocationInit, BrownFullBasicInit # Internal utils import DiffEqBase: ODE_DEFAULT_NORM, @@ -34,44 +42,55 @@ import SciMLOperators: AbstractSciMLOperator, AbstractSciMLScalarOperator, using DiffEqBase: DEIntegrator -import RecursiveArrayTools: chain, recursivecopy! +import RecursiveArrayTools: chain, recursivecopy!, recursivecopy, recursive_bottom_eltype, recursive_unitless_bottom_eltype, recursive_unitless_eltype, copyat_or_push!, DiffEqArray, recursivefill! -using SimpleUnPack, RecursiveArrayTools, DataStructures, ArrayInterface +using SimpleUnPack: @unpack +import RecursiveArrayTools +using DataStructures: BinaryHeap, FasterForward +import DataStructures +using ArrayInterface: ArrayInterface, issingular -import TruncatedStacktraces +import TruncatedStacktraces: @truncate_stacktrace, VERBOSE_MSG import StaticArraysCore: SArray, MVector, SVector, StaticArray, MMatrix, StaticMatrix # Integrator Interface -import DiffEqBase: resize!, deleteat!, addat!, full_cache, user_cache, u_cache, du_cache, +import SciMLBase: resize!, deleteat!, addat!, full_cache, user_cache, u_cache, du_cache, resize_non_user_cache!, deleteat_non_user_cache!, addat_non_user_cache!, terminate!, get_du, get_dt, get_proposed_dt, set_proposed_dt!, u_modified!, savevalues!, add_tstop!, has_tstop, first_tstop, pop_tstop!, add_saveat!, set_reltol!, set_abstol!, postamble!, last_step_failed, - isautodifferentiable, - get_tstops, get_tstops_array, get_tstops_max + isautodifferentiable +import DiffEqBase: get_tstops, get_tstops_array, get_tstops_max using DiffEqBase: check_error!, @def, _vec, _reshape using FastBroadcast: @.., True, False -using SciMLBase: NoInit, CheckInit, _unwrap_val +using SciMLBase: NoInit, CheckInit, OverrideInit, AbstractDEProblem, _unwrap_val, + ODEAliasSpecifier -import SciMLBase: alg_order +import SciMLBase: AbstractNonlinearProblem, alg_order, LinearAliasSpecifier +import SciMLBase: unwrap_cache, + islinear import DiffEqBase: calculate_residuals, - calculate_residuals!, unwrap_cache, - @tight_loop_macros, - islinear, timedepentdtmin + calculate_residuals!, @tight_loop_macros, + timedepentdtmin import Polyester -using MacroTools, Adapt -import ADTypes: AutoFiniteDiff, AutoForwardDiff +# MacroTools and Adapt imported but not directly used in OrdinaryDiffEqCore +# using MacroTools, Adapt +import ADTypes: AutoFiniteDiff, AutoForwardDiff, AbstractADType, AutoSparse +import Accessors: @reset + +# SciMLStructures symbols imported but not directly used in OrdinaryDiffEqCore +# using SciMLStructures: canonicalize, Tunable, isscimlstructure -using SciMLStructures: canonicalize, Tunable, isscimlstructure +using SymbolicIndexingInterface: state_values, parameter_values const CompiledFloats = Union{Float32, Float64} import Preferences @@ -109,6 +128,12 @@ const TryAgain = SlowConvergence DEFAULT_PRECS(W, du, u, p, t, newW, Plprev, Prprev, solverdata) = nothing, nothing isdiscretecache(cache) = false +@static if isdefined(DiffEqBase, :unitfulvalue) + unitfulvalue(x) = DiffEqBase.unitfulvalue(x) +else + unitfulvalue(x) = DiffEqBase.ForwardDiff.value(x) +end + include("doc_utils.jl") include("misc_utils.jl") diff --git a/lib/OrdinaryDiffEqCore/src/alg_utils.jl b/lib/OrdinaryDiffEqCore/src/alg_utils.jl index 5d144fcfae..7c33194c17 100644 --- a/lib/OrdinaryDiffEqCore/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqCore/src/alg_utils.jl @@ -17,6 +17,9 @@ end SciMLBase.forwarddiffs_model_time(alg::RosenbrockAlgorithm) = true +SciMLBase.allows_late_binding_tstops(::OrdinaryDiffEqAlgorithm) = true +SciMLBase.allows_late_binding_tstops(::DAEAlgorithm) = true + # isadaptive is defined below. ## OrdinaryDiffEq Internal Traits @@ -168,26 +171,41 @@ end function get_chunksize(alg::OrdinaryDiffEqAlgorithm) error("This algorithm does not have a chunk size defined.") end -function get_chunksize(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS}, - OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS}, - OrdinaryDiffEqImplicitAlgorithm{CS}, - OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS}, - DAEAlgorithm{CS}, - CompositeAlgorithm{CS}}) where {CS} - Val(CS) + +_get_fwd_chunksize(::Type{<:AutoForwardDiff{CS}}) where {CS} = Val(CS) +_get_fwd_chunksize_int(::Type{<:AutoForwardDiff{CS}}) where {CS} = CS +_get_fwd_chunksize(AD) = Val(0) +_get_fwd_chunksize_int(AD) = 0 +_get_fwd_chunksize_int(::AutoForwardDiff{CS}) where {CS} = CS +_get_fwd_tag(::AutoForwardDiff{CS, T}) where {CS, T} = T + +_get_fdtype(::AutoFiniteDiff{T1, T2, T3}) where {T1, T2, T3} = T1 +_get_fdtype(::Type{AutoFiniteDiff{T1,T2,T3}}) where {T1, T2, T3} = T1 + + +function get_chunksize(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS, AD}, + OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS, AD}, + OrdinaryDiffEqImplicitAlgorithm{CS, AD}, + OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD}, + DAEAlgorithm{CS, AD}, + CompositeAlgorithm{CS, AD}}) where {CS, AD} + _get_fwd_chunksize(AD) end function get_chunksize_int(alg::OrdinaryDiffEqAlgorithm) error("This algorithm does not have a chunk size defined.") end -function get_chunksize_int(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS}, + +function get_chunksize_int(alg::Union{ + OrdinaryDiffEqExponentialAlgorithm{CS}, OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS}, - OrdinaryDiffEqImplicitAlgorithm{CS}, - OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS}, - DAEAlgorithm{CS}, - CompositeAlgorithm{CS}}) where {CS} - CS + OrdinaryDiffEqImplicitAlgorithm{CS, AD}, + OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD}, + DAEAlgorithm{CS, AD}, + CompositeAlgorithm{CS, AD}}) where {CS, AD} + _get_fwd_chunksize_int(AD) end + # get_chunksize(alg::CompositeAlgorithm) = get_chunksize(alg.algs[alg.current_alg]) function alg_autodiff end @@ -229,7 +247,7 @@ function alg_difftype(alg::Union{ CJ}, DAEAlgorithm{CS, AD, FDT, ST, CJ}}) where {CS, AD, FDT, ST, CJ} - FDT + _get_fdtype(AD) end function standardtag(alg::Union{ @@ -341,7 +359,7 @@ qsteady_max_default(alg::OrdinaryDiffEqAdaptiveImplicitAlgorithm) = 6 // 5 # But don't re-use Jacobian if not adaptive: too risky and cannot pull back qsteady_max_default(alg::OrdinaryDiffEqImplicitAlgorithm) = isadaptive(alg) ? 1 // 1 : 0 #TODO -#DiffEqBase.nlsolve_default(::QNDF, ::Val{κ}) = 1//2 +#SciMLBase.nlsolve_default(::QNDF, ::Val{κ}) = 1//2 # SSP coefficients @@ -441,3 +459,6 @@ function Base.show(io::IO, ::MIME"text/plain", alg::OrdinaryDiffEqAlgorithm) end print(io, ")") end + +# Defaults in the current system: currently opt out DAEAlgorithms until complete +default_linear_interpolation(alg, prob) = alg isa DAEAlgorithm || prob isa DiscreteProblem \ No newline at end of file diff --git a/lib/OrdinaryDiffEqCore/src/algorithms.jl b/lib/OrdinaryDiffEqCore/src/algorithms.jl index 01c24467a6..5f03844211 100644 --- a/lib/OrdinaryDiffEqCore/src/algorithms.jl +++ b/lib/OrdinaryDiffEqCore/src/algorithms.jl @@ -1,4 +1,4 @@ -abstract type OrdinaryDiffEqAlgorithm <: DiffEqBase.AbstractODEAlgorithm end +abstract type OrdinaryDiffEqAlgorithm <: SciMLBase.AbstractODEAlgorithm end abstract type OrdinaryDiffEqAdaptiveAlgorithm <: OrdinaryDiffEqAlgorithm end abstract type OrdinaryDiffEqCompositeAlgorithm <: OrdinaryDiffEqAlgorithm end @@ -38,7 +38,7 @@ const ExponentialAlgorithm = Union{OrdinaryDiffEqExponentialAlgorithm, abstract type OrdinaryDiffEqAdamsVarOrderVarStepAlgorithm <: OrdinaryDiffEqAdaptiveAlgorithm end # DAE Specific Algorithms -abstract type DAEAlgorithm{CS, AD, FDT, ST, CJ} <: DiffEqBase.AbstractDAEAlgorithm end +abstract type DAEAlgorithm{CS, AD, FDT, ST, CJ} <: SciMLBase.AbstractDAEAlgorithm end # Partitioned ODE Specific Algorithms abstract type OrdinaryDiffEqPartitionedAlgorithm <: OrdinaryDiffEqAlgorithm end @@ -46,12 +46,12 @@ abstract type OrdinaryDiffEqAdaptivePartitionedAlgorithm <: OrdinaryDiffEqAdapti const PartitionedAlgorithm = Union{OrdinaryDiffEqPartitionedAlgorithm, OrdinaryDiffEqAdaptivePartitionedAlgorithm} -function DiffEqBase.remake(thing::OrdinaryDiffEqAlgorithm; kwargs...) +function SciMLBase.remake(thing::OrdinaryDiffEqAlgorithm; kwargs...) T = SciMLBase.remaker_of(thing) T(; SciMLBase.struct_as_namedtuple(thing)..., kwargs...) end -function DiffEqBase.remake( +function SciMLBase.remake( thing::Union{ OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD, FDT, ST, CJ}, @@ -59,9 +59,15 @@ function DiffEqBase.remake( }, DAEAlgorithm{CS, AD, FDT, ST, CJ}}; kwargs...) where {CS, AD, FDT, ST, CJ} + if haskey(kwargs, :autodiff) && kwargs[:autodiff] isa AutoForwardDiff + chunk_size = _get_fwd_chunksize(kwargs[:autodiff]) + else + chunk_size = Val{CS}() + end + T = SciMLBase.remaker_of(thing) T(; SciMLBase.struct_as_namedtuple(thing)..., - chunk_size = Val{CS}(), autodiff = Val{AD}(), standardtag = Val{ST}(), + chunk_size = chunk_size, autodiff = thing.autodiff, standardtag = Val{ST}(), concrete_jac = CJ === nothing ? CJ : Val{CJ}(), kwargs...) end @@ -84,16 +90,30 @@ end ######################################### +""" + CompositeAlgorithm(algs, choice_function) + +A composite algorithm that chooses between multiple ODE solvers based on a user-defined choice function. +This allows for adaptive algorithm switching based on problem characteristics or performance metrics. + +# Arguments + + - `algs`: Tuple or array of ODE algorithms to choose from + - `choice_function`: Function that determines which algorithm to use at each step + +The choice function receives the integrator and should return an index indicating which algorithm to use. +This enables sophisticated algorithm switching strategies based on solution behavior, step size, or other criteria. +""" struct CompositeAlgorithm{CS, T, F} <: OrdinaryDiffEqCompositeAlgorithm algs::T choice_function::F function CompositeAlgorithm(algs::T, choice_function::F) where {T, F} - CS = mapreduce(alg -> has_chunksize(alg) ? get_chunksize_int(alg) : 0, max, algs) + CS = mapreduce(alg -> 0, max, algs) new{CS, T, F}(algs, choice_function) end end -TruncatedStacktraces.@truncate_stacktrace CompositeAlgorithm 1 +@truncate_stacktrace CompositeAlgorithm 1 if isdefined(Base, :Experimental) && isdefined(Base.Experimental, :silence!) Base.Experimental.silence!(CompositeAlgorithm) @@ -142,6 +162,30 @@ mutable struct AutoSwitchCache{nAlg, sAlg, tolType, T} end end +""" + AutoSwitch(nonstiffalg, stiffalg; kwargs...) + +An automatic algorithm switching method that dynamically chooses between a nonstiff and stiff solver +based on the problem's stiffness detection. This provides robust performance across a wide range of problems +without requiring the user to know the problem's stiffness characteristics a priori. + +# Arguments + + - `nonstiffalg`: Algorithm to use for nonstiff regions (default: Tsit5()) + - `stiffalg`: Algorithm to use for stiff regions (default: Rodas5P()) + +# Keywords + + - `maxstiffstep`: Maximum number of consecutive steps before switching from nonstiff to stiff (default: 10) + - `maxnonstiffstep`: Maximum number of consecutive steps before switching from stiff to nonstiff (default: 3) + - `nonstifftol`: Tolerance for detecting nonstiff behavior (default: 3//4) + - `stifftol`: Tolerance for detecting stiff behavior (default: 9//10) + - `dtfac`: Factor for step size adjustment during switches (default: 2.0) + - `stiffalgfirst`: Whether to start with the stiff algorithm (default: false) + - `switch_max`: Maximum number of algorithm switches allowed (default: 10) + +The switching decision is based on step size rejections and stability estimates. +""" struct AutoSwitch{nAlg, sAlg, tolType, T} nonstiffalg::nAlg stiffalg::sAlg diff --git a/lib/OrdinaryDiffEqCore/src/cache_utils.jl b/lib/OrdinaryDiffEqCore/src/cache_utils.jl index 87b7f4a34c..34767ee899 100644 --- a/lib/OrdinaryDiffEqCore/src/cache_utils.jl +++ b/lib/OrdinaryDiffEqCore/src/cache_utils.jl @@ -5,7 +5,7 @@ function is_constant_cache(::DefaultCache{Cache1}) where {Cache1} Cache1 <: OrdinaryDiffEqConstantCache end -function DiffEqBase.unwrap_cache(integrator::ODEIntegrator, is_stiff) +function SciMLBase.unwrap_cache(integrator::ODEIntegrator, is_stiff) alg = integrator.alg cache = integrator.cache iscomp = alg isa CompositeAlgorithm diff --git a/lib/OrdinaryDiffEqCore/src/caches/basic_caches.jl b/lib/OrdinaryDiffEqCore/src/caches/basic_caches.jl index f836d61b9b..5b97865624 100644 --- a/lib/OrdinaryDiffEqCore/src/caches/basic_caches.jl +++ b/lib/OrdinaryDiffEqCore/src/caches/basic_caches.jl @@ -1,4 +1,4 @@ -abstract type OrdinaryDiffEqCache <: DiffEqBase.DECache end +abstract type OrdinaryDiffEqCache <: SciMLBase.DECache end abstract type OrdinaryDiffEqConstantCache <: OrdinaryDiffEqCache end abstract type OrdinaryDiffEqMutableCache <: OrdinaryDiffEqCache end struct ODEEmptyCache <: OrdinaryDiffEqConstantCache end @@ -73,7 +73,8 @@ function alg_cache(alg::CompositeAlgorithm{CS, Tuple{A1, A2, A3, A4, A5, A6}}, u args = (u, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, uprev, uprev2, f, t, dt, reltol, p, calck, Val(V)) - argT = map(typeof, args) + # Core.Typeof to turn uEltypeNoUnits into Type{uEltypeNoUnits} rather than DataType + argT = map(Core.Typeof, args) T1 = Base.promote_op(alg_cache, A1, argT...) T2 = Base.promote_op(alg_cache, A2, argT...) T3 = Base.promote_op(alg_cache, A3, argT...) @@ -121,5 +122,5 @@ end alg_cache(alg::OrdinaryDiffEqAlgorithm, prob, callback::F) where {F} = ODEEmptyCache() -get_chunksize(cache::DiffEqBase.DECache) = error("This cache does not have a chunksize.") +get_chunksize(cache::SciMLBase.DECache) = error("This cache does not have a chunksize.") get_chunksize(cache::ODEChunkCache{CS}) where {CS} = CS diff --git a/lib/OrdinaryDiffEqCore/src/dense/generic_dense.jl b/lib/OrdinaryDiffEqCore/src/dense/generic_dense.jl index f8dfa068e2..7a6bfb5fbf 100644 --- a/lib/OrdinaryDiffEqCore/src/dense/generic_dense.jl +++ b/lib/OrdinaryDiffEqCore/src/dense/generic_dense.jl @@ -127,12 +127,12 @@ end end return nothing end -@inline function DiffEqBase.addsteps!(integrator::ODEIntegrator, args...) +@inline function SciMLBase.addsteps!(integrator::ODEIntegrator, args...) ode_addsteps!(integrator, args...) end -@inline function ode_interpolant(Θ, integrator::DiffEqBase.DEIntegrator, idxs, deriv) - DiffEqBase.addsteps!(integrator) +@inline function ode_interpolant(Θ, integrator::SciMLBase.DEIntegrator, idxs, deriv) + SciMLBase.addsteps!(integrator) if integrator.cache isa CompositeCache val = composite_ode_interpolant(Θ, integrator, integrator.cache.caches, integrator.cache.current, idxs, deriv) @@ -168,10 +168,12 @@ function default_ode_interpolant( return ode_interpolant(Θ, integrator.dt, integrator.uprev, integrator.u, integrator.k, cache.cache5, idxs, deriv, integrator.differential_vars) - else # alg_choice == 6 + elseif alg_choice == 6 return ode_interpolant(Θ, integrator.dt, integrator.uprev, integrator.u, integrator.k, cache.cache6, idxs, deriv, integrator.differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end end @@ -195,8 +197,8 @@ end return expr end -@inline function ode_interpolant!(val, Θ, integrator::DiffEqBase.DEIntegrator, idxs, deriv) - DiffEqBase.addsteps!(integrator) +@inline function ode_interpolant!(val, Θ, integrator::SciMLBase.DEIntegrator, idxs, deriv) + SciMLBase.addsteps!(integrator) if integrator.cache isa CompositeCache ode_interpolant!(val, Θ, integrator.dt, integrator.uprev, integrator.u, integrator.k, integrator.cache.caches[integrator.cache.current], @@ -227,6 +229,8 @@ end ode_interpolant!(val, Θ, integrator.dt, integrator.uprev, integrator.u, integrator.k, integrator.cache.cache6, idxs, deriv, integrator.differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end else ode_interpolant!(val, Θ, integrator.dt, integrator.uprev, integrator.u, @@ -256,10 +260,12 @@ function default_ode_interpolant!( return ode_interpolant!(val, Θ, integrator.dt, integrator.uprev, integrator.u, integrator.k, cache.cache5, idxs, deriv, integrator.differential_vars) - else # alg_choice == 6 + elseif alg_choice == 6 return ode_interpolant!(val, Θ, integrator.dt, integrator.uprev, integrator.u, integrator.k, cache.cache6, idxs, deriv, integrator.differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end end @@ -284,30 +290,30 @@ end return expr end -@inline function current_interpolant(t::Number, integrator::DiffEqBase.DEIntegrator, idxs, +@inline function current_interpolant(t::Number, integrator::SciMLBase.DEIntegrator, idxs, deriv) Θ = (t - integrator.tprev) / integrator.dt ode_interpolant(Θ, integrator, idxs, deriv) end -@inline function current_interpolant(t, integrator::DiffEqBase.DEIntegrator, idxs, deriv) +@inline function current_interpolant(t, integrator::SciMLBase.DEIntegrator, idxs, deriv) Θ = (t .- integrator.tprev) ./ integrator.dt [ode_interpolant(ϕ, integrator, idxs, deriv) for ϕ in Θ] end -@inline function current_interpolant!(val, t::Number, integrator::DiffEqBase.DEIntegrator, +@inline function current_interpolant!(val, t::Number, integrator::SciMLBase.DEIntegrator, idxs, deriv) Θ = (t - integrator.tprev) / integrator.dt ode_interpolant!(val, Θ, integrator, idxs, deriv) end -@inline function current_interpolant!(val, t, integrator::DiffEqBase.DEIntegrator, idxs, +@inline function current_interpolant!(val, t, integrator::SciMLBase.DEIntegrator, idxs, deriv) Θ = (t .- integrator.tprev) ./ integrator.dt [ode_interpolant!(val, ϕ, integrator, idxs, deriv) for ϕ in Θ] end -@inline function current_interpolant!(val, t::Array, integrator::DiffEqBase.DEIntegrator, +@inline function current_interpolant!(val, t::Array, integrator::SciMLBase.DEIntegrator, idxs, deriv) Θ = similar(t) @inbounds @simd ivdep for i in eachindex(t) @@ -316,32 +322,32 @@ end [ode_interpolant!(val, ϕ, integrator, idxs, deriv) for ϕ in Θ] end -@inline function current_extrapolant(t::Number, integrator::DiffEqBase.DEIntegrator, +@inline function current_extrapolant(t::Number, integrator::SciMLBase.DEIntegrator, idxs = nothing, deriv = Val{0}) Θ = (t - integrator.tprev) / (integrator.t - integrator.tprev) ode_extrapolant(Θ, integrator, idxs, deriv) end -@inline function current_extrapolant!(val, t::Number, integrator::DiffEqBase.DEIntegrator, +@inline function current_extrapolant!(val, t::Number, integrator::SciMLBase.DEIntegrator, idxs = nothing, deriv = Val{0}) Θ = (t - integrator.tprev) / (integrator.t - integrator.tprev) ode_extrapolant!(val, Θ, integrator, idxs, deriv) end -@inline function current_extrapolant(t::AbstractArray, integrator::DiffEqBase.DEIntegrator, +@inline function current_extrapolant(t::AbstractArray, integrator::SciMLBase.DEIntegrator, idxs = nothing, deriv = Val{0}) Θ = (t .- integrator.tprev) ./ (integrator.t - integrator.tprev) [ode_extrapolant(ϕ, integrator, idxs, deriv) for ϕ in Θ] end -@inline function current_extrapolant!(val, t, integrator::DiffEqBase.DEIntegrator, +@inline function current_extrapolant!(val, t, integrator::SciMLBase.DEIntegrator, idxs = nothing, deriv = Val{0}) Θ = (t .- integrator.tprev) ./ (integrator.t - integrator.tprev) [ode_extrapolant!(val, ϕ, integrator, idxs, deriv) for ϕ in Θ] end -@inline function ode_extrapolant!(val, Θ, integrator::DiffEqBase.DEIntegrator, idxs, deriv) - DiffEqBase.addsteps!(integrator) +@inline function ode_extrapolant!(val, Θ, integrator::SciMLBase.DEIntegrator, idxs, deriv) + SciMLBase.addsteps!(integrator) if integrator.cache isa CompositeCache composite_ode_extrapolant!(val, Θ, integrator, integrator.cache.caches, integrator.cache.current, idxs, deriv) @@ -380,6 +386,8 @@ function default_ode_extrapolant!( ode_interpolant!(val, Θ, integrator.t - integrator.tprev, integrator.uprev2, integrator.uprev, integrator.k, cache.cache6, idxs, deriv, integrator.differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end end @@ -404,8 +412,8 @@ end return expr end -@inline function ode_extrapolant(Θ, integrator::DiffEqBase.DEIntegrator, idxs, deriv) - DiffEqBase.addsteps!(integrator) +@inline function ode_extrapolant(Θ, integrator::SciMLBase.DEIntegrator, idxs, deriv) + SciMLBase.addsteps!(integrator) if integrator.cache isa CompositeCache composite_ode_extrapolant(Θ, integrator, integrator.cache.caches, integrator.cache.current, idxs, deriv) @@ -444,6 +452,8 @@ function default_ode_extrapolant( ode_interpolant(Θ, integrator.t - integrator.tprev, integrator.uprev2, integrator.uprev, integrator.k, cache.cache6, idxs, deriv, integrator.differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end end @@ -467,17 +477,17 @@ end return expr end -function _evaluate_interpolant(f, Θ, dt, timeseries, i₋, i₊, +function _evaluate_interpolant(f::F, Θ, dt, timeseries, i₋, i₊, cache, idxs, - deriv, ks, ts, p, differential_vars) + deriv, ks, ts, p, differential_vars) where F _ode_addsteps!(ks[i₊], ts[i₋], timeseries[i₋], timeseries[i₊], dt, f, p, cache) # update the kcurrent return ode_interpolant(Θ, dt, timeseries[i₋], timeseries[i₊], ks[i₊], cache, idxs, deriv, differential_vars) end -function evaluate_composite_cache(f, Θ, dt, timeseries, i₋, i₊, +function evaluate_composite_cache(f::F, Θ, dt, timeseries, i₋, i₊, caches::Tuple{C1, C2, Vararg}, idxs, - deriv, ks, ts, p, cacheid, differential_vars) where {C1, C2} + deriv, ks, ts, p, cacheid, differential_vars) where {F, C1, C2} if (cacheid -= 1) != 0 return evaluate_composite_cache(f, Θ, dt, timeseries, i₋, i₊, Base.tail(caches), idxs, @@ -487,16 +497,16 @@ function evaluate_composite_cache(f, Θ, dt, timeseries, i₋, i₊, first(caches), idxs, deriv, ks, ts, p, differential_vars) end -function evaluate_composite_cache(f, Θ, dt, timeseries, i₋, i₊, +function evaluate_composite_cache(f::F, Θ, dt, timeseries, i₋, i₊, caches::Tuple{C}, idxs, - deriv, ks, ts, p, _, differential_vars) where {C} + deriv, ks, ts, p, _, differential_vars) where {F, C} _evaluate_interpolant(f, Θ, dt, timeseries, i₋, i₊, only(caches), idxs, deriv, ks, ts, p, differential_vars) end -function evaluate_default_cache(f, Θ, dt, timeseries, i₋, i₊, - cache::DefaultCache, idxs, deriv, ks, ts, p, cacheid, differential_vars) +function evaluate_default_cache(f::F, Θ, dt, timeseries, i₋, i₊, + cache::DefaultCache, idxs, deriv, ks, ts, p, cacheid, differential_vars) where F if cacheid == 1 return _evaluate_interpolant(f, Θ, dt, timeseries, i₋, i₊, cache.cache1, idxs, deriv, ks, ts, p, differential_vars) @@ -518,8 +528,8 @@ function evaluate_default_cache(f, Θ, dt, timeseries, i₋, i₊, end end -function evaluate_interpolant(f, Θ, dt, timeseries, i₋, i₊, cache, idxs, - deriv, ks, ts, id, p, differential_vars) +function evaluate_interpolant(f::F, Θ, dt, timeseries, i₋, i₊, cache, idxs, + deriv, ks, ts, id, p, differential_vars) where F if isdiscretecache(cache) return ode_interpolant(Θ, dt, timeseries[i₋], timeseries[i₊], 0, cache, idxs, deriv, differential_vars) @@ -543,8 +553,8 @@ ode_interpolation(tvals,ts,timeseries,ks) Get the value at tvals where the solution is known at the times ts (sorted), with values timeseries and derivatives ks """ -function ode_interpolation(tvals, id::I, idxs, deriv::D, p, - continuity::Symbol = :left) where {I, D} +function ode_interpolation(tvals, id::I, idxs, ::Type{deriv}, p, + continuity::Symbol = :left) where {I, deriv} @unpack ts, timeseries, ks, f, cache, differential_vars = id @inbounds tdir = sign(ts[end] - ts[1]) idx = sortperm(tvals, rev = tdir < 0) @@ -581,8 +591,8 @@ ode_interpolation(tvals,ts,timeseries,ks) Get the value at tvals where the solution is known at the times ts (sorted), with values timeseries and derivatives ks """ -function ode_interpolation!(vals, tvals, id::I, idxs, deriv::D, p, - continuity::Symbol = :left) where {I, D} +function ode_interpolation!(vals, tvals, id::I, idxs, ::Type{deriv}, p, + continuity::Symbol = :left) where {I, deriv} @unpack ts, timeseries, ks, f, cache, differential_vars = id @inbounds tdir = sign(ts[end] - ts[1]) idx = sortperm(tvals, rev = tdir < 0) @@ -746,8 +756,8 @@ ode_interpolation(tval::Number,ts,timeseries,ks) Get the value at tval where the solution is known at the times ts (sorted), with values timeseries and derivatives ks """ -function ode_interpolation(tval::Number, id::I, idxs, deriv::D, p, - continuity::Symbol = :left) where {I, D} +function ode_interpolation(tval::Number, id::I, idxs, ::Type{deriv}, p, + continuity::Symbol = :left) where {I, deriv} @unpack ts, timeseries, ks, f, cache, differential_vars = id @inbounds tdir = sign(ts[end] - ts[1]) @@ -810,6 +820,8 @@ function ode_interpolation(tval::Number, id::I, idxs, deriv::D, p, cache.cache6) # update the kcurrent val = ode_interpolant(Θ, dt, timeseries[i₋], timeseries[i₊], ks[i₊], cache.cache6, idxs, deriv, differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end else _ode_addsteps!(ks[i₊], ts[i₋], timeseries[i₋], timeseries[i₊], dt, f, p, @@ -828,8 +840,8 @@ ode_interpolation!(out,tval::Number,ts,timeseries,ks) Get the value at tval where the solution is known at the times ts (sorted), with values timeseries and derivatives ks """ -function ode_interpolation!(out, tval::Number, id::I, idxs, deriv::D, p, - continuity::Symbol = :left) where {I, D} +function ode_interpolation!(out, tval::Number, id::I, idxs, ::Type{deriv}, p, + continuity::Symbol = :left) where {I, deriv} @unpack ts, timeseries, ks, f, cache, differential_vars = id @inbounds tdir = sign(ts[end] - ts[1]) @@ -892,6 +904,8 @@ function ode_interpolation!(out, tval::Number, id::I, idxs, deriv::D, p, cache.cache6) # update the kcurrent ode_interpolant!(out, Θ, dt, timeseries[i₋], timeseries[i₊], ks[i₊], cache.cache6, idxs, deriv, differential_vars) + else + error("DefaultCache invalid alg_choice. File an issue.") end else _ode_addsteps!(ks[i₊], ts[i₋], timeseries[i₋], timeseries[i₊], dt, f, p, @@ -1037,11 +1051,11 @@ end #@.. broadcast=false (1-Θ)*y₀+Θ*y₁+Θ*(Θ-1)*((1-2Θ)*(y₁-y₀)+(Θ-1)*dt*k[1] + Θ*dt*k[2]) if all(differential_vars) @inbounds @.. broadcast=false (1 - Θ)*y₀+Θ*y₁+ - Θ*(Θ-1)* + Θ * (Θ-1) * ((1 - 2Θ)*(y₁ - y₀)+(Θ-1)*dt*k[1]+Θ*dt*k[2]) else @inbounds @.. broadcast=false (1 - Θ)*y₀+Θ*y₁+ - differential_vars*Θ*(Θ-1)* + differential_vars * Θ * (Θ-1) * ((1 - 2Θ)*(y₁ - y₀)+(Θ-1)*dt*k[1]+Θ*dt*k[2]) end end @@ -1075,15 +1089,15 @@ end @muladd function hermite_interpolant!( out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{0}}, differential_vars) if all(differential_vars) - @inbounds @.. broadcast=false out=(1 - Θ) * y₀ + Θ * y₁ + - Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁ - y₀) + (Θ - 1) * dt * k[1] + - Θ * dt * k[2]) + @inbounds @.. broadcast=false out=(1-Θ)*y₀+Θ*y₁+ + Θ*(Θ-1)* + ((1-2Θ)*(y₁-y₀)+(Θ-1)*dt*k[1]+ + Θ*dt*k[2]) else - @inbounds @.. broadcast=false out=(1 - Θ) * y₀ + Θ * y₁ + - differential_vars * Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁ - y₀) + (Θ - 1) * dt * k[1] + - Θ * dt * k[2]) + @inbounds @.. broadcast=false out=(1-Θ)*y₀+Θ*y₁+ + differential_vars*Θ*(Θ-1)* + ((1-2Θ)*(y₁-y₀)+(Θ-1)*dt*k[1]+ + Θ*dt*k[2]) end out end @@ -1101,15 +1115,15 @@ end @muladd function hermite_interpolant!( out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{0}}, differential_vars) if all(differential_vars) - @views @.. broadcast=false out=(1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + - Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + - (Θ - 1) * dt * k[1][idxs] + Θ * dt * k[2][idxs]) + @views @.. broadcast=false out=(1-Θ)*y₀[idxs]+Θ*y₁[idxs]+ + Θ*(Θ-1)* + ((1-2Θ)*(y₁[idxs]-y₀[idxs])+ + (Θ-1)*dt*k[1][idxs]+Θ*dt*k[2][idxs]) else - @views @.. broadcast=false out=(1 - Θ) * y₀[idxs] + Θ * y₁[idxs] + - differential_vars * Θ * (Θ - 1) * - ((1 - 2Θ) * (y₁[idxs] - y₀[idxs]) + - (Θ - 1) * dt * k[1][idxs] + Θ * dt * k[2][idxs]) + @views @.. broadcast=false out=(1-Θ)*y₀[idxs]+Θ*y₁[idxs]+ + differential_vars*Θ*(Θ-1)* + ((1-2Θ)*(y₁[idxs]-y₀[idxs])+ + (Θ-1)*dt*k[1][idxs]+Θ*dt*k[2][idxs]) end out end @@ -1189,19 +1203,19 @@ end out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{1}}, differential_vars) if all(differential_vars) @inbounds @.. broadcast=false out=( - k[1] + - Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + - 6 * y₁) / dt) + k[1]+ + Θ*(-4*dt*k[1]-2*dt*k[2]-6*y₀+ + Θ* + (3*dt*k[1]+3*dt*k[2]+6*y₀-6*y₁)+ + 6*y₁)/dt) else - @inbounds @.. broadcast=false out=!differential_vars * ((y₁ - y₀) / dt) + - differential_vars * ( - k[1] + - Θ * (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (3 * dt * k[1] + 3 * dt * k[2] + 6 * y₀ - 6 * y₁) + - 6 * y₁) / dt) + @inbounds @.. broadcast=false out=!differential_vars*((y₁-y₀)/dt)+ + differential_vars*( + k[1]+ + Θ*(-4*dt*k[1]-2*dt*k[2]-6*y₀+ + Θ* + (3*dt*k[1]+3*dt*k[2]+6*y₀-6*y₁)+ + 6*y₁)/dt) end out end @@ -1223,19 +1237,19 @@ end out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{1}}, differential_vars) if all(differential_vars) @views @.. broadcast=false out=( - k[1][idxs] + - Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - - 6 * y₀[idxs] + - Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + - 6 * y₀[idxs] - 6 * y₁[idxs]) + 6 * y₁[idxs]) / dt) + k[1][idxs]+ + Θ*(-4*dt*k[1][idxs]-2*dt*k[2][idxs]- + 6*y₀[idxs]+ + Θ*(3*dt*k[1][idxs]+3*dt*k[2][idxs]+ + 6*y₀[idxs]-6*y₁[idxs])+6*y₁[idxs])/dt) else - @views @.. broadcast=false out=!differential_vars * ((y₁ - y₀) / dt) + - differential_vars * ( - k[1][idxs] + - Θ * (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - - 6 * y₀[idxs] + - Θ * (3 * dt * k[1][idxs] + 3 * dt * k[2][idxs] + - 6 * y₀[idxs] - 6 * y₁[idxs]) + 6 * y₁[idxs]) / dt) + @views @.. broadcast=false out=!differential_vars*((y₁-y₀)/dt)+ + differential_vars*( + k[1][idxs]+ + Θ*(-4*dt*k[1][idxs]-2*dt*k[2][idxs]- + 6*y₀[idxs]+ + Θ*(3*dt*k[1][idxs]+3*dt*k[2][idxs]+ + 6*y₀[idxs]-6*y₁[idxs])+6*y₁[idxs])/dt) end end @@ -1291,10 +1305,7 @@ end Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / (dt * dt) else - @views out = differential_vars .* - (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + - Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - - 12 * y₁[idxs]) + 6 * y₁[idxs]) / (dt * dt) + @views out = differential_vars .* (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - 6 * y₀[idxs] + Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / (dt * dt) end out end @@ -1302,18 +1313,18 @@ end @muladd function hermite_interpolant!( out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{2}}, differential_vars) if all(differential_vars) - @inbounds @.. broadcast=false out=(-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - - 12 * y₁) + - 6 * y₁) / (dt * dt) + @inbounds @.. broadcast=false out=(-4*dt*k[1]-2*dt*k[2]-6*y₀+ + Θ* + (6*dt*k[1]+6*dt*k[2]+12*y₀- + 12*y₁)+ + 6*y₁)/(dt*dt) else - @inbounds @.. broadcast=false out=differential_vars * - (-4 * dt * k[1] - 2 * dt * k[2] - 6 * y₀ + - Θ * - (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - - 12 * y₁) + - 6 * y₁) / (dt * dt) + @inbounds @.. broadcast=false out=differential_vars* + (-4*dt*k[1]-2*dt*k[2]-6*y₀+ + Θ* + (6*dt*k[1]+6*dt*k[2]+12*y₀- + 12*y₁)+ + 6*y₁)/(dt*dt) end out end @@ -1332,18 +1343,18 @@ end @muladd function hermite_interpolant!( out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{2}}, differential_vars) if all(differential_vars) - @views @.. broadcast=false out=(-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - - 6 * y₀[idxs] + - Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + - 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / - (dt * dt) + @views @.. broadcast=false out=(-4*dt*k[1][idxs]-2*dt*k[2][idxs]- + 6*y₀[idxs]+ + Θ*(6*dt*k[1][idxs]+6*dt*k[2][idxs]+ + 12*y₀[idxs]-12*y₁[idxs])+6*y₁[idxs])/ + (dt*dt) else - @views @.. broadcast=false out=differential_vars * - (-4 * dt * k[1][idxs] - 2 * dt * k[2][idxs] - - 6 * y₀[idxs] + - Θ * (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + - 12 * y₀[idxs] - 12 * y₁[idxs]) + 6 * y₁[idxs]) / - (dt * dt) + @views @.. broadcast=false out=differential_vars* + (-4*dt*k[1][idxs]-2*dt*k[2][idxs]- + 6*y₀[idxs]+ + Θ*(6*dt*k[1][idxs]+6*dt*k[2][idxs]+ + 12*y₀[idxs]-12*y₁[idxs])+6*y₁[idxs])/ + (dt*dt) end out end @@ -1396,10 +1407,7 @@ end 12 * y₁[idxs]) / (dt * dt * dt) else - @views out = differential_vars .* - (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - - 12 * y₁[idxs]) / - (dt * dt * dt) + @views out = differential_vars .* (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + 12 * y₀[idxs] - 12 * y₁[idxs]) / (dt * dt * dt) end out end @@ -1407,14 +1415,14 @@ end @muladd function hermite_interpolant!( out, Θ, dt, y₀, y₁, k, idxs::Nothing, T::Type{Val{3}}, differential_vars) if all(differential_vars) - @inbounds @.. broadcast=false out=(6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - - 12 * y₁) / - (dt * dt * dt) + @inbounds @.. broadcast=false out=(6*dt*k[1]+6*dt*k[2]+12*y₀- + 12*y₁)/ + (dt*dt*dt) else - @inbounds @.. broadcast=false out=differential_vars * - (6 * dt * k[1] + 6 * dt * k[2] + 12 * y₀ - - 12 * y₁) / - (dt * dt * dt) + @inbounds @.. broadcast=false out=differential_vars* + (6*dt*k[1]+6*dt*k[2]+12*y₀- + 12*y₁)/ + (dt*dt*dt) end out end @@ -1432,12 +1440,12 @@ end @muladd function hermite_interpolant!( out, Θ, dt, y₀, y₁, k, idxs, T::Type{Val{3}}, differential_vars) if all(differential_vars) - @views @.. broadcast=false out=(6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + - 12 * y₀[idxs] - 12 * y₁[idxs]) / (dt * dt * dt) + @views @.. broadcast=false out=(6*dt*k[1][idxs]+6*dt*k[2][idxs]+ + 12*y₀[idxs]-12*y₁[idxs])/(dt*dt*dt) else - @views @.. broadcast=false out=differential_vars * - (6 * dt * k[1][idxs] + 6 * dt * k[2][idxs] + - 12 * y₀[idxs] - 12 * y₁[idxs]) / (dt * dt * dt) + @views @.. broadcast=false out=differential_vars* + (6*dt*k[1][idxs]+6*dt*k[2][idxs]+ + 12*y₀[idxs]-12*y₁[idxs])/(dt*dt*dt) end out end @@ -1467,13 +1475,13 @@ end @muladd @inline function linear_interpolant!(out, Θ, dt, y₀, y₁, idxs::Nothing, T::Type{Val{0}}) Θm1 = (1 - Θ) - @.. broadcast=false out=Θm1 * y₀ + Θ * y₁ + @.. broadcast=false out=Θm1*y₀+Θ*y₁ out end @muladd @inline function linear_interpolant!(out, Θ, dt, y₀, y₁, idxs, T::Type{Val{0}}) Θm1 = (1 - Θ) - @views @.. broadcast=false out=Θm1 * y₀[idxs] + Θ * y₁[idxs] + @views @.. broadcast=false out=Θm1*y₀[idxs]+Θ*y₁[idxs] out end @@ -1489,11 +1497,11 @@ end end @inline function linear_interpolant!(out, Θ, dt, y₀, y₁, idxs::Nothing, T::Type{Val{1}}) - @.. broadcast=false out=(y₁ - y₀) / dt + @.. broadcast=false out=(y₁-y₀)/dt out end @inline function linear_interpolant!(out, Θ, dt, y₀, y₁, idxs, T::Type{Val{1}}) - @views @.. broadcast=false out=(y₁[idxs] - y₀[idxs]) / dt + @views @.. broadcast=false out=(y₁[idxs]-y₀[idxs])/dt out end diff --git a/lib/OrdinaryDiffEqCore/src/doc_utils.jl b/lib/OrdinaryDiffEqCore/src/doc_utils.jl index 75eb00dc7d..44872a3585 100644 --- a/lib/OrdinaryDiffEqCore/src/doc_utils.jl +++ b/lib/OrdinaryDiffEqCore/src/doc_utils.jl @@ -82,7 +82,7 @@ function differentiation_rk_docstring(description::String, extra_keyword_default::String = "") keyword_default = """ chunk_size = Val{0}(), - autodiff = true, + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, diff_type = Val{:forward}, @@ -91,12 +91,14 @@ function differentiation_rk_docstring(description::String, """ * extra_keyword_default keyword_default_description = """ - - `chunk_size`: The chunk size used with ForwardDiff.jl. Defaults to `Val{0}()` - and thus uses the internal ForwardDiff.jl algorithm for the choice. - - `autodiff`: Specifies whether to use automatic differentiation via + - `autodiff`: Uses [ADTypes.jl](https://sciml.github.io/ADTypes.jl/stable/) + to specify whether to use automatic differentiation via [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) or finite - differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). - Defaults to `Val{true}()` for automatic differentiation. + differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). + Defaults to `AutoForwardDiff()` for automatic differentiation, which by default uses + `chunksize = 0`, and thus uses the internal ForwardDiff.jl algorithm for the choice. + To use `FiniteDiff.jl`, the `AutoFiniteDiff()` ADType can be used, which has a keyword argument + `fdtype` with default value `Val{:forward}()`, and alternatives `Val{:central}()` and `Val{:complex}()`. - `standardtag`: Specifies whether to use package-specific tags instead of the ForwardDiff default function-specific tags. For more information, see [this blog post](https://www.stochasticlifestyle.com/improved-forwarddiff-jl-stacktraces-with-package-tags/). @@ -104,9 +106,6 @@ function differentiation_rk_docstring(description::String, - `concrete_jac`: Specifies whether a Jacobian should be constructed. Defaults to `nothing`, which means it will be chosen true/false depending on circumstances of the solver, such as whether a Krylov subspace method is used for `linsolve`. - - `diff_type`: The type of differentiation used in FiniteDiff.jl if `autodiff=false`. - Defaults to `Val{:forward}`, with alternatives of `Val{:central}` and - `Val{:complex}`. - `linsolve`: Any [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl) compatible linear solver. For example, to use [KLU.jl](https://github.com/JuliaSparse/KLU.jl), specify `$name(linsolve = KLUFactorization()`). diff --git a/lib/OrdinaryDiffEqCore/src/initdt.jl b/lib/OrdinaryDiffEqCore/src/initdt.jl index 96d1fe3e17..991ed87ac9 100644 --- a/lib/OrdinaryDiffEqCore/src/initdt.jl +++ b/lib/OrdinaryDiffEqCore/src/initdt.jl @@ -1,5 +1,5 @@ @muladd function ode_determine_initdt(u0, t, tdir, dtmax, abstol, reltol, internalnorm, - prob::DiffEqBase.AbstractODEProblem{uType, tType, true + prob::SciMLBase.AbstractODEProblem{uType, tType, true }, integrator) where {tType, uType} _tType = eltype(tType) @@ -8,8 +8,8 @@ oneunit_tType = oneunit(_tType) dtmax_tdir = tdir * dtmax - dtmin = nextfloat(integrator.opts.dtmin) - smalldt = convert(_tType, oneunit_tType * 1 // 10^(6)) + dtmin = nextfloat(max(integrator.opts.dtmin, eps(t))) + smalldt = max(dtmin, convert(_tType, oneunit_tType * 1 // 10^(6))) if integrator.isdae return tdir * max(smalldt, dtmin) @@ -23,7 +23,7 @@ sk[i] = abstol + internalnorm(u0[i], t) * reltol end else - @.. broadcast=false sk=abstol + internalnorm(u0, t) * reltol + @.. broadcast=false sk=abstol+internalnorm(u0, t)*reltol end else if u0 isa Array && abstol isa Number && reltol isa Number @@ -119,7 +119,7 @@ tmp[i] = f₀[i] / sk[i] * oneunit_tType end else - @.. broadcast=false tmp=f₀ / sk * oneunit_tType + @.. broadcast=false tmp=f₀/sk*oneunit_tType end d₁ = internalnorm(tmp, t) @@ -127,8 +127,11 @@ # Better than checking any(x->any(isnan, x), f₀) # because it also checks if partials are NaN # https://discourse.julialang.org/t/incorporating-forcing-functions-in-the-ode-model/70133/26 - if integrator.opts.verbose && isnan(d₁) - @warn("First function call produced NaNs. Exiting. Double check that none of the initial conditions, parameters, or timespan values are NaN.") + if isnan(d₁) + if integrator.opts.verbose + @warn("First function call produced NaNs. Exiting. Double check that none of the initial conditions, parameters, or timespan values are NaN.") + end + return tdir * dtmin end @@ -159,7 +162,7 @@ u₁[i] = u0[i] + dt₀_tdir * f₀[i] end else - @.. broadcast=false u₁=u0 + dt₀_tdir * f₀ + @.. broadcast=false u₁=u0+dt₀_tdir*f₀ end f₁ = zero(f₀) f(f₁, u₁, p, t + dt₀_tdir) @@ -180,7 +183,7 @@ tmp[i] = (f₁[i] - f₀[i]) / sk[i] * oneunit_tType end else - @.. broadcast=false tmp=(f₁ - f₀) / sk * oneunit_tType + @.. broadcast=false tmp=(f₁-f₀)/sk*oneunit_tType end d₂ = internalnorm(tmp, t) / dt₀ * oneunit_tType @@ -226,7 +229,7 @@ function Base.showerror(io::IO, e::TypeNotConstantError) end @muladd function ode_determine_initdt(u0, t, tdir, dtmax, abstol, reltol, internalnorm, - prob::DiffEqBase.AbstractODEProblem{uType, tType, + prob::SciMLBase.AbstractODEProblem{uType, tType, false}, integrator) where {uType, tType} _tType = eltype(tType) @@ -235,8 +238,8 @@ end oneunit_tType = oneunit(_tType) dtmax_tdir = tdir * dtmax - dtmin = nextfloat(integrator.opts.dtmin) - smalldt = convert(_tType, oneunit_tType * 1 // 10^(6)) + dtmin = nextfloat(max(integrator.opts.dtmin, eps(t))) + smalldt = max(dtmin, convert(_tType, oneunit_tType * 1 // 10^(6))) if integrator.isdae return tdir * max(smalldt, dtmin) @@ -288,7 +291,7 @@ end end @inline function ode_determine_initdt(u0, t, tdir, dtmax, abstol, reltol, internalnorm, - prob::DiffEqBase.AbstractDAEProblem{duType, uType, + prob::SciMLBase.AbstractDAEProblem{duType, uType, tType}, integrator) where {duType, uType, tType} _tType = eltype(tType) diff --git a/lib/OrdinaryDiffEqCore/src/initialize_dae.jl b/lib/OrdinaryDiffEqCore/src/initialize_dae.jl index c352cb3ddf..f3d2ff90ad 100644 --- a/lib/OrdinaryDiffEqCore/src/initialize_dae.jl +++ b/lib/OrdinaryDiffEqCore/src/initialize_dae.jl @@ -1,35 +1,3 @@ -struct DefaultInit <: DiffEqBase.DAEInitializationAlgorithm end - -struct ShampineCollocationInit{T, F} <: DiffEqBase.DAEInitializationAlgorithm - initdt::T - nlsolve::F -end -function ShampineCollocationInit(; initdt = nothing, nlsolve = nothing) - ShampineCollocationInit(initdt, nlsolve) -end -function ShampineCollocationInit(initdt) - ShampineCollocationInit(; initdt = initdt, nlsolve = nothing) -end - -struct BrownFullBasicInit{T, F} <: DiffEqBase.DAEInitializationAlgorithm - abstol::T - nlsolve::F -end -function BrownFullBasicInit(; abstol = 1e-10, nlsolve = nothing) - BrownFullBasicInit(abstol, nlsolve) -end -BrownFullBasicInit(abstol) = BrownFullBasicInit(; abstol = abstol, nlsolve = nothing) - -struct OverrideInit{T, F} <: DiffEqBase.DAEInitializationAlgorithm - abstol::T - nlsolve::F -end - -function OverrideInit(; abstol = 1e-10, nlsolve = nothing) - OverrideInit(abstol, nlsolve) -end -OverrideInit(abstol) = OverrideInit(; abstol = abstol, nlsolve = nothing) - ## Notes #= @@ -49,38 +17,35 @@ function DiffEqBase.initialize_dae!(integrator::ODEIntegrator, initializealg = integrator.initializealg) _initialize_dae!(integrator, integrator.sol.prob, initializealg, - Val(DiffEqBase.isinplace(integrator.sol.prob))) + Val(SciMLBase.isinplace(integrator.sol.prob))) end ## Default algorithms -function _initialize_dae!(integrator, prob::ODEProblem, - alg::DefaultInit, x::Val{true}) +function _initialize_dae!(integrator::ODEIntegrator, prob::ODEProblem, + alg::DefaultInit, x::Union{Val{true}, Val{false}}) if SciMLBase.has_initializeprob(prob.f) _initialize_dae!(integrator, prob, OverrideInit(integrator.opts.abstol), x) + elseif !applicable(_initialize_dae!, integrator, prob, + BrownFullBasicInit(integrator.opts.abstol), x) + error("`OrdinaryDiffEqNonlinearSolve` is not loaded, which is required for the default initialization algorithm (`BrownFullBasicInit` or `ShampineCollocationInit`). To solve this problem, either do `using OrdinaryDiffEqNonlinearSolve` or pass `initializealg = CheckInit()` to the `solve` function. This second option requires consistent `u0`.") else _initialize_dae!(integrator, prob, BrownFullBasicInit(integrator.opts.abstol), x) end end -function _initialize_dae!(integrator, prob::ODEProblem, - alg::DefaultInit, x::Val{false}) - if SciMLBase.has_initializeprob(prob.f) - _initialize_dae!(integrator, prob, - OverrideInit(integrator.opts.abstol), x) - else - _initialize_dae!(integrator, prob, - BrownFullBasicInit(integrator.opts.abstol), x) - end -end - -function _initialize_dae!(integrator, prob::DAEProblem, - alg::DefaultInit, x::Val{false}) +function _initialize_dae!(integrator::ODEIntegrator, prob::DAEProblem, + alg::DefaultInit, x::Union{Val{true}, Val{false}}) if SciMLBase.has_initializeprob(prob.f) _initialize_dae!(integrator, prob, OverrideInit(integrator.opts.abstol), x) + elseif !applicable(_initialize_dae!, integrator, prob, + BrownFullBasicInit(), x) && + !applicable(_initialize_dae!, + integrator, prob, ShampineCollocationInit(), x) + error("`OrdinaryDiffEqNonlinearSolve` is not loaded, which is required for the default initialization algorithm (`BrownFullBasicInit` or `ShampineCollocationInit`). To solve this problem, either do `using OrdinaryDiffEqNonlinearSolve` or pass `initializealg = CheckInit()` to the `solve` function. This second option requires consistent `u0`.") elseif prob.differential_vars === nothing _initialize_dae!(integrator, prob, ShampineCollocationInit(), x) @@ -90,17 +55,11 @@ function _initialize_dae!(integrator, prob::DAEProblem, end end -function _initialize_dae!(integrator, prob::DAEProblem, - alg::DefaultInit, x::Val{true}) +function _initialize_dae!(integrator::ODEIntegrator, prob::DiscreteProblem, + alg::DefaultInit, x::Union{Val{true}, Val{false}}) if SciMLBase.has_initializeprob(prob.f) - _initialize_dae!(integrator, prob, - OverrideInit(integrator.opts.abstol), x) - elseif prob.differential_vars === nothing - _initialize_dae!(integrator, prob, - ShampineCollocationInit(), x) - else - _initialize_dae!(integrator, prob, - BrownFullBasicInit(integrator.opts.abstol), x) + # integrator.opts.abstol is `false` for `DiscreteProblem`. + _initialize_dae!(integrator, prob, OverrideInit(one(eltype(prob.u0)) * 1e-12), x) end end @@ -111,7 +70,7 @@ default_nlsolve(alg, isinplace, u, initprob, autodiff = false) = alg ## If the initialization is trivial just use nothing alg function default_nlsolve( - ::Nothing, isinplace::Val{true}, u::Nothing, ::NonlinearProblem, autodiff = false) + ::Nothing, isinplace::Val{true}, u::Nothing, ::AbstractNonlinearProblem, autodiff = false) nothing end @@ -121,7 +80,7 @@ function default_nlsolve( end function default_nlsolve( - ::Nothing, isinplace::Val{false}, u::Nothing, ::NonlinearProblem, autodiff = false) + ::Nothing, isinplace::Val{false}, u::Nothing, ::AbstractNonlinearProblem, autodiff = false) nothing end @@ -132,7 +91,7 @@ function default_nlsolve( end function OrdinaryDiffEqCore.default_nlsolve( - ::Nothing, isinplace, u, ::NonlinearProblem, autodiff = false) + ::Nothing, isinplace, u, ::AbstractNonlinearProblem, autodiff = false) error("This ODE requires a DAE initialization and thus a nonlinear solve but no nonlinear solve has been loaded. To solve this problem, do `using OrdinaryDiffEqNonlinearSolve` or pass a custom `nlsolve` choice into the `initializealg`.") end @@ -143,20 +102,21 @@ end ## NoInit -function _initialize_dae!(integrator, prob::Union{ODEProblem, DAEProblem}, +function _initialize_dae!(integrator::ODEIntegrator, prob::AbstractDEProblem, alg::NoInit, x::Union{Val{true}, Val{false}}) end ## OverrideInit -function _initialize_dae!(integrator, prob::Union{ODEProblem, DAEProblem}, +function _initialize_dae!(integrator::ODEIntegrator, prob::AbstractDEProblem, alg::OverrideInit, isinplace::Union{Val{true}, Val{false}}) - initializeprob = prob.f.initializeprob + initializeprob = prob.f.initialization_data.initializeprob # If it doesn't have autodiff, assume it comes from symbolic system like ModelingToolkit # Since then it's the case of not a DAE but has initializeprob # In which case, it should be differentiable - isAD = if initializeprob.u0 === nothing + iu0 = state_values(initializeprob) + isAD = if iu0 === nothing AutoForwardDiff elseif has_autodiff(integrator.alg) alg_autodiff(integrator.alg) isa AutoForwardDiff @@ -164,99 +124,34 @@ function _initialize_dae!(integrator, prob::Union{ODEProblem, DAEProblem}, true end - alg = default_nlsolve(alg.nlsolve, isinplace, initializeprob.u0, initializeprob, isAD) - nlsol = solve(initializeprob, alg) + nlsolve_alg = default_nlsolve(alg.nlsolve, isinplace, iu0, initializeprob, isAD) + + u0, p, + success = SciMLBase.get_initial_values( + prob, integrator, prob.f, alg, isinplace; nlsolve_alg, + abstol = integrator.opts.abstol, reltol = integrator.opts.reltol) + if isinplace === Val{true}() - integrator.u .= prob.f.initializeprobmap(nlsol) + integrator.u .= u0 elseif isinplace === Val{false}() - integrator.u = prob.f.initializeprobmap(nlsol) + integrator.u = u0 else error("Unreachable reached. Report this error.") end + integrator.p = p + sol = integrator.sol + @reset sol.prob.p = integrator.p + integrator.sol = sol - if nlsol.retcode != ReturnCode.Success + if !success integrator.sol = SciMLBase.solution_new_retcode(integrator.sol, ReturnCode.InitialFailure) end end ## CheckInit -struct CheckInitFailureError <: Exception - normresid::Any - abstol::Any -end - -function Base.showerror(io::IO, e::CheckInitFailureError) - print(io, - "CheckInit specified but initialization not satisifed. normresid = $(e.normresid) > abstol = $(e.abstol)") -end - -function _initialize_dae!(integrator, prob::ODEProblem, alg::CheckInit, - isinplace::Val{true}) - @unpack p, t, f = integrator - M = integrator.f.mass_matrix - tmp = first(get_tmp_cache(integrator)) - u0 = integrator.u - - algebraic_vars = [all(iszero, x) for x in eachcol(M)] - algebraic_eqs = [all(iszero, x) for x in eachrow(M)] - (iszero(algebraic_vars) || iszero(algebraic_eqs)) && return - update_coefficients!(M, u0, p, t) - f(tmp, u0, p, t) - tmp .= ArrayInterface.restructure(tmp, algebraic_eqs .* _vec(tmp)) - - normresid = integrator.opts.internalnorm(tmp, t) - if normresid > integrator.opts.abstol - throw(CheckInitFailureError(normresid, integrator.opts.abstol)) - end -end - -function _initialize_dae!(integrator, prob::ODEProblem, alg::CheckInit, - isinplace::Val{false}) - @unpack p, t, f = integrator - u0 = integrator.u - M = integrator.f.mass_matrix - - algebraic_vars = [all(iszero, x) for x in eachcol(M)] - algebraic_eqs = [all(iszero, x) for x in eachrow(M)] - (iszero(algebraic_vars) || iszero(algebraic_eqs)) && return - update_coefficients!(M, u0, p, t) - du = f(u0, p, t) - resid = _vec(du)[algebraic_eqs] - - normresid = integrator.opts.internalnorm(resid, t) - if normresid > integrator.opts.abstol - throw(CheckInitFailureError(normresid, integrator.opts.abstol)) - end -end - -function _initialize_dae!(integrator, prob::DAEProblem, - alg::CheckInit, isinplace::Val{true}) - @unpack p, t, f = integrator - u0 = integrator.u - resid = get_tmp_cache(integrator)[2] - - f(resid, integrator.du, u0, p, t) - normresid = integrator.opts.internalnorm(resid, t) - if normresid > integrator.opts.abstol - throw(CheckInitFailureError(normresid, integrator.opts.abstol)) - end -end - -function _initialize_dae!(integrator, prob::DAEProblem, - alg::CheckInit, isinplace::Val{false}) - @unpack p, t, f = integrator - u0 = integrator.u - - nlequation_oop = u -> begin - f((u - u0) / dt, u, p, t) - end - - nlequation = (u, _) -> nlequation_oop(u) - - resid = f(integrator.du, u0, p, t) - normresid = integrator.opts.internalnorm(resid, t) - if normresid > integrator.opts.abstol - throw(CheckInitFailureError(normresid, integrator.opts.abstol)) - end +function _initialize_dae!(integrator::ODEIntegrator, prob::AbstractDEProblem, alg::CheckInit, + isinplace::Union{Val{true}, Val{false}}) + SciMLBase.get_initial_values( + prob, integrator, prob.f, alg, isinplace; abstol = integrator.opts.abstol) end diff --git a/lib/OrdinaryDiffEqCore/src/integrators/controllers.jl b/lib/OrdinaryDiffEqCore/src/integrators/controllers.jl index a13c3daf88..9c58c48432 100644 --- a/lib/OrdinaryDiffEqCore/src/integrators/controllers.jl +++ b/lib/OrdinaryDiffEqCore/src/integrators/controllers.jl @@ -21,7 +21,7 @@ end reset_alg_dependent_opts!(controller::AbstractController, alg1, alg2) = nothing -DiffEqBase.reinit!(integrator::ODEIntegrator, controller::AbstractController) = nothing +SciMLBase.reinit!(integrator::ODEIntegrator, controller::AbstractController) = nothing # Standard integral (I) step size controller """ @@ -68,7 +68,7 @@ end q = inv(qmax) else expo = 1 / (get_current_adaptive_order(alg, integrator.cache) + 1) - qtmp = DiffEqBase.fastpow(EEst, expo) / gamma + qtmp = fastpower(EEst, expo) / gamma @fastmath q = DiffEqBase.value(max(inv(qmax), min(inv(qmin), qtmp))) # TODO: Shouldn't this be in `step_accept_controller!` as for the PI controller? integrator.qold = DiffEqBase.value(integrator.dt) / q @@ -141,8 +141,8 @@ end if iszero(EEst) q = inv(qmax) else - q11 = DiffEqBase.fastpow(EEst, float(beta1)) - q = q11 / DiffEqBase.fastpow(qold, float(beta2)) + q11 = fastpower(EEst, convert(typeof(EEst), beta1)) + q = q11 / fastpower(qold, convert(typeof(EEst), beta2)) integrator.q11 = q11 @fastmath q = max(inv(qmax), min(inv(qmin), q / gamma)) end @@ -370,8 +370,7 @@ the following logic is applied: ```julia if integrator.success_iter > 0 expo = 1 / (alg_adaptive_order(integrator.alg) + 1) - qgus = (integrator.dtacc / integrator.dt) * - (((integrator.EEst^2) / integrator.erracc)^expo) + qgus = (integrator.dtacc / integrator.dt) * (((integrator.EEst^2) / integrator.erracc)^expo) qgus = max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), qgus / integrator.opts.gamma)) qacc = max(q, qgus) @@ -400,3 +399,56 @@ function post_newton_controller!(integrator, alg) integrator.dt = integrator.dt / integrator.opts.failfactor nothing end + +@inline function stepsize_controller!(integrator, controller::PredictiveController, alg) + @unpack qmin, qmax, gamma = integrator.opts + EEst = DiffEqBase.value(integrator.EEst) + if iszero(EEst) + q = inv(qmax) + else + if fac_default_gamma(alg) + fac = gamma + else + if isfirk(alg) + @unpack iter = integrator.cache + @unpack maxiters = alg + else + @unpack iter, maxiters = integrator.cache.nlsolver + end + fac = min(gamma, (1 + 2 * maxiters) * gamma / (iter + 2 * maxiters)) + end + expo = 1 / (get_current_adaptive_order(alg, integrator.cache) + 1) + qtmp = fastpower(EEst, expo) / fac + @fastmath q = DiffEqBase.value(max(inv(qmax), min(inv(qmin), qtmp))) + integrator.qold = q + end + q +end + +function step_accept_controller!(integrator, controller::PredictiveController, alg, q) + @unpack qmin, qmax, gamma, qsteady_min, qsteady_max = integrator.opts + + EEst = DiffEqBase.value(integrator.EEst) + + if integrator.success_iter > 0 + expo = 1 / (get_current_adaptive_order(alg, integrator.cache) + 1) + qgus = (integrator.dtacc / integrator.dt) * + fastpower((EEst^2) / integrator.erracc, expo) + qgus = max(inv(qmax), min(inv(qmin), qgus / gamma)) + qacc = max(q, qgus) + else + qacc = q + end + if qsteady_min <= qacc <= qsteady_max + qacc = one(qacc) + end + integrator.dtacc = integrator.dt + integrator.erracc = max(1e-2, EEst) + + return integrator.dt / qacc +end + +function step_reject_controller!(integrator, controller::PredictiveController, alg) + @unpack dt, success_iter, qold = integrator + integrator.dt = success_iter == 0 ? 0.1 * dt : dt / qold +end diff --git a/lib/OrdinaryDiffEqCore/src/integrators/integrator_interface.jl b/lib/OrdinaryDiffEqCore/src/integrators/integrator_interface.jl index b629a81141..08fd1ed1d7 100644 --- a/lib/OrdinaryDiffEqCore/src/integrators/integrator_interface.jl +++ b/lib/OrdinaryDiffEqCore/src/integrators/integrator_interface.jl @@ -3,7 +3,7 @@ # Hence, we need to have two separate functions. function _change_t_via_interpolation!(integrator, t, - modify_save_endpoint::Type{Val{T}}) where {T} + modify_save_endpoint::Type{Val{T}}, reinitialize_alg = nothing) where {T} # Can get rid of an allocation here with a function # get_tmp_arr(integrator.cache) which gives a pointer to some # cache array which can be modified. @@ -17,25 +17,26 @@ function _change_t_via_interpolation!(integrator, t, end integrator.t = t integrator.dt = integrator.t - integrator.tprev - DiffEqBase.reeval_internals_due_to_modification!(integrator) + SciMLBase.reeval_internals_due_to_modification!( + integrator; callback_initializealg = reinitialize_alg) if T solution_endpoint_match_cur_integrator!(integrator) end end return nothing end -function DiffEqBase.change_t_via_interpolation!(integrator::ODEIntegrator, +function SciMLBase.change_t_via_interpolation!(integrator::ODEIntegrator, t, modify_save_endpoint::Type{Val{T}} = Val{ false, - }) where { + }, reinitialize_alg = nothing) where { T, } - _change_t_via_interpolation!(integrator, t, modify_save_endpoint) + _change_t_via_interpolation!(integrator, t, modify_save_endpoint, reinitialize_alg) return nothing end -function DiffEqBase.reeval_internals_due_to_modification!( +function SciMLBase.reeval_internals_due_to_modification!( integrator::ODEIntegrator, continuous_modification = true; callback_initializealg = nothing) if integrator.isdae @@ -59,7 +60,7 @@ function DiffEqBase.reeval_internals_due_to_modification!( integrator.reeval_fsal = true end -@inline function DiffEqBase.get_du(integrator::ODEIntegrator) +@inline function SciMLBase.get_du(integrator::ODEIntegrator) isdiscretecache(integrator.cache) && error("Derivatives are not defined for this stepper.") return if isfsal(integrator.alg) @@ -69,7 +70,7 @@ end end end -@inline function DiffEqBase.get_du!(out, integrator::ODEIntegrator) +@inline function SciMLBase.get_du!(out, integrator::ODEIntegrator) isdiscretecache(integrator.cache) && error("Derivatives are not defined for this stepper.") if isdiscretecache(integrator.cache) @@ -106,54 +107,54 @@ function set_proposed_dt!(integrator::ODEIntegrator, integrator2::ODEIntegrator) end #TODO: Bigger caches for most algorithms -@inline function DiffEqBase.get_tmp_cache(integrator::ODEIntegrator) +@inline function SciMLBase.get_tmp_cache(integrator::ODEIntegrator) get_tmp_cache(integrator::ODEIntegrator, integrator.alg, integrator.cache) end # the ordering of the cache arrays is important!!! -@inline function DiffEqBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqAlgorithm, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqAlgorithm, cache::OrdinaryDiffEqConstantCache) nothing end -@inline function DiffEqBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqAlgorithm, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.tmp,) end -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqNewtonAdaptiveAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.nlsolver.tmp, cache.atmp) end -@inline function DiffEqBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqNewtonAlgorithm, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqNewtonAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.nlsolver.tmp, cache.nlsolver.z) end -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqRosenbrockAdaptiveAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.tmp, cache.linsolve_tmp) end -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqAdaptiveExponentialAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.tmp, cache.utilde) end -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqExponentialAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.tmp, cache.dz) end -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqLinearExponentialAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.tmp,) end -@inline function DiffEqBase.get_tmp_cache(integrator, alg::CompositeAlgorithm, +@inline function SciMLBase.get_tmp_cache(integrator, alg::CompositeAlgorithm, cache::CompositeCache) get_tmp_cache(integrator, alg.algs[1], cache.caches[1]) end -@inline function DiffEqBase.get_tmp_cache(integrator, alg::CompositeAlgorithm, +@inline function SciMLBase.get_tmp_cache(integrator, alg::CompositeAlgorithm, cache::DefaultCache) init_ith_default_cache(cache, alg.algs, cache.current) if cache.current == 1 @@ -172,7 +173,7 @@ end end end -@inline function DiffEqBase.get_tmp_cache(integrator, alg::DAEAlgorithm, +@inline function SciMLBase.get_tmp_cache(integrator, alg::DAEAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.nlsolver.cache.dz, cache.atmp) end @@ -200,17 +201,17 @@ function full_cache(cache::DefaultCache) Iterators.flatten(full_cache(c) for c in caches) end -function DiffEqBase.add_tstop!(integrator::ODEIntegrator, t) +function SciMLBase.add_tstop!(integrator::ODEIntegrator, t) integrator.tdir * (t - integrator.t) < zero(integrator.t) && error("Tried to add a tstop that is behind the current time. This is strictly forbidden") push!(integrator.opts.tstops, integrator.tdir * t) end -DiffEqBase.has_tstop(integrator::ODEIntegrator) = !isempty(integrator.opts.tstops) -DiffEqBase.first_tstop(integrator::ODEIntegrator) = first(integrator.opts.tstops) -DiffEqBase.pop_tstop!(integrator::ODEIntegrator) = pop!(integrator.opts.tstops) +SciMLBase.has_tstop(integrator::ODEIntegrator) = !isempty(integrator.opts.tstops) +SciMLBase.first_tstop(integrator::ODEIntegrator) = first(integrator.opts.tstops) +SciMLBase.pop_tstop!(integrator::ODEIntegrator) = pop!(integrator.opts.tstops) -function DiffEqBase.add_saveat!(integrator::ODEIntegrator, t) +function SciMLBase.add_saveat!(integrator::ODEIntegrator, t) integrator.tdir * (t - integrator.t) < zero(integrator.t) && error("Tried to add a saveat that is behind the current time. This is strictly forbidden") push!(integrator.opts.saveat, integrator.tdir * t) @@ -251,7 +252,7 @@ end resize_f!(f, i) = nothing function resize_f!(f::SplitFunction, i) - resize!(f.cache, i) + resize!(f._func_cache, i) return nothing end @@ -316,12 +317,14 @@ function addat!(integrator::ODEIntegrator, idxs) end function terminate!(integrator::ODEIntegrator, retcode = ReturnCode.Terminated) - integrator.sol = DiffEqBase.solution_new_retcode(integrator.sol, retcode) + integrator.sol = SciMLBase.solution_new_retcode(integrator.sol, retcode) integrator.opts.tstops.valtree = typeof(integrator.opts.tstops.valtree)() end -DiffEqBase.has_reinit(integrator::ODEIntegrator) = true -function DiffEqBase.reinit!(integrator::ODEIntegrator, u0 = integrator.sol.prob.u0; +const EMPTY_ARRAY_OF_PAIRS = Pair[] + +SciMLBase.has_reinit(integrator::ODEIntegrator) = true +function SciMLBase.reinit!(integrator::ODEIntegrator, u0 = integrator.sol.prob.u0; t0 = integrator.sol.prob.tspan[1], tf = integrator.sol.prob.tspan[2], erase_sol = true, @@ -329,10 +332,29 @@ function DiffEqBase.reinit!(integrator::ODEIntegrator, u0 = integrator.sol.prob. saveat = integrator.opts.saveat_cache, d_discontinuities = integrator.opts.d_discontinuities_cache, reset_dt = (integrator.dtcache == zero(integrator.dt)) && - integrator.opts.adaptive, + integrator.opts.adaptive, + reinit_dae = true, reinit_callbacks = true, initialize_save = true, reinit_cache = true, reinit_retcode = true) + if reinit_dae && SciMLBase.has_initializeprob(integrator.sol.prob.f) + # This is `remake` infrastructure. `reinit!` is somewhat like `remake` for + # integrators, so we reuse some of the same pieces. If we pass `integrator.p` + # for `p`, it means we don't want to change it. If we pass `missing`, this + # function may (correctly) assume `newp` aliases `prob.p` and copy it, which we + # want to avoid. So we pass an empty array of pairs to make it think this is + # a symbolic `remake` and it can modify `newp` inplace. The array of pairs is a + # const global to avoid allocating every time this function is called. + u0, + newp = SciMLBase.late_binding_update_u0_p(integrator.sol.prob, u0, + EMPTY_ARRAY_OF_PAIRS, t0, u0, integrator.p) + if newp !== integrator.p + integrator.p = newp + sol = integrator.sol + @reset sol.prob.p = newp + integrator.sol = sol + end + end if isinplace(integrator.sol.prob) recursivecopy!(integrator.u, u0) recursivecopy!(integrator.uprev, integrator.u) @@ -405,6 +427,12 @@ function DiffEqBase.reinit!(integrator::ODEIntegrator, u0 = integrator.sol.prob. auto_dt_reset!(integrator) end + if reinit_dae && + (integrator.isdae || SciMLBase.has_initializeprob(integrator.sol.prob.f)) + DiffEqBase.initialize_dae!(integrator) + update_uprev!(integrator) + end + if reinit_callbacks initialize_callbacks!(integrator, initialize_save) end @@ -419,7 +447,7 @@ function DiffEqBase.reinit!(integrator::ODEIntegrator, u0 = integrator.sol.prob. return nothing end -function DiffEqBase.auto_dt_reset!(integrator::ODEIntegrator) +function SciMLBase.auto_dt_reset!(integrator::ODEIntegrator) integrator.dt = ode_determine_initdt(integrator.u, integrator.t, integrator.tdir, integrator.opts.dtmax, integrator.opts.abstol, integrator.opts.reltol, @@ -433,7 +461,7 @@ function increment_nf!(stats, amt = 1) stats.nf += amt end -function DiffEqBase.set_t!(integrator::ODEIntegrator, t::Real) +function SciMLBase.set_t!(integrator::ODEIntegrator, t::Real) if integrator.opts.save_everystep error("Integrator time cannot be reset unless it is initialized", " with save_everystep=false") @@ -449,7 +477,7 @@ function DiffEqBase.set_t!(integrator::ODEIntegrator, t::Real) end end -function DiffEqBase.set_u!(integrator::ODEIntegrator, u) +function SciMLBase.set_u!(integrator::ODEIntegrator, u) if integrator.opts.save_everystep error("Integrator state cannot be reset unless it is initialized", " with save_everystep=false") @@ -458,7 +486,7 @@ function DiffEqBase.set_u!(integrator::ODEIntegrator, u) u_modified!(integrator, true) end -DiffEqBase.has_stats(i::ODEIntegrator) = true +SciMLBase.has_stats(i::ODEIntegrator) = true DiffEqBase.get_tstops(integ::ODEIntegrator) = integ.opts.tstops DiffEqBase.get_tstops_array(integ::ODEIntegrator) = get_tstops(integ).valtree diff --git a/lib/OrdinaryDiffEqCore/src/integrators/integrator_utils.jl b/lib/OrdinaryDiffEqCore/src/integrators/integrator_utils.jl index fbc46e93bf..c46f5d8c52 100644 --- a/lib/OrdinaryDiffEqCore/src/integrators/integrator_utils.jl +++ b/lib/OrdinaryDiffEqCore/src/integrators/integrator_utils.jl @@ -8,19 +8,20 @@ function loopheader!(integrator) # Accept or reject the step if integrator.iter > 0 - if ((integrator.opts.adaptive && integrator.accept_step) || - !integrator.opts.adaptive) && !integrator.force_stepfail - integrator.success_iter += 1 - apply_step!(integrator) - elseif integrator.opts.adaptive && !integrator.accept_step + if (integrator.opts.adaptive && !integrator.accept_step) || + integrator.force_stepfail if integrator.isout integrator.dt = integrator.dt * integrator.opts.qmin elseif !integrator.force_stepfail step_reject_controller!(integrator, integrator.alg) end + else + integrator.success_iter += 1 + apply_step!(integrator) end elseif integrator.u_modified # && integrator.iter == 0 update_uprev!(integrator) + update_fsal!(integrator) end integrator.iter += 1 @@ -31,6 +32,42 @@ function loopheader!(integrator) return nothing end +function apply_step!(integrator) + update_uprev!(integrator) + + #Update dt if adaptive or if fixed and the dt is allowed to change + if integrator.opts.adaptive || integrator.dtchangeable + integrator.dt = integrator.dtpropose + elseif integrator.dt != integrator.dtpropose && !integrator.dtchangeable + error("The current setup does not allow for changing dt.") + end + + update_fsal!(integrator) + return nothing +end + +function update_fsal!(integrator) + if has_discontinuity(integrator) && + first_discontinuity(integrator) == integrator.tdir * integrator.t + handle_discontinuities!(integrator) + get_current_isfsal(integrator.alg, integrator.cache) && reset_fsal!(integrator) + elseif all_fsal(integrator.alg, integrator.cache) || + get_current_isfsal(integrator.alg, integrator.cache) + if integrator.reeval_fsal || integrator.u_modified || + (isdp8(integrator.alg) && !integrator.opts.calck) || + (only_diagonal_mass_matrix(integrator.alg) && + !integrator.opts.adaptive) + reset_fsal!(integrator) + else # Do not reeval_fsal, instead copyto! over + if isinplace(integrator.sol.prob) + recursivecopy!(integrator.fsalfirst, integrator.fsallast) + else + integrator.fsalfirst = integrator.fsallast + end + end + end +end + function last_step_failed(integrator::ODEIntegrator) integrator.last_stepfail && !integrator.opts.adaptive end @@ -68,7 +105,7 @@ function _savevalues!(integrator, force_save, reduce_size)::Tuple{Bool, Bool} saved = true curt = integrator.tdir * pop!(saveat) if curt != integrator.t # If tdir_tstop if !integrator.dtchangeable - DiffEqBase.change_t_via_interpolation!(integrator, + SciMLBase.change_t_via_interpolation!(integrator, integrator.tdir * pop_tstop!(integrator), Val{true}) integrator.just_hit_tstop = true diff --git a/lib/OrdinaryDiffEqCore/src/integrators/type.jl b/lib/OrdinaryDiffEqCore/src/integrators/type.jl index 1f9bef031d..7dc9e1a9c6 100644 --- a/lib/OrdinaryDiffEqCore/src/integrators/type.jl +++ b/lib/OrdinaryDiffEqCore/src/integrators/type.jl @@ -37,6 +37,7 @@ mutable struct DEOptions{absType, relType, QT, tType, Controller, F1, F2, F3, F4 save_on::Bool save_start::Bool save_end::Bool + save_discretes::Bool save_end_user::F3 callback::F4 isoutofdomain::F5 @@ -84,7 +85,7 @@ mutable struct ODEIntegrator{algType <: Union{OrdinaryDiffEqAlgorithm, DAEAlgori uType, duType, tType, pType, eigenType, EEstT, QT, tdirType, ksEltype, SolType, F, CacheType, O, FSALType, EventErrorType, CallbackCacheType, IA, DV} <: - DiffEqBase.AbstractODEIntegrator{algType, IIP, uType, tType} + SciMLBase.AbstractODEIntegrator{algType, IIP, uType, tType} sol::SolType u::uType du::duType diff --git a/lib/OrdinaryDiffEqCore/src/interp_func.jl b/lib/OrdinaryDiffEqCore/src/interp_func.jl index d0f991142b..11b7371194 100644 --- a/lib/OrdinaryDiffEqCore/src/interp_func.jl +++ b/lib/OrdinaryDiffEqCore/src/interp_func.jl @@ -1,5 +1,5 @@ abstract type OrdinaryDiffEqInterpolation{cacheType} <: - DiffEqBase.AbstractDiffEqInterpolation end + SciMLBase.AbstractDiffEqInterpolation end struct InterpolationData{ F, uType, tType, kType, algType <: Union{Nothing, Vector{Int}}, cacheType, DV} <: @@ -23,23 +23,23 @@ end end end -function DiffEqBase.interp_summary(interp::OrdinaryDiffEqInterpolation{ +function SciMLBase.interp_summary(interp::OrdinaryDiffEqInterpolation{ cacheType, }) where { cacheType, } - DiffEqBase.interp_summary(cacheType, interp.dense) + SciMLBase.interp_summary(cacheType, interp.dense) end -function DiffEqBase.interp_summary(::Type{cacheType}, dense::Bool) where {cacheType} +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where {cacheType} dense ? "3rd order Hermite" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where {cacheType <: CompositeCache} if !dense return "1st order linear" end caches = fieldtype(cacheType, :caches) - join([DiffEqBase.interp_summary(ct, dense) for ct in fieldtypes(caches)], ", ") + join([SciMLBase.interp_summary(ct, dense) for ct in fieldtypes(caches)], ", ") end function (interp::InterpolationData)(tvals, idxs, deriv, p, continuity::Symbol = :left) @@ -75,21 +75,15 @@ function SciMLBase.strip_interpolation(id::InterpolationData) end function strip_cache(cache) - if hasfield(typeof(cache), :jac_config) - SciMLBase.@reset cache.jac_config = nothing + if !(cache isa OrdinaryDiffEqCore.DefaultCache) + cache = SciMLBase.constructorof(typeof(cache))([nothing + for name in + fieldnames(typeof(cache))]...) + else + # need to do something special for default cache + cache = OrdinaryDiffEqCore.DefaultCache{Nothing, Nothing, Nothing, Nothing, + Nothing, Nothing, Nothing, Nothing}(nothing, nothing, 0, nothing) end - if hasfield(typeof(cache), :grad_config) - SciMLBase.@reset cache.grad_config = nothing - end - if hasfield(typeof(cache), :nlsolver) - SciMLBase.@reset cache.nlsolver = nothing - end - if hasfield(typeof(cache), :tf) - SciMLBase.@reset cache.tf = nothing - end - if hasfield(typeof(cache), :uf) - SciMLBase.@reset cache.uf = nothing - end - + cache end diff --git a/lib/OrdinaryDiffEqCore/src/iterator_interface.jl b/lib/OrdinaryDiffEqCore/src/iterator_interface.jl index 09828e042b..66bdd67fb0 100644 --- a/lib/OrdinaryDiffEqCore/src/iterator_interface.jl +++ b/lib/OrdinaryDiffEqCore/src/iterator_interface.jl @@ -1,25 +1,26 @@ -@inline function step!(integrator::ODEIntegrator) +function step!(integrator::ODEIntegrator) if integrator.opts.advance_to_tstop - @inbounds while integrator.tdir * integrator.t < first(integrator.opts.tstops) + while integrator.tdir * integrator.t < first(integrator.opts.tstops) loopheader!(integrator) (integrator.do_error_check && check_error!(integrator) != ReturnCode.Success) && - return + return integrator.sol.retcode perform_step!(integrator, integrator.cache) loopfooter!(integrator) end else - @inbounds loopheader!(integrator) + loopheader!(integrator) (integrator.do_error_check && check_error!(integrator) != ReturnCode.Success) && - return - @inbounds perform_step!(integrator, integrator.cache) - @inbounds loopfooter!(integrator) - @inbounds while !integrator.accept_step + return integrator.sol.retcode + perform_step!(integrator, integrator.cache) + loopfooter!(integrator) + while !integrator.accept_step loopheader!(integrator) (integrator.do_error_check && check_error!(integrator) != ReturnCode.Success) && - return + return integrator.sol.retcode perform_step!(integrator, integrator.cache) loopfooter!(integrator) end end - @inbounds handle_tstop!(integrator) + handle_tstop!(integrator) + return integrator.sol.retcode end diff --git a/lib/OrdinaryDiffEqCore/src/misc_utils.jl b/lib/OrdinaryDiffEqCore/src/misc_utils.jl index c6f67947eb..c3b6082802 100644 --- a/lib/OrdinaryDiffEqCore/src/misc_utils.jl +++ b/lib/OrdinaryDiffEqCore/src/misc_utils.jl @@ -37,7 +37,7 @@ function constvalue(x) return _x isa Complex ? DiffEqBase.value(real(_x)) : DiffEqBase.value(_x) end -function diffdir(integrator::DiffEqBase.DEIntegrator) +function diffdir(integrator::SciMLBase.DEIntegrator) difference = maximum(abs, integrator.uprev) * sqrt(eps(typeof(integrator.t))) dir = integrator.tdir > zero(integrator.tdir) ? integrator.t > integrator.sol.prob.tspan[2] - difference ? -1 : 1 : @@ -114,19 +114,91 @@ are differential variables. Returns `DifferentialVarsUndefined` if it cannot be determined (i.e. the mass matrix is not diagonal). """ function get_differential_vars(f, u) - differential_vars = nothing if hasproperty(f, :mass_matrix) mm = f.mass_matrix mm = mm isa MatrixOperator ? mm.A : mm - if mm isa UniformScaling || all(!iszero, mm) + if mm isa UniformScaling return nothing + elseif all(!iszero, mm) + return trues(size(mm, 1)) elseif !(mm isa SciMLOperators.AbstractSciMLOperator) && isdiag(mm) - differential_vars = reshape(diag(mm) .!= 0, size(u)) + return reshape(diag(mm) .!= 0, size(u)) else return DifferentialVarsUndefined() end + else + return nothing end end isnewton(::Any) = false + +function _bool_to_ADType(::Val{true}, ::Val{CS}, _) where {CS} + Base.depwarn( + "Using a `Bool` for keyword argument `autodiff` is deprecated. Please use an `ADType` specifier.", + :_bool_to_ADType) + _CS = CS === 0 ? nothing : CS + return AutoForwardDiff{_CS}(nothing) +end + +function _bool_to_ADType(::Val{false}, _, ::Val{FD}) where {FD} + Base.depwarn( + "Using a `Bool` for keyword argument `autodiff` is deprecated. Please use an `ADType` specifier.", + :_bool_to_ADType) + return AutoFiniteDiff(; fdtype = Val{FD}(), dir = 1) +end + +# Functions to get ADType type from Bool or ADType object, or ADType type +function _process_AD_choice(ad_alg::Bool, CS::Int, ::Val{FD}) where {FD} + return _bool_to_ADType(Val(ad_alg), Val{CS}(), Val{FD}()), Val{CS}(), Val{FD}() +end + +function _process_AD_choice(ad_alg::Bool, ::Val{CS}, ::Val{FD}) where {CS, FD} + return _bool_to_ADType(Val(ad_alg), Val{CS}(), Val{FD}()), Val{CS}(), Val{FD}() +end + +function _process_AD_choice( + ad_alg::AutoForwardDiff{CS}, ::Val{CS2}, ::Val{FD}) where {CS, CS2, FD} + # Non-default `chunk_size` + if (CS2 != 0) && (isnothing(CS) || (CS2 !== CS)) + @warn "The `chunk_size` keyword is deprecated. Please use an `ADType` specifier. For now defaulting to using `AutoForwardDiff` with `chunksize=$(CS2)`." + return _bool_to_ADType(Val{true}(), Val{CS2}(), Val{FD}()), Val{CS2}(), Val{FD}() + end + + _CS = CS === nothing ? 0 : CS + return ad_alg, Val{_CS}(), Val{FD}() +end + +function _process_AD_choice( + ad_alg::AutoForwardDiff{CS}, CS2::Int, ::Val{FD}) where {CS, FD} + # Non-default `chunk_size` + if CS2 != 0 + @warn "The `chunk_size` keyword is deprecated. Please use an `ADType` specifier. For now defaulting to using `AutoForwardDiff` with `chunksize=$(CS2)`." + return _bool_to_ADType(Val{true}(), Val{CS2}(), Val{FD}()), Val{CS2}(), Val{FD}() + end + _CS = CS === nothing ? 0 : CS + return ad_alg, Val{_CS}(), Val{FD}() +end + +function _process_AD_choice( + ad_alg::AutoFiniteDiff{FD}, ::Val{CS}, ::Val{FD2}) where {FD, CS, FD2} + # Non-default `diff_type` + if FD2 !== :forward + @warn "The `diff_type` keyword is deprecated. Please use an `ADType` specifier. For now defaulting to using `AutoFiniteDiff` with `fdtype=Val{$FD2}()`." + return _bool_to_ADType(Val{false}(), Val{CS}(), Val{FD2}()), Val{CS}(), Val{FD2}() + end + if ad_alg.dir isa Bool # default dir of true makes integration non-reversible + @reset ad_alg.dir = Int(ad_alg.dir) + end + return ad_alg, Val{CS}(), ad_alg.fdtype +end + +function _process_AD_choice(ad_alg::AutoSparse, cs2::Val{CS2}, fd::Val{FD}) where {CS2, FD} + _, cs, fd = _process_AD_choice(ad_alg.dense_ad, cs2, fd) + ad_alg, cs, fd +end + +function _process_AD_choice(ad_alg, cs2, fd) + ad_alg, cs2, fd +end diff --git a/lib/OrdinaryDiffEqCore/src/precompilation_setup.jl b/lib/OrdinaryDiffEqCore/src/precompilation_setup.jl index bfb61ff69a..969df25bea 100644 --- a/lib/OrdinaryDiffEqCore/src/precompilation_setup.jl +++ b/lib/OrdinaryDiffEqCore/src/precompilation_setup.jl @@ -23,8 +23,8 @@ PrecompileTools.@compile_workload begin ODEProblem{true, SciMLBase.NoSpecialize}(lorenz, [1.0; 0.0; 0.0], (0.0, 1.0), Float64[]) - lorenz([1.0; 0.0; 0.0], [1.0; 0.0; 0.0], DiffEqBase.NullParameters(), 0.0) + lorenz([1.0; 0.0; 0.0], [1.0; 0.0; 0.0], SciMLBase.NullParameters(), 0.0) lorenz([1.0; 0.0; 0.0], [1.0; 0.0; 0.0], Float64[], 0.0) - lorenz_oop([1.0; 0.0; 0.0], DiffEqBase.NullParameters(), 0.0) + lorenz_oop([1.0; 0.0; 0.0], SciMLBase.NullParameters(), 0.0) lorenz_oop([1.0; 0.0; 0.0], Float64[], 0.0) end diff --git a/lib/OrdinaryDiffEqCore/src/solve.jl b/lib/OrdinaryDiffEqCore/src/solve.jl index a5efe16d43..6ddd866f87 100644 --- a/lib/OrdinaryDiffEqCore/src/solve.jl +++ b/lib/OrdinaryDiffEqCore/src/solve.jl @@ -1,36 +1,35 @@ -function DiffEqBase.__solve( - prob::Union{DiffEqBase.AbstractODEProblem, - DiffEqBase.AbstractDAEProblem}, +function SciMLBase.__solve( + prob::Union{SciMLBase.AbstractODEProblem, + SciMLBase.AbstractDAEProblem}, alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}, args...; kwargs...) - integrator = DiffEqBase.__init(prob, alg, args...; kwargs...) + integrator = SciMLBase.__init(prob, alg, args...; kwargs...) solve!(integrator) integrator.sol end -function DiffEqBase.__init( - prob::Union{DiffEqBase.AbstractODEProblem, - DiffEqBase.AbstractDAEProblem}, +function SciMLBase.__init( + prob::Union{SciMLBase.AbstractODEProblem, + SciMLBase.AbstractDAEProblem}, alg::Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm}, timeseries_init = (), ts_init = (), - ks_init = (), - recompile::Type{Val{recompile_flag}} = Val{true}; + ks_init = (); saveat = (), tstops = (), d_discontinuities = (), save_idxs = nothing, save_everystep = isempty(saveat), save_on = true, + save_discretes = true, save_start = save_everystep || isempty(saveat) || - saveat isa Number || prob.tspan[1] in saveat, + saveat isa Number || prob.tspan[1] in saveat, save_end = nothing, callback = nothing, - dense = save_everystep && - !(alg isa DAEAlgorithm) && !(prob isa DiscreteProblem) && - isempty(saveat), + dense = save_everystep && isempty(saveat) && + !default_linear_interpolation(prob, alg), calck = (callback !== nothing && callback !== CallbackSet()) || - (dense) || !isempty(saveat), # and no dense output + (dense) || !isempty(saveat), # and no dense output dt = isdiscretealg(alg) && isempty(tstops) ? eltype(prob.tspan)(1) : eltype(prob.tspan)(0), dtmin = eltype(prob.tspan)(0), @@ -52,7 +51,7 @@ function DiffEqBase.__init( failfactor = 2, maxiters = anyadaptive(alg) ? 1000000 : typemax(Int), internalnorm = ODE_DEFAULT_NORM, - internalopnorm = LinearAlgebra.opnorm, + internalopnorm = opnorm, isoutofdomain = ODE_DEFAULT_ISOUTOFDOMAIN, unstable_check = ODE_DEFAULT_UNSTABLE_CHECK, verbose = true, @@ -69,20 +68,19 @@ function DiffEqBase.__init( userdata = nothing, allow_extrapolation = alg_extrapolates(alg), initialize_integrator = true, - alias_u0 = false, - alias_du0 = false, + alias = ODEAliasSpecifier(), initializealg = DefaultInit(), - kwargs...) where {recompile_flag} - if prob isa DiffEqBase.AbstractDAEProblem && alg isa OrdinaryDiffEqAlgorithm + kwargs...) + if prob isa SciMLBase.AbstractDAEProblem && alg isa OrdinaryDiffEqAlgorithm error("You cannot use an ODE Algorithm with a DAEProblem") end - if prob isa DiffEqBase.AbstractODEProblem && alg isa DAEAlgorithm + if prob isa SciMLBase.AbstractODEProblem && alg isa DAEAlgorithm error("You cannot use an DAE Algorithm with a ODEProblem") end - if prob isa DiffEqBase.ODEProblem - if !(prob.f isa DiffEqBase.DynamicalODEFunction) && alg isa PartitionedAlgorithm + if prob isa SciMLBase.ODEProblem + if !(prob.f isa SciMLBase.DynamicalODEFunction) && alg isa PartitionedAlgorithm error("You can not use a solver designed for partitioned ODE with this problem. Please choose a solver suitable for your problem") end end @@ -91,8 +89,8 @@ function DiffEqBase.__init( if any(mm != I for mm in prob.f.mass_matrix) error("This solver is not able to use mass matrices. For compatible solvers see https://docs.sciml.ai/DiffEqDocs/stable/solvers/dae_solve/") end - elseif !(prob isa DiscreteProblem) && - !(prob isa DiffEqBase.AbstractDAEProblem) && + elseif !(prob isa SciMLBase.AbstractDiscreteProblem) && + !(prob isa SciMLBase.AbstractDAEProblem) && !is_mass_matrix_alg(alg) && prob.f.mass_matrix != I error("This solver is not able to use mass matrices. For compatible solvers see https://docs.sciml.ai/DiffEqDocs/stable/solvers/dae_solve/") @@ -112,7 +110,7 @@ function DiffEqBase.__init( if only_diagonal_mass_matrix(alg) && prob.f.mass_matrix isa AbstractMatrix && !isdiag(prob.f.mass_matrix) - error("$(typeof(alg).name.name) only works with diagonal mass matrices. Please choose a solver suitable for your problem (e.g. Rodas5P)") + throw(ArgumentError("$(typeof(alg).name.name) only works with diagonal mass matrices. Please choose a solver suitable for your problem (e.g. Rodas5P)")) end if !isempty(saveat) && dense @@ -131,10 +129,13 @@ function DiffEqBase.__init( !(alg isa OrdinaryDiffEqCompositeAlgorithm) && !(alg isa DAEAlgorithm)) || !adaptive || !isadaptive(alg)) && dt == tType(0) && isempty(tstops)) && dt_required(alg) - error("Fixed timestep methods require a choice of dt or choosing the tstops") + throw(ArgumentError("Fixed timestep methods require a choice of dt or choosing the tstops")) + end + if !isadaptive(alg) && adaptive + throw(ArgumentError("Fixed timestep methods can not be run with adaptive=true")) end - isdae = alg isa DAEAlgorithm || (!(prob isa DiscreteProblem) && + isdae = alg isa DAEAlgorithm || (!(prob isa SciMLBase.AbstractDiscreteProblem) && prob.f.mass_matrix != I && !(prob.f.mass_matrix isa Tuple) && ArrayInterface.issingular(prob.f.mass_matrix)) @@ -155,19 +156,63 @@ function DiffEqBase.__init( else _alg = alg end - f = prob.f - p = prob.p - # Get the control variables + use_old_kwargs = haskey(kwargs, :alias_u0) || haskey(kwargs, :alias_du0) + + if use_old_kwargs + aliases = ODEAliasSpecifier() + if haskey(kwargs, :alias_u0) + message = "`alias_u0` keyword argument is deprecated, to set `alias_u0`, + please use an ODEAliasSpecifier, e.g. `solve(prob, alias = ODEAliasSpecifier(alias_u0 = true))" + Base.depwarn(message, :init) + Base.depwarn(message, :solve) + aliases = ODEAliasSpecifier(alias_u0 = values(kwargs).alias_u0) + else + aliases = ODEAliasSpecifier(alias_u0 = nothing) + end + + if haskey(kwargs, :alias_du0) + message = "`alias_du0` keyword argument is deprecated, to set `alias_du0`, + please use an ODEAliasSpecifier, e.g. `solve(prob, alias = ODEAliasSpecifier(alias_du0 = true))" + Base.depwarn(message, :init) + Base.depwarn(message, :solve) + aliases = ODEAliasSpecifier( + alias_u0 = aliases.alias_u0, alias_du0 = values(kwargs).alias_du0) + else + aliases = ODEAliasSpecifier(alias_u0 = aliases.alias_u0, alias_du0 = nothing) + end + + aliases + + else + # If alias isa Bool, all fields of ODEAliases set to alias + if alias isa Bool + aliases = ODEAliasSpecifier(alias = alias) + elseif alias isa ODEAliasSpecifier + aliases = alias + end + end + + if isnothing(aliases.alias_f) || aliases.alias_f + f = prob.f + else + f = deepcopy(prob.f) + end + + if isnothing(aliases.alias_p) || aliases.alias_p + p = prob.p + else + p = recursivecopy(prob.p) + end - if alias_u0 + if !isnothing(aliases.alias_u0) && aliases.alias_u0 u = prob.u0 else u = recursivecopy(prob.u0) end if _alg isa DAEAlgorithm - if alias_du0 + if !isnothing(aliases.alias_du0) && aliases.alias_du0 du = prob.du0 else du = recursivecopy(prob.du0) @@ -185,28 +230,28 @@ function DiffEqBase.__init( uEltypeNoUnits = recursive_unitless_eltype(u) tTypeNoUnits = typeof(one(tType)) - if prob isa DiscreteProblem + if prob isa SciMLBase.AbstractDiscreteProblem abstol_internal = false elseif abstol === nothing if uBottomEltypeNoUnits == uBottomEltype - abstol_internal = DiffEqBase.ForwardDiff.value(real(convert(uBottomEltype, + abstol_internal = unitfulvalue(real(convert(uBottomEltype, oneunit(uBottomEltype) * 1 // 10^6))) else - abstol_internal = DiffEqBase.ForwardDiff.value.(real.(oneunit.(u) .* 1 // 10^6)) + abstol_internal = unitfulvalue.(real.(oneunit.(u) .* 1 // 10^6)) end else abstol_internal = real.(abstol) end - if prob isa DiscreteProblem + if prob isa SciMLBase.AbstractDiscreteProblem reltol_internal = false elseif reltol === nothing if uBottomEltypeNoUnits == uBottomEltype - reltol_internal = DiffEqBase.ForwardDiff.value(real(convert(uBottomEltype, + reltol_internal = unitfulvalue(real(convert(uBottomEltype, oneunit(uBottomEltype) * 1 // 10^3))) else - reltol_internal = DiffEqBase.ForwardDiff.value.(real.(oneunit.(u) .* 1 // 10^3)) + reltol_internal = unitfulvalue.(real.(oneunit.(u) .* 1 // 10^3)) end else reltol_internal = real.(reltol) @@ -239,6 +284,18 @@ function DiffEqBase.__init( resType = typeof(res_prototype) end + if isnothing(aliases.alias_tstops) || aliases.alias_tstops + tstops = tstops + else + tstops = recursivecopy(tstops) + end + + if tstops isa AbstractArray || tstops isa Tuple || tstops isa Number + _tstops = nothing + else + _tstops = tstops + tstops = () + end tstops_internal = initialize_tstops(tType, tstops, d_discontinuities, tspan) saveat_internal = initialize_saveat(tType, saveat, tspan) d_discontinuities_internal = initialize_d_discontinuities(tType, d_discontinuities, @@ -261,6 +318,10 @@ function DiffEqBase.__init( end ### Algorithm-specific defaults ### + save_idxs, + saved_subsystem = SciMLBase.get_save_idxs_and_saved_subsystem( + prob, save_idxs) + if save_idxs === nothing ksEltype = Vector{rateType} else @@ -319,7 +380,7 @@ function DiffEqBase.__init( QT, EEstT = if tTypeNoUnits <: Integer typeof(qmin), typeof(qmin) - elseif prob isa DiscreteProblem + elseif prob isa SciMLBase.AbstractDiscreteProblem # The QT fields are not used for DiscreteProblems constvalue(tTypeNoUnits), constvalue(tTypeNoUnits) else @@ -408,7 +469,7 @@ function DiffEqBase.__init( timeseries_errors, dense_errors, dense, save_on, save_start, - save_end, save_end_user, + save_end, save_discretes, save_end_user, callbacks_internal, isoutofdomain, unstable_check, @@ -422,24 +483,13 @@ function DiffEqBase.__init( id = InterpolationData( f, timeseries, ts, ks, alg_choice, dense, cache, differential_vars, false) - sol = DiffEqBase.build_solution(prob, _alg, ts, timeseries, + sol = SciMLBase.build_solution(prob, _alg, ts, timeseries, dense = dense, k = ks, interp = id, alg_choice = alg_choice, - calculate_error = false, stats = stats) + calculate_error = false, stats = stats, saved_subsystem = saved_subsystem) - if recompile_flag == true - FType = typeof(f) - SolType = typeof(sol) - cacheType = typeof(cache) - else - FType = Function - if _alg isa OrdinaryDiffEqAlgorithm - SolType = DiffEqBase.AbstractODESolution - cacheType = OrdinaryDiffEqCache - else - SolType = DiffEqBase.AbstractDAESolution - cacheType = DAECache - end - end + FType = typeof(f) + SolType = typeof(sol) + cacheType = typeof(cache) # rate/state = (state/time)/state = 1/t units, internalnorm drops units # we don't want to differentiate through eigenvalue estimation @@ -460,7 +510,9 @@ function DiffEqBase.__init( do_error_check = true event_last_time = 0 vector_event_last_time = 1 - last_event_error = prob isa DiscreteProblem ? false : zero(uBottomEltypeNoUnits) + last_event_error = prob isa SciMLBase.AbstractDiscreteProblem ? false : + (Base.isbitstype(uBottomEltypeNoUnits) ? zero(uBottomEltypeNoUnits) : + 0.0) dtchangeable = isdtchangeable(_alg) q11 = QT(1) success_iter = 0 @@ -499,9 +551,10 @@ function DiffEqBase.__init( fsalfirst, fsallast) if initialize_integrator - if isdae || SciMLBase.has_initializeprob(prob.f) + if isdae || SciMLBase.has_initializeprob(prob.f) || + prob isa SciMLBase.ImplicitDiscreteProblem DiffEqBase.initialize_dae!(integrator) - update_uprev!(integrator) + !isnothing(integrator.u) && update_uprev!(integrator) end if save_start @@ -537,11 +590,18 @@ function DiffEqBase.__init( end end + if _tstops !== nothing + tstops = _tstops(parameter_values(integrator), prob.tspan) + for tstop in tstops + add_tstop!(integrator, tstop) + end + end + handle_dt!(integrator) integrator end -function DiffEqBase.solve!(integrator::ODEIntegrator) +function SciMLBase.solve!(integrator::ODEIntegrator) @inbounds while !isempty(integrator.opts.tstops) while integrator.tdir * integrator.t < first(integrator.opts.tstops) loopheader!(integrator) @@ -560,15 +620,15 @@ function DiffEqBase.solve!(integrator::ODEIntegrator) f = integrator.sol.prob.f - if DiffEqBase.has_analytic(f) - DiffEqBase.calculate_solution_errors!(integrator.sol; + if SciMLBase.has_analytic(f) + SciMLBase.calculate_solution_errors!(integrator.sol; timeseries_errors = integrator.opts.timeseries_errors, dense_errors = integrator.opts.dense_errors) end if integrator.sol.retcode != ReturnCode.Default return integrator.sol end - integrator.sol = DiffEqBase.solution_new_retcode(integrator.sol, ReturnCode.Success) + integrator.sol = SciMLBase.solution_new_retcode(integrator.sol, ReturnCode.Success) end # Helpers @@ -686,4 +746,8 @@ function initialize_callbacks!(integrator, initialize_save = true) # reset this as it is now handled so the integrators should proceed as normal integrator.u_modified = false + + if initialize_save + SciMLBase.save_discretes_if_enabled!(integrator, integrator.opts.callback; skip_duplicates = true) + end end diff --git a/lib/OrdinaryDiffEqCore/test/jet.jl b/lib/OrdinaryDiffEqCore/test/jet.jl new file mode 100644 index 0000000000..7c00258e56 --- /dev/null +++ b/lib/OrdinaryDiffEqCore/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqCore +using JET, Test + +@testset "JET Tests" begin + @test test_package( + OrdinaryDiffEqCore, target_defined_modules = true, mode = :typo) === nothing broken=true +end diff --git a/lib/OrdinaryDiffEqCore/test/qa.jl b/lib/OrdinaryDiffEqCore/test/qa.jl new file mode 100644 index 0000000000..3805fa490b --- /dev/null +++ b/lib/OrdinaryDiffEqCore/test/qa.jl @@ -0,0 +1,10 @@ +using OrdinaryDiffEqCore +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqCore; + piracies = false, + unbound_args = false + ) +end diff --git a/lib/OrdinaryDiffEqCore/test/runtests.jl b/lib/OrdinaryDiffEqCore/test/runtests.jl index 8b13789179..b3775af183 100644 --- a/lib/OrdinaryDiffEqCore/test/runtests.jl +++ b/lib/OrdinaryDiffEqCore/test/runtests.jl @@ -1 +1,7 @@ +using SafeTestsets +# Only run QA tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") +end diff --git a/lib/OrdinaryDiffEqDefault/Project.toml b/lib/OrdinaryDiffEqDefault/Project.toml index 6962deaa5f..64c6b513dc 100644 --- a/lib/OrdinaryDiffEqDefault/Project.toml +++ b/lib/OrdinaryDiffEqDefault/Project.toml @@ -1,49 +1,75 @@ name = "OrdinaryDiffEqDefault" uuid = "50262376-6c5a-4cf5-baba-aaf4f84d72d7" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.8.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" -OrdinaryDiffEqBDF = "6ad6398a-0878-4a85-9266-38940aa047c8" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -OrdinaryDiffEqRosenbrock = "43230ef6-c299-4910-a778-202eb28ce4ce" OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" +OrdinaryDiffEqBDF = "6ad6398a-0878-4a85-9266-38940aa047c8" OrdinaryDiffEqVerner = "79d7bb75-1356-48c1-b8c0-6832512096c2" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" Preferences = "21216c6a-2e73-6563-6e65-726566657250" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +OrdinaryDiffEqRosenbrock = "43230ef6-c299-4910-a778-202eb28ce4ce" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -EnumX = "1.0.4" -LinearAlgebra = "<0.0.1, 1" -LinearSolve = "2.32.0" -OrdinaryDiffEqBDF = "<0.0.1, 1" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqRosenbrock = "<0.0.1, 1" -OrdinaryDiffEqTsit5 = "<0.0.1, 1" -OrdinaryDiffEqVerner = "<0.0.1, 1" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -StaticArrays = "1.0" -Test = "<0.0.1, 1" -julia = "1.10" - [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" + +[compat] +OrdinaryDiffEqTsit5 = "1.4.0" +Test = "<0.0.1, 1" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +OrdinaryDiffEqBDF = "1.9.0" +OrdinaryDiffEqVerner = "1.5.0" +LinearSolve = "3.26" +PrecompileTools = "1.2" +EnumX = "1.0" +LinearAlgebra = "1.10" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +SparseArrays = "1.10" +Aqua = "0.8.11" +Preferences = "1.4" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +OrdinaryDiffEqRosenbrock = "1.15.1" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" +AllocCheck = "0.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "SparseArrays", "StaticArrays", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "SparseArrays", "StaticArrays", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqTsit5] +path = "../OrdinaryDiffEqTsit5" + +[sources.OrdinaryDiffEqBDF] +path = "../OrdinaryDiffEqBDF" + +[sources.OrdinaryDiffEqRosenbrock] +path = "../OrdinaryDiffEqRosenbrock" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" + +[sources.OrdinaryDiffEqVerner] +path = "../OrdinaryDiffEqVerner" diff --git a/lib/OrdinaryDiffEqDefault/src/OrdinaryDiffEqDefault.jl b/lib/OrdinaryDiffEqDefault/src/OrdinaryDiffEqDefault.jl index 182b3c70c1..ea030b19ca 100644 --- a/lib/OrdinaryDiffEqDefault/src/OrdinaryDiffEqDefault.jl +++ b/lib/OrdinaryDiffEqDefault/src/OrdinaryDiffEqDefault.jl @@ -11,12 +11,13 @@ using OrdinaryDiffEqBDF: FBDF import OrdinaryDiffEqCore import OrdinaryDiffEqCore: is_mass_matrix_alg, default_autoswitch, isdefaultalg +import ADTypes: AutoFiniteDiff, AutoForwardDiff, AbstractADType import LinearSolve using LinearAlgebra: I, isdiag using EnumX using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("default_alg.jl") @@ -29,7 +30,7 @@ PrecompileTools.@compile_workload begin prob_list = [] default_ode = [ - DefaultODEAlgorithm(autodiff = false) + DefaultODEAlgorithm(autodiff = AutoFiniteDiff()) ] default_autodiff_ode = [ @@ -76,6 +77,7 @@ PrecompileTools.@compile_workload begin end for prob in prob_list, solver in solver_list + solve(prob, solver)(5.0) end @@ -83,6 +85,6 @@ PrecompileTools.@compile_workload begin solver_list = nothing end -export DefaultODEAlgorithm +export DefaultODEAlgorithm, DefaultImplicitODEAlgorithm end # module OrdinaryDiffEqDefault diff --git a/lib/OrdinaryDiffEqDefault/src/default_alg.jl b/lib/OrdinaryDiffEqDefault/src/default_alg.jl index 37686303f1..afc9585b1f 100644 --- a/lib/OrdinaryDiffEqDefault/src/default_alg.jl +++ b/lib/OrdinaryDiffEqDefault/src/default_alg.jl @@ -39,11 +39,15 @@ function isdefaultalg(alg::CompositeAlgorithm{ true end -function DiffEqBase.__init(prob::ODEProblem, ::Nothing, args...; kwargs...) - DiffEqBase.init(prob, DefaultODEAlgorithm(autodiff = false), args...; kwargs...) +function SciMLBase.__init(prob::ODEProblem, ::Nothing, args...; kwargs...) + SciMLBase.__init( + prob, DefaultODEAlgorithm(autodiff = AutoFiniteDiff()), + args...; wrap = Val(false), kwargs...) end -function DiffEqBase.__solve(prob::ODEProblem, ::Nothing, args...; kwargs...) - DiffEqBase.solve(prob, DefaultODEAlgorithm(autodiff = false), args...; kwargs...) +function SciMLBase.__solve(prob::ODEProblem, ::Nothing, args...; kwargs...) + SciMLBase.__solve( + prob, DefaultODEAlgorithm(autodiff = AutoFiniteDiff()), + args...; wrap = Val(false), kwargs...) end function is_stiff(integrator, alg, ntol, stol, is_stiffalg, current) @@ -81,7 +85,7 @@ function stiffchoice(reltol, len, mass_matrix) elseif len > SMALLSIZE DefaultSolverChoice.FBDF else - if reltol < LOW_TOL || !isdiag(mass_matrix) + if reltol < LOW_TOL || mass_matrix != I DefaultSolverChoice.Rodas5P else DefaultSolverChoice.Rosenbrock23 @@ -131,3 +135,12 @@ function is_mass_matrix_alg(alg::CompositeAlgorithm{ <:Any, <:Tuple{Tsit5, Vern7, Rosenbrock23, Rodas5P, FBDF, FBDF}}) true end + +function DefaultImplicitODEAlgorithm(; lazy = true, stol = 0, ntol = Inf, kwargs...) + nonstiff = (Tsit5(), Vern7(lazy = lazy)) + stiff = (Rosenbrock23(; kwargs...), Rodas5P(; kwargs...), + FBDF(; kwargs...), + FBDF(; linsolve = LinearSolve.KrylovJL_GMRES(), kwargs...)) + AutoAlgSwitch( + nonstiff, stiff; stiffalgfirst = true, stifftol = stol, nonstifftol = ntol) +end diff --git a/lib/OrdinaryDiffEqDefault/test/default_solver_tests.jl b/lib/OrdinaryDiffEqDefault/test/default_solver_tests.jl index 8676b4a57a..493c708d5d 100644 --- a/lib/OrdinaryDiffEqDefault/test/default_solver_tests.jl +++ b/lib/OrdinaryDiffEqDefault/test/default_solver_tests.jl @@ -1,5 +1,5 @@ using OrdinaryDiffEqDefault, OrdinaryDiffEqTsit5, OrdinaryDiffEqVerner, - OrdinaryDiffEqRosenbrock, OrdinaryDiffEqBDF + OrdinaryDiffEqRosenbrock, OrdinaryDiffEqBDF, ADTypes using Test, LinearSolve, LinearAlgebra, SparseArrays, StaticArrays f_2dlinear = (du, u, p, t) -> (@. du = p * u) @@ -16,6 +16,10 @@ tsitsol = solve(prob_ode_2Dlinear, Tsit5()) x = [zeros(4, 2) for _ in 1:5] @test sol(x, 0:0.1:0.4) == tsitsol(x, 0:0.1:0.4) +sol_implicit = @inferred solve(prob_ode_2Dlinear, DefaultImplicitODEAlgorithm()) +@test all(isequal(3), sol_implicit.alg_choice) +@test sol(0.5)≈sol_implicit(0.5) rtol=1e-3 atol=1e-6 + sol = solve(prob_ode_2Dlinear, reltol = 1e-10) vernsol = solve(prob_ode_2Dlinear, Vern7(), reltol = 1e-10) # test that default is the same as Vern7 (we expect it to use Vern7 for this). @@ -24,12 +28,19 @@ vernsol = solve(prob_ode_2Dlinear, Vern7(), reltol = 1e-10) @test all(isequal(2), sol.alg_choice) @test sol(0.5) == only(sol([0.5]).u) == vernsol(0.5) +sol_implicit = @inferred solve(prob_ode_2Dlinear, DefaultImplicitODEAlgorithm(), reltol = 1e-10) +@test all(isequal(4), sol_implicit.alg_choice) +@test sol(0.5)≈sol_implicit(0.5) rtol=1e-10 atol=1e-6 + prob_ode_linear_fast = ODEProblem( ODEFunction(f_2dlinear, mass_matrix = 2 * I(2)), rand(2), (0.0, 1.0), 1.01) sol = solve(prob_ode_linear_fast) -@test all(isequal(3), sol.alg_choice) +@test all(isequal(4), sol.alg_choice) # for some reason the timestepping here is different from regular Rosenbrock23 (including the initial timestep) +sol_implicit = @inferred solve(prob_ode_linear_fast, DefaultImplicitODEAlgorithm(), reltol = 1e-10) +@test all(isequal(4), sol_implicit.alg_choice) + function rober(u, p, t) y₁, y₂, y₃ = u k₁, k₂, k₃ = p @@ -39,7 +50,9 @@ function rober(u, p, t) end prob_rober = ODEProblem(rober, [1.0, 0.0, 0.0], (0.0, 1e3), (0.04, 3e7, 1e4)) sol = solve(prob_rober) -rosensol = solve(prob_rober, AutoTsit5(Rosenbrock23(autodiff = false))) +rosensol = solve(prob_rober, AutoTsit5(Rosenbrock23(autodiff = AutoFiniteDiff()))) +#test that cache is type stable +@test typeof(sol.interp.cache.cache3) == typeof(rosensol.interp.cache.caches[2]) # test that default has the same performance as AutoTsit5(Rosenbrock23()) (which we expect it to use for this). @test sol.stats.naccept == rosensol.stats.naccept @test sol.stats.nf == rosensol.stats.nf @@ -49,7 +62,9 @@ rosensol = solve(prob_rober, AutoTsit5(Rosenbrock23(autodiff = false))) sol = solve(prob_rober, reltol = 1e-7, abstol = 1e-7) rosensol = solve( - prob_rober, AutoVern7(Rodas5P(autodiff = false)), reltol = 1e-7, abstol = 1e-7) + prob_rober, AutoVern7(Rodas5P(autodiff = AutoFiniteDiff())), reltol = 1e-7, abstol = 1e-7) +#test that cache is type stable +@test typeof(sol.interp.cache.cache4) == typeof(rosensol.interp.cache.caches[2]) # test that default has the same performance as AutoTsit5(Rosenbrock23()) (which we expect it to use for this). @test sol.stats.naccept == rosensol.stats.naccept @test sol.stats.nf == rosensol.stats.nf @@ -75,7 +90,7 @@ for n in (100, 600) prob_ex_rober = ODEProblem(ODEFunction(exrober; jac_prototype), vcat([1.0, 0.0, 0.0], ones(n)), (0.0, 100.0), (0.04, 3e7, 1e4)) global sol = solve(prob_ex_rober) - fsol = solve(prob_ex_rober, AutoTsit5(FBDF(; autodiff = false, linsolve))) + fsol = solve(prob_ex_rober, AutoTsit5(FBDF(; autodiff = AutoFiniteDiff(), linsolve))) # test that default has the same performance as AutoTsit5(Rosenbrock23()) (which we expect it to use for this). @test sol.stats.naccept == fsol.stats.naccept @test sol.stats.nf == fsol.stats.nf @@ -104,7 +119,7 @@ end f = ODEFunction(rober_mm, mass_matrix = [1 0 0; 0 1 0; 0 0 0]) prob_rober_mm = ODEProblem(f, [1.0, 0.0, 1.0], (0.0, 1e5), (0.04, 3e7, 1e4)) sol = solve(prob_rober_mm) -@test all(isequal(3), sol.alg_choice) +@test all(isequal(4), sol.alg_choice) @test sol(0.5) isa Vector{Float64} # test dense output # test callback on ConstantCache (https://github.com/SciML/OrdinaryDiffEq.jl/issues/2287) @@ -113,6 +128,9 @@ cb = ContinuousCallback((u, t, integrator) -> t - 1, (integrator) -> nothing) SA_ode_problem = ODEProblem((u, p, t) -> zero(u), SA[0], 2) @test solve(SA_ode_problem; callback = cb).retcode == ReturnCode.Success +# Regression test callback doubling, https://github.com/SciML/ModelingToolkit.jl/issues/3327 +@test length(init(SA_ode_problem; callback = cb).opts.callback.continuous_callbacks) == 1 + # test Complex numbers H(s) = (1 - s) * complex([0 1; 1 0]) + s * complex([1 0; 0 -1]) schrod_eq(state, time, s) = -im * time * H(s) * state @@ -120,3 +138,12 @@ schrod_eq(state, time, s) = -im * time * H(s) * state prob_complex = ODEProblem(schrod_eq, complex([1, -1] / sqrt(2)), (0, 1), 100) complex_sol = solve(prob_complex) @test complex_sol.retcode == ReturnCode.Success + +# Make sure callback doesn't recurse init, which would cause initialize to be hit twice +counter = Ref{Int}(0) +cb = DiscreteCallback((u, t, integ)->false, (integ)->nothing; + initialize = (c, u, t, integ)->counter[]+=1) + +prob = ODEProblem((u, p, t)->[0.0], [0.0], (0.0, 1.0)) +sol = solve(prob, callback = cb) +@test counter[] == 1 diff --git a/lib/OrdinaryDiffEqDefault/test/jet.jl b/lib/OrdinaryDiffEqDefault/test/jet.jl new file mode 100644 index 0000000000..e9745ea006 --- /dev/null +++ b/lib/OrdinaryDiffEqDefault/test/jet.jl @@ -0,0 +1,9 @@ +import OrdinaryDiffEqDefault +using JET + +if isempty(VERSION.prerelease) + @testset "JET Tests" begin + test_package( + OrdinaryDiffEqDefault, target_defined_modules = true, mode = :typo) + end +end diff --git a/lib/OrdinaryDiffEqDefault/test/qa.jl b/lib/OrdinaryDiffEqDefault/test/qa.jl new file mode 100644 index 0000000000..da05ddc9ce --- /dev/null +++ b/lib/OrdinaryDiffEqDefault/test/qa.jl @@ -0,0 +1,9 @@ +using OrdinaryDiffEqDefault +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqDefault; + piracies = false + ) +end diff --git a/lib/OrdinaryDiffEqDefault/test/runtests.jl b/lib/OrdinaryDiffEqDefault/test/runtests.jl index 642678b538..809c14d90c 100644 --- a/lib/OrdinaryDiffEqDefault/test/runtests.jl +++ b/lib/OrdinaryDiffEqDefault/test/runtests.jl @@ -1,2 +1,4 @@ using SafeTestsets @time @safetestset "Default Solver Tests" include("default_solver_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqDifferentiation/Project.toml b/lib/OrdinaryDiffEqDifferentiation/Project.toml index f1a8b2371c..32a601b7f5 100644 --- a/lib/OrdinaryDiffEqDifferentiation/Project.toml +++ b/lib/OrdinaryDiffEqDifferentiation/Project.toml @@ -1,52 +1,75 @@ name = "OrdinaryDiffEqDifferentiation" uuid = "4302a76b-040a-498a-8c04-15b101fed76b" authors = ["Chris Rackauckas ", "Yingbo Ma "] -version = "1.1.0" +version = "1.16.1" [deps] -ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" FunctionWrappersWrappers = "77dc65aa-8811-40c2-897b-53d922fa7daf" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" +StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718" +DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804" -StaticArrayInterface = "0d7ed370-da01-4f52-bd93-41d350b8b718" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ConcreteStructs = "2569d6c7-a4a2-43d3-a901-331e8e4be471" +ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +SparseMatrixColorings = "0a514795-09f3-496d-8182-132a7b665d35" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" + +[weakdeps] +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + +[extensions] +OrdinaryDiffEqDifferentiationSparseArraysExt = "SparseArrays" + +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] -ADTypes = "1" -ArrayInterface = "7" -DiffEqBase = "6" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3" -FiniteDiff = "2" -ForwardDiff = "0.10" +ForwardDiff = "0.10.38, 1" FunctionWrappersWrappers = "0.1" -LinearAlgebra = "1.10" -LinearSolve = "2" -OrdinaryDiffEqCore = "1.1" +FastBroadcast = "0.3" Random = "<0.0.1, 1" -SafeTestsets = "0.1.0" -SciMLBase = "2" -SparseArrays = "1" -SparseDiffTools = "2" -StaticArrayInterface = "1" -StaticArrays = "1" +DiffEqDevTools = "2.44.4" Test = "<0.0.1, 1" +FiniteDiff = "2.27" +StaticArrayInterface = "1.8" +DifferentiationInterface = "0.6.54, 0.7" +LinearSolve = "3.26" +ConstructionBase = "1.5.8" +LinearAlgebra = "1.10" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +ConcreteStructs = "0.2" +SparseArrays = "1.10" +Aqua = "0.8.11" +ArrayInterface = "7.19" +StaticArrays = "1.9" +SparseMatrixColorings = "0.4.14" julia = "1.10" - -[extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +ADTypes = "1.16" +JET = "0.9.18, 0.10.4" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +SciMLOperators = "1.4" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck", "SparseArrays"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqDifferentiation/ext/OrdinaryDiffEqDifferentiationSparseArraysExt.jl b/lib/OrdinaryDiffEqDifferentiation/ext/OrdinaryDiffEqDifferentiationSparseArraysExt.jl new file mode 100644 index 0000000000..cb19915333 --- /dev/null +++ b/lib/OrdinaryDiffEqDifferentiation/ext/OrdinaryDiffEqDifferentiationSparseArraysExt.jl @@ -0,0 +1,19 @@ +module OrdinaryDiffEqDifferentiationSparseArraysExt + +using OrdinaryDiffEqDifferentiation +import SparseArrays +import SparseArrays: nonzeros, spzeros, SparseMatrixCSC, AbstractSparseMatrix + +# Override the sparse checking functions +OrdinaryDiffEqDifferentiation.is_sparse(::AbstractSparseMatrix) = true +OrdinaryDiffEqDifferentiation.is_sparse_csc(::SparseMatrixCSC) = true + +# Override the sparse array manipulation functions +OrdinaryDiffEqDifferentiation.nonzeros(A::AbstractSparseMatrix) = nonzeros(A) +OrdinaryDiffEqDifferentiation.spzeros(T::Type, m::Integer, n::Integer) = spzeros(T, m, n) + +# Helper functions for accessing sparse matrix internals +OrdinaryDiffEqDifferentiation.get_nzval(A::SparseMatrixCSC) = A.nzval +OrdinaryDiffEqDifferentiation.set_all_nzval!(A::SparseMatrixCSC, val) = (A.nzval .= val; A) + +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl b/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl index bc1e42339d..677b81e880 100644 --- a/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl +++ b/lib/OrdinaryDiffEqDifferentiation/src/OrdinaryDiffEqDifferentiation.jl @@ -1,25 +1,23 @@ module OrdinaryDiffEqDifferentiation -import ADTypes: AutoFiniteDiff, AutoForwardDiff - -import SparseDiffTools: SparseDiffTools, matrix_colors, forwarddiff_color_jacobian!, - forwarddiff_color_jacobian, ForwardColorJacCache, - default_chunk_size, getsize, JacVec +import ADTypes +import ADTypes: AutoFiniteDiff, AutoForwardDiff, AbstractADType, AutoSparse import ForwardDiff, FiniteDiff import ForwardDiff.Dual import LinearSolve import LinearSolve: OperatorAssumptions import FunctionWrappersWrappers -using DiffEqBase +import DiffEqBase import LinearAlgebra import LinearAlgebra: Diagonal, I, UniformScaling, diagind, mul!, lmul!, axpby!, opnorm, lu import LinearAlgebra: LowerTriangular, UpperTriangular -import SparseArrays: SparseMatrixCSC, AbstractSparseMatrix, nonzeros import ArrayInterface +import ArrayInterface: fast_scalar_indexing, zeromatrix, lu_instance -import StaticArrayInterface +# StaticArrayInterface imported but not used +# import StaticArrayInterface import StaticArrays import StaticArrays: SArray, MVector, SVector, @SVector, StaticArray, MMatrix, SA, StaticMatrix @@ -27,7 +25,11 @@ import StaticArrays: SArray, MVector, SVector, @SVector, StaticArray, MMatrix, S using DiffEqBase: TimeGradientWrapper, UJacobianWrapper, TimeDerivativeWrapper, UDerivativeWrapper -using SciMLBase: AbstractSciMLOperator +import SciMLBase: SciMLBase, constructorof, @set, isinplace, has_jvp, unwrapped_f, DEIntegrator, ODEFunction, SplitFunction, DynamicalODEFunction, DAEFunction, islinear, remake, solve!, isconstant +using SciMLBase: @set, @reset +import SciMLOperators: SciMLOperators, IdentityOperator, update_coefficients, update_coefficients!, MatrixOperator, AbstractSciMLOperator, ScalarOperator +import SparseMatrixColorings: ConstantColoringAlgorithm, GreedyColoringAlgorithm, ColoringProblem, + ncolors, column_colors, coloring, sparsity_pattern import OrdinaryDiffEqCore using OrdinaryDiffEqCore: OrdinaryDiffEqAlgorithm, OrdinaryDiffEqAdaptiveImplicitAlgorithm, DAEAlgorithm, @@ -44,19 +46,48 @@ using OrdinaryDiffEqCore: OrdinaryDiffEqAlgorithm, OrdinaryDiffEqAdaptiveImplici FastConvergence, Convergence, SlowConvergence, VerySlowConvergence, Divergence, NLStatus, MethodType, constvalue -import OrdinaryDiffEqCore: get_chunksize, resize_J_W!, resize_nlsolver!, alg_autodiff +import OrdinaryDiffEqCore: get_chunksize, resize_J_W!, resize_nlsolver!, alg_autodiff, + _get_fwd_tag + +import ConstructionBase +using ConstructionBase: constructorof + +import DifferentiationInterface as DI using FastBroadcast: @.. -@static if isdefined(DiffEqBase, :OrdinaryDiffEqTag) +using ConcreteStructs: @concrete + +@static if isdefined(SciMLBase, :OrdinaryDiffEqTag) + import SciMLBase: OrdinaryDiffEqTag +elseif isdefined(DiffEqBase, :OrdinaryDiffEqTag) import DiffEqBase: OrdinaryDiffEqTag else struct OrdinaryDiffEqTag end end +# Functions for sparse array handling - will be overloaded by extension +# Default implementations return false/error for non-sparse types +is_sparse(::Any) = false +is_sparse_csc(::Any) = false + +# These will error if called without the extension, but should never be called +# on non-sparse types due to the is_sparse checks +function nonzeros end +function spzeros end +function get_nzval end +function set_all_nzval! end + +# Provide error messages if these are called without extension +nonzeros(A) = error("SparseArrays extension not loaded. Please load SparseArrays to use sparse matrix functionality.") +spzeros(args...) = error("SparseArrays extension not loaded. Please load SparseArrays to use sparse matrix functionality.") +get_nzval(A) = error("SparseArrays extension not loaded. Please load SparseArrays to use sparse matrix functionality.") +set_all_nzval!(A, val) = error("SparseArrays extension not loaded. Please load SparseArrays to use sparse matrix functionality.") + include("alg_utils.jl") include("linsolve_utils.jl") include("derivative_utils.jl") include("derivative_wrappers.jl") +include("operators.jl") end diff --git a/lib/OrdinaryDiffEqDifferentiation/src/alg_utils.jl b/lib/OrdinaryDiffEqDifferentiation/src/alg_utils.jl index 50e605e409..01bd3b86ca 100644 --- a/lib/OrdinaryDiffEqDifferentiation/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqDifferentiation/src/alg_utils.jl @@ -2,30 +2,33 @@ function _alg_autodiff(alg::OrdinaryDiffEqAlgorithm) error("This algorithm does not have an autodifferentiation option defined.") end -_alg_autodiff(::OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD}) where {CS, AD} = Val{AD}() -_alg_autodiff(::DAEAlgorithm{CS, AD}) where {CS, AD} = Val{AD}() -_alg_autodiff(::OrdinaryDiffEqImplicitAlgorithm{CS, AD}) where {CS, AD} = Val{AD}() +function _alg_autodiff(alg::OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD}) where {CS, AD} + alg.autodiff +end +_alg_autodiff(alg::DAEAlgorithm{CS, AD}) where {CS, AD} = alg.autodiff +_alg_autodiff(alg::OrdinaryDiffEqImplicitAlgorithm{CS, AD}) where {CS, AD} = alg.autodiff _alg_autodiff(alg::CompositeAlgorithm) = _alg_autodiff(alg.algs[end]) -function _alg_autodiff(::Union{OrdinaryDiffEqExponentialAlgorithm{CS, AD}, +function _alg_autodiff(alg::Union{OrdinaryDiffEqExponentialAlgorithm{CS, AD}, OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS, AD} }) where { CS, AD } - Val{AD}() + alg.autodiff end function alg_autodiff(alg) autodiff = _alg_autodiff(alg) - if autodiff == Val(false) - return AutoFiniteDiff() - elseif autodiff == Val(true) + + if autodiff == Val(true) return AutoForwardDiff() + elseif autodiff == Val(false) + return AutoFiniteDiff() else - return _unwrap_val(autodiff) + return autodiff end end -Base.@pure function determine_chunksize(u, alg::DiffEqBase.DEAlgorithm) +Base.@pure function determine_chunksize(u, alg::SciMLBase.DEAlgorithm) determine_chunksize(u, get_chunksize(alg)) end Base.@pure function determine_chunksize(u, CS) @@ -38,41 +41,115 @@ end function DiffEqBase.prepare_alg( alg::Union{ - OrdinaryDiffEqAdaptiveImplicitAlgorithm{0, AD, + OrdinaryDiffEqAdaptiveImplicitAlgorithm{CS, AD, FDT}, - OrdinaryDiffEqImplicitAlgorithm{0, AD, FDT}, - DAEAlgorithm{0, AD, FDT}, - OrdinaryDiffEqExponentialAlgorithm{0, AD, FDT}}, + OrdinaryDiffEqImplicitAlgorithm{CS, AD, FDT}, + DAEAlgorithm{CS, AD, FDT}, + OrdinaryDiffEqExponentialAlgorithm{CS, AD, FDT}}, u0::AbstractArray{T}, - p, prob) where {AD, FDT, T} + p, prob) where {CS, AD, FDT, T} + prepped_AD = prepare_ADType(alg_autodiff(alg), prob, u0, p, standardtag(alg)) + + sparse_prepped_AD = prepare_user_sparsity(prepped_AD, prob) + + # if u0 is a StaticArray or eltype is Complex etc. don't use sparsity + if (((typeof(u0) <: StaticArray) || (eltype(u0) <: Complex) || + (!(prob.f isa DAEFunction) && prob.f.mass_matrix isa MatrixOperator)) && + sparse_prepped_AD isa AutoSparse) + @warn "Input type or problem definition is incompatible with sparse automatic differentiation. Switching to using dense automatic differentiation." + autodiff = ADTypes.dense_ad(sparse_prepped_AD) + else + autodiff = sparse_prepped_AD + end + + return remake(alg, autodiff = autodiff) +end + +function prepare_ADType(autodiff_alg::AutoSparse, prob, u0, p, standardtag) + SciMLBase.@set autodiff_alg.dense_ad = prepare_ADType( + ADTypes.dense_ad(autodiff_alg), prob, u0, p, standardtag) +end + +function prepare_ADType(autodiff_alg::AutoForwardDiff, prob, u0, p, standardtag) + tag = if standardtag + ForwardDiff.Tag(OrdinaryDiffEqTag(), eltype(u0)) + else + nothing + end + + T = eltype(u0) - # If not using autodiff or norecompile mode or very large bitsize (like a dual number u0 already) - # don't use a large chunksize as it will either error or not be beneficial - if !(alg_autodiff(alg) isa AutoForwardDiff) || - (isbitstype(T) && sizeof(T) > 24) || - (prob.f isa ODEFunction && + fwd_cs = OrdinaryDiffEqCore._get_fwd_chunksize_int(autodiff_alg) + + cs = fwd_cs == 0 ? nothing : fwd_cs + + if ((prob.f isa ODEFunction && + prob.f.f isa FunctionWrappersWrappers.FunctionWrappersWrapper) || + (isbitstype(T) && sizeof(T) > 24)) && (cs == 0 || isnothing(cs)) + return AutoForwardDiff{1}(tag) + else + return AutoForwardDiff{cs}(tag) + end +end + +function prepare_ADType(alg::AutoFiniteDiff, prob, u0, p, standardtag) + # If the autodiff alg is AutoFiniteDiff, prob.f.f isa FunctionWrappersWrapper, + # and fdtype is complex, fdtype needs to change to something not complex + if alg.fdtype == Val{:complex}() && (prob.f isa ODEFunction && prob.f.f isa FunctionWrappersWrappers.FunctionWrappersWrapper) - return remake(alg, chunk_size = Val{1}()) + @warn "AutoFiniteDiff fdtype complex is not compatible with this function" + return AutoFiniteDiff(fdtype = Val{:forward}()) end + return alg +end + +function prepare_user_sparsity(ad_alg, prob) + jac_prototype = prob.f.jac_prototype + sparsity = prob.f.sparsity - L = StaticArrayInterface.known_length(typeof(u0)) - if L === nothing # dynamic sized - # If chunksize is zero, pick chunksize right at the start of solve and - # then do function barrier to infer the full solve - x = if prob.f.colorvec === nothing - length(u0) - else - maximum(prob.f.colorvec) + if !isnothing(sparsity) && !(ad_alg isa AutoSparse) + if is_sparse_csc(sparsity) && !SciMLBase.has_jac(prob.f) + if prob.f.mass_matrix isa UniformScaling + idxs = diagind(sparsity) + @. @view(sparsity[idxs]) = 1 + + if !isnothing(jac_prototype) + @. @view(jac_prototype[idxs]) = 1 + end + else + idxs = findall(!iszero, prob.f.mass_matrix) + for idx in idxs + sparsity[idx] = prob.f.mass_matrix[idx] + end + + if !isnothing(jac_prototype) + for idx in idxs + jac_prototype[idx] = prob.f.mass_matrix[idx] + end + end + end end - cs = ForwardDiff.pickchunksize(x) - return remake(alg, chunk_size = Val{cs}()) - else # statically sized - cs = pick_static_chunksize(Val{L}()) - return remake(alg, chunk_size = cs) + # KnownJacobianSparsityDetector needs an AbstractMatrix + sparsity = sparsity isa MatrixOperator ? sparsity.A : sparsity + + color_alg = SciMLBase.has_colorvec(prob.f) ? + ConstantColoringAlgorithm( + sparsity, prob.f.colorvec) : GreedyColoringAlgorithm() + + sparsity_detector = ADTypes.KnownJacobianSparsityDetector(sparsity) + + return AutoSparse( + ad_alg, sparsity_detector = sparsity_detector, coloring_algorithm = color_alg) + else + return ad_alg end end +function prepare_ADType(alg::AbstractADType, prob, u0, p, standardtag) + return alg +end + @generated function pick_static_chunksize(::Val{chunksize}) where {chunksize} x = ForwardDiff.pickchunksize(chunksize) :(Val{$x}()) diff --git a/lib/OrdinaryDiffEqDifferentiation/src/derivative_utils.jl b/lib/OrdinaryDiffEqDifferentiation/src/derivative_utils.jl index abf994e5bc..553e128857 100644 --- a/lib/OrdinaryDiffEqDifferentiation/src/derivative_utils.jl +++ b/lib/OrdinaryDiffEqDifferentiation/src/derivative_utils.jl @@ -34,30 +34,74 @@ function calc_tderivative!(integrator, cache, dtd1, repeat_step) # Time derivative if !repeat_step # skip calculation if step is repeated - if DiffEqBase.has_tgrad(f) + if SciMLBase.has_tgrad(f) f.tgrad(dT, uprev, p, t) else tf.uprev = uprev tf.p = p - derivative!(dT, tf, t, du2, integrator, cache.grad_config) + alg = unwrap_alg(integrator, true) + + autodiff_alg = ADTypes.dense_ad(gpu_safe_autodiff(alg_autodiff(alg), u)) + + # Convert t to eltype(dT) if using ForwardDiff, to make FunctionWrappers work + t = autodiff_alg isa AutoForwardDiff ? convert(eltype(dT), t) : t + + grad_config_tup = cache.grad_config + + if autodiff_alg isa AutoFiniteDiff + grad_config = diffdir(integrator) > 0 ? grad_config_tup[1] : + grad_config_tup[2] + else + grad_config = grad_config_tup[1] + end + + if integrator.iter == 1 + try + DI.derivative!( + tf, linsolve_tmp, dT, grad_config, autodiff_alg, t) + catch e + throw(FirstAutodiffTgradError(e)) + end + else + DI.derivative!(tf, linsolve_tmp, dT, grad_config, autodiff_alg, t) + end + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end end - @.. broadcast=false linsolve_tmp=fsalfirst + dtd1 * dT + @.. broadcast=false linsolve_tmp=fsalfirst+dtd1*dT end end function calc_tderivative(integrator, cache) - @unpack t, dt, uprev, u, f, p = integrator + @unpack t, dt, uprev, u, f, p, alg = integrator # Time derivative - if DiffEqBase.has_tgrad(f) + if SciMLBase.has_tgrad(f) dT = f.tgrad(uprev, p, t) else tf = cache.tf tf.u = uprev tf.p = p - dT = derivative(tf, t, integrator) + + autodiff_alg = ADTypes.dense_ad(gpu_safe_autodiff(alg_autodiff(alg), u)) + + if alg_autodiff isa AutoFiniteDiff + autodiff_alg = SciMLBase.@set autodiff_alg.dir = diffdir(integrator) + end + + if integrator.iter == 1 + try + dT = DI.derivative(tf, autodiff_alg, t) + catch e + throw(FirstAutodiffTgradError(e)) + end + else + dT = DI.derivative(tf, autodiff_alg, t) + end + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end dT end @@ -79,7 +123,7 @@ function calc_J(integrator, cache, next_step::Bool = false) end if alg isa DAEAlgorithm - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) duprev = integrator.duprev uf = cache.uf J = f.jac(duprev, uprev, p, uf.α * uf.invγdt, t) @@ -89,7 +133,7 @@ function calc_J(integrator, cache, next_step::Bool = false) J = jacobian(uf, x, integrator) end else - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) J = f.jac(uprev, p, t) else @unpack uf = cache @@ -97,7 +141,6 @@ function calc_J(integrator, cache, next_step::Bool = false) uf.f = nlsolve_f(f, alg) uf.p = p uf.t = t - J = jacobian(uf, uprev, integrator) end @@ -127,10 +170,23 @@ function calc_J!(J, integrator, cache, next_step::Bool = false) end if alg isa DAEAlgorithm - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) duprev = integrator.duprev uf = cache.uf - f.jac(J, duprev, uprev, p, uf.α * uf.invγdt, t) + # need to do some jank here to account for sparsity pattern of W + # https://github.com/SciML/OrdinaryDiffEq.jl/issues/2653 + + # we need to set all nzval to a non-zero number + # otherwise in the following line any zero gets interpreted as a structural zero + if !isnothing(integrator.f.jac_prototype) && + is_sparse_csc(integrator.f.jac_prototype) + set_all_nzval!(integrator.f.jac_prototype, true) + J .= true .* integrator.f.jac_prototype + set_all_nzval!(J, false) + f.jac(J, duprev, uprev, p, uf.α * uf.invγdt, t) + else + f.jac(J, duprev, uprev, p, uf.α * uf.invγdt, t) + end else @unpack du1, uf, jac_config = cache # using `dz` as temporary array @@ -140,14 +196,26 @@ function calc_J!(J, integrator, cache, next_step::Bool = false) jacobian!(J, uf, x, du1, integrator, jac_config) end else - if DiffEqBase.has_jac(f) - f.jac(J, uprev, p, t) + if SciMLBase.has_jac(f) + # need to do some jank here to account for sparsity pattern of W + # https://github.com/SciML/OrdinaryDiffEq.jl/issues/2653 + + # we need to set all nzval to a non-zero number + # otherwise in the following line any zero gets interpreted as a structural zero + if !isnothing(integrator.f.jac_prototype) && + is_sparse_csc(integrator.f.jac_prototype) + set_all_nzval!(integrator.f.jac_prototype, true) + J .= true .* integrator.f.jac_prototype + set_all_nzval!(J, false) + f.jac(J, uprev, p, t) + else + f.jac(J, uprev, p, t) + end else @unpack du1, uf, jac_config = cache - uf.f = nlsolve_f(f, alg) uf.t = t - if !(p isa DiffEqBase.NullParameters) + if !(p isa SciMLBase.NullParameters) uf.p = p end jacobian!(J, uf, uprev, du1, integrator, jac_config) @@ -210,7 +278,7 @@ mutable struct WOperator{IIP, T, if AJ isa AbstractMatrix mm = mass_matrix isa MatrixOperator ? convert(AbstractMatrix, mass_matrix) : mass_matrix - if AJ isa AbstractSparseMatrix + if is_sparse(AJ) # If gamma is zero, then it's just an initialization and we want to make sure # we get the right sparsity pattern. If gamma is not zero, then it's a case where @@ -255,8 +323,19 @@ mutable struct WOperator{IIP, T, _func_cache, _concrete_form, jacvec) end + + function Base.copy(W::WOperator{IIP, T, MType, GType, JType, F, C, JV}) where {IIP, T, MType, GType, JType, F, C, JV} + return new{IIP, T, MType, GType, JType, F, C, JV}( + W.mass_matrix, + W.gamma, + W.J, + W._func_cache === nothing ? nothing : copy(W._func_cache), + W._concrete_form === nothing ? nothing : copy(W._concrete_form), + W.jacvec + ) + end end -function WOperator{IIP}(f, u, gamma) where {IIP} +function WOperator{IIP}(f::F, u, gamma) where {IIP, F} if isa(f, Union{SplitFunction, DynamicalODEFunction}) error("WOperator does not support $(typeof(f)) yet") end @@ -268,7 +347,7 @@ function WOperator{IIP}(f, u, gamma) where {IIP} # Convert jacobian, if needed J = deepcopy(f.jac_prototype) if J isa AbstractMatrix - @assert DiffEqBase.has_jac(f) "f needs to have an associated jacobian" + @assert SciMLBase.has_jac(f) "f needs to have an associated jacobian" J = MatrixOperator(J; update_func! = f.jac) end return WOperator{IIP}(mass_matrix, gamma, J, u) @@ -346,7 +425,7 @@ function LinearAlgebra.mul!(Y::AbstractVecOrMat, W::WOperator, B::AbstractVecOrM # Compute mass_matrix * B if isa(W.mass_matrix, UniformScaling) a = -W.mass_matrix.λ / W.gamma - @.. broadcast=false Y=a * B + @.. broadcast=false Y=a*B else mul!(_vec(Y), W.mass_matrix, _vec(B)) lmul!(-inv(W.gamma), Y) @@ -372,7 +451,7 @@ islinearfunction(integrator) = islinearfunction(integrator.f, integrator.alg) return the tuple `(is_linear_wrt_odealg, islinearodefunction)`. """ -function islinearfunction(f, alg)::Tuple{Bool, Bool} +function islinearfunction(f::F, alg)::Tuple{Bool, Bool} where F isode = f isa ODEFunction && islinear(f.f) islin = isode || (issplit(alg) && f isa SplitFunction && islinear(f.f1.f)) return islin, isode @@ -510,7 +589,7 @@ function calc_W!(W, integrator, nlsolver::Union{Nothing, AbstractNLSolver}, cach is_compos = integrator.alg isa CompositeAlgorithm # handle Wfact - if DiffEqBase.has_Wfact_t(f) + if SciMLBase.has_Wfact_t(f) f.Wfact_t(W, u, p, dtgamma, t) isnewton(nlsolver) && set_W_γdt!(nlsolver, dtgamma) is_compos && (integrator.eigen_est = constvalue(opnorm(LowerTriangular(W), Inf)) + @@ -614,6 +693,7 @@ end W = J else W = J - mass_matrix * inv(dtgamma) + if !isa(W, Number) W = DiffEqBase.default_factorize(W) end @@ -678,7 +758,7 @@ function update_W!(nlsolver::AbstractNLSolver, nothing end -function build_J_W(alg, u, uprev, p, t, dt, f::F, ::Type{uEltypeNoUnits}, +function build_J_W(alg, u, uprev, p, t, dt, f::F, jac_config, ::Type{uEltypeNoUnits}, ::Val{IIP}) where {IIP, uEltypeNoUnits, F} # TODO - make J, W AbstractSciMLOperators (lazily defined with scimlops functionality) # TODO - if jvp given, make it SciMLOperators.FunctionOperator @@ -709,12 +789,10 @@ function build_J_W(alg, u, uprev, p, t, dt, f::F, ::Type{uEltypeNoUnits}, # If the user has chosen GMRES but no sparse Jacobian, assume that the dense # Jacobian is a bad idea and create a fully matrix-free solver. This can # be overridden with concrete_jac. + jacvec = JVPCache(f, copy(u), u, p, t, autodiff = alg_autodiff(alg)) - _f = islin ? (isode ? f.f : f.f1.f) : f - jacvec = JacVec((du, u, p, t) -> _f(du, u, p, t), copy(u), p, t; - autodiff = alg_autodiff(alg), tag = OrdinaryDiffEqTag()) J = jacvec - W = WOperator{IIP}(f.mass_matrix, dt, J, u, jacvec) + W = WOperator{IIP}(f.mass_matrix, promote(t, dt)[2], J, u, jacvec) elseif alg.linsolve !== nothing && !LinearSolve.needs_concrete_A(alg.linsolve) || concrete_jac(alg) !== nothing && concrete_jac(alg) # The linear solver does not need a concrete Jacobian, but the user has @@ -722,31 +800,50 @@ function build_J_W(alg, u, uprev, p, t, dt, f::F, ::Type{uEltypeNoUnits}, # Thus setup JacVec and a concrete J, using sparsity when possible _f = islin ? (isode ? f.f : f.f1.f) : f J = if f.jac_prototype === nothing - ArrayInterface.undefmatrix(u) + if alg_autodiff(alg) isa AutoSparse + if isnothing(f.sparsity) + !isnothing(jac_config) ? + convert.( + eltype(u), sparsity_pattern(jac_config[1])) : + spzeros(eltype(u), length(u), length(u)) + elseif eltype(f.sparsity) == Bool + convert.(eltype(u), f.sparsity) + else + f.sparsity + end + else + ArrayInterface.zeromatrix(u) + end else deepcopy(f.jac_prototype) end W = if J isa StaticMatrix StaticWOperator(J, false) else - __f = if IIP - (du, u, p, t) -> _f(du, u, p, t) - else - (u, p, t) -> _f(u, p, t) - end - jacvec = JacVec(__f, copy(u), p, t; - autodiff = alg_autodiff(alg), tag = OrdinaryDiffEqTag()) - WOperator{IIP}(f.mass_matrix, dt, J, u, jacvec) + jacvec = JVPCache(f, copy(u), u, p, t, autodiff = alg_autodiff(alg)) + + WOperator{IIP}(f.mass_matrix, promote(t, dt)[2], J, u, jacvec) end else - J = if !IIP && DiffEqBase.has_jac(f) + J = if !IIP && SciMLBase.has_jac(f) if f isa DAEFunction f.jac(uprev, uprev, p, one(t), t) else f.jac(uprev, p, t) end elseif f.jac_prototype === nothing - ArrayInterface.undefmatrix(u) + if alg_autodiff(alg) isa AutoSparse + if isnothing(f.sparsity) + !isnothing(jac_config) ? convert.(eltype(u), sparsity_pattern(jac_config[1])) : + spzeros(eltype(u), length(u), length(u)) + elseif eltype(f.sparsity) == Bool + convert.(eltype(u), f.sparsity) + else + f.sparsity + end + else + ArrayInterface.zeromatrix(u) + end else deepcopy(f.jac_prototype) end @@ -818,15 +915,17 @@ function resize_J_W!(cache, integrator, i) islin = f isa Union{ODEFunction, SplitFunction} && islinear(nf.f) if !islin if cache.J isa AbstractSciMLOperator - resize!(cache.J, i) + resize_JVPCache!( + cache.J, f, cache.du1, integrator.u, alg_autodiff(integrator.alg)) elseif f.jac_prototype !== nothing J = similar(f.jac_prototype, i, i) J = MatrixOperator(J; update_func! = f.jac) end if cache.W.jacvec isa AbstractSciMLOperator - resize!(cache.W.jacvec, i) + resize_JVPCache!(cache.W.jacvec, f, cache.du1, integrator.u, + alg_autodiff(integrator.alg)) end - cache.W = WOperator{DiffEqBase.isinplace(integrator.sol.prob)}(f.mass_matrix, + cache.W = WOperator{SciMLBase.isinplace(integrator.sol.prob)}(f.mass_matrix, integrator.dt, cache.J, integrator.u, @@ -842,3 +941,6 @@ function resize_J_W!(cache, integrator, i) nothing end + +getsize(::Val{N}) where {N} = N +getsize(N::Integer) = N diff --git a/lib/OrdinaryDiffEqDifferentiation/src/derivative_wrappers.jl b/lib/OrdinaryDiffEqDifferentiation/src/derivative_wrappers.jl index 8c7b94a85a..46df552537 100644 --- a/lib/OrdinaryDiffEqDifferentiation/src/derivative_wrappers.jl +++ b/lib/OrdinaryDiffEqDifferentiation/src/derivative_wrappers.jl @@ -4,7 +4,7 @@ const FIRST_AUTODIFF_TGRAD_MESSAGE = """ with automatic differentiation. Methods to fix this include: 1. Turn off automatic differentiation (e.g. Rosenbrock23() becomes - Rosenbrock23(autodiff=false)). More details can be found at + Rosenbrock23(autodiff=AutoFiniteDiff())). More details can be found at https://docs.sciml.ai/DiffEqDocs/stable/features/performance_overloads/ 2. Improving the compatibility of `f` with ForwardDiff.jl automatic differentiation (using tools like PreallocationTools.jl). More details @@ -14,7 +14,7 @@ const FIRST_AUTODIFF_TGRAD_MESSAGE = """ Note 1: this failure occurred inside of the time gradient function. These time gradients are only required by Rosenbrock methods (`Rosenbrock23`, - `Rodas4`, etc.) are are done by automatic differentiation w.r.t. the + `Rodas4`, etc.) and are done by automatic differentiation w.r.t. the argument `t`. If your function is compatible with automatic differentiation w.r.t. `u`, i.e. for Jacobian generation, another way to work around this issue is to switch to a non-Rosenbrock method. @@ -46,7 +46,7 @@ const FIRST_AUTODIFF_JAC_MESSAGE = """ with automatic differentiation. Methods to fix this include: 1. Turn off automatic differentiation (e.g. Rosenbrock23() becomes - Rosenbrock23(autodiff=false)). More details can befound at + Rosenbrock23(autodiff = AutoFiniteDiff())). More details can befound at https://docs.sciml.ai/DiffEqDocs/stable/features/performance_overloads/ 2. Improving the compatibility of `f` with ForwardDiff.jl automatic differentiation (using tools like PreallocationTools.jl). More details @@ -75,200 +75,181 @@ function Base.showerror(io::IO, e::FirstAutodiffJacError) Base.showerror(io, e.e) end -function derivative!(df::AbstractArray{<:Number}, f, - x::Union{Number, AbstractArray{<:Number}}, fx::AbstractArray{<:Number}, - integrator, grad_config) +function jacobian(f::F, x::AbstractArray{<:Number}, integrator) where F alg = unwrap_alg(integrator, true) - tmp = length(x) # We calculate derivative for all elements in gradient - if alg_autodiff(alg) isa AutoForwardDiff - T = if standardtag(alg) - typeof(ForwardDiff.Tag(OrdinaryDiffEqTag(), eltype(df))) - else - typeof(ForwardDiff.Tag(f, eltype(df))) - end - xdual = Dual{T, eltype(df), 1}(convert(eltype(df), x), - ForwardDiff.Partials((one(eltype(df)),))) + # Update stats.nf - if integrator.iter == 1 - try - f(grad_config, xdual) - catch e - throw(FirstAutodiffTgradError(e)) - end - else - f(grad_config, xdual) + dense = ADTypes.dense_ad(alg_autodiff(alg)) + + if dense isa AutoForwardDiff + sparsity, colorvec = sparsity_colorvec(integrator.f, x) + maxcolor = maximum(colorvec) + chunk_size = (get_chunksize(alg) == Val(0) || get_chunksize(alg) == Val(nothing)) ? + nothing : get_chunksize(alg) + num_of_chunks = div(maxcolor, + isnothing(chunk_size) ? + getsize(ForwardDiff.pickchunksize(maxcolor)) : _unwrap_val(chunk_size), + RoundUp) + + integrator.stats.nf += num_of_chunks + + elseif dense isa AutoFiniteDiff + sparsity, colorvec = sparsity_colorvec(integrator.f, x) + if dense.fdtype == Val(:forward) + integrator.stats.nf += maximum(colorvec) + 1 + elseif dense.fdtype == Val(:central) + integrator.stats.nf += 2*maximum(colorvec) + elseif dense.fdtype == Val(:complex) + integrator.stats.nf += maximum(colorvec) end + else + integrator.stats.nf += 1 + end - df .= first.(ForwardDiff.partials.(grad_config)) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - elseif alg_autodiff(alg) isa AutoFiniteDiff - FiniteDiff.finite_difference_gradient!(df, f, x, grad_config, - dir = diffdir(integrator)) - fdtype = alg_difftype(alg) - if fdtype == Val{:forward} || fdtype == Val{:central} - tmp *= 2 - if eltype(df) <: Complex - tmp *= 2 - end + if dense isa AutoFiniteDiff + dense = SciMLBase.@set dense.dir = diffdir(integrator) + end + + # Apply GPU-safe wrapping for AutoForwardDiff when dealing with GPU arrays + dense = gpu_safe_autodiff(dense, x) + + autodiff_alg = gpu_safe_autodiff(alg_autodiff(alg), x) + + if alg_autodiff(alg) isa AutoSparse + autodiff_alg = SciMLBase.@set autodiff_alg.dense_ad = dense + else + autodiff_alg = dense + end + + if integrator.iter == 1 + try + jac = DI.jacobian(f, autodiff_alg, x) + catch e + throw(FirstAutodiffJacError(e)) end - integrator.stats.nf += tmp else - error("$alg_autodiff not yet supported in derivative! function") + jac = DI.jacobian(f, autodiff_alg, x) end - nothing + + return jac end -function derivative(f, x::Union{Number, AbstractArray{<:Number}}, - integrator) - local d - tmp = length(x) # We calculate derivative for all elements in gradient +# fallback for scalar x, is needed for calc_J to work +function jacobian(f::F, x, integrator) where F alg = unwrap_alg(integrator, true) - if alg_autodiff(alg) isa AutoForwardDiff - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - if integrator.iter == 1 - try - d = ForwardDiff.derivative(f, x) - catch e - throw(FirstAutodiffTgradError(e)) - end - else - d = ForwardDiff.derivative(f, x) - end - elseif alg_autodiff(alg) isa AutoFiniteDiff - d = FiniteDiff.finite_difference_derivative(f, x, alg_difftype(alg), - dir = diffdir(integrator)) - if alg_difftype(alg) === Val{:central} || alg_difftype(alg) === Val{:forward} - tmp *= 2 + + dense = ADTypes.dense_ad(alg_autodiff(alg)) + + if dense isa AutoForwardDiff + integrator.stats.nf += 1 + elseif dense isa AutoFiniteDiff + if dense.fdtype == Val(:forward) + integrator.stats.nf += 2 + elseif dense.fdtype == Val(:central) + integrator.stats.nf += 2 + elseif dense.fdtype == Val(:complex) + integrator.stats.nf += 1 end - integrator.stats.nf += tmp - d else - error("$alg_autodiff not yet supported in derivative function") + integrator.stats.nf += 1 end -end -jacobian_autodiff(f, x, odefun, alg) = (ForwardDiff.derivative(f, x), 1, alg) -function jacobian_autodiff(f, x::AbstractArray, odefun, alg) - jac_prototype = odefun.jac_prototype - sparsity, colorvec = sparsity_colorvec(odefun, x) - maxcolor = maximum(colorvec) - chunk_size = get_chunksize(alg) === Val(0) ? nothing : get_chunksize(alg) - num_of_chunks = chunk_size === nothing ? - Int(ceil(maxcolor / getsize(ForwardDiff.pickchunksize(maxcolor)))) : - Int(ceil(maxcolor / _unwrap_val(chunk_size))) - ( - forwarddiff_color_jacobian(f, x, colorvec = colorvec, sparsity = sparsity, - jac_prototype = jac_prototype, chunksize = chunk_size), - num_of_chunks) -end + if dense isa AutoFiniteDiff + dense = SciMLBase.@set dense.dir = diffdir(integrator) + end + + # Apply GPU-safe wrapping for AutoForwardDiff when dealing with GPU arrays + dense = gpu_safe_autodiff(dense, x) -function _nfcount(N, ::Type{diff_type}) where {diff_type} - if diff_type === Val{:complex} - tmp = N - elseif diff_type === Val{:forward} - tmp = N + 1 + autodiff_alg = gpu_safe_autodiff(alg_autodiff(alg), x) + + if autodiff_alg isa AutoSparse + autodiff_alg = SciMLBase.@set autodiff_alg.dense_ad = dense else - tmp = 2N + autodiff_alg = dense end - tmp -end -function jacobian_finitediff(f, x, ::Type{diff_type}, dir, colorvec, sparsity, - jac_prototype) where {diff_type} - (FiniteDiff.finite_difference_derivative(f, x, diff_type, eltype(x), dir = dir), 2) -end -function jacobian_finitediff(f, x::AbstractArray, ::Type{diff_type}, dir, colorvec, - sparsity, jac_prototype) where {diff_type} - f_in = diff_type === Val{:forward} ? f(x) : similar(x) - ret_eltype = eltype(f_in) - J = FiniteDiff.finite_difference_jacobian(f, x, diff_type, ret_eltype, f_in, - dir = dir, colorvec = colorvec, - sparsity = sparsity, - jac_prototype = jac_prototype) - return J, _nfcount(maximum(colorvec), diff_type) -end -function jacobian(f, x, integrator) - alg = unwrap_alg(integrator, true) - local tmp - if alg_autodiff(alg) isa AutoForwardDiff - if integrator.iter == 1 - try - J, tmp = jacobian_autodiff(f, x, integrator.f, alg) - catch e - throw(FirstAutodiffJacError(e)) - end - else - J, tmp = jacobian_autodiff(f, x, integrator.f, alg) + if integrator.iter == 1 + try + jac = DI.derivative(f, autodiff_alg, x) + catch e + throw(FirstAutodiffJacError(e)) end - elseif alg_autodiff(alg) isa AutoFiniteDiff - jac_prototype = integrator.f.jac_prototype - sparsity, colorvec = sparsity_colorvec(integrator.f, x) - dir = diffdir(integrator) - J, tmp = jacobian_finitediff(f, x, alg_difftype(alg), dir, colorvec, sparsity, - jac_prototype) else - bleh + jac = DI.derivative(f, autodiff_alg, x) end - integrator.stats.nf += tmp - J -end -function jacobian_finitediff_forward!(J, f, x, jac_config, forwardcache, integrator) - (FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config, forwardcache, - dir = diffdir(integrator)); - maximum(jac_config.colorvec)) -end -function jacobian_finitediff!(J, f, x, jac_config, integrator) - (FiniteDiff.finite_difference_jacobian!(J, f, x, jac_config, - dir = diffdir(integrator)); - 2 * maximum(jac_config.colorvec)) + return jac end -function jacobian!(J::AbstractMatrix{<:Number}, f, x::AbstractArray{<:Number}, - fx::AbstractArray{<:Number}, integrator::DiffEqBase.DEIntegrator, - jac_config) +function jacobian!(J::AbstractMatrix{<:Number}, f::F, x::AbstractArray{<:Number}, + fx::AbstractArray{<:Number}, integrator::SciMLBase.DEIntegrator, + jac_config) where F alg = unwrap_alg(integrator, true) - if alg_autodiff(alg) isa AutoForwardDiff - if integrator.iter == 1 - try - forwarddiff_color_jacobian!(J, f, x, jac_config) - catch e - throw(FirstAutodiffJacError(e)) - end + + dense = ADTypes.dense_ad(alg_autodiff(alg)) + + if dense isa AutoForwardDiff + if alg_autodiff(alg) isa AutoSparse + integrator.stats.nf += maximum(ncolors(jac_config[1])) else - forwarddiff_color_jacobian!(J, f, x, jac_config) + sparsity, colorvec = sparsity_colorvec(integrator.f, x) + maxcolor = maximum(colorvec) + chunk_size = (get_chunksize(alg) == Val(0) || + get_chunksize(alg) == Val(nothing)) ? nothing : get_chunksize(alg) + num_of_chunks = chunk_size === nothing ? + Int(ceil(maxcolor / + getsize(ForwardDiff.pickchunksize(maxcolor)))) : + Int(ceil(maxcolor / _unwrap_val(chunk_size))) + + integrator.stats.nf += num_of_chunks end - OrdinaryDiffEqCore.increment_nf!(integrator.stats, maximum(jac_config.colorvec)) - elseif alg_autodiff(alg) isa AutoFiniteDiff - isforward = alg_difftype(alg) === Val{:forward} - if isforward - forwardcache = get_tmp_cache(integrator, alg, unwrap_cache(integrator, true))[2] - f(forwardcache, x) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - tmp = jacobian_finitediff_forward!(J, f, x, jac_config, forwardcache, - integrator) - else # not forward difference - tmp = jacobian_finitediff!(J, f, x, jac_config, integrator) + + elseif dense isa AutoFiniteDiff + sparsity, colorvec = sparsity_colorvec(integrator.f, x) + if dense.fdtype == Val(:forward) + integrator.stats.nf += maximum(colorvec) + 1 + elseif dense.fdtype == Val(:central) + integrator.stats.nf += 2 * maximum(colorvec) + elseif dense.fdtype == Val(:complex) + integrator.stats.nf += maximum(colorvec) + end + else + integrator.stats.nf += 1 + end + + if dense isa AutoFiniteDiff + config = diffdir(integrator) > 0 ? jac_config[1] : jac_config[2] + else + config = jac_config[1] + end + + if integrator.iter == 1 + try + DI.jacobian!(f, fx, J, config, gpu_safe_autodiff(alg_autodiff(alg), x), x) + catch e + throw(FirstAutodiffJacError(e)) end - integrator.stats.nf += tmp else - error("$alg_autodiff not yet supported in jacobian! function") + DI.jacobian!(f, fx, J, config, gpu_safe_autodiff(alg_autodiff(alg), x), x) end + nothing end -function build_jac_config(alg, f::F1, uf::F2, du1, uprev, u, tmp, du2) where {F1, F2} +function build_jac_config(alg, f::F1, uf::F2, du1, uprev, + u, tmp, du2) where {F1, F2} haslinsolve = hasfield(typeof(alg), :linsolve) - if !DiffEqBase.has_jac(f) && # No Jacobian if has analytical solution - (!DiffEqBase.has_Wfact_t(f)) && - ((concrete_jac(alg) === nothing && (!haslinsolve || (haslinsolve && # No Jacobian if linsolve doesn't want it + if !SciMLBase.has_jac(f) && + (!SciMLBase.has_Wfact_t(f)) && + ((concrete_jac(alg) === nothing && (!haslinsolve || (haslinsolve && (alg.linsolve === nothing || LinearSolve.needs_concrete_A(alg.linsolve))))) || - (concrete_jac(alg) !== nothing && concrete_jac(alg))) # Jacobian if explicitly asked for + (concrete_jac(alg) !== nothing && concrete_jac(alg))) jac_prototype = f.jac_prototype - if jac_prototype isa SparseMatrixCSC + if is_sparse_csc(jac_prototype) if f.mass_matrix isa UniformScaling idxs = diagind(jac_prototype) @. @view(jac_prototype[idxs]) = 1 @@ -278,35 +259,36 @@ function build_jac_config(alg, f::F1, uf::F2, du1, uprev, u, tmp, du2) where {F1 end end - sparsity, colorvec = sparsity_colorvec(f, u) + autodiff_alg = gpu_safe_autodiff(alg_autodiff(alg), u) + dense = autodiff_alg isa AutoSparse ? ADTypes.dense_ad(autodiff_alg) : autodiff_alg - if alg_autodiff(alg) isa AutoForwardDiff - _chunksize = get_chunksize(alg) === Val(0) ? nothing : get_chunksize(alg) # SparseDiffEq uses different convection... - T = if standardtag(alg) - typeof(ForwardDiff.Tag(OrdinaryDiffEqTag(), eltype(u))) - else - typeof(ForwardDiff.Tag(uf, eltype(u))) - end - jac_config = ForwardColorJacCache(uf, uprev, _chunksize; colorvec = colorvec, - sparsity = sparsity, tag = T) - elseif alg_autodiff(alg) isa AutoFiniteDiff - if alg_difftype(alg) !== Val{:complex} - jac_config = FiniteDiff.JacobianCache(tmp, du1, du2, alg_difftype(alg), - colorvec = colorvec, - sparsity = sparsity) + if dense isa AutoFiniteDiff + dir_forward = @set dense.dir = 1 + dir_reverse = @set dense.dir = -1 + + if autodiff_alg isa AutoSparse + autodiff_alg_forward = @set autodiff_alg.dense_ad = dir_forward + autodiff_alg_reverse = @set autodiff_alg.dense_ad = dir_reverse else - jac_config = FiniteDiff.JacobianCache(Complex{eltype(tmp)}.(tmp), - Complex{eltype(du1)}.(du1), nothing, - alg_difftype(alg), eltype(u), - colorvec = colorvec, - sparsity = sparsity) + autodiff_alg_forward = dir_forward + autodiff_alg_reverse = dir_reverse end + + jac_config_forward = DI.prepare_jacobian( + uf, du1, autodiff_alg_forward, u, strict = Val(false)) + jac_config_reverse = DI.prepare_jacobian( + uf, du1, autodiff_alg_reverse, u, strict = Val(false)) + + jac_config = (jac_config_forward, jac_config_reverse) else - error("$alg_autodiff not yet supported in build_jac_config function") + jac_config1 = DI.prepare_jacobian(uf, du1, autodiff_alg, u, strict = Val(false)) + jac_config = (jac_config1, jac_config1) end + else - jac_config = nothing + jac_config = (nothing, nothing) end + jac_config end @@ -320,80 +302,101 @@ function get_chunksize(jac_config::ForwardDiff.JacobianConfig{ Val(N) end # don't degrade compile time information to runtime information -function resize_jac_config!(jac_config::SparseDiffTools.ForwardColorJacCache, i) - resize!(jac_config.fx, i) - resize!(jac_config.dx, i) - resize!(jac_config.t, i) - ps = SparseDiffTools.adapt.(DiffEqBase.parameterless_type(jac_config.dx), - SparseDiffTools.generate_chunked_partials(jac_config.dx, - 1:length(jac_config.dx), - Val(ForwardDiff.npartials(jac_config.t[1])))) - resize!(jac_config.p, length(ps)) - jac_config.p .= ps -end +function resize_jac_config!(cache, integrator) + if !isnothing(cache.jac_config) && !isnothing(cache.jac_config[1]) + uf = cache.uf + uf = SciMLBase.@set uf.f = SciMLBase.unwrapped_f(uf.f) -function resize_jac_config!(jac_config::FiniteDiff.JacobianCache, i) - resize!(jac_config, i) - jac_config -end + # for correct FiniteDiff dirs + autodiff_alg = alg_autodiff(integrator.alg) + if autodiff_alg isa AutoFiniteDiff + ad_right = SciMLBase.@set autodiff_alg.dir = 1 + ad_left = SciMLBase.@set autodiff_alg.dir = -1 + else + ad_right = autodiff_alg + ad_left = autodiff_alg + end -function resize_grad_config!(grad_config::AbstractArray, i) - resize!(grad_config, i) - grad_config + cache.jac_config = ([DI.prepare!_jacobian( + uf, cache.du1, config, ad, integrator.u) + for (ad, config) in zip( + (ad_right, ad_left), cache.jac_config)]...,) + end + cache.jac_config end -function resize_grad_config!(grad_config::ForwardDiff.DerivativeConfig, i) - resize!(grad_config.duals, i) - grad_config +function resize_grad_config!(cache, integrator) + if !isnothing(cache.grad_config) && !isnothing(cache.grad_config[1]) + + # for correct FiniteDiff dirs + autodiff_alg = ADTypes.dense_ad(alg_autodiff(integrator.alg)) + if autodiff_alg isa AutoFiniteDiff + ad_right = SciMLBase.@set autodiff_alg.dir = 1 + ad_left = SciMLBase.@set autodiff_alg.dir = -1 + else + ad_right = autodiff_alg + ad_left = autodiff_alg + end + + cache.grad_config = ([DI.prepare!_derivative( + cache.tf, cache.du1, config, ad, integrator.t) + for (ad, config) in zip( + (ad_right, ad_left), cache.grad_config)]...,) + end + cache.grad_config end -function resize_grad_config!(grad_config::FiniteDiff.GradientCache, i) - @unpack fx, c1, c2 = grad_config - fx !== nothing && resize!(fx, i) - c1 !== nothing && resize!(c1, i) - c2 !== nothing && resize!(c2, i) - grad_config +""" + gpu_safe_autodiff(backend, u) + +Automatically wrap AutoForwardDiff with AutoForwardFromPrimitive for GPU arrays +that don't support fast scalar indexing (e.g., GPU arrays). +""" +function gpu_safe_autodiff(backend::AutoForwardDiff, u) + if ArrayInterface.fast_scalar_indexing(u) + # CPU arrays with fast scalar indexing - use original backend + return backend + else + # GPU arrays or arrays without fast scalar indexing - use primitive wrapper + return DI.AutoForwardFromPrimitive(backend) + end end +# Fallback for other AD backends +gpu_safe_autodiff(backend, u) = backend + function build_grad_config(alg, f::F1, tf::F2, du1, t) where {F1, F2} - if !DiffEqBase.has_tgrad(f) - if alg_autodiff(alg) isa AutoForwardDiff - T = if standardtag(alg) - typeof(ForwardDiff.Tag(OrdinaryDiffEqTag(), eltype(du1))) - else - typeof(ForwardDiff.Tag(f, eltype(du1))) - end + if !SciMLBase.has_tgrad(f) + ad = ADTypes.dense_ad(alg_autodiff(alg)) - if du1 isa Array - dualt = Dual{T, eltype(du1), 1}(first(du1) * t, - ForwardDiff.Partials((one(eltype(du1)),))) - grad_config = similar(du1, typeof(dualt)) - fill!(grad_config, false) - else - grad_config = ArrayInterface.restructure(du1, - Dual{ - T, - eltype(du1), - 1 - }.(du1, - (ForwardDiff.Partials((one(eltype(du1)),)),)) .* - false) - end - elseif alg_autodiff(alg) isa AutoFiniteDiff - grad_config = FiniteDiff.GradientCache(du1, t, alg_difftype(alg)) + # Apply GPU-safe wrapping for AutoForwardDiff when dealing with GPU arrays + ad = gpu_safe_autodiff(ad, du1) + + if ad isa AutoFiniteDiff + dir_true = @set ad.dir = 1 + dir_false = @set ad.dir = -1 + + grad_config_true = DI.prepare_derivative(tf, du1, dir_true, t) + grad_config_false = DI.prepare_derivative(tf, du1, dir_false, t) + + grad_config = (grad_config_true, grad_config_false) + elseif ad isa AutoForwardDiff + grad_config1 = DI.prepare_derivative(tf, du1, ad, convert(eltype(du1), t)) + grad_config = (grad_config1, grad_config1) else - error("$alg_autodiff not yet supported in build_grad_config function") + grad_config1 = DI.prepare_derivative(tf, du1, ad, t) + grad_config = (grad_config1, grad_config1) end + return grad_config else - grad_config = nothing + return (nothing, nothing) end - grad_config end -function sparsity_colorvec(f, x) +function sparsity_colorvec(f::F, x) where F sparsity = f.sparsity - if sparsity isa SparseMatrixCSC + if is_sparse_csc(sparsity) if f.mass_matrix isa UniformScaling idxs = diagind(sparsity) @. @view(sparsity[idxs]) = 1 @@ -403,7 +406,9 @@ function sparsity_colorvec(f, x) end end - colorvec = DiffEqBase.has_colorvec(f) ? f.colorvec : - (isnothing(sparsity) ? (1:length(x)) : matrix_colors(sparsity)) + col_alg = GreedyColoringAlgorithm() + col_prob = ColoringProblem() + colorvec = SciMLBase.has_colorvec(f) ? f.colorvec : + (isnothing(sparsity) ? (1:length(x)) : column_colors(coloring(sparsity, col_prob, col_alg))) sparsity, colorvec end diff --git a/lib/OrdinaryDiffEqDifferentiation/src/linsolve_utils.jl b/lib/OrdinaryDiffEqDifferentiation/src/linsolve_utils.jl index aa48161e1b..4d8f5ecdb9 100644 --- a/lib/OrdinaryDiffEqDifferentiation/src/linsolve_utils.jl +++ b/lib/OrdinaryDiffEqDifferentiation/src/linsolve_utils.jl @@ -17,7 +17,8 @@ function dolinsolve(integrator, linsolve; A = nothing, linu = nothing, b = nothi _alg = unwrap_alg(integrator, true) - _Pl, _Pr = _alg.precs(linsolve.A, du, u, p, t, A !== nothing, Plprev, Prprev, + _Pl, + _Pr = _alg.precs(linsolve.A, du, u, p, t, A !== nothing, Plprev, Prprev, solverdata) if (_Pl !== nothing || _Pr !== nothing) __Pl = _Pl === nothing ? SciMLOperators.IdentityOperator(length(integrator.u)) : _Pl @@ -28,16 +29,17 @@ function dolinsolve(integrator, linsolve; A = nothing, linu = nothing, b = nothi linres = solve!(linsolve; reltol) + ad = alg_autodiff(_alg) isa ADTypes.AutoSparse ? ADTypes.dense_ad(alg_autodiff(_alg)) : + alg_autodiff(_alg) + # TODO: this ignores the add of the `f` count for add_steps! if integrator isa SciMLBase.DEIntegrator && _alg.linsolve !== nothing && !LinearSolve.needs_concrete_A(_alg.linsolve) && linsolve.A isa WOperator && linsolve.A.J isa AbstractSciMLOperator - if alg_autodiff(_alg) isa AutoForwardDiff - integrator.stats.nf += linres.iters - elseif alg_autodiff(_alg) isa AutoFiniteDiff - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) * linres.iters + if ad isa ADTypes.AutoFiniteDiff || ad isa ADTypes.AutoFiniteDifferences + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2 * linres.iters) else - error("$alg_autodiff not yet supported in dolinsolve function") + integrator.stats.nf += linres.iters end end diff --git a/lib/OrdinaryDiffEqDifferentiation/src/operators.jl b/lib/OrdinaryDiffEqDifferentiation/src/operators.jl new file mode 100644 index 0000000000..8a27ffd4d2 --- /dev/null +++ b/lib/OrdinaryDiffEqDifferentiation/src/operators.jl @@ -0,0 +1,89 @@ +""" + JVPCache{T} <: AbstractSciMLOperator{T} + +JVPCache provides a JVP operator wrapper for performing the DifferentiationInterface pushforward operation. + +### Constructor + +```julia +JVPCache(f::SciMLBase.AbstractDiffEqFunction, du, u, p, t; autodiff) +``` + +JVPCache construction builds a DifferentiationInterface "prep" object using `prepare_pushforward!`. The "prep" object is used +when applying the operator. + +### Computing the JVP + +Computing the JVP is done with the DifferentiationInterface function `pushforward!`, which takes advantage of the preparation done upon construction. +""" +@concrete mutable struct JVPCache{T} <: SciMLOperators.AbstractSciMLOperator{T} + jvp_op::Any + f::Any + du::Any + u::Any + p::Any + t::Any +end + +SciMLBase.isinplace(::JVPCache) = true +ArrayInterface.can_setindex(::JVPCache) = false +function ArrayInterface.restructure(y::JVPCache, x::JVPCache) + @assert size(y)==size(x) "cannot restructure operators. ensure their sizes match." + return x +end + +function ConstructionBase.constructorof(::Type{<:JVPCache{T}}) where {T} + return JVPCache{T} +end + +Base.size(J::JVPCache) = (length(J.u), length(J.u)) + +function JVPCache(f::SciMLBase.AbstractDiffEqFunction, du, u, p, t; autodiff) + jvp_op = prepare_jvp(f, du, u, p, t, autodiff) + return JVPCache{eltype(du)}(jvp_op, f, du, u, p, t) +end + +function (op::JVPCache)(Jv, v, u, p, t) + op.jvp_op(Jv, v, u, p, t) + return Jv +end + +function LinearAlgebra.mul!( + Jv::AbstractArray, J::JVPCache, v::AbstractArray) + J.jvp_op(Jv, v, J.u, J.p, J.t) + return Jv +end + +# helper functions + +function prepare_jvp(f::SciMLBase.AbstractDiffEqFunction, du, u, p, t, autodiff) + SciMLBase.has_jvp(f) && return f.jvp + autodiff = autodiff isa AutoSparse ? ADTypes.dense_ad(autodiff) : autodiff + @assert DI.check_inplace(autodiff) "AD backend $(autodiff) doesn't support in-place problems." + di_prep = DI.prepare_pushforward( + f, du, autodiff, u, (u,), DI.ConstantOrCache(p), DI.Constant(t)) + return (Jv, + v, + u, + p, + t) -> DI.pushforward!(f, du, (reshape(Jv, size(du)),), di_prep, autodiff, u, + (reshape(v, size(u)),), DI.ConstantOrCache(p), DI.Constant(t)) +end + +function SciMLOperators.update_coefficients!(J::JVPCache, u, p, t) + J.u = u + J.p = p + J.t = t +end + +function resize_JVPCache!(J::JVPCache, f, du, u, p, t, autodiff) + J.jvp_op = prepare_jvp(f, du, u, p, t, autodiff) + J.du = du + update_coefficients!(J, u, p, t) +end + +function resize_JVPCache!(J::JVPCache, f, du, u, autodiff) + J.jvp_op = prepare_jvp(f, du, u, J.p, J.t, autodiff) + J.du = du + update_coefficients!(J, u, J.p, J.t) +end diff --git a/lib/OrdinaryDiffEqDifferentiation/test/jet.jl b/lib/OrdinaryDiffEqDifferentiation/test/jet.jl new file mode 100644 index 0000000000..b31509a034 --- /dev/null +++ b/lib/OrdinaryDiffEqDifferentiation/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqDifferentiation +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqDifferentiation, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqDifferentiation/test/qa.jl b/lib/OrdinaryDiffEqDifferentiation/test/qa.jl new file mode 100644 index 0000000000..35a110b433 --- /dev/null +++ b/lib/OrdinaryDiffEqDifferentiation/test/qa.jl @@ -0,0 +1,10 @@ +using OrdinaryDiffEqDifferentiation +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqDifferentiation; + piracies = false, + ambiguities = false + ) +end diff --git a/lib/OrdinaryDiffEqDifferentiation/test/runtests.jl b/lib/OrdinaryDiffEqDifferentiation/test/runtests.jl index 8b13789179..75ab3bccf9 100644 --- a/lib/OrdinaryDiffEqDifferentiation/test/runtests.jl +++ b/lib/OrdinaryDiffEqDifferentiation/test/runtests.jl @@ -1 +1,4 @@ +using SafeTestsets +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqExplicitRK/Project.toml b/lib/OrdinaryDiffEqExplicitRK/Project.toml index f0640c2e31..e0d6678dd9 100644 --- a/lib/OrdinaryDiffEqExplicitRK/Project.toml +++ b/lib/OrdinaryDiffEqExplicitRK/Project.toml @@ -1,38 +1,49 @@ name = "OrdinaryDiffEqExplicitRK" uuid = "9286f039-9fbf-40e8-bf65-aa933bdc4db0" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.4.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" + +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" [compat] -DiffEqBase = "6" -DiffEqDevTools = "2.44.4" +Test = "<0.0.1, 1" FastBroadcast = "0.3" -LinearAlgebra = "1.10" -MuladdMacro = "0.2" -OrdinaryDiffEqCore = "1" Random = "<0.0.1, 1" -RecursiveArrayTools = "3" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Test = "<0.0.1, 1" -TruncatedStacktraces = "1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearAlgebra = "1.10" +TruncatedStacktraces = "1.4" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" julia = "1.10" - -[extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqExplicitRK/src/OrdinaryDiffEqExplicitRK.jl b/lib/OrdinaryDiffEqExplicitRK/src/OrdinaryDiffEqExplicitRK.jl index 6274afbf6f..2c5d1d1758 100644 --- a/lib/OrdinaryDiffEqExplicitRK/src/OrdinaryDiffEqExplicitRK.jl +++ b/lib/OrdinaryDiffEqExplicitRK/src/OrdinaryDiffEqExplicitRK.jl @@ -7,12 +7,13 @@ import OrdinaryDiffEqCore: alg_order, alg_adaptive_order, alg_stability_size, OrdinaryDiffEqMutableCache, initialize!, perform_step!, isfsal, CompositeAlgorithm, calculate_residuals!, calculate_residuals, full_cache, get_fsalfirstlast -using TruncatedStacktraces, RecursiveArrayTools, FastBroadcast, MuladdMacro, DiffEqBase +using TruncatedStacktraces: @truncate_stacktrace +using RecursiveArrayTools, FastBroadcast, MuladdMacro, DiffEqBase import LinearAlgebra: norm import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqExplicitRK/src/algorithms.jl b/lib/OrdinaryDiffEqExplicitRK/src/algorithms.jl index dbde167d17..e3b669e516 100644 --- a/lib/OrdinaryDiffEqExplicitRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqExplicitRK/src/algorithms.jl @@ -37,9 +37,21 @@ Sets the default tableau for the ODE solver. Currently Dormand-Prince 4/5. """ const ODE_DEFAULT_TABLEAU = constructDormandPrince() +@doc raw""" + ExplicitRK(; tableau = ODE_DEFAULT_TABLEAU) + +A generic explicit Runge-Kutta method that allows you to define a custom tableau. +The default tableau is Dormand-Prince 4/5. This solver is primarily for research +purposes or when you need a specific tableau not already implemented. + +# Parameters +- `tableau`: A `DiffEqBase.ExplicitRKTableau` object defining the Runge-Kutta tableau. + +For most applications, prefer the named methods like `DP5()`, `Tsit5()`, etc. +""" struct ExplicitRK{TabType} <: OrdinaryDiffEqAdaptiveAlgorithm tableau::TabType end ExplicitRK(; tableau = ODE_DEFAULT_TABLEAU) = ExplicitRK(tableau) -TruncatedStacktraces.@truncate_stacktrace ExplicitRK +@truncate_stacktrace ExplicitRK diff --git a/lib/OrdinaryDiffEqExplicitRK/src/explicit_rk_perform_step.jl b/lib/OrdinaryDiffEqExplicitRK/src/explicit_rk_perform_step.jl index 093c62b4f8..fca3a71c77 100644 --- a/lib/OrdinaryDiffEqExplicitRK/src/explicit_rk_perform_step.jl +++ b/lib/OrdinaryDiffEqExplicitRK/src/explicit_rk_perform_step.jl @@ -85,13 +85,13 @@ end @generated function accumulate_explicit_stages!(out, A, uprev, kk, dt, ::Val{s}, ::Val{r} = Val(s)) where {s, r} if s == 1 - return :(@muladd @.. broadcast=false out=uprev + dt * kk[1]) + return :(@muladd @.. broadcast=false out=uprev+dt*kk[1]) elseif s == 2 # Note that `A` is transposed - return :(@muladd @.. broadcast=false out=uprev + dt * (A[1, $r] * kk[1])) + return :(@muladd @.. broadcast=false out=uprev+dt*(A[1, $r]*kk[1])) else - expr = :(@muladd @.. broadcast=false out=uprev + - dt * (A[1, $r] * kk[1] + A[2, $r] * kk[2])) + expr = :(@muladd @.. broadcast=false out=uprev+ + dt*(A[1, $r]*kk[1]+A[2, $r]*kk[2])) acc = expr.args[end].args[end].args[end].args[end].args[end].args for i in 3:(s - 1) push!(acc, :(A[$i, $r] * kk[$i])) @@ -102,9 +102,9 @@ end @generated function accumulate_EEst!(out, αEEst, kk, dt, ::Val{s}) where {s} if s == 1 - return :(@muladd @.. broadcast=false out=dt * (αEEst[1] * kk[1])) + return :(@muladd @.. broadcast=false out=dt*(αEEst[1]*kk[1])) else - expr = :(@muladd @.. broadcast=false out=dt * (αEEst[1] * kk[1] + αEEst[2] * kk[2])) + expr = :(@muladd @.. broadcast=false out=dt*(αEEst[1]*kk[1]+αEEst[2]*kk[2])) acc = expr.args[end].args[end].args[end].args[end].args for i in 3:s push!(acc, :(αEEst[$i] * kk[$i])) @@ -114,11 +114,11 @@ end end function accumulate_EEst!(out, αEEst, utilde, kk, dt, stages) - @.. broadcast=false utilde=αEEst[1] * kk[1] + @.. broadcast=false utilde=αEEst[1]*kk[1] for i in 2:stages - @.. broadcast=false utilde=utilde + αEEst[i] * kk[i] + @.. broadcast=false utilde=utilde+αEEst[i]*kk[i] end - @.. broadcast=false out=dt * utilde + @.. broadcast=false out=dt*utilde end @muladd function compute_stages!(f::F, A, c, utilde, u, tmp, uprev, kk, p, t, dt, @@ -127,18 +127,18 @@ end for i in 2:(stages - 1) @.. broadcast=false utilde=zero(kk[1][1]) for j in 1:(i - 1) - @.. broadcast=false utilde=utilde + A[j, i] * kk[j] + @.. broadcast=false utilde=utilde+A[j, i]*kk[j] end - @.. broadcast=false tmp=uprev + dt * utilde + @.. broadcast=false tmp=uprev+dt*utilde f(kk[i], tmp, p, t + c[i] * dt) end #Last @.. broadcast=false utilde=zero(kk[1][1]) for j in 1:(stages - 1) - @.. broadcast=false utilde=utilde + A[j, end] * kk[j] + @.. broadcast=false utilde=utilde+A[j, end]*kk[j] end - @.. broadcast=false u=uprev + dt * utilde + @.. broadcast=false u=uprev+dt*utilde f(kk[end], u, p, t + c[end] * dt) #fsallast is tmp even if not fsal return nothing end @@ -174,11 +174,11 @@ function runtime_split_stages!(f::F, A, c, utilde, u, tmp, uprev, kk, p, t, dt, end function accumulate_fsal!(u, α, utilde, uprev, kk, dt, stages) - @.. broadcast=false utilde=α[1] * kk[1] + @.. broadcast=false utilde=α[1]*kk[1] for i in 2:stages - @.. broadcast=false utilde=utilde + α[i] * kk[i] + @.. broadcast=false utilde=utilde+α[i]*kk[i] end - @.. broadcast=false u=uprev + dt * utilde + @.. broadcast=false u=uprev+dt*utilde end function runtime_split_fsal!(out, A, utilde, uprev, kk, dt, stages) @@ -219,7 +219,7 @@ end if integrator.alg isa CompositeAlgorithm # Hairer II, page 22 modified to use Inf norm - @.. broadcast=false utilde=abs((kk[end] - kk[end - 1]) / (u - tmp)) + @.. broadcast=false utilde=abs((kk[end]-kk[end - 1])/(u-tmp)) integrator.eigen_est = integrator.opts.internalnorm(norm(utilde, Inf), t) end diff --git a/lib/OrdinaryDiffEqExplicitRK/test/allocation_tests.jl b/lib/OrdinaryDiffEqExplicitRK/test/allocation_tests.jl new file mode 100644 index 0000000000..c03c6999fb --- /dev/null +++ b/lib/OrdinaryDiffEqExplicitRK/test/allocation_tests.jl @@ -0,0 +1,46 @@ +using OrdinaryDiffEqExplicitRK +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqExplicitRK solvers using AllocCheck.jl. +These tests verify that the step! operation does not allocate during stepping. +""" + +@testset "ExplicitRK Allocation Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported ExplicitRK solvers for allocation-free behavior + explicit_rk_solvers = [ExplicitRK()] + + @testset "ExplicitRK Solver Allocation Analysis" begin + for solver in explicit_rk_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test_broken length(allocs) == 0 + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqExplicitRK/test/jet.jl b/lib/OrdinaryDiffEqExplicitRK/test/jet.jl new file mode 100644 index 0000000000..5dbac17184 --- /dev/null +++ b/lib/OrdinaryDiffEqExplicitRK/test/jet.jl @@ -0,0 +1,37 @@ +import OrdinaryDiffEqExplicitRK +using OrdinaryDiffEqExplicitRK +using OrdinaryDiffEqCore +using JET +using Test + +@testset "JET Tests" begin + # Test package for typos - now passing + test_package( + OrdinaryDiffEqExplicitRK, target_defined_modules = true, mode = :typo) + + # Test individual solver type stability + @testset "Solver Type Stability Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported ExplicitRK solvers + explicit_rk_solvers = [ExplicitRK()] + + for solver in explicit_rk_solvers + @testset "$(typeof(solver)) type stability" begin + try + @test_opt broken=true init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + end +end diff --git a/lib/OrdinaryDiffEqExplicitRK/test/qa.jl b/lib/OrdinaryDiffEqExplicitRK/test/qa.jl new file mode 100644 index 0000000000..b4c63ca2d7 --- /dev/null +++ b/lib/OrdinaryDiffEqExplicitRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqExplicitRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqExplicitRK + ) +end diff --git a/lib/OrdinaryDiffEqExplicitRK/test/runtests.jl b/lib/OrdinaryDiffEqExplicitRK/test/runtests.jl index 8b13789179..5ed6ac4c1c 100644 --- a/lib/OrdinaryDiffEqExplicitRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqExplicitRK/test/runtests.jl @@ -1 +1,8 @@ +using SafeTestsets +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqExponentialRK/Project.toml b/lib/OrdinaryDiffEqExponentialRK/Project.toml index 3dce2d7dd4..f0b4519f9f 100644 --- a/lib/OrdinaryDiffEqExponentialRK/Project.toml +++ b/lib/OrdinaryDiffEqExponentialRK/Project.toml @@ -1,52 +1,72 @@ name = "OrdinaryDiffEqExponentialRK" uuid = "e0540318-69ee-4070-8777-9e2de6de23de" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.8.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" -OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" -OrdinaryDiffEqVerner = "79d7bb75-1356-48c1-b8c0-6832512096c2" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -ExponentialUtilities = "1.26.1" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -LinearSolve = "2.32.0" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqSDIRK = "<0.0.1, 1" -OrdinaryDiffEqTsit5 = "<0.0.1, 1" -OrdinaryDiffEqVerner = "<0.0.1, 1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -SciMLBase = "2.48.1" -SparseArrays = "<0.0.1, 1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +OrdinaryDiffEqVerner = "79d7bb75-1356-48c1-b8c0-6832512096c2" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" + +[compat] +OrdinaryDiffEqTsit5 = "1.4.0" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +OrdinaryDiffEqVerner = "1.5.0" +LinearSolve = "3.26" +ExponentialUtilities = "1.27" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +OrdinaryDiffEqSDIRK = "1.6.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +SparseArrays = "1.10" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "OrdinaryDiffEqTsit5", "LinearSolve", "SparseArrays"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "OrdinaryDiffEqTsit5", "LinearSolve", "SparseArrays", "JET", "Aqua", "OrdinaryDiffEqVerner", "OrdinaryDiffEqSDIRK", "AllocCheck"] + +[sources.OrdinaryDiffEqSDIRK] +path = "../OrdinaryDiffEqSDIRK" + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" + +[sources.OrdinaryDiffEqVerner] +path = "../OrdinaryDiffEqVerner" diff --git a/lib/OrdinaryDiffEqExponentialRK/src/OrdinaryDiffEqExponentialRK.jl b/lib/OrdinaryDiffEqExponentialRK/src/OrdinaryDiffEqExponentialRK.jl index 98fde5722c..ad51a34e39 100644 --- a/lib/OrdinaryDiffEqExponentialRK/src/OrdinaryDiffEqExponentialRK.jl +++ b/lib/OrdinaryDiffEqExponentialRK/src/OrdinaryDiffEqExponentialRK.jl @@ -10,19 +10,21 @@ import OrdinaryDiffEqCore: alg_order, alg_adaptive_order, ismultistep, ExponentialAlgorithm, fsal_typeof, isdtchangeable, calculate_residuals, calculate_residuals!, full_cache, get_fsalfirstlast, - generic_solver_docstring + generic_solver_docstring, _bool_to_ADType, _process_AD_choice import OrdinaryDiffEqCore using RecursiveArrayTools using MuladdMacro, FastBroadcast using LinearAlgebra: axpy!, mul! -using DiffEqBase, SciMLBase +import DiffEqBase +import DiffEqBase: prepare_alg using ExponentialUtilities import RecursiveArrayTools: recursivecopy! using OrdinaryDiffEqDifferentiation: build_jac_config, UJacobianWrapper, UDerivativeWrapper, calc_J, calc_J! +import ADTypes: AutoForwardDiff, AbstractADType using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqExponentialRK/src/algorithms.jl b/lib/OrdinaryDiffEqExponentialRK/src/algorithms.jl index 6f83541846..9a079d8ae2 100644 --- a/lib/OrdinaryDiffEqExponentialRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqExponentialRK/src/algorithms.jl @@ -3,11 +3,11 @@ Hochbruck, Marlis, and Alexander Ostermann. “Exponential Integrators.” Acta Numerica 19 (2010): 209–286. doi:10.1017/S0962492910000048. """ for (Alg, Description, Ref) in [ - (:LawsonEuler, "First order exponential Euler scheme.", REF1), + (:LawsonEuler, "First order exponential Euler scheme (fixed timestepping)", REF1), (:NorsettEuler, "First order exponential-RK scheme. Alias: `ETD1`", REF1), (:ETDRK2, "2nd order exponential-RK scheme.", REF1), (:ETDRK3, "3rd order exponential-RK scheme.", REF1), - (:ETDRK4, "4th order exponential-RK scheme", REF1), + (:ETDRK4, "4th order exponential-RK scheme (fixed timestepping)", REF1), (:HochOst4, "4th order exponential-RK scheme with stiff order 4.", REF1) ] @eval begin @@ -32,16 +32,22 @@ for (Alg, Description, Ref) in [ krylov::Bool m::Int iop::Int + autodiff::AD end end - @eval function $Alg(; krylov = false, m = 30, iop = 0, autodiff = true, + @eval function $Alg(; krylov = false, m = 30, iop = 0, autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, chunk_size = Val{0}(), - diff_type = Val{:forward}) - $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), + diff_type = Val{:forward}()) + AD_choice, chunk_size, + diff_type = _process_AD_choice( + autodiff, chunk_size, diff_type) + + $Alg{_unwrap_val(chunk_size), typeof(AD_choice), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(krylov, m, - iop) + iop, + AD_choice) end end @@ -72,15 +78,22 @@ for (Alg, Description, Ref) in [ OrdinaryDiffEqAdaptiveExponentialAlgorithm{CS, AD, FDT, ST, CJ} m::Int iop::Int + autodiff::AD end end - @eval function $Alg(; m = 30, iop = 0, autodiff = true, standardtag = Val{true}(), + @eval function $Alg(; + m = 30, iop = 0, autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, chunk_size = Val{0}(), - diff_type = Val{:forward}) - $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), + diff_type = Val{:forward}()) + AD_choice, chunk_size, + diff_type = _process_AD_choice( + autodiff, chunk_size, diff_type) + + $Alg{_unwrap_val(chunk_size), typeof(AD_choice), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(m, - iop) + iop, + AD_choice) end end @@ -96,17 +109,17 @@ Tokman, M., Loffeld, J., & Tranquilli, P. (2012). New Adaptive Exponential Propa """ for (Alg, Description, Ref) in [(:Exp4, "4th order EPIRK scheme.", REF3) - (:EPIRK4s3A, - "4th order EPIRK scheme with stiff order 4.", REF4) - (:EPIRK4s3B, - "4th order EPIRK scheme with stiff order 4.", REF4) - (:EPIRK5s3, - "5th order “horizontal” EPIRK scheme with stiff order 5. Broken.", - REF4) - (:EXPRB53s3, - "5th order EPIRK scheme with stiff order 5.", REF4) - (:EPIRK5P1, "5th order EPIRK scheme", REF5) - (:EPIRK5P2, "5th order EPIRK scheme", REF5)] + (:EPIRK4s3A, + "4th order EPIRK scheme with stiff order 4.", REF4) + (:EPIRK4s3B, + "4th order EPIRK scheme with stiff order 4.", REF4) + (:EPIRK5s3, + "5th order “horizontal” EPIRK scheme with stiff order 5. Broken.", + REF4) + (:EXPRB53s3, + "5th order EPIRK scheme with stiff order 5.", REF4) + (:EPIRK5P1, "5th order EPIRK scheme", REF5) + (:EPIRK5P2, "5th order EPIRK scheme", REF5)] @eval begin @doc generic_solver_docstring($Description, $(string(Alg)), @@ -123,20 +136,28 @@ for (Alg, Description, Ref) in [(:Exp4, "4th order EPIRK scheme.", REF3) m = 30, iop = 0, """) + struct $Alg{CS, AD, FDT, ST, CJ} <: OrdinaryDiffEqExponentialAlgorithm{CS, AD, FDT, ST, CJ} adaptive_krylov::Bool m::Int iop::Int + autodiff::AD end end - @eval function $Alg(; adaptive_krylov = true, m = 30, iop = 0, autodiff = true, + @eval function $Alg(; + adaptive_krylov = true, m = 30, iop = 0, autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - chunk_size = Val{0}(), diff_type = Val{:forward}) - $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), diff_type, + chunk_size = Val{0}(), diff_type = Val{:forward}()) + AD_choice, chunk_size, + diff_type = _process_AD_choice( + autodiff, chunk_size, diff_type) + + $Alg{_unwrap_val(chunk_size), typeof(AD_choice), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(adaptive_krylov, m, - iop) + iop, + AD_choice) end end diff --git a/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_caches.jl b/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_caches.jl index 6a2217e3e0..bf1891e40a 100644 --- a/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_caches.jl +++ b/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_caches.jl @@ -87,7 +87,7 @@ for (Alg, Cache) in [(:LawsonEuler, :LawsonEulerConstantCache), convert(AbstractMatrix, f.f1.f) ops = expRK_operators(alg, dt, A) end - if isa(f, SplitFunction) || DiffEqBase.has_jac(f) + if isa(f, SplitFunction) || SciMLBase.has_jac(f) uf = nothing else uf = UDerivativeWrapper(f, t, p) @@ -110,7 +110,7 @@ function alg_cache_expRK( n = length(u) T = eltype(u) # Allocate cache for ForwardDiff - if isa(f, SplitFunction) || DiffEqBase.has_jac(f) + if isa(f, SplitFunction) || SciMLBase.has_jac(f) uf = nothing jac_config = nothing else @@ -120,7 +120,7 @@ function alg_cache_expRK( # Allocate cache for the Jacobian if isa(f, SplitFunction) J = nothing - elseif DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + elseif SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), n, n) @@ -170,7 +170,7 @@ function alg_cache(alg::LawsonEuler, u, rate_prototype, ::Type{uEltypeNoUnits}, n = length(u) T = eltype(u) # Allocate caches for ForwardDiff - if isa(f, SplitFunction) || DiffEqBase.has_jac(f) + if isa(f, SplitFunction) || SciMLBase.has_jac(f) uf = nothing jac_config = nothing else @@ -180,7 +180,7 @@ function alg_cache(alg::LawsonEuler, u, rate_prototype, ::Type{uEltypeNoUnits}, # Allocate cache for the Jacobian if isa(f, SplitFunction) J = nothing - elseif DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + elseif SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), n, n) @@ -222,7 +222,10 @@ function alg_cache(alg::NorsettEuler, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, G, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches plist = (1,) - uf, jac_config, J, phihA, KsCache = alg_cache_expRK( + uf, jac_config, + J, + phihA, + KsCache = alg_cache_expRK( alg, u, uEltypeNoUnits, uprev, f, t, dt, p, du1, tmp, dz, plist) # other caches NorsettEulerCache(u, uprev, tmp, dz, rtmp, G, du1, jac_config, uf, J, phihA, KsCache) @@ -251,7 +254,10 @@ function alg_cache(alg::ETDRK2, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, F2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches plist = (2, 2) - uf, jac_config, J, ops, KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, + uf, jac_config, + J, + ops, + KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, dt, p, du1, tmp, dz, plist) # other caches ETDRK2Cache(u, uprev, tmp, dz, rtmp, F2, du1, jac_config, uf, J, ops, KsCache) end @@ -281,7 +287,10 @@ function alg_cache(alg::ETDRK3, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, Au, F2, F3, du1 = (zero(rate_prototype) for i in 1:5) # rateType caches plist = (1, 3, 3, 3) - uf, jac_config, J, ops, KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, + uf, jac_config, + J, + ops, + KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, dt, p, du1, tmp, dz, plist) # other caches ETDRK3Cache(u, uprev, tmp, dz, rtmp, Au, F2, F3, du1, jac_config, uf, J, ops, KsCache) end @@ -312,7 +321,10 @@ function alg_cache(alg::ETDRK4, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, Au, F2, F3, F4, du1 = (zero(rate_prototype) for i in 1:6) # rateType caches plist = (1, 1, 3, 3, 3, 3) - uf, jac_config, J, ops, KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, + uf, jac_config, + J, + ops, + KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, dt, p, du1, tmp, dz, plist) # other caches ETDRK4Cache(u, uprev, tmp, dz, rtmp, Au, F2, F3, F4, du1, jac_config, uf, J, ops, KsCache) @@ -346,7 +358,10 @@ function alg_cache(alg::HochOst4, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, Au, F2, F3, F4, F5, du1 = (zero(rate_prototype) for i in 1:8) # rateType caches plist = (3, 3, 3, 3, 3, 3, 3, 3, 3) - uf, jac_config, J, ops, KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, + uf, jac_config, + J, + ops, + KsCache = alg_cache_expRK(alg, u, uEltypeNoUnits, uprev, f, t, dt, p, du1, tmp, dz, plist) # other caches HochOst4Cache(u, uprev, tmp, dz, rtmp, rtmp2, Au, F2, F3, F4, F5, du1, jac_config, uf, J, ops, KsCache) @@ -381,7 +396,7 @@ for (Alg, Cache) in [(:Exp4, :Exp4ConstantCache), uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing else uf = UDerivativeWrapper(f, t, p) @@ -413,14 +428,14 @@ function alg_cache(alg::Exp4, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -460,14 +475,14 @@ function alg_cache(alg::EPIRK4s3A, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -506,14 +521,14 @@ function alg_cache(alg::EPIRK4s3B, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -552,14 +567,14 @@ function alg_cache(alg::EPIRK5s3, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz, k = (zero(u) for i in 1:3) # uType caches rtmp, rtmp2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -597,14 +612,14 @@ function alg_cache(alg::EXPRB53s3, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -643,14 +658,14 @@ function alg_cache(alg::EPIRK5P1, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -690,14 +705,14 @@ function alg_cache(alg::EPIRK5P2, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp, dz = (zero(u) for i in 1:2) # uType caches rtmp, rtmp2, dR, du1 = (zero(rate_prototype) for i in 1:4) # rateType caches # Allocate jacobian and caches for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else uf = UJacobianWrapper(f, t, p) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), length(u), length(u)) @@ -727,7 +742,7 @@ for (Alg, Cache) in [(:Exprb32, :Exprb32ConstantCache), uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing else uf = UDerivativeWrapper(f, t, p) @@ -754,7 +769,7 @@ function alg_cache_exprb(alg::OrdinaryDiffEqAdaptiveExponentialAlgorithm, u, n = length(u) T = eltype(u) # Allocate cache for ForwardDiff - if DiffEqBase.has_jac(f) + if SciMLBase.has_jac(f) uf = nothing jac_config = nothing else @@ -762,7 +777,7 @@ function alg_cache_exprb(alg::OrdinaryDiffEqAdaptiveExponentialAlgorithm, u, jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dz) end # Allocate cache for the Jacobian - if DiffEqBase.has_jac(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && f.jac_prototype !== nothing J = deepcopy(f.jac_prototype) else J = fill(zero(uEltypeNoUnits), n, n) @@ -797,7 +812,9 @@ function alg_cache(alg::Exprb32, u, rate_prototype, ::Type{uEltypeNoUnits}, utilde, tmp, dz = (zero(u) for i in 1:3) # uType caches rtmp, F2, du1 = (zero(rate_prototype) for i in 1:3) # rateType caches plist = (3, 3) - uf, jac_config, J, KsCache = alg_cache_exprb(alg, u, uEltypeNoUnits, uprev, f, t, p, + uf, jac_config, + J, + KsCache = alg_cache_exprb(alg, u, uEltypeNoUnits, uprev, f, t, p, du1, tmp, dz, plist) # other caches Exprb32Cache(u, uprev, utilde, tmp, dz, rtmp, F2, du1, jac_config, uf, J, KsCache) end @@ -825,7 +842,9 @@ function alg_cache(alg::Exprb43, u, rate_prototype, ::Type{uEltypeNoUnits}, utilde, tmp, dz = (zero(u) for i in 1:3) # uType caches rtmp, Au, F2, F3, du1 = (zero(rate_prototype) for i in 1:5) # rateType caches plist = (1, 4, 4, 4) - uf, jac_config, J, KsCache = alg_cache_exprb(alg, u, uEltypeNoUnits, uprev, f, t, p, + uf, jac_config, + J, + KsCache = alg_cache_exprb(alg, u, uEltypeNoUnits, uprev, f, t, p, du1, tmp, dz, plist) # other caches Exprb43Cache(u, uprev, utilde, tmp, dz, rtmp, Au, F2, F3, du1, jac_config, uf, J, KsCache) diff --git a/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_perform_step.jl b/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_perform_step.jl index 5944b40e88..a0352a99b8 100644 --- a/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_perform_step.jl +++ b/lib/OrdinaryDiffEqExponentialRK/src/exponential_rk_perform_step.jl @@ -76,7 +76,7 @@ function perform_step!(integrator, cache::LawsonEulerCache, repeat_step = false) else OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end - @muladd @.. broadcast=false tmp=uprev + dt * G + @muladd @.. broadcast=false tmp=uprev+dt*G if alg.krylov Ks, expv_cache = KsCache arnoldi!(Ks, A, tmp; m = min(alg.m, size(A, 1)), @@ -126,10 +126,10 @@ function perform_step!(integrator, cache::NorsettEulerCache, repeat_step = false arnoldi!(Ks, A, integrator.fsalfirst; m = min(alg.m, size(A, 1)), opnorm = integrator.opts.internalopnorm, iop = alg.iop) phiv!(w, dt, Ks, 1; cache = phiv_cache) - @muladd @.. broadcast=false u=uprev + dt * @view(w[:, 2]) + @muladd @.. broadcast=false u=uprev+dt*@view(w[:, 2]) else mul!(rtmp, cache.phihA, integrator.fsalfirst) - @muladd @.. broadcast=false u=uprev + dt * rtmp + @muladd @.. broadcast=false u=uprev+dt*rtmp end # Update integrator state @@ -192,7 +192,7 @@ function perform_step!(integrator, cache::ETDRK2Cache, repeat_step = false) opnorm = integrator.opts.internalopnorm, iop = alg.iop) phiv!(w1, dt, Ks, 2; cache = phiv_cache) # Krylov for F2 - @muladd @.. broadcast=false tmp=uprev + dt * @view(w1[:, 2]) + @muladd @.. broadcast=false tmp=uprev+dt*@view(w1[:, 2]) _compute_nl!(F2, f, tmp, p, t + dt, A, rtmp) if isa(f, SplitFunction) integrator.stats.nf2 += 1 @@ -214,7 +214,7 @@ function perform_step!(integrator, cache::ETDRK2Cache, repeat_step = false) # The caching version uses a special formula to save computation # Compute U2 mul!(rtmp, phi1, F1) - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U2 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U2 # Compute G2 - G1, storing result in the cache F2 f.f2(rtmp, uprev, p, t) integrator.stats.nf2 += 1 @@ -323,22 +323,22 @@ function perform_step!(integrator, cache::ETDRK3Cache, repeat_step = false) arnoldi!(Ks, A, F3; kwargs...) phiv!(w3, dt, Ks, 3; cache = phiv_cache) # Update u - @views @.. broadcast=false rtmp=4w1[:, 4] - 3w1[:, 3] + w1[:, 2] - 8w2[:, 4] + - 4w2[:, 3] + 4w3[:, 4] - w3[:, 3] - @muladd @.. broadcast=false u=uprev + dt * rtmp + @views @.. broadcast=false rtmp=4w1[:, 4]-3w1[:, 3]+w1[:, 2]-8w2[:, 4]+ + 4w2[:, 3]+4w3[:, 4]-w3[:, 3] + @muladd @.. broadcast=false u=uprev+dt*rtmp else A21, A3, B1, B2, B3 = cache.ops # stage 1 (fsaled) # stage 2 mul!(rtmp, A21, F1) - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U2 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U2 f.f2(F2, tmp, p, t + halfdt) F2 .+= Au integrator.stats.nf2 += 1 # stage 3 - @muladd @.. broadcast=false F3=2 * F2 - F1 # use F3 temporarily as cache + @muladd @.. broadcast=false F3=2*F2-F1 # use F3 temporarily as cache mul!(rtmp, A3, F3) - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U3 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U3 f.f2(F3, tmp, p, t + dt) F3 .+= Au integrator.stats.nf2 += 1 @@ -471,21 +471,22 @@ function perform_step!(integrator, cache::ETDRK4Cache, repeat_step = false) arnoldi!(Ks, A, F4; kwargs...) phiv!(w4, dt, Ks, 3; cache = phiv_cache) # update u - @views @.. broadcast=false rtmp=w1[:, 2] - 3w1[:, 3] + 4w1[:, 4] + 2w2[:, 3] - - 4w2[:, 4] + - 2w3[:, 3] - 4w3[:, 4] + 4w4[:, 4] - w4[:, 3] - @muladd @.. broadcast=false u=uprev + dt * rtmp + @views @.. broadcast=false rtmp=w1[:, 2]-3w1[:, 3]+4w1[:, 4]+2w2[ + :, 3]- + 4w2[:, 4]+ + 2w3[:, 3]-4w3[:, 4]+4w4[:, 4]-w4[:, 3] + @muladd @.. broadcast=false u=uprev+dt*rtmp else A21, A41, A43, B1, B2, B4 = cache.ops # stage 1 (fsaled) # stage 2 mul!(rtmp, A21, F1) - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U2 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U2 f.f2(F2, tmp, p, t + halfdt) F2 .+= Au # stage 3 mul!(rtmp, A21, F2) # A32 = A21 - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U3 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U3 f.f2(F3, tmp, p, t + halfdt) F3 .+= Au # stage 4 @@ -656,20 +657,20 @@ function perform_step!(integrator, cache::HochOst4Cache, repeat_step = false) @muladd @.. broadcast=false @views rtmp = w1[:, 2] - 3w1[:, 3] + 4w1[:, 4] - w4[:, 3] + 4w4[:, 4] + 4w5[:, 3] - 8w5[:, 4] - @muladd @.. broadcast=false u=uprev + dt * rtmp + @muladd @.. broadcast=false u=uprev+dt*rtmp else A21, A31, A32, A41, A42, A51, A52, A54, B1, B4, B5 = cache.ops # stage 1 (fsaled) # stage 2 mul!(rtmp, A21, F1) - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U2 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U2 f.f2(F2, tmp, p, t + halfdt) F2 .+= Au # stage 3 mul!(rtmp, A31, F1) mul!(rtmp2, A32, F2) rtmp .+= rtmp2 - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U3 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U3 f.f2(F3, tmp, p, t + halfdt) F3 .+= Au # stage 4 @@ -677,7 +678,7 @@ function perform_step!(integrator, cache::HochOst4Cache, repeat_step = false) mul!(rtmp, A41, F1) mul!(rtmp2, A42, F2) rtmp .+= rtmp2 - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U4 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U4 f.f2(F4, tmp, p, t + dt) F4 .+= Au # stage 5 @@ -686,7 +687,7 @@ function perform_step!(integrator, cache::HochOst4Cache, repeat_step = false) rtmp .+= rtmp2 mul!(rtmp2, A54, F4) rtmp .+= rtmp2 - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is U5 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is U5 f.f2(F5, tmp, p, t + halfdt) F5 .+= Au integrator.stats.nf2 += 4 @@ -696,7 +697,7 @@ function perform_step!(integrator, cache::HochOst4Cache, repeat_step = false) rtmp .+= rtmp2 mul!(rtmp2, B5, F5) rtmp .+= rtmp2 - @muladd @.. broadcast=false u=uprev + dt * rtmp + @muladd @.. broadcast=false u=uprev+dt*rtmp end # Update integrator state @@ -772,14 +773,14 @@ function perform_step!(integrator, cache::Exp4Cache, repeat_step = false) K[:, i] ./= ts[i] end mul!(rtmp, K, [-7 / 300, 97 / 150, -37 / 300]) # rtmp is now w4 - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is now u4 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is now u4 mul!(rtmp2, J, rtmp) f(rtmp, tmp, p, t + dt) # TODO: what should be the time? OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @muladd @.. broadcast=false @view(B[:, 2])=rtmp - f0 - dt * rtmp2 # B[:,2] is now d4 + @muladd @.. broadcast=false @view(B[:, 2])=rtmp-f0-dt*rtmp2 # B[:,2] is now d4 # Partially update entities that use k1, k2, k3 mul!(rtmp, K, [59 / 300, -7 / 75, 269 / 300]) # rtmp is now w7 - @muladd @.. broadcast=false u=uprev + dt * @view(K[:, 3]) + @muladd @.. broadcast=false u=uprev+dt*@view(K[:, 3]) # Krylov for the first remainder d4 phiv_timestep!(K, ts, J, B; kwargs...) @inbounds for i in 1:3 @@ -787,11 +788,11 @@ function perform_step!(integrator, cache::Exp4Cache, repeat_step = false) end mul!(rtmp2, K, [2 / 3, 2 / 3, 2 / 3]) rtmp .+= rtmp2 # w7 fully updated - @muladd @.. broadcast=false tmp=uprev + dt * rtmp # tmp is now u7 + @muladd @.. broadcast=false tmp=uprev+dt*rtmp # tmp is now u7 mul!(rtmp2, J, rtmp) f(rtmp, tmp, p, t + dt) # TODO: what should be the time? OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @muladd @.. broadcast=false @view(B[:, 2])=rtmp - f0 - dt * rtmp2 # B[:,2] is now d7 + @muladd @.. broadcast=false @view(B[:, 2])=rtmp-f0-dt*rtmp2 # B[:,2] is now d7 # Partially update entities that use k4, k5, k6 mul!(rtmp, K, [1.0, -4 / 3, 1.0]) axpy!(dt, rtmp, u) @@ -855,17 +856,17 @@ function perform_step!(integrator, cache::EPIRK4s3ACache, repeat_step = false) B[:, 2] .= f0 phiv_timestep!(K, [dt / 2, 2dt / 3], J, @view(B[:, 1:2]); kwargs...) ## U2 and R2 - @.. broadcast=false tmp=uprev + @view(K[:, 1]) # tmp is now U2 + @.. broadcast=false tmp=uprev+@view(K[:, 1]) # tmp is now U2 f(rtmp, tmp, p, t + dt / 2) mul!(rtmp2, J, @view(K[:, 1])) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R2 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R2 B[:, 4] .= (32 / dt^2) * rtmp B[:, 5] .= (-144 / dt^3) * rtmp ## U3 and R3 - @.. broadcast=false tmp=uprev + @view(K[:, 2]) # tmp is now U3 + @.. broadcast=false tmp=uprev+@view(K[:, 2]) # tmp is now U3 f(rtmp, tmp, p, t + 2dt / 3) mul!(rtmp2, J, @view(K[:, 2])) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R3 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R3 B[:, 4] .-= (13.5 / dt^2) * rtmp B[:, 5] .+= (81 / dt^3) * rtmp OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) @@ -873,7 +874,7 @@ function perform_step!(integrator, cache::EPIRK4s3ACache, repeat_step = false) # Update u du = @view(K[:, 1]) phiv_timestep!(du, dt, J, B; kwargs...) - @.. broadcast=false u=uprev + du + @.. broadcast=false u=uprev+du # Update integrator state f(integrator.fsallast, u, p, t + dt) @@ -934,17 +935,17 @@ function perform_step!(integrator, cache::EPIRK4s3BCache, repeat_step = false) K[:, 1] .*= 8 / (3 * dt) K[:, 2] .*= 16 / (9 * dt) ## U2 and R2 - @.. broadcast=false tmp=uprev + @view(K[:, 1]) # tmp is now U2 + @.. broadcast=false tmp=uprev+@view(K[:, 1]) # tmp is now U2 f(rtmp, tmp, p, t + dt / 2) mul!(rtmp2, J, @view(K[:, 1])) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R2 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R2 B[:, 4] .= (54 / dt^2) * rtmp B[:, 5] .= (-324 / dt^3) * rtmp ## U3 and R3 - @.. broadcast=false tmp=uprev + @view(K[:, 2]) # tmp is now U3 + @.. broadcast=false tmp=uprev+@view(K[:, 2]) # tmp is now U3 f(rtmp, tmp, p, t + 3dt / 4) mul!(rtmp2, J, @view(K[:, 2])) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R3 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R3 B[:, 4] .-= (16 / dt^2) * rtmp B[:, 5] .+= (144 / dt^3) * rtmp OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) @@ -954,7 +955,7 @@ function perform_step!(integrator, cache::EPIRK4s3BCache, repeat_step = false) B[:, 2] .= f0 du = @view(K[:, 1]) phiv_timestep!(du, dt, J, B; kwargs...) - @.. broadcast=false u=uprev + du + @.. broadcast=false u=uprev+du # Update integrator state f(integrator.fsallast, u, p, t + dt) @@ -1022,11 +1023,11 @@ function perform_step!(integrator, cache::EPIRK5s3Cache, repeat_step = false) B[:, 4] .= (-3025 / (192 * dt^2)) .* f0 phiv_timestep!(k, 48dt / 55, J, @view(B[:, 1:4]); kwargs...) ## Compute R2 - @.. broadcast=false tmp=uprev + k # tmp is now U2 + @.. broadcast=false tmp=uprev+k # tmp is now U2 f(rtmp, tmp, p, t + 48dt / 55) mul!(rtmp2, J, k) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R2 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R2 # Compute U3 horizontally B[:, 2] .= (53 / 5) .* f0 @@ -1039,17 +1040,17 @@ function perform_step!(integrator, cache::EPIRK5s3Cache, repeat_step = false) B[:, 4] .= (-166375 / (61056 * dt^2)) .* rtmp B[:, 5] .= (499125 / (27136 * dt^3)) .* rtmp ## Compute R3 and update B - @.. broadcast=false tmp=uprev + k # tmp is now U3 + @.. broadcast=false tmp=uprev+k # tmp is now U3 f(rtmp, tmp, p, t + 4dt / 9) mul!(rtmp2, J, k) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R3 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R3 B[:, 4] .+= (2187 / (106 * dt^2)) .* rtmp B[:, 5] .-= (2187 / (106 * dt^3)) .* rtmp # Update u phiv_timestep!(k, dt, J, B; kwargs...) - @.. broadcast=false u=uprev + k + @.. broadcast=false u=uprev+k # Update integrator state f(integrator.fsallast, u, p, t + dt) @@ -1112,12 +1113,12 @@ function perform_step!(integrator, cache::EXPRB53s3Cache, repeat_step = false) B[:, 2] .= f0 phiv_timestep!(K, [dt / 2, 9dt / 10], J, @view(B[:, 1:2]); kwargs...) ## U2 and R2 - @.. broadcast=false tmp=uprev + @view(K[:, 1]) # tmp is now U2 + @.. broadcast=false tmp=uprev+@view(K[:, 1]) # tmp is now U2 f(rtmp, tmp, p, t + dt / 2) mul!(rtmp2, J, @view(K[:, 1])) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R2 - @.. broadcast=false tmp=uprev + @view(K[:, 2]) # tmp is now U3 (partially) + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R2 + @.. broadcast=false tmp=uprev+@view(K[:, 2]) # tmp is now U3 (partially) # Compute the second group for U3 fill!(@view(B[:, 2]), zero(eltype(B))) @@ -1133,7 +1134,7 @@ function perform_step!(integrator, cache::EXPRB53s3Cache, repeat_step = false) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tmp .-= uprev mul!(rtmp2, J, tmp) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R3 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R3 ## Update B using R3 B[:, 4] .-= (250 / (81 * dt^2)) * rtmp B[:, 5] .+= (500 / (27 * dt^3)) * rtmp @@ -1141,7 +1142,7 @@ function perform_step!(integrator, cache::EXPRB53s3Cache, repeat_step = false) # Update u du = @view(K[:, 1]) phiv_timestep!(du, dt, J, B; kwargs...) - @.. broadcast=false u=uprev + du + @.. broadcast=false u=uprev+du # Update integrator state f(integrator.fsallast, u, p, t + dt) @@ -1225,15 +1226,15 @@ function perform_step!(integrator, cache::EPIRK5P1Cache, repeat_step = false) B[:, 2] .= f0 phiv_timestep!(K, [g11, g21, g31], J, @view(B[:, 1:2]); kwargs...) ## U1 and R1 - @.. broadcast=false tmp=uprev + @view(K[:, 1]) # tmp is now U1 + @.. broadcast=false tmp=uprev+@view(K[:, 1]) # tmp is now U1 f(rtmp, tmp, p, t + g11) mul!(rtmp2, J, @view(K[:, 1])) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R1 - @.. broadcast=false tmp=uprev + @view(K[:, 2]) # partially update U2 (stored tmp) - @.. broadcast=false u=uprev + @view(K[:, 3]) # partially update u + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R1 + @.. broadcast=false tmp=uprev+@view(K[:, 2]) # partially update U2 (stored tmp) + @.. broadcast=false u=uprev+@view(K[:, 3]) # partially update u B[:, 2] .= rtmp - @.. broadcast=false @view(B[:, 4])=(-2) * rtmp + @.. broadcast=false @view(B[:, 4])=(-2)*rtmp # Compute the second column (R1) k = @view(K[:, 1]) @@ -1244,7 +1245,7 @@ function perform_step!(integrator, cache::EPIRK5P1Cache, repeat_step = false) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tmp .-= uprev mul!(rtmp2, J, tmp) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R2 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R2 axpy!(b2, k, u) # partially update u B[:, 4] .+= rtmp # is now dR @@ -1339,13 +1340,13 @@ function perform_step!(integrator, cache::EPIRK5P2Cache, repeat_step = false) B[:, 2] .= f0 phiv_timestep!(K, [g11, g21, g31], J, @view(B[:, 1:2]); kwargs...) ## U1 and R1 - @.. broadcast=false tmp=uprev + @view(K[:, 1]) # tmp is now U1 + @.. broadcast=false tmp=uprev+@view(K[:, 1]) # tmp is now U1 f(rtmp, tmp, p, t + g11) mul!(rtmp2, J, @view(K[:, 1])) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R1 - @.. broadcast=false tmp=uprev + @view(K[:, 2]) # partially update U2 (stored in tmp) - @.. broadcast=false u=uprev + @view(K[:, 3]) # partially update u + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R1 + @.. broadcast=false tmp=uprev+@view(K[:, 2]) # partially update U2 (stored in tmp) + @.. broadcast=false u=uprev+@view(K[:, 3]) # partially update u @.. broadcast=false dR=-2rtmp # partially update dR # Compute the second column (R1) @@ -1359,14 +1360,14 @@ function perform_step!(integrator, cache::EPIRK5P2Cache, repeat_step = false) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tmp .-= uprev mul!(rtmp2, J, tmp) - @.. broadcast=false rtmp=rtmp - f0 - rtmp2 # rtmp is now R2 + @.. broadcast=false rtmp=rtmp-f0-rtmp2 # rtmp is now R2 dR .+= rtmp # dR is now R2 - 2R1 axpy!(b2, k, u) # partially update u # Compute the third column (dR = R2 - 2R1) - @.. broadcast=false @view(B[:, 2])=b31 * dR - @.. broadcast=false @view(B[:, 3])=b32 * dR - @.. broadcast=false @view(B[:, 4])=b33 * dR + @.. broadcast=false @view(B[:, 2])=b31*dR + @.. broadcast=false @view(B[:, 3])=b32*dR + @.. broadcast=false @view(B[:, 4])=b33*dR phiv_timestep!(k, g33, J, B; kwargs...) u .+= k @@ -1423,7 +1424,7 @@ function perform_step!(integrator, cache::Exprb32Cache, repeat_step = false) iop = alg.iop) phiv!(w1, dt, Ks, 3; cache = phiv_cache) # Krylov for F2 - @muladd @.. broadcast=false tmp=uprev + dt * @view(w1[:, 2]) + @muladd @.. broadcast=false tmp=uprev+dt*@view(w1[:, 2]) _compute_nl!(F2, f, tmp, p, t + dt, J, rtmp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) F2 .+= mul!(rtmp, J, uprev) @@ -1438,7 +1439,7 @@ function perform_step!(integrator, cache::Exprb32Cache, repeat_step = false) axpy!(2dt, @view(w2[:, 4]), u) if integrator.opts.adaptive # error estimator for the imbedded method - @views @.. broadcast=false utilde=(2 * dt) * (-w1[:, 4] + w2[:, 4]) + @views @.. broadcast=false utilde=(2*dt)*(-w1[:, 4]+w2[:, 4]) calculate_residuals!(tmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(tmp, t) @@ -1524,12 +1525,12 @@ function perform_step!(integrator, cache::Exprb43Cache, repeat_step = false) arnoldi!(Ks, J, F3; kwargs...) phiv!(w3, dt, Ks, 4; cache = phiv_cache) # Update u - @views @.. broadcast=false rtmp=w1[:, 2] - 14w1[:, 4] + 36w1[:, 5] + 16w2[:, 4] - - 48w2[:, 5] - 2w3[:, 4] + 12w3[:, 5] - @muladd @.. broadcast=false u=uprev + dt * rtmp + @views @.. broadcast=false rtmp=w1[:, 2]-14w1[:, 4]+36w1[:, 5]+16w2[:, 4]- + 48w2[:, 5]-2w3[:, 4]+12w3[:, 5] + @muladd @.. broadcast=false u=uprev+dt*rtmp if integrator.opts.adaptive - @views @.. broadcast=false rtmp=36w1[:, 5] - 48w2[:, 5] + 12w3[:, 5] - @.. broadcast=false utilde=dt * rtmp + @views @.. broadcast=false rtmp=36w1[:, 5]-48w2[:, 5]+12w3[:, 5] + @.. broadcast=false utilde=dt*rtmp calculate_residuals!(tmp, utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(tmp, t) @@ -1608,17 +1609,17 @@ function perform_step!(integrator, cache::ETD2Cache, repeat_step = false) @unpack t, dt, uprev, u, f, p = integrator @unpack lin, nl, nlprev = integrator.fsalfirst @unpack utmp, rtmp1, rtmp2, exphA, phihA, B1, B0 = cache - @.. broadcast=false integrator.k[1]=lin + nl + @.. broadcast=false integrator.k[1]=lin+nl if integrator.iter == 1 # ETD1 for initial step mul!(utmp, exphA, uprev) mul!(rtmp1, phihA, nl) - @muladd @.. broadcast=false u=utmp + dt * rtmp1 + @muladd @.. broadcast=false u=utmp+dt*rtmp1 else mul!(utmp, exphA, uprev) mul!(rtmp1, B1, nl) mul!(rtmp2, B0, nlprev) - @muladd @.. broadcast=false u=utmp + dt * (rtmp1 + rtmp2) + @muladd @.. broadcast=false u=utmp+dt*(rtmp1+rtmp2) end # Push the fsal at t+dt @@ -1628,5 +1629,5 @@ function perform_step!(integrator, cache::ETD2Cache, repeat_step = false) f.f2(fsallast.nl, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 - @.. broadcast=false integrator.k[2]=fsallast.lin + fsallast.nl + @.. broadcast=false integrator.k[2]=fsallast.lin+fsallast.nl end diff --git a/lib/OrdinaryDiffEqExponentialRK/test/jet.jl b/lib/OrdinaryDiffEqExponentialRK/test/jet.jl new file mode 100644 index 0000000000..8af9662860 --- /dev/null +++ b/lib/OrdinaryDiffEqExponentialRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqExponentialRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqExponentialRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqExponentialRK/test/qa.jl b/lib/OrdinaryDiffEqExponentialRK/test/qa.jl new file mode 100644 index 0000000000..7697d47cb5 --- /dev/null +++ b/lib/OrdinaryDiffEqExponentialRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqExponentialRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqExponentialRK + ) +end diff --git a/lib/OrdinaryDiffEqExponentialRK/test/runtests.jl b/lib/OrdinaryDiffEqExponentialRK/test/runtests.jl index 2a6b824669..73e81d7d9d 100644 --- a/lib/OrdinaryDiffEqExponentialRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqExponentialRK/test/runtests.jl @@ -2,3 +2,5 @@ using SafeTestsets @time @safetestset "Linear-Nonlinear Krylov Methods Tests" include("linear_nonlinear_krylov_tests.jl") @time @safetestset "Linear-Nonlinear Convergence Tests" include("linear_nonlinear_convergence_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqExtrapolation/Project.toml b/lib/OrdinaryDiffEqExtrapolation/Project.toml index 8889d5355e..3c53dfe14f 100644 --- a/lib/OrdinaryDiffEqExtrapolation/Project.toml +++ b/lib/OrdinaryDiffEqExtrapolation/Project.toml @@ -1,41 +1,58 @@ name = "OrdinaryDiffEqExtrapolation" uuid = "becaefa8-8ca2-5cf9-886d-c06f3d2bd2c4" authors = ["Chris Rackauckas ", "Yingbo Ma "] -version = "1.1.0" +version = "1.9.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +FastPower = "a4df4552-cc26-4903-aec0-212e50a0e84b" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearSolve = "2.32.0" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Test = "<0.0.1, 1" -julia = "1.10" - [extras] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearSolve = "3.26" +Polyester = "0.7" +OrdinaryDiffEqDifferentiation = "1.12.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +FastPower = "1.1" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "DiffEqBase"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqExtrapolation/src/OrdinaryDiffEqExtrapolation.jl b/lib/OrdinaryDiffEqExtrapolation/src/OrdinaryDiffEqExtrapolation.jl index 29bbc6ca8b..194b30e166 100644 --- a/lib/OrdinaryDiffEqExtrapolation/src/OrdinaryDiffEqExtrapolation.jl +++ b/lib/OrdinaryDiffEqExtrapolation/src/OrdinaryDiffEqExtrapolation.jl @@ -13,20 +13,23 @@ import OrdinaryDiffEqCore: alg_order, alg_maximum_order, get_current_adaptive_or OrdinaryDiffEqAdaptiveAlgorithm, OrdinaryDiffEqAdaptiveImplicitAlgorithm, alg_cache, CompiledFloats, @threaded, stepsize_controller!, - DEFAULT_PRECS, full_cache, + DEFAULT_PRECS, full_cache, qmin_default, constvalue, PolyesterThreads, Sequential, BaseThreads, _digest_beta1_beta2, timedepentdtmin, _unwrap_val, _reshape, _vec, get_fsalfirstlast, generic_solver_docstring, - differentiation_rk_docstring -using DiffEqBase, FastBroadcast, Polyester, MuladdMacro, RecursiveArrayTools, LinearSolve + differentiation_rk_docstring, _bool_to_ADType, + _process_AD_choice, LinearAliasSpecifier +using FastBroadcast, Polyester, MuladdMacro, RecursiveArrayTools, LinearSolve import OrdinaryDiffEqCore +import FastPower import OrdinaryDiffEqDifferentiation: TimeDerivativeWrapper, UDerivativeWrapper, calc_J, WOperator, TimeGradientWrapper, UJacobianWrapper, build_grad_config, build_jac_config, calc_J!, jacobian2W!, dolinsolve +import ADTypes: AutoForwardDiff, AbstractADType using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") @@ -34,7 +37,7 @@ include("controllers.jl") include("extrapolation_caches.jl") include("extrapolation_perform_step.jl") -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::OrdinaryDiffEqImplicitExtrapolationAlgorithm, cache::OrdinaryDiffEqMutableCache) (cache.tmp, cache.utilde) diff --git a/lib/OrdinaryDiffEqExtrapolation/src/algorithms.jl b/lib/OrdinaryDiffEqExtrapolation/src/algorithms.jl index 205e8e1f3d..b62fc80f16 100644 --- a/lib/OrdinaryDiffEqExtrapolation/src/algorithms.jl +++ b/lib/OrdinaryDiffEqExtrapolation/src/algorithms.jl @@ -64,14 +64,17 @@ struct ImplicitEulerExtrapolation{CS, AD, F, P, FDT, ST, CJ, TO} <: init_order::Int threading::TO sequence::Symbol # Name of the subdividing sequence + autodiff::AD end -function ImplicitEulerExtrapolation(; chunk_size = Val{0}(), autodiff = true, +function ImplicitEulerExtrapolation(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, linsolve = nothing, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, max_order = 12, min_order = 3, init_order = 5, threading = false, sequence = :harmonic) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + linsolve = (linsolve === nothing && (threading == true || threading isa PolyesterThreads)) ? RFLUFactorization(; thread = Val(false)) : linsolve @@ -99,12 +102,12 @@ Initial order: " * lpad(init_order, 2, " ") * " --> " * lpad(init_order, 2, " ") :$(sequence) --> :harmonic" sequence = :harmonic end - ImplicitEulerExtrapolation{_unwrap_val(chunk_size), _unwrap_val(autodiff), + ImplicitEulerExtrapolation{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(threading)}(linsolve, precs, max_order, min_order, init_order, - threading, sequence) + threading, sequence, AD_choice) end @doc generic_solver_docstring("Midpoint extrapolation using Barycentric coordinates.", @@ -204,13 +207,17 @@ struct ImplicitDeuflhardExtrapolation{CS, AD, F, P, FDT, ST, CJ, TO} <: max_order::Int # Maximal extrapolation order sequence::Symbol # Name of the subdividing sequence threading::TO + autodiff::AD end -function ImplicitDeuflhardExtrapolation(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ImplicitDeuflhardExtrapolation(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, linsolve = nothing, precs = DEFAULT_PRECS, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), min_order = 1, init_order = 5, max_order = 10, sequence = :harmonic, threading = false) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + # Enforce 1 <= min_order <= init_order <= max_order: min_order = max(1, min_order) init_order = max(min_order, init_order) @@ -242,12 +249,12 @@ Initial order: " * lpad(init_order, 2, " ") * " --> " * lpad(init_order, 2, " ") end # Initialize algorithm - ImplicitDeuflhardExtrapolation{_unwrap_val(chunk_size), _unwrap_val(autodiff), + ImplicitDeuflhardExtrapolation{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(threading)}(linsolve, precs, min_order, init_order, max_order, - sequence, threading) + sequence, threading, AD_choice) end @doc generic_solver_docstring("Midpoint extrapolation using Barycentric coordinates, @@ -351,15 +358,18 @@ struct ImplicitHairerWannerExtrapolation{CS, AD, F, P, FDT, ST, CJ, TO} <: max_order::Int # Maximal extrapolation order sequence::Symbol # Name of the subdividing sequence threading::TO + autodiff::AD end -function ImplicitHairerWannerExtrapolation(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ImplicitHairerWannerExtrapolation(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, linsolve = nothing, precs = DEFAULT_PRECS, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), min_order = 2, init_order = 5, max_order = 10, sequence = :harmonic, threading = false) + # Enforce 2 <= min_order # and min_order + 1 <= init_order <= max_order - 1: min_order = max(2, min_order) @@ -390,13 +400,14 @@ Initial order: " * lpad(init_order, 2, " ") * " --> " * lpad(init_order, 2, " ") sequence = :harmonic end + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) # Initialize algorithm - ImplicitHairerWannerExtrapolation{_unwrap_val(chunk_size), _unwrap_val(autodiff), + ImplicitHairerWannerExtrapolation{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(threading)}(linsolve, precs, min_order, init_order, - max_order, sequence, threading) + max_order, sequence, threading, AD_choice) end @doc differentiation_rk_docstring("Euler extrapolation using Barycentric coordinates, @@ -430,14 +441,15 @@ struct ImplicitEulerBarycentricExtrapolation{CS, AD, F, P, FDT, ST, CJ, TO} <: sequence::Symbol # Name of the subdividing sequence threading::TO sequence_factor::Int + autodiff::AD end function ImplicitEulerBarycentricExtrapolation(; chunk_size = Val{0}(), - autodiff = Val{true}(), + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, linsolve = nothing, precs = DEFAULT_PRECS, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), min_order = 3, init_order = 5, max_order = 12, sequence = :harmonic, threading = false, sequence_factor = 2) @@ -471,8 +483,9 @@ Initial order: " * lpad(init_order, 2, " ") * " --> " * lpad(init_order, 2, " ") sequence = :harmonic end + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) # Initialize algorithm - ImplicitEulerBarycentricExtrapolation{_unwrap_val(chunk_size), _unwrap_val(autodiff), + ImplicitEulerBarycentricExtrapolation{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(threading)}(linsolve, @@ -482,5 +495,6 @@ Initial order: " * lpad(init_order, 2, " ") * " --> " * lpad(init_order, 2, " ") max_order, sequence, threading, - sequence_factor) + sequence_factor, + AD_choice) end diff --git a/lib/OrdinaryDiffEqExtrapolation/src/controllers.jl b/lib/OrdinaryDiffEqExtrapolation/src/controllers.jl index 84a280f565..a62d61cb77 100644 --- a/lib/OrdinaryDiffEqExtrapolation/src/controllers.jl +++ b/lib/OrdinaryDiffEqExtrapolation/src/controllers.jl @@ -14,7 +14,7 @@ end ImplicitDeuflhardExtrapolation}) # Dummy function # ExtrapolationMidpointDeuflhard's stepsize scaling is stored in the cache; - # it is computed by stepsize_controller_internal! (in perfom_step!) resp. stepsize_predictor! + # it is computed by stepsize_controller_internal! (in perform_step!) resp. stepsize_predictor! # (in step_accept_controller! and step_reject_controller!) zero(typeof(integrator.opts.qmax)) end @@ -31,10 +31,11 @@ function stepsize_controller_internal!(integrator, else # Update gamma and beta1 controller.beta1 = typeof(controller.beta1)(1 // (2integrator.cache.n_curr + 1)) - integrator.opts.gamma = DiffEqBase.fastpow(typeof(integrator.opts.gamma)(1 // 4), + integrator.opts.gamma = FastPower.fastpower(typeof(integrator.opts.gamma)(1 // 4), controller.beta1) # Compute new stepsize scaling - qtmp = DiffEqBase.fastpow(integrator.EEst, controller.beta1) / integrator.opts.gamma + qtmp = FastPower.fastpower(integrator.EEst, controller.beta1) / + integrator.opts.gamma @fastmath q = max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), qtmp)) end integrator.cache.Q[integrator.cache.n_curr - alg.min_order + 1] = q @@ -57,10 +58,11 @@ function stepsize_predictor!(integrator, s_new = stage_number[n_new - alg.min_order + 1] # Update gamma and beta1 controller.beta1 = typeof(controller.beta1)(1 // (2integrator.cache.n_curr + 1)) - integrator.opts.gamma = DiffEqBase.fastpow(typeof(integrator.opts.gamma)(1 // 4), + integrator.opts.gamma = FastPower.fastpower(typeof(integrator.opts.gamma)(1 // 4), controller.beta1) # Compute new stepsize scaling - qtmp = EEst * DiffEqBase.fastpow(DiffEqBase.fastpow(tol, (1.0 - s_curr / s_new)), + qtmp = EEst * + FastPower.fastpower(FastPower.fastpower(tol, (1.0 - s_curr / s_new)), controller.beta1) / integrator.opts.gamma @fastmath q = max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), qtmp)) end @@ -88,7 +90,7 @@ function step_accept_controller!(integrator, n_new = argmin(work) + min_order - 1 # Check if n_new may be increased - if n_new == n_curr < min(max_order, n_old + 1) # cf. win_max in perfom_step! of the last step + if n_new == n_curr < min(max_order, n_old + 1) # cf. win_max in perform_step! of the last step # Predict stepsize scaling for order (n_new + 1) stepsize_predictor!(integrator, alg, n_new + 1) # Update cache.Q @@ -129,7 +131,7 @@ end ImplicitEulerBarycentricExtrapolation}) # Dummy function # ExtrapolationMidpointHairerWanner's stepsize scaling is stored in the cache; - # it is computed by stepsize_controller_internal! (in perfom_step!), step_accept_controller! or step_reject_controller! + # it is computed by stepsize_controller_internal! (in perform_step!), step_accept_controller! or step_reject_controller! zero(typeof(integrator.opts.qmax)) end @@ -158,12 +160,12 @@ function stepsize_controller_internal!(integrator, controller.beta1 = typeof(controller.beta1)(1 // (integrator.cache.n_curr - 1)) end - integrator.opts.gamma = DiffEqBase.fastpow( + integrator.opts.gamma = FastPower.fastpower( typeof(integrator.opts.gamma)(65 // 100), controller.beta1) # Compute new stepsize scaling - qtmp = DiffEqBase.fastpow(integrator.EEst, controller.beta1) / + qtmp = FastPower.fastpower(integrator.EEst, controller.beta1) / (integrator.opts.gamma) @fastmath q = max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), qtmp)) @@ -175,12 +177,12 @@ function stepsize_controller_internal!(integrator, else # Update gamma and beta1 controller.beta1 = typeof(controller.beta1)(1 // (2integrator.cache.n_curr + 1)) - integrator.opts.gamma = DiffEqBase.fastpow( + integrator.opts.gamma = FastPower.fastpower( typeof(integrator.opts.gamma)(65 // 100), controller.beta1) # Compute new stepsize scaling - qtmp = DiffEqBase.fastpow(integrator.EEst, controller.beta1) / + qtmp = FastPower.fastpower(integrator.EEst, controller.beta1) / integrator.opts.gamma @fastmath q = max(inv(integrator.opts.qmax), min(inv(integrator.opts.qmin), qtmp)) @@ -200,12 +202,12 @@ function step_accept_controller!(integrator, s = integrator.cache.stage_number # Compute new order based on available quantities - win_min_old = min(n_old, n_curr) - 1 # cf. win_min in perfom_step! of the last step + win_min_old = min(n_old, n_curr) - 1 # cf. win_min in perform_step! of the last step tmp = win_min_old:(max(n_curr, n_old) + 1) # Index range for the new order fill!(dt_new, zero(eltype(dt_new))) - @.. broadcast=false Q=integrator.dt / Q + @.. broadcast=false Q=integrator.dt/Q copyto!(dt_new, win_min_old, Q, win_min_old, (max(n_curr, n_old) + 1) - win_min_old + 1) - @.. broadcast=false Q=integrator.dt / Q + @.. broadcast=false Q=integrator.dt/Q dtmin = timedepentdtmin(integrator) fill!(work, zero(eltype(work))) # work[n] is the work for order (n-1) for i in tmp diff --git a/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_caches.jl b/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_caches.jl index 30c8fc16c9..418ef01b5a 100644 --- a/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_caches.jl +++ b/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_caches.jl @@ -1,6 +1,12 @@ abstract type ExtrapolationMutableCache <: OrdinaryDiffEqMutableCache end get_fsalfirstlast(cache::ExtrapolationMutableCache, u) = (cache.fsalfirst, cache.k) +# Helper function to determine appropriate thread count for array allocation +# Uses maxthreadid() when threading is enabled, otherwise just 1 for maximum memory efficiency +@inline function get_thread_count(alg) + return isthreaded(alg.threading) ? Threads.maxthreadid() : 1 +end + @cache mutable struct AitkenNevilleCache{ uType, rateType, @@ -48,11 +54,11 @@ function alg_cache(alg::AitkenNeville, u, rate_prototype, ::Type{uEltypeNoUnits} T = Array{typeof(u), 2}(undef, alg.max_order, alg.max_order) # Array of arrays of length equal to number of threads to store intermediate # values of u and k. [Thread Safety] - u_tmps = Array{typeof(u), 1}(undef, Threads.nthreads()) - k_tmps = Array{typeof(k), 1}(undef, Threads.nthreads()) + u_tmps = Array{typeof(u), 1}(undef, get_thread_count(alg)) + k_tmps = Array{typeof(k), 1}(undef, get_thread_count(alg)) # Initialize each element of u_tmps and k_tmps to different instance of # zeros array similar to u and k respectively - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_tmps[i] = zero(u) k_tmps[i] = zero(rate_prototype) end @@ -116,7 +122,7 @@ end Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter sigma::Rational{Int} # Parameter for order selection res::uNoUnitsType # Storage for the scaled residual of u and utilde @@ -159,7 +165,7 @@ function alg_cache(alg::ImplicitEulerExtrapolation, u, rate_prototype, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} dtpropose = zero(dt) #cur_order = max(alg.init_order, alg.min_order) - QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. DiffEqBase.__init in solve.jl + QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. SciMLBase.__init in solve.jl Q = fill(zero(QType), alg.max_order + 1) n_curr = alg.init_order n_old = alg.init_order @@ -196,26 +202,26 @@ function alg_cache(alg::ImplicitEulerExtrapolation, u, rate_prototype, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} u_tmp = zero(u) - u_tmps = Array{typeof(u_tmp), 1}(undef, Threads.nthreads()) + u_tmps = Array{typeof(u_tmp), 1}(undef, get_thread_count(alg)) u_tmps[1] = u_tmp - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) u_tmps[i] = zero(u_tmp) end - u_tmps2 = Array{typeof(u_tmp), 1}(undef, Threads.nthreads()) + u_tmps2 = Array{typeof(u_tmp), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_tmps2[i] = zero(u_tmp) end utilde = zero(u) tmp = zero(u) k_tmp = zero(rate_prototype) - k_tmps = Array{typeof(k_tmp), 1}(undef, Threads.nthreads()) + k_tmps = Array{typeof(k_tmp), 1}(undef, get_thread_count(alg)) k_tmps[1] = k_tmp - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) k_tmps[i] = zero(rate_prototype) end @@ -236,7 +242,7 @@ function alg_cache(alg::ImplicitEulerExtrapolation, u, rate_prototype, du1 = zero(rate_prototype) du2 = zero(rate_prototype) - if DiffEqBase.has_jac(f) && !DiffEqBase.has_Wfact(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && !SciMLBase.has_Wfact(f) && f.jac_prototype !== nothing W_el = WOperator(f, dt, true) J = nothing # is J = W.J better? else @@ -244,9 +250,9 @@ function alg_cache(alg::ImplicitEulerExtrapolation, u, rate_prototype, W_el = zero(J) end - W = Array{typeof(W_el), 1}(undef, Threads.nthreads()) + W = Array{typeof(W_el), 1}(undef, get_thread_count(alg)) W[1] = W_el - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) if W_el isa WOperator W[i] = WOperator(f, dt, true) else @@ -257,22 +263,24 @@ function alg_cache(alg::ImplicitEulerExtrapolation, u, rate_prototype, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) - linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, Threads.nthreads()) + linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) linsolve_tmps[i] = zero(rate_prototype) end linprob = LinearProblem(W[1], _vec(linsolve_tmps[1]); u0 = _vec(k_tmps[1])) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) - linsolve = Array{typeof(linsolve1), 1}(undef, Threads.nthreads()) + linsolve = Array{typeof(linsolve1), 1}(undef, get_thread_count(alg)) linsolve[1] = linsolve1 - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) linprob = LinearProblem(W[i], _vec(linsolve_tmps[i]); u0 = _vec(k_tmps[i])) - linsolve[i] = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve[i] = init(linprob, alg.linsolve, + alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) end @@ -283,9 +291,9 @@ function alg_cache(alg::ImplicitEulerExtrapolation, u, rate_prototype, sequence = generate_sequence(constvalue(uBottomEltypeNoUnits), alg) cc = alg_cache(alg, u, rate_prototype, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits, uprev, uprev2, f, t, dt, reltol, p, calck, Val(false)) - diff1 = Array{typeof(u), 1}(undef, Threads.nthreads()) - diff2 = Array{typeof(u), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + diff1 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + diff2 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) diff1[i] = zero(u) diff2[i] = zero(u) end @@ -301,7 +309,7 @@ struct extrapolation_coefficients{T1, T2, T3} # This structure is used by the caches of the algorithms # ExtrapolationMidpointDeuflhard() and ExtrapolationMidpointHairerWanner(). # It contains the constant coefficients used to extrapolate the internal discretisations - # in their perfom_step! function and some additional constant data. + # in their perform_step! function and some additional constant data. subdividing_sequence::T1 # subdividing_sequence[n] is used for the (n -1)th internal discretisation @@ -516,19 +524,19 @@ function create_extrapolation_coefficients(T::Type{<:CompiledFloats}, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 4.0870096435546874e17 9.80882314453125e19; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.7293822569102705e19] extrapolation_scalars = T[-1.0, 0.5, -0.16666666666666666, 0.041666666666666664, - -0.008333333333333333, 0.001388888888888889, - -0.0001984126984126984, 2.48015873015873e-5, - -2.7557319223985893e-6, 2.755731922398589e-7, - -2.505210838544172e-8, 2.08767569878681e-9, - -1.6059043836821613e-10, 1.1470745597729725e-11, - -7.647163731819816e-13, 4.779477332387385e-14] + -0.008333333333333333, 0.001388888888888889, + -0.0001984126984126984, 2.48015873015873e-5, + -2.7557319223985893e-6, 2.755731922398589e-7, + -2.505210838544172e-8, 2.08767569878681e-9, + -1.6059043836821613e-10, 1.1470745597729725e-11, + -7.647163731819816e-13, 4.779477332387385e-14] extrapolation_scalars_2 = T[-0.5, 0.16666666666666666, -0.041666666666666664, - 0.008333333333333333, -0.001388888888888889, - 0.0001984126984126984, -2.48015873015873e-5, - 2.7557319223985893e-6, -2.755731922398589e-7, - 2.505210838544172e-8, -2.08767569878681e-9, - 1.6059043836821613e-10, -1.1470745597729725e-11, - 7.647163731819816e-13, -4.779477332387385e-14] + 0.008333333333333333, -0.001388888888888889, + 0.0001984126984126984, -2.48015873015873e-5, + 2.7557319223985893e-6, -2.755731922398589e-7, + 2.505210838544172e-8, -2.08767569878681e-9, + 1.6059043836821613e-10, -1.1470745597729725e-11, + 7.647163731819816e-13, -4.779477332387385e-14] elseif sequence == :romberg subdividing_sequence = [ 1, @@ -580,18 +588,18 @@ function create_extrapolation_coefficients(T::Type{<:CompiledFloats}, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.4044854458583944e32 4.602217908988787e36; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -4.602498823223603e36] extrapolation_scalars = T[-1.0, 0.5, -0.125, 0.015625, -0.0009765625, - 3.0517578125e-5, -4.76837158203125e-7, - 3.725290298461914e-9, -1.4551915228366852e-11, - 2.842170943040401e-14, -2.7755575615628914e-17, - 1.3552527156068805e-20, -3.308722450212111e-24, - 4.0389678347315804e-28, -2.465190328815662e-32, - 7.52316384526264e-37] + 3.0517578125e-5, -4.76837158203125e-7, + 3.725290298461914e-9, -1.4551915228366852e-11, + 2.842170943040401e-14, -2.7755575615628914e-17, + 1.3552527156068805e-20, -3.308722450212111e-24, + 4.0389678347315804e-28, -2.465190328815662e-32, + 7.52316384526264e-37] extrapolation_scalars_2 = T[-0.5, 0.125, -0.015625, 0.0009765625, -3.0517578125e-5, - 4.76837158203125e-7, -3.725290298461914e-9, - 1.4551915228366852e-11, -2.842170943040401e-14, - 2.7755575615628914e-17, -1.3552527156068805e-20, - 3.308722450212111e-24, -4.0389678347315804e-28, - 2.465190328815662e-32, -7.52316384526264e-37] + 4.76837158203125e-7, -3.725290298461914e-9, + 1.4551915228366852e-11, -2.842170943040401e-14, + 2.7755575615628914e-17, -1.3552527156068805e-20, + 3.308722450212111e-24, -4.0389678347315804e-28, + 2.465190328815662e-32, -7.52316384526264e-37] else # sequence == :bulirsch subdividing_sequence = [1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256] extrapolation_weights = T[-1.0 -2.0 -3.0 -4.0 -4.8 -5.485714285714286 -5.984415584415585 -6.383376623376623 -6.660914737436476 -6.875782954773137 -7.022076209130012 -7.13353773625906 -7.20862760716705 -7.265388454467578 -7.3034271374752615 -7.332068028210459; @@ -626,19 +634,19 @@ function create_extrapolation_coefficients(T::Type{<:CompiledFloats}, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.662517163307765e19 2.0448131814203635e22; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0231987972010274e22] extrapolation_scalars = T[-1.0, 0.5, -0.16666666666666666, 0.041666666666666664, - -0.006944444444444444, 0.0008680555555555555, - -7.233796296296296e-5, 4.521122685185185e-6, - -1.8838011188271604e-7, 5.886878496334876e-9, - -1.226433020069766e-10, 1.9163015938590095e-12, - -1.9961474936031345e-14, 1.5594902293774489e-16, - -8.122344944674213e-19, 3.1727909940133645e-21] + -0.006944444444444444, 0.0008680555555555555, + -7.233796296296296e-5, 4.521122685185185e-6, + -1.8838011188271604e-7, 5.886878496334876e-9, + -1.226433020069766e-10, 1.9163015938590095e-12, + -1.9961474936031345e-14, 1.5594902293774489e-16, + -8.122344944674213e-19, 3.1727909940133645e-21] extrapolation_scalars_2 = T[-0.5, 0.16666666666666666, -0.041666666666666664, - 0.006944444444444444, -0.0008680555555555555, - 7.233796296296296e-5, -4.521122685185185e-6, - 1.8838011188271604e-7, -5.886878496334876e-9, - 1.226433020069766e-10, -1.9163015938590095e-12, - 1.9961474936031345e-14, -1.5594902293774489e-16, - 8.122344944674213e-19, -3.1727909940133645e-21] + 0.006944444444444444, -0.0008680555555555555, + 7.233796296296296e-5, -4.521122685185185e-6, + 1.8838011188271604e-7, -5.886878496334876e-9, + 1.226433020069766e-10, -1.9163015938590095e-12, + 1.9961474936031345e-14, -1.5594902293774489e-16, + 8.122344944674213e-19, -3.1727909940133645e-21] end extrapolation_coefficients(subdividing_sequence, extrapolation_weights, extrapolation_scalars, @@ -714,19 +722,19 @@ function create_extrapolation_coefficients(T::Type{<:CompiledFloats}, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.461344563824385e27 4.57333699600918e30; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.1278129999388386e30] extrapolation_scalars = T[-1.0, 0.25, -0.027777777777777776, 0.001736111111111111, - -6.944444444444444e-5, 1.9290123456790124e-6, - -3.936759889140842e-8, 6.151187326782565e-10, - -7.594058428126624e-12, 7.594058428126623e-14, - -6.276081345559193e-16, 4.358389823304995e-18, - -2.5789288895295828e-20, 1.3157800456783586e-22, - -5.8479113141260385e-25, 2.2843403570804838e-27] + -6.944444444444444e-5, 1.9290123456790124e-6, + -3.936759889140842e-8, 6.151187326782565e-10, + -7.594058428126624e-12, 7.594058428126623e-14, + -6.276081345559193e-16, 4.358389823304995e-18, + -2.5789288895295828e-20, 1.3157800456783586e-22, + -5.8479113141260385e-25, 2.2843403570804838e-27] extrapolation_scalars_2 = T[-0.25, 0.027777777777777776, -0.001736111111111111, - 6.944444444444444e-5, -1.9290123456790124e-6, - 3.936759889140842e-8, -6.151187326782565e-10, - 7.594058428126624e-12, -7.594058428126623e-14, - 6.276081345559193e-16, -4.358389823304995e-18, - 2.5789288895295828e-20, -1.3157800456783586e-22, - 5.8479113141260385e-25, -2.2843403570804838e-27] + 6.944444444444444e-5, -1.9290123456790124e-6, + 3.936759889140842e-8, -6.151187326782565e-10, + 7.594058428126624e-12, -7.594058428126623e-14, + 6.276081345559193e-16, -4.358389823304995e-18, + 2.5789288895295828e-20, -1.3157800456783586e-22, + 5.8479113141260385e-25, -2.2843403570804838e-27] elseif sequence == :romberg subdividing_sequence = [ 1, @@ -778,19 +786,19 @@ function create_extrapolation_coefficients(T::Type{<:CompiledFloats}, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.3898545256223295e63 8.553622524787915e71; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.5660867669957927e72] extrapolation_scalars = T[-1.0, 0.25, -0.015625, 0.000244140625, - -9.5367431640625e-7, 9.313225746154785e-10, - -2.2737367544323206e-13, 1.3877787807814457e-17, - -2.117582368135751e-22, 8.077935669463161e-28, - -7.703719777548943e-34, 1.8367099231598242e-40, - -1.0947644252537633e-47, 1.6313261169996311e-55, - -6.077163357286271e-64, 5.659799424266695e-73] + -9.5367431640625e-7, 9.313225746154785e-10, + -2.2737367544323206e-13, 1.3877787807814457e-17, + -2.117582368135751e-22, 8.077935669463161e-28, + -7.703719777548943e-34, 1.8367099231598242e-40, + -1.0947644252537633e-47, 1.6313261169996311e-55, + -6.077163357286271e-64, 5.659799424266695e-73] extrapolation_scalars_2 = T[-0.25, 0.015625, -0.000244140625, 9.5367431640625e-7, - -9.313225746154785e-10, 2.2737367544323206e-13, - -1.3877787807814457e-17, 2.117582368135751e-22, - -8.077935669463161e-28, 7.703719777548943e-34, - -1.8367099231598242e-40, 1.0947644252537633e-47, - -1.6313261169996311e-55, 6.077163357286271e-64, - -5.659799424266695e-73] + -9.313225746154785e-10, 2.2737367544323206e-13, + -1.3877787807814457e-17, 2.117582368135751e-22, + -8.077935669463161e-28, 7.703719777548943e-34, + -1.8367099231598242e-40, 1.0947644252537633e-47, + -1.6313261169996311e-55, 6.077163357286271e-64, + -5.659799424266695e-73] else # sequence == :bulirsch subdividing_sequence = [1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256] extrapolation_weights = T[-1.0 -1.3333333333333333 -1.5 -1.6 -1.6457142857142857 -1.6718367346938776 -1.6835279006707577 -1.6901299708694666 -1.693069327340544 -1.6947243315705933 -1.6954602083971546 -1.695874240194077 -1.6960582742950205 -1.6961617997954963 -1.6962078123772122 -1.6962336948493626; @@ -825,19 +833,19 @@ function create_extrapolation_coefficients(T::Type{<:CompiledFloats}, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 4.627542501479674e36 3.8991937548467816e41; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -4.023929415318473e41] extrapolation_scalars = T[-1.0, 0.25, -0.027777777777777776, 0.001736111111111111, - -4.8225308641975306e-5, 7.535204475308642e-7, - -5.232780885631001e-9, 2.0440550334496098e-11, - -3.548706655294462e-14, 3.465533843060998e-17, - -1.5041379527174468e-20, 3.672211798626579e-24, - -3.9846048162180767e-28, 2.4320097755237285e-32, - -6.597248740027475e-37, 1.0066602691692314e-41] + -4.8225308641975306e-5, 7.535204475308642e-7, + -5.232780885631001e-9, 2.0440550334496098e-11, + -3.548706655294462e-14, 3.465533843060998e-17, + -1.5041379527174468e-20, 3.672211798626579e-24, + -3.9846048162180767e-28, 2.4320097755237285e-32, + -6.597248740027475e-37, 1.0066602691692314e-41] extrapolation_scalars_2 = T[-0.25, 0.027777777777777776, -0.001736111111111111, - 4.8225308641975306e-5, -7.535204475308642e-7, - 5.232780885631001e-9, -2.0440550334496098e-11, - 3.548706655294462e-14, -3.465533843060998e-17, - 1.5041379527174468e-20, -3.672211798626579e-24, - 3.9846048162180767e-28, -2.4320097755237285e-32, - 6.597248740027475e-37, -1.0066602691692314e-41] + 4.8225308641975306e-5, -7.535204475308642e-7, + 5.232780885631001e-9, -2.0440550334496098e-11, + 3.548706655294462e-14, -3.465533843060998e-17, + 1.5041379527174468e-20, -3.672211798626579e-24, + 3.9846048162180767e-28, -2.4320097755237285e-32, + 6.597248740027475e-37, -1.0066602691692314e-41] end extrapolation_coefficients(subdividing_sequence, extrapolation_weights, extrapolation_scalars, @@ -889,7 +897,7 @@ end # Values that are mutated Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n + alg.min_order - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter # Constant values coefficients::extrapolation_coefficients @@ -901,7 +909,7 @@ function alg_cache(alg::ExtrapolationMidpointDeuflhard, u, rate_prototype, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} # Initialize cache's members - QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. DiffEqBase.__init in solve.jl + QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. SciMLBase.__init in solve.jl Q = fill(zero(QType), alg.max_order - alg.min_order + 1) n_curr = alg.init_order @@ -943,7 +951,7 @@ end # Constant values Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n + alg.min_order - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter coefficients::extrapolation_coefficients stage_number::Vector{Int} # Stage_number[n] contains information for extrapolation order (n + alg.min_order - 1) end @@ -956,10 +964,10 @@ function alg_cache(alg::ExtrapolationMidpointDeuflhard, u, rate_prototype, utilde = zero(u) u_temp1 = zero(u) u_temp2 = zero(u) - u_temp3 = Array{typeof(u), 1}(undef, Threads.nthreads()) - u_temp4 = Array{typeof(u), 1}(undef, Threads.nthreads()) + u_temp3 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + u_temp4 = Array{typeof(u), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_temp3[i] = zero(u) u_temp4[i] = zero(u) end @@ -973,8 +981,8 @@ function alg_cache(alg::ExtrapolationMidpointDeuflhard, u, rate_prototype, fsalfirst = zero(rate_prototype) k = zero(rate_prototype) - k_tmps = Array{typeof(k), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + k_tmps = Array{typeof(k), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) k_tmps[i] = zero(rate_prototype) end @@ -994,7 +1002,7 @@ end # Values that are mutated Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n + alg.min_order - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter # Constant values coefficients::extrapolation_coefficients @@ -1027,7 +1035,7 @@ end # Constant values Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n + alg.min_order - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter coefficients::extrapolation_coefficients stage_number::Vector{Int} # Stage_number[n] contains information for extrapolation order (n + alg.min_order - 1) @@ -1051,7 +1059,7 @@ function alg_cache(alg::ImplicitDeuflhardExtrapolation, u, rate_prototype, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} # Initialize cache's members - QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. DiffEqBase.__init in solve.jl + QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. SciMLBase.__init in solve.jl Q = fill(zero(QType), alg.max_order - alg.min_order + 1) n_curr = alg.init_order @@ -1095,10 +1103,10 @@ function alg_cache(alg::ImplicitDeuflhardExtrapolation, u, rate_prototype, utilde = zero(u) u_temp1 = zero(u) u_temp2 = zero(u) - u_temp3 = Array{typeof(u), 1}(undef, Threads.nthreads()) - u_temp4 = Array{typeof(u), 1}(undef, Threads.nthreads()) + u_temp3 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + u_temp4 = Array{typeof(u), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_temp3[i] = zero(u) u_temp4[i] = zero(u) end @@ -1112,8 +1120,8 @@ function alg_cache(alg::ImplicitDeuflhardExtrapolation, u, rate_prototype, fsalfirst = zero(rate_prototype) k = zero(rate_prototype) - k_tmps = Array{typeof(k), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + k_tmps = Array{typeof(k), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) k_tmps[i] = zero(rate_prototype) end @@ -1124,7 +1132,7 @@ function alg_cache(alg::ImplicitDeuflhardExtrapolation, u, rate_prototype, du1 = zero(rate_prototype) du2 = zero(rate_prototype) - if DiffEqBase.has_jac(f) && !DiffEqBase.has_Wfact(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && !SciMLBase.has_Wfact(f) && f.jac_prototype !== nothing W_el = WOperator(f, dt, true) J = nothing # is J = W.J better? else @@ -1132,9 +1140,9 @@ function alg_cache(alg::ImplicitDeuflhardExtrapolation, u, rate_prototype, W_el = zero(J) end - W = Array{typeof(W_el), 1}(undef, Threads.nthreads()) + W = Array{typeof(W_el), 1}(undef, get_thread_count(alg)) W[1] = W_el - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) if W_el isa WOperator W[i] = WOperator(f, dt, true) else @@ -1144,31 +1152,33 @@ function alg_cache(alg::ImplicitDeuflhardExtrapolation, u, rate_prototype, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) - linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, Threads.nthreads()) + linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) linsolve_tmps[i] = zero(rate_prototype) end linprob = LinearProblem(W[1], _vec(linsolve_tmps[1]); u0 = _vec(k_tmps[1])) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) - linsolve = Array{typeof(linsolve1), 1}(undef, Threads.nthreads()) + linsolve = Array{typeof(linsolve1), 1}(undef, get_thread_count(alg)) linsolve[1] = linsolve1 - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) linprob = LinearProblem(W[i], _vec(linsolve_tmps[i]); u0 = _vec(k_tmps[i])) - linsolve[i] = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve[i] = init(linprob, alg.linsolve, + alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) end grad_config = build_grad_config(alg, f, tf, du1, t) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, du1, du2) - diff1 = Array{typeof(u), 1}(undef, Threads.nthreads()) - diff2 = Array{typeof(u), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + diff1 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + diff2 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) diff1[i] = zero(u) diff2[i] = zero(u) end @@ -1187,7 +1197,7 @@ end # Values that are mutated Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter # Constant values coefficients::extrapolation_coefficients @@ -1204,7 +1214,7 @@ function alg_cache(alg::ExtrapolationMidpointHairerWanner, u, rate_prototype, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} # Initialize cache's members - QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. DiffEqBase.__init in solve.jl + QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. SciMLBase.__init in solve.jl Q = fill(zero(QType), alg.max_order + 1) n_curr = alg.init_order @@ -1250,7 +1260,7 @@ end # Constant values Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter coefficients::extrapolation_coefficients stage_number::Vector{Int} # stage_number[n] contains information for extrapolation order (n - 1) sigma::Rational{Int} # Parameter for order selection @@ -1268,10 +1278,10 @@ function alg_cache(alg::ExtrapolationMidpointHairerWanner, u, rate_prototype, utilde = zero(u) u_temp1 = zero(u) u_temp2 = zero(u) - u_temp3 = Array{typeof(u), 1}(undef, Threads.nthreads()) - u_temp4 = Array{typeof(u), 1}(undef, Threads.nthreads()) + u_temp3 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + u_temp4 = Array{typeof(u), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_temp3[i] = zero(u) u_temp4[i] = zero(u) end @@ -1283,8 +1293,8 @@ function alg_cache(alg::ExtrapolationMidpointHairerWanner, u, rate_prototype, res = uEltypeNoUnits.(zero(u)) fsalfirst = zero(rate_prototype) k = zero(rate_prototype) - k_tmps = Array{typeof(k), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + k_tmps = Array{typeof(k), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) k_tmps[i] = zero(rate_prototype) end @@ -1305,7 +1315,7 @@ end # Values that are mutated Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter # Constant values coefficients::extrapolation_coefficients @@ -1325,7 +1335,7 @@ function alg_cache(alg::ImplicitHairerWannerExtrapolation, u, rate_prototype, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} # Initialize cache's members - QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. DiffEqBase.__init in solve.jl + QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. SciMLBase.__init in solve.jl Q = fill(zero(QType), alg.max_order + 1) n_curr = alg.init_order @@ -1393,7 +1403,7 @@ end # Constant values Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter coefficients::extrapolation_coefficients stage_number::Vector{Int} # stage_number[n] contains information for extrapolation order (n - 1) sigma::Rational{Int} # Parameter for order selection @@ -1425,10 +1435,10 @@ function alg_cache(alg::ImplicitHairerWannerExtrapolation, u, rate_prototype, utilde = zero(u) u_temp1 = zero(u) u_temp2 = zero(u) - u_temp3 = Array{typeof(u), 1}(undef, Threads.nthreads()) - u_temp4 = Array{typeof(u), 1}(undef, Threads.nthreads()) + u_temp3 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + u_temp4 = Array{typeof(u), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_temp3[i] = zero(u) u_temp4[i] = zero(u) end @@ -1440,8 +1450,8 @@ function alg_cache(alg::ImplicitHairerWannerExtrapolation, u, rate_prototype, res = uEltypeNoUnits.(zero(u)) fsalfirst = zero(rate_prototype) k = zero(rate_prototype) - k_tmps = Array{typeof(k), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + k_tmps = Array{typeof(k), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) k_tmps[i] = zero(rate_prototype) end @@ -1451,7 +1461,7 @@ function alg_cache(alg::ImplicitHairerWannerExtrapolation, u, rate_prototype, du1 = zero(rate_prototype) du2 = zero(rate_prototype) - if DiffEqBase.has_jac(f) && !DiffEqBase.has_Wfact(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && !SciMLBase.has_Wfact(f) && f.jac_prototype !== nothing W_el = WOperator(f, dt, true) J = nothing # is J = W.J better? else @@ -1459,9 +1469,9 @@ function alg_cache(alg::ImplicitHairerWannerExtrapolation, u, rate_prototype, W_el = zero(J) end - W = Array{typeof(W_el), 1}(undef, Threads.nthreads()) + W = Array{typeof(W_el), 1}(undef, get_thread_count(alg)) W[1] = W_el - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) if W_el isa WOperator W[i] = WOperator(f, dt, true) else @@ -1472,31 +1482,33 @@ function alg_cache(alg::ImplicitHairerWannerExtrapolation, u, rate_prototype, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) - linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, Threads.nthreads()) + linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) linsolve_tmps[i] = zero(rate_prototype) end linprob = LinearProblem(W[1], _vec(linsolve_tmps[1]); u0 = _vec(k_tmps[1])) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) - linsolve = Array{typeof(linsolve1), 1}(undef, Threads.nthreads()) + linsolve = Array{typeof(linsolve1), 1}(undef, get_thread_count(alg)) linsolve[1] = linsolve1 - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) linprob = LinearProblem(W[i], _vec(linsolve_tmps[i]); u0 = _vec(k_tmps[i])) - linsolve[i] = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve[i] = init(linprob, alg.linsolve, + alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) end grad_config = build_grad_config(alg, f, tf, du1, t) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, du1, du2) - diff1 = Array{typeof(u), 1}(undef, Threads.nthreads()) - diff2 = Array{typeof(u), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + diff1 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + diff2 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) diff1[i] = zero(u) diff2[i] = zero(u) end @@ -1518,7 +1530,7 @@ end # Values that are mutated Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter # Constant values coefficients::extrapolation_coefficients @@ -1538,7 +1550,7 @@ function alg_cache(alg::ImplicitEulerBarycentricExtrapolation, u, rate_prototype ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} # Initialize cache's members - QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. DiffEqBase.__init in solve.jl + QType = tTypeNoUnits <: Integer ? typeof(qmin_default(alg)) : tTypeNoUnits # Cf. SciMLBase.__init in solve.jl Q = fill(zero(QType), alg.max_order + 1) n_curr = alg.init_order @@ -1590,7 +1602,7 @@ end # Constant values Q::Vector{QType} # Storage for stepsize scaling factors. Q[n] contains information for extrapolation order (n - 1) n_curr::Int # Storage for the current extrapolation order - n_old::Int # Storage for the extrapolation order n_curr before perfom_step! changes the latter + n_old::Int # Storage for the extrapolation order n_curr before perform_step! changes the latter coefficients::extrapolation_coefficients stage_number::Vector{Int} # stage_number[n] contains information for extrapolation order (n - 1) sigma::Rational{Int} # Parameter for order selection @@ -1621,10 +1633,10 @@ function alg_cache(alg::ImplicitEulerBarycentricExtrapolation, u, rate_prototype utilde = zero(u) u_temp1 = zero(u) u_temp2 = zero(u) - u_temp3 = Array{typeof(u), 1}(undef, Threads.nthreads()) - u_temp4 = Array{typeof(u), 1}(undef, Threads.nthreads()) + u_temp3 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + u_temp4 = Array{typeof(u), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) u_temp3[i] = zero(u) u_temp4[i] = zero(u) end @@ -1636,8 +1648,8 @@ function alg_cache(alg::ImplicitEulerBarycentricExtrapolation, u, rate_prototype res = uEltypeNoUnits.(zero(u)) fsalfirst = zero(rate_prototype) k = zero(rate_prototype) - k_tmps = Array{typeof(k), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + k_tmps = Array{typeof(k), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) k_tmps[i] = zero(rate_prototype) end @@ -1647,7 +1659,7 @@ function alg_cache(alg::ImplicitEulerBarycentricExtrapolation, u, rate_prototype du1 = zero(rate_prototype) du2 = zero(rate_prototype) - if DiffEqBase.has_jac(f) && !DiffEqBase.has_Wfact(f) && f.jac_prototype !== nothing + if SciMLBase.has_jac(f) && !SciMLBase.has_Wfact(f) && f.jac_prototype !== nothing W_el = WOperator(f, dt, true) J = nothing # is J = W.J better? else @@ -1655,9 +1667,9 @@ function alg_cache(alg::ImplicitEulerBarycentricExtrapolation, u, rate_prototype W_el = zero(J) end - W = Array{typeof(W_el), 1}(undef, Threads.nthreads()) + W = Array{typeof(W_el), 1}(undef, get_thread_count(alg)) W[1] = W_el - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) if W_el isa WOperator W[i] = WOperator(f, dt, true) else @@ -1668,31 +1680,33 @@ function alg_cache(alg::ImplicitEulerBarycentricExtrapolation, u, rate_prototype tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) - linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, Threads.nthreads()) + linsolve_tmps = Array{typeof(linsolve_tmp), 1}(undef, get_thread_count(alg)) - for i in 1:Threads.nthreads() + for i in 1:get_thread_count(alg) linsolve_tmps[i] = zero(rate_prototype) end linprob = LinearProblem(W[1], _vec(linsolve_tmps[1]); u0 = _vec(k_tmps[1])) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) - linsolve = Array{typeof(linsolve1), 1}(undef, Threads.nthreads()) + linsolve = Array{typeof(linsolve1), 1}(undef, get_thread_count(alg)) linsolve[1] = linsolve1 - for i in 2:Threads.nthreads() + for i in 2:get_thread_count(alg) linprob = LinearProblem(W[i], _vec(linsolve_tmps[i]); u0 = _vec(k_tmps[i])) - linsolve[i] = init(linprob, alg.linsolve, alias_A = true, alias_b = true) + linsolve[i] = init(linprob, alg.linsolve, + alias = LinearAliasSpecifier(alias_A = true, alias_b = true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) end grad_config = build_grad_config(alg, f, tf, du1, t) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, du1, du2) - diff1 = Array{typeof(u), 1}(undef, Threads.nthreads()) - diff2 = Array{typeof(u), 1}(undef, Threads.nthreads()) - for i in 1:Threads.nthreads() + diff1 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + diff2 = Array{typeof(u), 1}(undef, get_thread_count(alg)) + for i in 1:get_thread_count(alg) diff1[i] = zero(u) diff2[i] = zero(u) end diff --git a/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_perform_step.jl b/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_perform_step.jl index c205f1b48e..f4858d5fc2 100644 --- a/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_perform_step.jl +++ b/lib/OrdinaryDiffEqExtrapolation/src/extrapolation_perform_step.jl @@ -25,11 +25,11 @@ function perform_step!(integrator, cache::AitkenNevilleCache, repeat_step = fals for i in 1:max_order dt_temp = dt / (2^(i - 1)) # Solve using Euler method - @muladd @.. broadcast=false u=uprev + dt_temp * fsalfirst + @muladd @.. broadcast=false u=uprev+dt_temp*fsalfirst f(k, u, p, t + dt_temp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - for j in 2:(2^(i - 1)) - @muladd @.. broadcast=false u=u + dt_temp * k + for j in 2:(2 ^ (i - 1)) + @muladd @.. broadcast=false u=u+dt_temp*k f(k, u, p, t + j * dt_temp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end @@ -37,8 +37,7 @@ function perform_step!(integrator, cache::AitkenNevilleCache, repeat_step = fals end else let max_order = max_order, uprev = uprev, dt = dt, fsalfirst = fsalfirst, p = p, - t = t, - u_tmps = u_tmps, k_tmps = k_tmps, T = T + t = t, u_tmps = u_tmps, k_tmps = k_tmps, T = T # Balance workload of threads by computing T[1,1] with T[max_order,1] on # same thread, T[2,1] with T[max_order-1,1] on same thread. Similarly fill # first column of T matrix @@ -48,15 +47,15 @@ function perform_step!(integrator, cache::AitkenNevilleCache, repeat_step = fals for index in startIndex:endIndex dt_temp = dt / (2^(index - 1)) # Solve using Euler method - @muladd @.. broadcast=false u_tmps[Threads.threadid()]=uprev + - dt_temp * - fsalfirst + @muladd @.. broadcast=false u_tmps[Threads.threadid()]=uprev+ + dt_temp* + fsalfirst f(k_tmps[Threads.threadid()], u_tmps[Threads.threadid()], p, t + dt_temp) - for j in 2:(2^(index - 1)) - @muladd @.. broadcast=false u_tmps[Threads.threadid()]=u_tmps[Threads.threadid()] + - dt_temp * - k_tmps[Threads.threadid()] + for j in 2:(2 ^ (index - 1)) + @muladd @.. broadcast=false u_tmps[Threads.threadid()]=u_tmps[Threads.threadid()]+ + dt_temp* + k_tmps[Threads.threadid()] f(k_tmps[Threads.threadid()], u_tmps[Threads.threadid()], p, t + j * dt_temp) end @@ -72,7 +71,7 @@ function perform_step!(integrator, cache::AitkenNevilleCache, repeat_step = fals for j in 2:max_order tmp *= 2 for i in j:max_order - @.. broadcast=false T[i, j]=(tmp * T[i, j - 1] - T[i - 1, j - 1]) / (tmp - 1) + @.. broadcast=false T[i, j]=(tmp*T[i, j - 1]-T[i - 1, j - 1])/(tmp-1) end end @@ -86,7 +85,7 @@ function perform_step!(integrator, cache::AitkenNevilleCache, repeat_step = fals for i in range_start:max_order A = 2^(i - 1) - @.. broadcast=false utilde=T[i, i] - T[i, i - 1] + @.. broadcast=false utilde=T[i, i]-T[i, i - 1] atmp = calculate_residuals(utilde, uprev, T[i, i], integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) @@ -154,7 +153,7 @@ function perform_step!(integrator, cache::AitkenNevilleConstantCache, repeat_ste k = f(u, p, t + dt_temp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - for j in 2:(2^(i - 1)) + for j in 2:(2 ^ (i - 1)) @muladd u = @.. broadcast=false u+dt_temp * k k = f(u, p, t + j * dt_temp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -175,7 +174,7 @@ function perform_step!(integrator, cache::AitkenNevilleConstantCache, repeat_ste dt_temp = dt / 2^(index - 1) @muladd u = @.. broadcast=false uprev+dt_temp * integrator.fsalfirst k_temp = f(u, p, t + dt_temp) - for j in 2:(2^(index - 1)) + for j in 2:(2 ^ (index - 1)) @muladd u = @.. broadcast=false u+dt_temp * k_temp k_temp = f(u, p, t + j * dt_temp) end @@ -312,11 +311,11 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, integrator.stats.nsolve += 1 @.. broadcast=false u_tmps2[1]=u_tmps[1] - @.. broadcast=false u_tmps[1]=u_tmps[1] - k_tmps[1] + @.. broadcast=false u_tmps[1]=u_tmps[1]-k_tmps[1] if index <= 2 && j >= 2 # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[1]=u_tmps[1] - u_tmps2[1] - @.. broadcast=false diff2[1]=0.5 * (diff2[1] - diff1[1]) + @.. broadcast=false diff2[1]=u_tmps[1]-u_tmps2[1] + @.. broadcast=false diff2[1]=0.5*(diff2[1]-diff1[1]) if integrator.opts.internalnorm(diff1[1], t) < integrator.opts.internalnorm(diff2[1], t) # Divergence of iteration, overflow is possible. Force fail and start with smaller step @@ -324,7 +323,7 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, return end end - @.. broadcast=false diff1[1]=u_tmps[1] - u_tmps2[1] + @.. broadcast=false diff1[1]=u_tmps[1]-u_tmps2[1] f(k_tmps[1], u_tmps[1], p, t + j * dt_temp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -366,15 +365,15 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, cache.linsolve[Threads.threadid()] = linres.cache @.. broadcast=false u_tmps2[Threads.threadid()]=u_tmps[Threads.threadid()] - @.. broadcast=false u_tmps[Threads.threadid()]=u_tmps[Threads.threadid()] - - k_tmps[Threads.threadid()] + @.. broadcast=false u_tmps[Threads.threadid()]=u_tmps[Threads.threadid()]- + k_tmps[Threads.threadid()] if index <= 2 && j >= 2 # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[Threads.threadid()]=u_tmps[Threads.threadid()] - - u_tmps2[Threads.threadid()] - @.. broadcast=false diff2[Threads.threadid()]=0.5 * - (diff2[Threads.threadid()] - - diff1[Threads.threadid()]) + @.. broadcast=false diff2[Threads.threadid()]=u_tmps[Threads.threadid()]- + u_tmps2[Threads.threadid()] + @.. broadcast=false diff2[Threads.threadid()]=0.5* + (diff2[Threads.threadid()]- + diff1[Threads.threadid()]) if integrator.opts.internalnorm(diff1[Threads.threadid()], t) < integrator.opts.internalnorm(diff2[Threads.threadid()], t) # Divergence of iteration, overflow is possible. Force fail and start with smaller step @@ -382,8 +381,8 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, return end end - @.. broadcast=false diff1[Threads.threadid()]=u_tmps[Threads.threadid()] - - u_tmps2[Threads.threadid()] + @.. broadcast=false diff1[Threads.threadid()]=u_tmps[Threads.threadid()]- + u_tmps2[Threads.threadid()] f(k_tmps[Threads.threadid()], u_tmps[Threads.threadid()], p, t + j * dt_temp) end @@ -407,9 +406,10 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, # Polynomial extrapolation for j in 2:(n_curr + 1) for i in j:(n_curr + 1) - @.. broadcast=false T[i, j]=((sequence[i] / sequence[i - j + 1]) * T[i, j - 1] - - T[i - 1, j - 1]) / - ((sequence[i] / sequence[i - j + 1]) - 1) + @.. broadcast=false T[i, j]=((sequence[i]/sequence[i - j + 1])*T[ + i, j - 1]- + T[i - 1, j - 1])/ + ((sequence[i]/sequence[i - j + 1])-1) end end @@ -466,7 +466,7 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false u_tmps[1]=u_tmps[1] - k_tmps[1] + @.. broadcast=false u_tmps[1]=u_tmps[1]-k_tmps[1] f(k_tmps[1], u_tmps[1], p, t + j * dt_temp) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end @@ -475,10 +475,10 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationCache, for j in 2:(n_curr + 1) for i in j:(n_curr + 1) - @.. broadcast=false T[i, j]=((sequence[i] / sequence[i - j + 1]) * - T[i, j - 1] - T[i - 1, j - 1]) / - ((sequence[i] / sequence[i - j + 1]) - - 1) + @.. broadcast=false T[i, j]=((sequence[i]/sequence[i - j + 1])* + T[i, j - 1]-T[i - 1, j - 1])/ + ((sequence[i]/sequence[i - j + 1])- + 1) end end @@ -572,8 +572,7 @@ function perform_step!(integrator, cache::ImplicitEulerExtrapolationConstantCach else J = calc_J(integrator, cache) # Store the calculated jac as it won't change in internal discretisation let n_curr = n_curr, dt = dt, integrator = integrator, cache = cache, - repeat_step = repeat_step, - uprev = uprev, T = T + repeat_step = repeat_step, uprev = uprev, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 1 : n_curr + 1 @@ -757,11 +756,11 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, j_int = sequence_factor * subdividing_sequence[i + 1] dt_int = dt / j_int # Stepsize of the ith internal discretisation @.. broadcast=false u_temp2=uprev - @.. broadcast=false u_temp1=u_temp2 + dt_int * fsalfirst # Euler starting step + @.. broadcast=false u_temp1=u_temp2+dt_int*fsalfirst # Euler starting step for j in 2:j_int f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false T[i + 1]=u_temp2 + 2 * dt_int * k # Explicit Midpoint rule + @.. broadcast=false T[i + 1]=u_temp2+2*dt_int*k # Explicit Midpoint rule @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[i + 1] end @@ -774,8 +773,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -784,16 +783,16 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, j_int_temp = sequence_factor * subdividing_sequence[index + 1] dt_int_temp = dt / j_int_temp # Stepsize of the ith internal discretisation @.. broadcast=false u_temp4[Threads.threadid()]=uprev - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] + - dt_int_temp * - fsalfirst # Euler starting step + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]+ + dt_int_temp* + fsalfirst # Euler starting step for j in 2:j_int_temp f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()] + - 2 * dt_int_temp * - k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()]+ + 2*dt_int_temp* + k_tmps[Threads.threadid()] # Explicit Midpoint rule @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] end @@ -802,8 +801,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = (i, n_curr - i) @@ -811,15 +810,15 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, j_int_temp = sequence_factor * subdividing_sequence[index + 1] dt_int_temp = dt / j_int_temp # Stepsize of the ith internal discretisation @.. broadcast=false u_temp4[Threads.threadid()]=uprev - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] + - dt_int_temp * - fsalfirst # Euler starting step + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]+ + dt_int_temp* + fsalfirst # Euler starting step for j in 2:j_int_temp f(k_tmps[Threads.threadid()], u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()] + - 2 * dt_int_temp * - k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()]+ + 2*dt_int_temp* + k_tmps[Threads.threadid()] # Explicit Midpoint rule @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] end @@ -849,8 +848,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, for j in 2:(i + 1) @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, i] end - @.. broadcast=false integrator.u=extrapolation_scalars[i + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[i] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[i + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[i]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -877,11 +876,11 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, j_int = sequence_factor * subdividing_sequence[n_curr + 1] dt_int = dt / j_int # Stepsize of the new internal discretisation @.. broadcast=false u_temp2=uprev - @.. broadcast=false u_temp1=u_temp2 + dt_int * fsalfirst # Euler starting step + @.. broadcast=false u_temp1=u_temp2+dt_int*fsalfirst # Euler starting step for j in 2:j_int f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false T[n_curr + 1]=u_temp2 + 2 * dt_int * k + @.. broadcast=false T[n_curr + 1]=u_temp2+2*dt_int*k @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[n_curr + 1] end @@ -900,8 +899,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, n_curr] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -920,7 +919,7 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardCache, for j in 1:(n_curr + 1) @.. broadcast=false u_temp1+=cache.T[j] * extrapolation_weights[j, (n_curr + 1)] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 end f(cache.k, integrator.u, p, t + dt) # Update FSAL @@ -994,8 +993,7 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardConstant # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, - integrator = integrator, p = p, t = t, T = T + dt = dt, integrator = integrator, p = p, t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -1017,8 +1015,7 @@ function perform_step!(integrator, cache::ExtrapolationMidpointDeuflhardConstant end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, dt = dt, - uprev = uprev, - p = p, t = t, T = T + uprev = uprev, p = p, t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = (i, n_curr - i) @@ -1186,12 +1183,12 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false u_temp1=u_temp2 - k # Euler starting step - @.. broadcast=false diff1[1]=u_temp1 - u_temp2 + @.. broadcast=false u_temp1=u_temp2-k # Euler starting step + @.. broadcast=false diff1[1]=u_temp1-u_temp2 for j in 2:j_int f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false linsolve_tmps[1]=k - (u_temp1 - u_temp2) / dt_int + @.. broadcast=false linsolve_tmps[1]=k-(u_temp1-u_temp2)/dt_int linsolve = cache.linsolve[1] @@ -1205,12 +1202,12 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false T[i + 1]=2 * u_temp1 - u_temp2 - 2 * k # Explicit Midpoint rule + @.. broadcast=false T[i + 1]=2*u_temp1-u_temp2-2*k # Explicit Midpoint rule @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[i + 1] if (i <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[1]=u_temp1 - u_temp2 + @.. broadcast=false diff2[1]=u_temp1-u_temp2 if (integrator.opts.internalnorm(diff1[1], t) < integrator.opts.internalnorm(0.5 * (diff2[1] - diff1[1]), t)) # Divergence of iteration, overflow is possible. Force fail and start with smaller step @@ -1228,8 +1225,8 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -1258,18 +1255,18 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, cache.linsolve[Threads.threadid()] = linres.cache @.. broadcast=false k_tmps[Threads.threadid()]=-k_tmps[Threads.threadid()] - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] + - k_tmps[Threads.threadid()] # Euler starting step - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]+ + k_tmps[Threads.threadid()] # Euler starting step + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] for j in 2:j_int_temp f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false linsolve_tmps[Threads.threadid()]=k_tmps[Threads.threadid()] - - (u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()]) / - dt_int_temp + @.. broadcast=false linsolve_tmps[Threads.threadid()]=k_tmps[Threads.threadid()]- + (u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()])/ + dt_int_temp linsolve = cache.linsolve[Threads.threadid()] @@ -1285,19 +1282,19 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false T[index + 1]=2 * - u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - - 2 * k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=2* + u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()]- + 2*k_tmps[Threads.threadid()] # Explicit Midpoint rule @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] if (index <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - @.. broadcast=false diff2[Threads.threadid()]=0.5 * - (diff2[Threads.threadid()] - - diff1[Threads.threadid()]) + @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] + @.. broadcast=false diff2[Threads.threadid()]=0.5* + (diff2[Threads.threadid()]- + diff1[Threads.threadid()]) if (integrator.opts.internalnorm(diff1[Threads.threadid()], t) < integrator.opts.internalnorm(diff2[Threads.threadid()], @@ -1314,8 +1311,8 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) #Use flag to avoid union @@ -1343,18 +1340,18 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, cache.linsolve[Threads.threadid()] = linres.cache @.. broadcast=false k_tmps[Threads.threadid()]=-k_tmps[Threads.threadid()] - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] + - k_tmps[Threads.threadid()] # Euler starting step - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]+ + k_tmps[Threads.threadid()] # Euler starting step + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] for j in 2:j_int_temp f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false linsolve_tmps[Threads.threadid()]=k_tmps[Threads.threadid()] - - (u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()]) / - dt_int_temp + @.. broadcast=false linsolve_tmps[Threads.threadid()]=k_tmps[Threads.threadid()]- + (u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()])/ + dt_int_temp linsolve = cache.linsolve[Threads.threadid()] @@ -1370,19 +1367,19 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false T[index + 1]=2 * - u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - - 2 * k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=2* + u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()]- + 2*k_tmps[Threads.threadid()] # Explicit Midpoint rule @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] if (index <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - @.. broadcast=false diff2[Threads.threadid()]=0.5 * - (diff2[Threads.threadid()] - - diff1[Threads.threadid()]) + @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] + @.. broadcast=false diff2[Threads.threadid()]=0.5* + (diff2[Threads.threadid()]- + diff1[Threads.threadid()]) if (integrator.opts.internalnorm(diff1[Threads.threadid()], t) < integrator.opts.internalnorm(diff2[Threads.threadid()], @@ -1419,8 +1416,8 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, for j in 2:(i + 1) @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, i] end - @.. broadcast=false integrator.u=extrapolation_scalars[i + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[i] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[i + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[i]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -1459,11 +1456,11 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false u_temp1=u_temp2 - k # Euler starting step + @.. broadcast=false u_temp1=u_temp2-k # Euler starting step for j in 2:j_int f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false linsolve_tmps[1]=dt_int * k - (u_temp1 - u_temp2) + @.. broadcast=false linsolve_tmps[1]=dt_int*k-(u_temp1-u_temp2) linsolve = cache.linsolve[1] linres = dolinsolve(integrator, linsolve; b = _vec(linsolve_tmps[1]), @@ -1471,7 +1468,7 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false T[n_curr + 1]=2 * u_temp1 - u_temp2 - 2 * k # Explicit Midpoint rule + @.. broadcast=false T[n_curr + 1]=2*u_temp1-u_temp2-2*k # Explicit Midpoint rule @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[n_curr + 1] end @@ -1490,8 +1487,8 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, n_curr] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -1510,7 +1507,7 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationCache, for j in 1:(n_curr + 1) @.. broadcast=false u_temp1+=cache.T[j] * extrapolation_weights[j, (n_curr + 1)] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 end f(cache.k, integrator.u, p, t + dt) # Update FSAL @@ -1602,8 +1599,7 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationConstant # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp2 = u_temp2, - u_temp2 = u_temp2, p = p, t = t, T = T + dt = dt, u_temp2 = u_temp2, u_temp2 = u_temp2, p = p, t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -1649,8 +1645,7 @@ function perform_step!(integrator, cache::ImplicitDeuflhardExtrapolationConstant end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, - integrator = integrator, p = p, t = t, T = T + dt = dt, integrator = integrator, p = p, t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) @@ -1833,11 +1828,11 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache j_int = sequence_factor * subdividing_sequence[i + 1] dt_int = dt / j_int # Stepsize of the ith internal discretisation @.. broadcast=false u_temp2=uprev - @.. broadcast=false u_temp1=u_temp2 + dt_int * fsalfirst # Euler starting step + @.. broadcast=false u_temp1=u_temp2+dt_int*fsalfirst # Euler starting step for j in 2:j_int f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false T[i + 1]=u_temp2 + 2 * dt_int * k # Explicit Midpoint rule + @.. broadcast=false T[i + 1]=u_temp2+2*dt_int*k # Explicit Midpoint rule @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[i + 1] end @@ -1850,8 +1845,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -1861,16 +1856,16 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache j_int_temp = sequence_factor * subdividing_sequence[index + 1] dt_int_temp = dt / j_int_temp # Stepsize of the ith internal discretisation @.. broadcast=false u_temp4[Threads.threadid()]=uprev - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] + - dt_int_temp * - fsalfirst # Euler starting step + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]+ + dt_int_temp* + fsalfirst # Euler starting step for j in 2:j_int_temp f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()] + - 2 * dt_int_temp * - k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()]+ + 2*dt_int_temp* + k_tmps[Threads.threadid()] # Explicit Midpoint rule @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] end @@ -1879,8 +1874,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) @@ -1889,16 +1884,16 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache j_int_temp = sequence_factor * subdividing_sequence[index + 1] dt_int_temp = dt / j_int_temp # Stepsize of the ith internal discretisation @.. broadcast=false u_temp4[Threads.threadid()]=uprev - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] + - dt_int_temp * - fsalfirst # Euler starting step + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]+ + dt_int_temp* + fsalfirst # Euler starting step for j in 2:j_int_temp f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()] + - 2 * dt_int_temp * - k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=u_temp4[Threads.threadid()]+ + 2*dt_int_temp* + k_tmps[Threads.threadid()] # Explicit Midpoint rule @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] end @@ -1925,8 +1920,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache for j in 2:(i + 1) @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, i] end - @.. broadcast=false integrator.u=extrapolation_scalars[i + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[i] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[i + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[i]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -1955,11 +1950,11 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache j_int = sequence_factor * subdividing_sequence[n_curr + 1] dt_int = dt / j_int # Stepsize of the new internal discretisation @.. broadcast=false u_temp2=uprev - @.. broadcast=false u_temp1=u_temp2 + dt_int * fsalfirst # Euler starting step + @.. broadcast=false u_temp1=u_temp2+dt_int*fsalfirst # Euler starting step for j in 2:j_int f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false T[n_curr + 1]=u_temp2 + 2 * dt_int * k + @.. broadcast=false T[n_curr + 1]=u_temp2+2*dt_int*k @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[n_curr + 1] end @@ -1978,8 +1973,8 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, n_curr] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -1998,7 +1993,7 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerCache for j in 1:(n_curr + 1) @.. broadcast=false u_temp1+=cache.T[j] * extrapolation_weights[j, (n_curr + 1)] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 end f(cache.k, integrator.u, p, t + dt) # Update FSAL @@ -2074,8 +2069,7 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerConst # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, dt = dt, - uprev = uprev, - integrator = integrator, T = T, p = p, t = t + uprev = uprev, integrator = integrator, T = T, p = p, t = t @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -2097,8 +2091,7 @@ function perform_step!(integrator, cache::ExtrapolationMidpointHairerWannerConst end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, dt = dt, - uprev = uprev, - integrator = integrator, T = T, p = p, t = t + uprev = uprev, integrator = integrator, T = T, p = p, t = t @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) @@ -2293,8 +2286,7 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationConst # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp2 = u_temp2, - u_temp2 = u_temp2, p = p, t = t, T = T + dt = dt, u_temp2 = u_temp2, u_temp2 = u_temp2, p = p, t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -2342,8 +2334,7 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationConst end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, - integrator = integrator, p = p, t = t, T = T + dt = dt, integrator = integrator, p = p, t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) @@ -2550,12 +2541,12 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false u_temp1=u_temp2 - k # Euler starting step - @.. broadcast=false diff1[1]=u_temp1 - u_temp2 + @.. broadcast=false u_temp1=u_temp2-k # Euler starting step + @.. broadcast=false diff1[1]=u_temp1-u_temp2 for j in 2:(j_int + 1) f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false linsolve_tmps[1]=k - (u_temp1 - u_temp2) / dt_int + @.. broadcast=false linsolve_tmps[1]=k-(u_temp1-u_temp2)/dt_int linsolve = cache.linsolve[1] @@ -2569,16 +2560,16 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false T[i + 1]=2 * u_temp1 - u_temp2 - 2 * k # Explicit Midpoint rule + @.. broadcast=false T[i + 1]=2*u_temp1-u_temp2-2*k # Explicit Midpoint rule if (j == j_int + 1) - @.. broadcast=false T[i + 1]=0.5(T[i + 1] + u_temp2) + @.. broadcast=false T[i + 1]=0.5(T[i + 1]+u_temp2) end @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[i + 1] if (i <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[1]=u_temp1 - u_temp2 - @.. broadcast=false diff2[1]=0.5 * (diff2[1] - diff1[1]) + @.. broadcast=false diff2[1]=u_temp1-u_temp2 + @.. broadcast=false diff2[1]=0.5*(diff2[1]-diff1[1]) if (integrator.opts.internalnorm(diff1[1], t) < integrator.opts.internalnorm(diff2[1], t)) # Divergence of iteration, overflow is possible. Force fail and start with smaller step @@ -2586,7 +2577,7 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache return end end - @.. broadcast=false diff1[1]=u_temp1 - u_temp2 + @.. broadcast=false diff1[1]=u_temp1-u_temp2 end end else @@ -2597,8 +2588,8 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -2626,18 +2617,18 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] - - k_tmps[Threads.threadid()] # Euler starting step - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]- + k_tmps[Threads.threadid()] # Euler starting step + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] for j in 2:(j_int_temp + 1) f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false linsolve_tmps[Threads.threadid()]=k_tmps[Threads.threadid()] - - (u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()]) / - dt_int_temp + @.. broadcast=false linsolve_tmps[Threads.threadid()]=k_tmps[Threads.threadid()]- + (u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()])/ + dt_int_temp linsolve = cache.linsolve[Threads.threadid()] if !repeat_step && j == 1 @@ -2652,23 +2643,23 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false T[index + 1]=2 * - u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - - 2 * k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=2* + u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()]- + 2*k_tmps[Threads.threadid()] # Explicit Midpoint rule if (j == j_int_temp + 1) - @.. broadcast=false T[index + 1]=0.5(T[index + 1] + - u_temp4[Threads.threadid()]) + @.. broadcast=false T[index + 1]=0.5(T[index + 1]+ + u_temp4[Threads.threadid()]) end @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] if (index <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - @.. broadcast=false diff2[Threads.threadid()]=0.5 * - (diff2[Threads.threadid()] - - diff1[Threads.threadid()]) + @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] + @.. broadcast=false diff2[Threads.threadid()]=0.5* + (diff2[Threads.threadid()]- + diff1[Threads.threadid()]) if (integrator.opts.internalnorm(diff1[Threads.threadid()], t) < integrator.opts.internalnorm(diff2[Threads.threadid()], @@ -2678,8 +2669,8 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache return end end - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] end end integrator.force_stepfail ? break : continue @@ -2687,8 +2678,8 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) tid = Threads.threadid() @@ -2713,13 +2704,13 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache end cache.linsolve[tid] = linres.cache - @.. broadcast=false u_temp3[tid]=u_temp4[tid] - ktmp # Euler starting step - @.. broadcast=false diff1[tid]=u_temp3[tid] - u_temp4[tid] + @.. broadcast=false u_temp3[tid]=u_temp4[tid]-ktmp # Euler starting step + @.. broadcast=false diff1[tid]=u_temp3[tid]-u_temp4[tid] for j in 2:(j_int_temp + 1) f(ktmp, cache.u_temp3[tid], p, t + (j - 1) * dt_int_temp) - @.. broadcast=false linsolvetmp=ktmp - - (u_temp3[tid] - u_temp4[tid]) / - dt_int_temp + @.. broadcast=false linsolvetmp=ktmp- + (u_temp3[tid]-u_temp4[tid])/ + dt_int_temp linsolve = cache.linsolve[tid] @@ -2734,19 +2725,19 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache end cache.linsolve[tid] = linres.cache - @.. broadcast=false T[index + 1]=2 * u_temp3[tid] - - u_temp4[tid] - 2 * ktmp # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=2*u_temp3[tid]- + u_temp4[tid]-2*ktmp # Explicit Midpoint rule if (j == j_int_temp + 1) - @.. broadcast=false T[index + 1]=0.5(T[index + 1] + - u_temp4[tid]) + @.. broadcast=false T[index + 1]=0.5(T[index + 1]+ + u_temp4[tid]) end @.. broadcast=false u_temp4[tid]=u_temp3[tid] @.. broadcast=false u_temp3[tid]=T[index + 1] if (index <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[tid]=u_temp3[tid] - u_temp4[tid] - @.. broadcast=false diff2[tid]=0.5 * - (diff2[tid] - diff1[tid]) + @.. broadcast=false diff2[tid]=u_temp3[tid]-u_temp4[tid] + @.. broadcast=false diff2[tid]=0.5* + (diff2[tid]-diff1[tid]) if (integrator.opts.internalnorm(diff1[tid], t) < integrator.opts.internalnorm(diff2[tid], t)) # Divergence of iteration, overflow is possible. Force fail and start with smaller step @@ -2754,7 +2745,7 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache return end end - @.. broadcast=false diff1[tid]=u_temp3[tid] - u_temp4[tid] + @.. broadcast=false diff1[tid]=u_temp3[tid]-u_temp4[tid] end end integrator.force_stepfail ? break : continue @@ -2782,8 +2773,8 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache for j in 2:(i + 1) @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, i] end - @.. broadcast=false integrator.u=extrapolation_scalars[i + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[i] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[i + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[i]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -2830,11 +2821,11 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false u_temp1=u_temp2 - k # Euler starting step + @.. broadcast=false u_temp1=u_temp2-k # Euler starting step for j in 2:(j_int + 1) f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false linsolve_tmps[1]=k - (u_temp1 - u_temp2) / dt_int + @.. broadcast=false linsolve_tmps[1]=k-(u_temp1-u_temp2)/dt_int linsolve = cache.linsolve[1] @@ -2848,9 +2839,9 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false T[n_curr + 1]=2 * u_temp1 - u_temp2 - 2 * k # Explicit Midpoint rule + @.. broadcast=false T[n_curr + 1]=2*u_temp1-u_temp2-2*k # Explicit Midpoint rule if (j == j_int + 1) - @.. broadcast=false T[n_curr + 1]=0.5(T[n_curr + 1] + u_temp2) + @.. broadcast=false T[n_curr + 1]=0.5(T[n_curr + 1]+u_temp2) end @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[n_curr + 1] @@ -2870,8 +2861,8 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, n_curr] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -2890,7 +2881,7 @@ function perform_step!(integrator, cache::ImplicitHairerWannerExtrapolationCache for j in 1:(n_curr + 1) @.. broadcast=false u_temp1+=cache.T[j] * extrapolation_weights[j, (n_curr + 1)] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 end f(cache.k, integrator.u, p, t + dt) # Update FSAL @@ -2989,8 +2980,7 @@ function perform_step!(integrator, # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp2 = u_temp2, - u_temp2 = u_temp2, p = p, t = t, T = T + dt = dt, u_temp2 = u_temp2, u_temp2 = u_temp2, p = p, t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -3036,8 +3026,7 @@ function perform_step!(integrator, end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, - integrator = integrator, p = p, t = t, T = T + dt = dt, integrator = integrator, p = p, t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) @@ -3242,8 +3231,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false u_temp1=u_temp2 - k # Euler starting step - @.. broadcast=false diff1[1]=u_temp1 - u_temp2 + @.. broadcast=false u_temp1=u_temp2-k # Euler starting step + @.. broadcast=false diff1[1]=u_temp1-u_temp2 for j in 2:(j_int + 1) f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -3260,16 +3249,16 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false T[i + 1]=u_temp1 - k + @.. broadcast=false T[i + 1]=u_temp1-k if (j == j_int + 1) - @.. broadcast=false T[i + 1]=0.25(T[i + 1] + 2 * u_temp1 + u_temp2) + @.. broadcast=false T[i + 1]=0.25(T[i + 1]+2*u_temp1+u_temp2) end @.. broadcast=false u_temp2=u_temp1 @.. broadcast=false u_temp1=T[i + 1] if (i <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[1]=u_temp1 - u_temp2 - @.. broadcast=false diff2[1]=0.5 * (diff2[1] - diff1[1]) + @.. broadcast=false diff2[1]=u_temp1-u_temp2 + @.. broadcast=false diff2[1]=0.5*(diff2[1]-diff1[1]) if (integrator.opts.internalnorm(diff1[1], t) < integrator.opts.internalnorm(diff2[1], t)) # Divergence of iteration, overflow is possible. Force fail and start with smaller step @@ -3277,7 +3266,7 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC return end end - @.. broadcast=false diff1[1]=u_temp1 - u_temp2 + @.. broadcast=false diff1[1]=u_temp1-u_temp2 end end else @@ -3288,8 +3277,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC # Romberg sequence --> 1, 2, 4, 8, ..., 2^(i) # 1 + 2 + 4 + ... + 2^(i-1) = 2^(i) - 1 let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 1:2 startIndex = (i == 1) ? 0 : n_curr @@ -3318,10 +3307,10 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC cache.linsolve[Threads.threadid()] = linres.cache @.. broadcast=false k_tmps[Threads.threadid()]=-k_tmps[Threads.threadid()] - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] - - k_tmps[Threads.threadid()] # Euler starting step - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]- + k_tmps[Threads.threadid()] # Euler starting step + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] for j in 2:(j_int_temp + 1) f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], @@ -3342,23 +3331,23 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false T[index + 1]=u_temp3[Threads.threadid()] - - k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=u_temp3[Threads.threadid()]- + k_tmps[Threads.threadid()] # Explicit Midpoint rule if (j == j_int_temp + 1) - @.. broadcast=false T[index + 1]=0.25(T[index + 1] + - 2 * - u_temp3[Threads.threadid()] + + @.. broadcast=false T[index + 1]=0.25(T[index + 1]+ + 2* + u_temp3[Threads.threadid()]+ u_temp4[Threads.threadid()]) end @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] if (index <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - @.. broadcast=false diff2[Threads.threadid()]=0.5 * - (diff2[Threads.threadid()] - - diff1[Threads.threadid()]) + @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] + @.. broadcast=false diff2[Threads.threadid()]=0.5* + (diff2[Threads.threadid()]- + diff1[Threads.threadid()]) if (integrator.opts.internalnorm(diff1[Threads.threadid()], t) < integrator.opts.internalnorm(diff2[Threads.threadid()], @@ -3368,8 +3357,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC return end end - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] end end integrator.force_stepfail ? break : continue @@ -3377,8 +3366,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC end else let n_curr = n_curr, subdividing_sequence = subdividing_sequence, uprev = uprev, - dt = dt, u_temp3 = u_temp3, - u_temp4 = u_temp4, k_tmps = k_tmps, p = p, t = t, T = T + dt = dt, u_temp3 = u_temp3, u_temp4 = u_temp4, k_tmps = k_tmps, p = p, + t = t, T = T @threaded alg.threading for i in 0:(n_curr ÷ 2) indices = i != n_curr - i ? (i, n_curr - i) : (-1, n_curr - i) @@ -3405,10 +3394,10 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()] - - k_tmps[Threads.threadid()] # Euler starting step - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false u_temp3[Threads.threadid()]=u_temp4[Threads.threadid()]- + k_tmps[Threads.threadid()] # Euler starting step + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] for j in 2:(j_int_temp + 1) f(k_tmps[Threads.threadid()], cache.u_temp3[Threads.threadid()], @@ -3429,23 +3418,23 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC end cache.linsolve[Threads.threadid()] = linres.cache - @.. broadcast=false T[index + 1]=u_temp3[Threads.threadid()] - - k_tmps[Threads.threadid()] # Explicit Midpoint rule + @.. broadcast=false T[index + 1]=u_temp3[Threads.threadid()]- + k_tmps[Threads.threadid()] # Explicit Midpoint rule if (j == j_int_temp + 1) - @.. broadcast=false T[index + 1]=0.25(T[index + 1] + - 2 * - u_temp3[Threads.threadid()] + + @.. broadcast=false T[index + 1]=0.25(T[index + 1]+ + 2* + u_temp3[Threads.threadid()]+ u_temp4[Threads.threadid()]) end @.. broadcast=false u_temp4[Threads.threadid()]=u_temp3[Threads.threadid()] @.. broadcast=false u_temp3[Threads.threadid()]=T[index + 1] if (index <= 1) # Deuflhard Stability check for initial two sequences - @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] - @.. broadcast=false diff2[Threads.threadid()]=0.5 * - (diff2[Threads.threadid()] - - diff1[Threads.threadid()]) + @.. broadcast=false diff2[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] + @.. broadcast=false diff2[Threads.threadid()]=0.5* + (diff2[Threads.threadid()]- + diff1[Threads.threadid()]) if (integrator.opts.internalnorm(diff1[Threads.threadid()], t) < integrator.opts.internalnorm(diff2[Threads.threadid()], @@ -3455,8 +3444,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC return end end - @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()] - - u_temp4[Threads.threadid()] + @.. broadcast=false diff1[Threads.threadid()]=u_temp3[Threads.threadid()]- + u_temp4[Threads.threadid()] end end integrator.force_stepfail ? break : continue @@ -3484,8 +3473,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC for j in 2:(i + 1) @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, i] end - @.. broadcast=false integrator.u=extrapolation_scalars[i + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[i] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[i + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[i]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -3535,7 +3524,7 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC integrator.stats.nsolve += 1 @.. broadcast=false k=-k - @.. broadcast=false u_temp1=u_temp2 + k # Euler starting step + @.. broadcast=false u_temp1=u_temp2+k # Euler starting step for j in 2:(j_int + 1) f(k, cache.u_temp1, p, t + (j - 1) * dt_int) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -3547,9 +3536,9 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC cache.linsolve[1] = linres.cache integrator.stats.nsolve += 1 - @.. broadcast=false T[n_curr + 1]=u_temp1 - k # Explicit Midpoint rule + @.. broadcast=false T[n_curr + 1]=u_temp1-k # Explicit Midpoint rule if (j == j_int + 1) - @.. broadcast=false T[n_curr + 1]=0.25(T[n_curr + 1] + 2 * u_temp1 + + @.. broadcast=false T[n_curr + 1]=0.25(T[n_curr + 1]+2*u_temp1+ u_temp2) end @.. broadcast=false u_temp2=u_temp1 @@ -3570,8 +3559,8 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC @.. broadcast=false u_temp2+=cache.T[j] * extrapolation_weights_2[j - 1, n_curr] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 - @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr] * u_temp2 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 + @.. broadcast=false cache.utilde=extrapolation_scalars_2[n_curr]*u_temp2 calculate_residuals!(cache.res, integrator.u, cache.utilde, integrator.opts.abstol, integrator.opts.reltol, @@ -3590,7 +3579,7 @@ function perform_step!(integrator, cache::ImplicitEulerBarycentricExtrapolationC for j in 1:(n_curr + 1) @.. broadcast=false u_temp1+=cache.T[j] * extrapolation_weights[j, (n_curr + 1)] end - @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1] * u_temp1 + @.. broadcast=false integrator.u=extrapolation_scalars[n_curr + 1]*u_temp1 end f(cache.k, integrator.u, p, t + dt) # Update FSAL diff --git a/lib/OrdinaryDiffEqExtrapolation/test/jet.jl b/lib/OrdinaryDiffEqExtrapolation/test/jet.jl new file mode 100644 index 0000000000..31152862f7 --- /dev/null +++ b/lib/OrdinaryDiffEqExtrapolation/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqExtrapolation +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqExtrapolation, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqExtrapolation/test/ode_extrapolation_tests.jl b/lib/OrdinaryDiffEqExtrapolation/test/ode_extrapolation_tests.jl index 66a7404f8d..73841a2460 100644 --- a/lib/OrdinaryDiffEqExtrapolation/test/ode_extrapolation_tests.jl +++ b/lib/OrdinaryDiffEqExtrapolation/test/ode_extrapolation_tests.jl @@ -48,10 +48,13 @@ testTol = 0.2 AitkenNeville(max_order = 9, min_order = 1, init_order = 9, threading = false), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) sol = solve(prob, AitkenNeville(max_order = 9, min_order = 1, init_order = 9, threading = false), reltol = 1e-6) @test length(sol.u) < 18 + @test SciMLBase.successful_retcode(sol) end end end # AitkenNeville @@ -81,6 +84,7 @@ testTol = 0.2 init_order = 9, sequence = seq, threading = false), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) end end @@ -109,6 +113,7 @@ testTol = 0.2 threading = false), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) end end @@ -134,6 +139,7 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end @@ -158,6 +164,7 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end @@ -186,6 +193,7 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end end # ExtrapolationMidpointDeuflhard @@ -215,6 +223,7 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end end # ExtrapolationMidpointHairerWanner diff --git a/lib/OrdinaryDiffEqExtrapolation/test/qa.jl b/lib/OrdinaryDiffEqExtrapolation/test/qa.jl new file mode 100644 index 0000000000..b2f09dee0b --- /dev/null +++ b/lib/OrdinaryDiffEqExtrapolation/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqExtrapolation +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqExtrapolation + ) +end diff --git a/lib/OrdinaryDiffEqExtrapolation/test/runtests.jl b/lib/OrdinaryDiffEqExtrapolation/test/runtests.jl index 738c8013cc..69d2eff6d8 100644 --- a/lib/OrdinaryDiffEqExtrapolation/test/runtests.jl +++ b/lib/OrdinaryDiffEqExtrapolation/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "Extrapolation Tests" include("ode_extrapolation_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqFIRK/Project.toml b/lib/OrdinaryDiffEqFIRK/Project.toml index 2ffd2e2710..64249c963d 100644 --- a/lib/OrdinaryDiffEqFIRK/Project.toml +++ b/lib/OrdinaryDiffEqFIRK/Project.toml @@ -1,51 +1,73 @@ name = "OrdinaryDiffEqFIRK" uuid = "5960d6e9-dd7a-4743-88e7-cf307b64f125" authors = ["ParamThakkar123 "] -version = "1.1.1" +version = "1.16.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -GenericLinearAlgebra = "14197337-ba66-59df-a3e3-ca00e7dcff7a" -GenericSchur = "c145ed77-6b09-5dd9-b285-bf645a82121e" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" -OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" -Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +FastPower = "a4df4552-cc26-4903-aec0-212e50a0e84b" +OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -RootedTrees = "47965b36-3f3e-11e9-0dcf-4570dfd42a8c" SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" -Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -LinearSolve = "2.32.0" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqNonlinearSolve = "<0.0.1, 1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -SciMLOperators = "0.3.9" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +GenericSchur = "c145ed77-6b09-5dd9-b285-bf645a82121e" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +FastGaussQuadrature = "1.0.2" +MuladdMacro = "0.2" +LinearSolve = "3.26" +Polyester = "0.7" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +GenericSchur = "0.5" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +FastPower = "1.1" +ODEProblemLibrary = "0.1.8" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" +SciMLOperators = "1.4" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "GenericSchur", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqNonlinearSolve] +path = "../OrdinaryDiffEqNonlinearSolve" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqFIRK/src/OrdinaryDiffEqFIRK.jl b/lib/OrdinaryDiffEqFIRK/src/OrdinaryDiffEqFIRK.jl index 40305282d7..7ab3cffccf 100644 --- a/lib/OrdinaryDiffEqFIRK/src/OrdinaryDiffEqFIRK.jl +++ b/lib/OrdinaryDiffEqFIRK/src/OrdinaryDiffEqFIRK.jl @@ -6,8 +6,9 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, OrdinaryDiffEqAlgorithm, OrdinaryDiffEqNewtonAdaptiveAlgorithm, OrdinaryDiffEqMutableCache, OrdinaryDiffEqConstantCache, OrdinaryDiffEqAdaptiveAlgorithm, CompiledFloats, uses_uprev, - alg_cache, _vec, _reshape, @cache, isfsal, full_cache, - constvalue, _unwrap_val, + alg_cache, _vec, _reshape, @cache, @threaded, isthreaded, + PolyesterThreads, + isfsal, full_cache, constvalue, _unwrap_val, differentiation_rk_docstring, trivial_limiter!, _ode_interpolant!, _ode_addsteps!, AbstractController, qmax_default, alg_adaptive_order, DEFAULT_PRECS, @@ -16,24 +17,27 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, PredictiveController, alg_can_repeat_jac, NewtonAlgorithm, fac_default_gamma, get_current_adaptive_order, get_fsalfirstlast, - isfirk, generic_solver_docstring -using MuladdMacro, DiffEqBase, RecursiveArrayTools -using Polynomials, GenericLinearAlgebra, GenericSchur + isfirk, generic_solver_docstring, _bool_to_ADType, + _process_AD_choice, LinearAliasSpecifier +using MuladdMacro, DiffEqBase, RecursiveArrayTools, Polyester +isfirk, generic_solver_docstring using SciMLOperators: AbstractSciMLOperator using LinearAlgebra: I, UniformScaling, mul!, lu import LinearSolve import FastBroadcast: @.. import OrdinaryDiffEqCore - +import OrdinaryDiffEqCore: _ode_interpolant, _ode_interpolant!, has_stiff_interpolation +import FastPower: fastpower using OrdinaryDiffEqDifferentiation: UJacobianWrapper, build_J_W, build_jac_config, UDerivativeWrapper, calc_J!, dolinsolve, calc_J, islinearfunction using OrdinaryDiffEqNonlinearSolve: du_alias_or_new, Convergence, FastConvergence, NLStatus, VerySlowConvergence, Divergence, get_new_W_γdt_cutoff +import ADTypes: AutoForwardDiff, AbstractADType using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") @@ -41,6 +45,8 @@ include("controllers.jl") include("firk_caches.jl") include("firk_tableaus.jl") include("firk_perform_step.jl") +include("firk_interpolants.jl") +include("firk_addsteps.jl") include("integrator_interface.jl") export RadauIIA3, RadauIIA5, RadauIIA9, AdaptiveRadau diff --git a/lib/OrdinaryDiffEqFIRK/src/alg_utils.jl b/lib/OrdinaryDiffEqFIRK/src/alg_utils.jl index 428393e0bf..4d68b1142f 100644 --- a/lib/OrdinaryDiffEqFIRK/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqFIRK/src/alg_utils.jl @@ -1,9 +1,9 @@ -qmax_default(alg::Union{RadauIIA3, RadauIIA5, RadauIIA9}) = 8 +qmax_default(alg::Union{RadauIIA3, RadauIIA5, RadauIIA9, AdaptiveRadau}) = 8 alg_order(alg::RadauIIA3) = 3 alg_order(alg::RadauIIA5) = 5 alg_order(alg::RadauIIA9) = 9 -alg_order(alg::AdaptiveRadau) = 5 +alg_order(alg::AdaptiveRadau) = 5 #dummy value isfirk(alg::RadauIIA3) = true isfirk(alg::RadauIIA5) = true @@ -13,3 +13,10 @@ isfirk(alg::AdaptiveRadau) = true alg_adaptive_order(alg::RadauIIA3) = 1 alg_adaptive_order(alg::RadauIIA5) = 3 alg_adaptive_order(alg::RadauIIA9) = 5 + +get_current_alg_order(alg::AdaptiveRadau, cache) = cache.num_stages * 2 - 1 +get_current_adaptive_order(alg::AdaptiveRadau, cache) = cache.num_stages + +function has_stiff_interpolation(::Union{RadauIIA3, RadauIIA5, RadauIIA9, AdaptiveRadau}) + true +end diff --git a/lib/OrdinaryDiffEqFIRK/src/algorithms.jl b/lib/OrdinaryDiffEqFIRK/src/algorithms.jl index 25165422c8..9a06a5edd0 100644 --- a/lib/OrdinaryDiffEqFIRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqFIRK/src/algorithms.jl @@ -37,17 +37,20 @@ struct RadauIIA3{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter} <: new_W_γdt_cutoff::C2 controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function RadauIIA3(; chunk_size = Val{0}(), autodiff = Val{true}(), +function RadauIIA3(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, extrapolant = :dense, fast_convergence_cutoff = 1 // 5, new_W_γdt_cutoff = 1 // 5, controller = :Predictive, κ = nothing, maxiters = 10, step_limiter! = trivial_limiter!) - RadauIIA3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + RadauIIA3{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(fast_convergence_cutoff), typeof(new_W_γdt_cutoff), typeof(step_limiter!)}(linsolve, @@ -58,12 +61,12 @@ function RadauIIA3(; chunk_size = Val{0}(), autodiff = Val{true}(), fast_convergence_cutoff, new_W_γdt_cutoff, controller, - step_limiter!) + step_limiter!, + AD_choice) end @doc differentiation_rk_docstring( - "An A-B-L stable fully implicit Runge-Kutta method with internal tableau complex basis transform for efficiency. -Similar to Hairer's SEULEX.", + "An A-B-L stable fully implicit Runge-Kutta method with internal tableau complex basis transform for efficiency. 5th order method with excellent numerical stability. Good for highly stiff systems, problems requiring high-order implicit integration, systems with complex eigenvalue structures. Best for low tolerance stiff problems (<1e-9).", "RadauIIA5", "Fully-Implicit Runge-Kutta Method."; references = hairer1999stiff, @@ -81,17 +84,20 @@ struct RadauIIA5{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter} <: new_W_γdt_cutoff::C2 controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function RadauIIA5(; chunk_size = Val{0}(), autodiff = Val{true}(), +function RadauIIA5(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, extrapolant = :dense, fast_convergence_cutoff = 1 // 5, new_W_γdt_cutoff = 1 // 5, controller = :Predictive, κ = nothing, maxiters = 10, smooth_est = true, step_limiter! = trivial_limiter!) - RadauIIA5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + RadauIIA5{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(fast_convergence_cutoff), typeof(new_W_γdt_cutoff), typeof(step_limiter!)}(linsolve, @@ -103,7 +109,8 @@ function RadauIIA5(; chunk_size = Val{0}(), autodiff = Val{true}(), fast_convergence_cutoff, new_W_γdt_cutoff, controller, - step_limiter!) + step_limiter!, + AD_choice) end @doc differentiation_rk_docstring( @@ -126,17 +133,20 @@ struct RadauIIA9{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter} <: new_W_γdt_cutoff::C2 controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function RadauIIA9(; chunk_size = Val{0}(), autodiff = Val{true}(), +function RadauIIA9(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, extrapolant = :dense, fast_convergence_cutoff = 1 // 5, new_W_γdt_cutoff = 1 // 5, controller = :Predictive, κ = nothing, maxiters = 10, smooth_est = true, step_limiter! = trivial_limiter!) - RadauIIA9{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + RadauIIA9{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(fast_convergence_cutoff), typeof(new_W_γdt_cutoff), typeof(step_limiter!)}(linsolve, @@ -148,44 +158,50 @@ function RadauIIA9(; chunk_size = Val{0}(), autodiff = Val{true}(), fast_convergence_cutoff, new_W_γdt_cutoff, controller, - step_limiter!) + step_limiter!, + AD_choice) end -struct AdaptiveRadau{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter} <: - OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} - linsolve::F - precs::P - smooth_est::Bool - extrapolant::Symbol - κ::Tol - maxiters::Int - fast_convergence_cutoff::C1 - new_W_γdt_cutoff::C2 - controller::Symbol - step_limiter!::StepLimiter - num_stages::Int +struct AdaptiveRadau{CS, AD, F, P, FDT, ST, CJ, Tol, C1, C2, StepLimiter, TO} <: + OrdinaryDiffEqNewtonAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} + linsolve::F + precs::P + smooth_est::Bool + extrapolant::Symbol + κ::Tol + maxiters::Int + fast_convergence_cutoff::C1 + new_W_γdt_cutoff::C2 + controller::Symbol + step_limiter!::StepLimiter + min_order::Int + max_order::Int + threading::TO + autodiff::AD end -function AdaptiveRadau(; chunk_size = Val{0}(), autodiff = Val{true}(), - standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, num_stages = 3, - linsolve = nothing, precs = DEFAULT_PRECS, - extrapolant = :dense, fast_convergence_cutoff = 1 // 5, - new_W_γdt_cutoff = 1 // 5, - controller = :Predictive, κ = nothing, maxiters = 10, smooth_est = true, - step_limiter! = trivial_limiter!) - AdaptiveRadau{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), - typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), - typeof(κ), typeof(fast_convergence_cutoff), - typeof(new_W_γdt_cutoff), typeof(step_limiter!)}(linsolve, - precs, - smooth_est, - extrapolant, - κ, - maxiters, - fast_convergence_cutoff, - new_W_γdt_cutoff, - controller, - step_limiter!, num_stages) -end +function AdaptiveRadau(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), + standardtag = Val{true}(), concrete_jac = nothing, + diff_type = Val{:forward}(), min_order = 5, max_order = 13, threading = false, + linsolve = nothing, precs = DEFAULT_PRECS, + extrapolant = :dense, fast_convergence_cutoff = 1 // 5, + new_W_γdt_cutoff = 1 // 5, + controller = :Predictive, κ = nothing, maxiters = 10, smooth_est = true, + step_limiter! = trivial_limiter!) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + AdaptiveRadau{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), + typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), + typeof(κ), typeof(fast_convergence_cutoff), + typeof(new_W_γdt_cutoff), typeof(step_limiter!), typeof(threading)}(linsolve, + precs, + smooth_est, + extrapolant, + κ, + maxiters, + fast_convergence_cutoff, + new_W_γdt_cutoff, + controller, + step_limiter!, min_order, max_order, threading, + AD_choice) +end diff --git a/lib/OrdinaryDiffEqFIRK/src/controllers.jl b/lib/OrdinaryDiffEqFIRK/src/controllers.jl index df6cf153ab..f491a9e7d5 100644 --- a/lib/OrdinaryDiffEqFIRK/src/controllers.jl +++ b/lib/OrdinaryDiffEqFIRK/src/controllers.jl @@ -1,37 +1,15 @@ -@inline function stepsize_controller!(integrator, controller::PredictiveController, alg) - @unpack qmin, qmax, gamma = integrator.opts - EEst = DiffEqBase.value(integrator.EEst) - - if iszero(EEst) - q = inv(qmax) - else - if fac_default_gamma(alg) - fac = gamma - else - if isfirk(alg) - @unpack iter = integrator.cache - @unpack maxiters = alg - else - @unpack iter, maxiters = integrator.cache.nlsolver - end - fac = min(gamma, (1 + 2 * maxiters) * gamma / (iter + 2 * maxiters)) - end - expo = 1 / (get_current_adaptive_order(alg, integrator.cache) + 1) - qtmp = DiffEqBase.fastpow(EEst, expo) / fac - @fastmath q = DiffEqBase.value(max(inv(qmax), min(inv(qmin), qtmp))) - integrator.qold = q - end - q -end - -function step_accept_controller!(integrator, controller::PredictiveController, alg, q) +function step_accept_controller!( + integrator, controller::PredictiveController, alg::AdaptiveRadau, q) @unpack qmin, qmax, gamma, qsteady_min, qsteady_max = integrator.opts + @unpack cache = integrator + @unpack num_stages, step, iter, hist_iter, index = cache + EEst = DiffEqBase.value(integrator.EEst) if integrator.success_iter > 0 expo = 1 / (get_current_adaptive_order(alg, integrator.cache) + 1) qgus = (integrator.dtacc / integrator.dt) * - DiffEqBase.fastpow((EEst^2) / integrator.erracc, expo) + fastpow((EEst^2) / integrator.erracc, expo) qgus = max(inv(qmax), min(inv(qmin), qgus / gamma)) qacc = max(q, qgus) else @@ -42,10 +20,45 @@ function step_accept_controller!(integrator, controller::PredictiveController, a end integrator.dtacc = integrator.dt integrator.erracc = max(1e-2, EEst) + cache.step = step + 1 + hist_iter = hist_iter * 0.8 + iter * 0.2 + cache.hist_iter = hist_iter + max_stages = (alg.max_order - 1) ÷ 4 * 2 + 1 + min_stages = (alg.min_order - 1) ÷ 4 * 2 + 1 + if (step > 10) + if (hist_iter < 2.6 && num_stages < max_stages) + cache.num_stages += 2 + cache.index += 1 + cache.step = 1 + cache.hist_iter = iter + elseif ((hist_iter > 8 || cache.status == VerySlowConvergence || + cache.status == Divergence) && num_stages > min_stages) + cache.num_stages -= 2 + cache.index -= 1 + cache.step = 1 + cache.hist_iter = iter + end + end return integrator.dt / qacc end -function step_reject_controller!(integrator, controller::PredictiveController, alg) +function step_reject_controller!( + integrator, controller::PredictiveController, alg::AdaptiveRadau) @unpack dt, success_iter, qold = integrator + @unpack cache = integrator + @unpack num_stages, step, iter, hist_iter = cache integrator.dt = success_iter == 0 ? 0.1 * dt : dt / qold + cache.step = step + 1 + hist_iter = hist_iter * 0.8 + iter * 0.2 + cache.hist_iter = hist_iter + min_stages = (alg.min_order - 1) ÷ 4 * 2 + 1 + if (step > 10) + if ((hist_iter > 8 || cache.status == VerySlowConvergence || + cache.status == Divergence) && num_stages > min_stages) + cache.num_stages -= 2 + cache.index -= 1 + cache.step = 1 + cache.hist_iter = iter + end + end end diff --git a/lib/OrdinaryDiffEqFIRK/src/firk_addsteps.jl b/lib/OrdinaryDiffEqFIRK/src/firk_addsteps.jl new file mode 100644 index 0000000000..d376a45e88 --- /dev/null +++ b/lib/OrdinaryDiffEqFIRK/src/firk_addsteps.jl @@ -0,0 +1,1642 @@ +function _ode_addsteps!(integrator, cache::RadauIIA3ConstantCache) + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack T11, T12, T21, T22, TI11, TI12, TI21, TI22 = cache.tab + @unpack c1, c2, α, β, e1, e2 = cache.tab + @unpack κ, cont1, cont2 = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations + rtol = @. reltol^(3 / 4) / 10 + atol = @. rtol * (abstol / reltol) + αdt, βdt = α / dt, β / dt + J = calc_J(integrator, cache) + + c1m1 = c1 - 1 + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = zero(eltype(u)) + z1 = @.. uzero + z2 = @.. uzero + w1 = @.. uzero + w2 = @.. uzero + integrator.k[3] = uzero + integrator.k[4] = uzero + else + c2′ = dt / cache.dtprev + c1′ = c1 * c2′ + z1 = @.. c1′ * (k[3] + (c1′ - c1m1) * k[4]) + z2 = @.. c2′ * (k[3] + (c2′ - c1m1) * k[4]) + w1 = @.. TI11 * z1 + TI12 * z2 + w2 = @.. TI21 * z1 + TI22 * z2 + end + + if u isa Number + LU1 = -(αdt + βdt * im) * mass_matrix + J + else + LU1 = lu(-(αdt + βdt * im) * mass_matrix + J) + end + integrator.stats.nw += 1 + + # Newton iteration + local ndw, ff1, ff2 + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + # evaluate function + ff1 = f(uprev + z1, p, t + c1 * dt) + ff2 = f(uprev + z2, p, t + c2 * dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) + + fw1 = @. TI11 * ff1 + TI12 * ff2 + fw2 = @. TI21 * ff1 + TI22 * ff2 + + if mass_matrix isa UniformScaling + Mw1 = @. mass_matrix.λ * w1 + Mw2 = @. mass_matrix.λ * w2 + else + Mw1 = mass_matrix * w1 + Mw2 = mass_matrix * w2 + end + + rhs1 = @. fw1 - αdt * Mw1 + βdt * Mw2 + rhs2 = @. fw2 - βdt * Mw1 - αdt * Mw2 + dw12 = _reshape(LU1 \ _vec(@. rhs1 + rhs2 * im), axes(u)) + integrator.stats.nsolve += 1 + dw1 = real(dw12) + dw2 = imag(dw12) + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + atmp1 = calculate_residuals(dw1, uprev, u, atol, rtol, internalnorm, t) + atmp2 = calculate_residuals(dw2, uprev, u, atol, rtol, internalnorm, t) + ndw = internalnorm(atmp1, t) + internalnorm(atmp2, t) + + # check divergence (not in initial step) + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + w1 = @. w1 - dw1 + w2 = @. w2 - dw2 + + # transform `w` to `z` + z1 = @. T11 * w1 + T12 * w2 + z2 = @. T21 * w1 + T22 * w2 + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + + if integrator.EEst <= oneunit(integrator.EEst) + if alg.extrapolant != :constant + integrator.k[3] = (z1 - z2) / c1m1 + integrator.k[4] = integrator.k[3] - (z1 / c1) + end + end + + u = @. uprev + z2 + + integrator.fsallast = f(u, p, t + dt) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + integrator.u = u + return +end + +function _ode_addsteps!(integrator, cache::RadauIIA3Cache, repeat_step = false) + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst = integrator + @unpack T11, T12, T21, T22, TI11, TI12, TI21, TI22 = cache.tab + @unpack c1, c2, α, β, e1, e2 = cache.tab + @unpack κ = cache + @unpack z1, z2, w1, w2, + dw12, cubuff, + k, k2, fw1, fw2, + J, W1, + tmp, atmp, jac_config, rtol, atol, step_limiter! = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + # precalculations + αdt, βdt = α / dt, β / dt + new_jac = false + if (new_W = do_newW(integrator, alg, new_jac, cache.W_γdt)) + @inbounds for II in CartesianIndices(J) + W1[II] = -(αdt + βdt * im) * mass_matrix[Tuple(II)...] + J[II] + end + integrator.stats.nw += 1 + end + + c1m1 = c1 - 1 + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = zero(eltype(u)) + @.. z1=uzero + @.. z2=uzero + @.. w1=uzero + @.. w2=uzero + @.. integrator.k[3]=uzero + @.. integrator.k[4]=uzero + else + c2′ = dt / cache.dtprev + c1′ = c1 * c2′ + @.. z1=c1′ * (integrator.k[3] + (c1′ - c1m1) * integrator.k[4]) + @.. z2=c2′ * (integrator.k[3] + (c2′ - c1m1) * integrator.k[4]) + @.. w1=TI11 * z1 + TI12 * z2 + @.. w2=TI21 * z1 + TI22 * z2 + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + # evaluate function + @. tmp = uprev + z1 + f(fsallast, tmp, p, t + c1 * dt) + @. tmp = uprev + z2 + f(k2, tmp, p, t + c2 * dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) + + @. fw1 = TI11 * fsallast + TI12 * k2 + @. fw2 = TI21 * fsallast + TI22 * k2 + + if mass_matrix === I + Mw1 = w1 + Mw2 = w2 + elseif mass_matrix isa UniformScaling + mul!(z1, mass_matrix.λ, w1) + mul!(z2, mass_matrix.λ, w2) + Mw1 = z1 + Mw2 = z2 + else + mul!(z1, mass_matrix, w1) + mul!(z2, mass_matrix, w2) + Mw1 = z1 + Mw2 = z2 + end + + @. cubuff = complex(fw1 - αdt * Mw1 + βdt * Mw2, fw2 - βdt * Mw1 - αdt * Mw2) + needfactor = iter == 1 + + linsolve = cache.linsolve + + if needfactor + linres = dolinsolve(integrator, linsolve; A = W1, b = _vec(cubuff), + linu = _vec(dw12)) + else + linres = dolinsolve(integrator, linsolve; A = nothing, b = _vec(cubuff), + linu = _vec(dw12)) + end + + cache.linsolve = linres.cache + + integrator.stats.nsolve += 1 + dw1 = real(dw12) + dw2 = imag(dw12) + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + calculate_residuals!(atmp, dw1, uprev, u, atol, rtol, internalnorm, t) + ndw1 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw2, uprev, u, atol, rtol, internalnorm, t) + ndw2 = internalnorm(atmp, t) + ndw = ndw1 + ndw2 + + # check divergence (not in initial step) + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 2) && (cache.status = Divergence) + if diverge + break + end + end + + @. w1 = w1 - dw1 + @. w2 = w2 - dw2 + + # transform `w` to `z` + @. z1 = T11 * w1 + T12 * w2 + @. z2 = T21 * w1 + T22 * w2 + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + return + end + cache.ηold = η + cache.iter = iter + + @. u = uprev + z2 + step_limiter!(u, integrator, p, t + dt) + + if integrator.EEst <= oneunit(integrator.EEst) + cache.dtprev = dt + if alg.extrapolant != :constant + integrator.k[3] = (z1 - z2) / c1m1 + integrator.k[4] = integrator.k[3] - (z1 / c1) + end + end + + f(fsallast, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + return +end + +function _ode_addsteps!(integrator, cache::RadauIIA5ConstantCache, + repeat_step = false) + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack T11, T12, T13, T21, T22, T23, T31, TI11, TI12, TI13, + TI21, TI22, TI23, TI31, TI32, TI33 = cache.tab + @unpack c1, c2, γ, α, β, e1, e2, e3 = cache.tab + @unpack κ, cont1, cont2, cont3 = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations + rtol = @.. reltol^(2 / 3)/10 + atol = @.. rtol*(abstol / reltol) + c1m1 = c1 - 1 + c2m1 = c2 - 1 + c1mc2 = c1 - c2 + γdt, αdt, βdt = γ / dt, α / dt, β / dt + J = calc_J(integrator, cache) + if u isa Number + LU1 = -γdt * mass_matrix + J + LU2 = -(αdt + βdt * im) * mass_matrix + J + else + LU1 = lu(-γdt * mass_matrix + J) + LU2 = lu(-(αdt + βdt * im) * mass_matrix + J) + end + integrator.stats.nw += 1 + + # TODO better initial guess + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = map(zero, u) + z1 = @.. uzero + z2 = @.. uzero + z3 = @.. uzero + w1 = @.. uzero + w2 = @.. uzero + w3 = @.. uzero + integrator.k[3] = uzero + integrator.k[4] = uzero + integrator.k[5] = uzero + else + c3′ = dt / cache.dtprev + c1′ = c1 * c3′ + c2′ = c2 * c3′ + z1 = @.. c1′ * (k[3] + (c1′ - c2m1) * (k[4] + (c1′ - c1m1) * k[5])) + z2 = @.. c2′ * (k[3] + (c2′ - c2m1) * (k[4] + (c2′ - c1m1) * k[5])) + z3 = @.. c3′ * (k[3] + (c3′ - c2m1) * (k[4] + (c3′ - c1m1) * k[5])) + w1 = @.. TI11*z1+TI12*z2+TI13*z3 + w2 = @.. TI21*z1+TI22*z2+TI23*z3 + w3 = @.. TI31*z1+TI32*z2+TI33*z3 + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + + # evaluate function + ff1 = f(uprev + z1, p, t + c1 * dt) + ff2 = f(uprev + z2, p, t + c2 * dt) + ff3 = f(uprev + z3, p, t + dt) # c3 = 1 + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) + + fw1 = @.. TI11*ff1+TI12*ff2+TI13*ff3 + fw2 = @.. TI21*ff1+TI22*ff2+TI23*ff3 + fw3 = @.. TI31*ff1+TI32*ff2+TI33*ff3 + + if mass_matrix isa UniformScaling # `UniformScaling` doesn't play nicely with broadcast + Mw1 = @.. mass_matrix.λ*w1 + Mw2 = @.. mass_matrix.λ*w2 + Mw3 = @.. mass_matrix.λ*w3 + else + Mw1 = mass_matrix * w1 + Mw2 = mass_matrix * w2 + Mw3 = mass_matrix * w3 + end + + rhs1 = @.. fw1-γdt * Mw1 + rhs2 = @.. fw2 - αdt * Mw2+βdt * Mw3 + rhs3 = @.. fw3 - βdt * Mw2-αdt * Mw3 + dw1 = _reshape(LU1 \ _vec(rhs1), axes(u)) + dw23 = _reshape(LU2 \ _vec(@.. rhs2+rhs3 * im), axes(u)) + integrator.stats.nsolve += 2 + dw2 = real(dw23) + dw3 = imag(dw23) + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + atmp1 = calculate_residuals(dw1, uprev, u, atol, rtol, internalnorm, t) + atmp2 = calculate_residuals(dw2, uprev, u, atol, rtol, internalnorm, t) + atmp3 = calculate_residuals(dw3, uprev, u, atol, rtol, internalnorm, t) + ndw = internalnorm(atmp1, t) + internalnorm(atmp2, t) + internalnorm(atmp3, t) + # check divergence (not in initial step) + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + w1 = @.. w1-dw1 + w2 = @.. w2-dw2 + w3 = @.. w3-dw3 + + # transform `w` to `z` + z1 = @.. T11*w1+T12*w2+T13*w3 + z2 = @.. T21*w1+T22*w2+T23*w3 + z3 = @.. T31 * w1+w2 # T32 = 1, T33 = 0 + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + error("This shouldn't happen. Report a bug please.") + end + cache.ηold = η + cache.iter = iter + + u = @.. uprev+z3 + + if integrator.EEst <= oneunit(integrator.EEst) + if alg.extrapolant != :constant + integrator.k[3] = (z2 - z3)/c2m1 + tmp = @.. (z1 - z2)/c1mc2 + integrator.k[4] = (tmp - integrator.k[3])/c1m1 + integrator.k[5] = integrator.k[4]-(tmp - z1 / c1) / c2 + end + end + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + return +end + +function _ode_addsteps!(integrator, cache::RadauIIA5Cache, repeat_step = false) + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst, k = integrator + @unpack T11, T12, T13, T21, T22, T23, T31, TI11, TI12, TI13, + TI21, TI22, TI23, TI31, TI32, TI33 = cache.tab + @unpack c1, c2, γ, α, β, e1, e2, e3 = cache.tab + @unpack κ = cache + @unpack z1, z2, z3, w1, w2, w3, + dw1, ubuff, dw23, cubuff, + k, k2, k3, fw1, fw2, fw3, + J, W1, W2, + tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol, step_limiter! = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations + c1m1 = c1 - 1 + c2m1 = c2 - 1 + c1mc2 = c1 - c2 + γdt, αdt, βdt = γ / dt, α / dt, β / dt + new_jac = false + if (new_W = do_newW(integrator, alg, new_jac, cache.W_γdt)) + @inbounds for II in CartesianIndices(J) + W1[II] = -γdt * mass_matrix[Tuple(II)...] + J[II] + W2[II] = -(αdt + βdt * im) * mass_matrix[Tuple(II)...] + J[II] + end + integrator.stats.nw += 1 + end + + # TODO better initial guess + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = zero(eltype(u)) + @.. z1=uzero + @.. z2=uzero + @.. z3=uzero + @.. w1=uzero + @.. w2=uzero + @.. w3=uzero + @.. integrator.k[3] = uzero + @.. integrator.k[4] = uzero + @.. integrator.k[5] = uzero + else + c3′ = dt / cache.dtprev + c1′ = c1 * c3′ + c2′ = c2 * c3′ + @.. z1=c1′ * (integrator.k[3] + + (c1′ - c2m1) * (integrator.k[4] + (c1′ - c1m1) * integrator.k[5])) + @.. z1=c2′ * (integrator.k[3] + + (c2′ - c2m1) * (integrator.k[4] + (c2′ - c1m1) * integrator.k[5])) + @.. z1=c3′ * (integrator.k[3] + + (c3′ - c2m1) * (integrator.k[4] + (c3′ - c1m1) * integrator.k[5])) + @.. w1=TI11 * z1 + TI12 * z2 + TI13 * z3 + @.. w2=TI21 * z1 + TI22 * z2 + TI23 * z3 + @.. w3=TI31 * z1 + TI32 * z2 + TI33 * z3 + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + + # evaluate function + @.. tmp=uprev + z1 + f(fsallast, tmp, p, t + c1 * dt) + @.. tmp=uprev + z2 + f(k2, tmp, p, t + c2 * dt) + @.. tmp=uprev + z3 + f(k3, tmp, p, t + dt) # c3 = 1 + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) + + @.. fw1=TI11 * fsallast + TI12 * k2 + TI13 * k3 + @.. fw2=TI21 * fsallast + TI22 * k2 + TI23 * k3 + @.. fw3=TI31 * fsallast + TI32 * k2 + TI33 * k3 + + if mass_matrix === I + Mw1 = w1 + Mw2 = w2 + Mw3 = w3 + elseif mass_matrix isa UniformScaling + mul!(z1, mass_matrix.λ, w1) + mul!(z2, mass_matrix.λ, w2) + mul!(z3, mass_matrix.λ, w3) + Mw1 = z1 + Mw2 = z2 + Mw3 = z3 + else + mul!(z1, mass_matrix, w1) + mul!(z2, mass_matrix, w2) + mul!(z3, mass_matrix, w3) + Mw1 = z1 + Mw2 = z2 + Mw3 = z3 + end + + @.. ubuff=fw1 - γdt * Mw1 + needfactor = iter == 1 && new_W + + linsolve1 = cache.linsolve1 + + if needfactor + linres1 = dolinsolve(integrator, linsolve1; A = W1, b = _vec(ubuff), + linu = _vec(dw1)) + else + linres1 = dolinsolve(integrator, linsolve1; A = nothing, b = _vec(ubuff), + linu = _vec(dw1)) + end + + cache.linsolve1 = linres1.cache + + @.. cubuff=complex(fw2 - αdt * Mw2 + βdt * Mw3, + fw3 - βdt * Mw2 - αdt * Mw3) + + linsolve2 = cache.linsolve2 + + if needfactor + linres2 = dolinsolve(integrator, linsolve2; A = W2, b = _vec(cubuff), + linu = _vec(dw23)) + else + linres2 = dolinsolve(integrator, linsolve2; A = nothing, b = _vec(cubuff), + linu = _vec(dw23)) + end + + cache.linsolve2 = linres2.cache + + integrator.stats.nsolve += 2 + dw2 = z2 + dw3 = z3 + @.. dw2=real(dw23) + @.. dw3=imag(dw23) + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + calculate_residuals!(atmp, dw1, uprev, u, atol, rtol, internalnorm, t) + ndw1 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw2, uprev, u, atol, rtol, internalnorm, t) + ndw2 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw3, uprev, u, atol, rtol, internalnorm, t) + ndw3 = internalnorm(atmp, t) + ndw = ndw1 + ndw2 + ndw3 + + # check divergence (not in initial step) + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + @.. w1=w1 - dw1 + @.. w2=w2 - dw2 + @.. w3=w3 - dw3 + + # transform `w` to `z` + @.. z1=T11 * w1 + T12 * w2 + T13 * w3 + @.. z2=T21 * w1 + T22 * w2 + T23 * w3 + @.. z3=T31 * w1 + w2 # T32 = 1, T33 = 0 + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + return + end + cache.ηold = η + cache.iter = iter + + @.. u=uprev + z3 + step_limiter!(u, integrator, p, t + dt) + + if integrator.EEst <= oneunit(integrator.EEst) + cache.dtprev = dt + if alg.extrapolant != :constant + integrator.k[3] = (z2 - z3) / c2m1 + @.. tmp=(z1 - z2) / c1mc2 + integrator.k[4] = (tmp - integrator.k[3]) / c1m1 + integrator.k[5] = integrator.k[4] - (tmp - z1 / c1) / c2 + end + end + + f(fsallast, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + return +end + +function _ode_addsteps!(integrator, cache::RadauIIA9ConstantCache, + repeat_step = false) + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, + T33, T34, T35, T41, T42, T43, T44, T45, T51 = cache.tab#= T52 = 1, T53 = 0, T54 = 1, T55 = 0=# + @unpack TI11, + TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, + TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55 = cache.tab + @unpack c1, c2, c3, c4, γ, α1, β1, α2, β2, e1, e2, e3, e4, e5 = cache.tab + @unpack κ = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations rtol pow is (num stages + 1)/(2*num stages) + rtol = @.. reltol^(3 / 5)/10 + atol = @.. rtol*(abstol / reltol) + c1m1 = c1 - 1 + c2m1 = c2 - 1 + c3m1 = c3 - 1 + c4m1 = c4 - 1 + c1mc2 = c1 - c2 + c1mc3 = c1 - c3 + c1mc4 = c1 - c4 + c2mc3 = c2 - c3 + c2mc4 = c2 - c4 + c3mc4 = c3 - c4 + + γdt, α1dt, β1dt, α2dt, β2dt = γ / dt, α1 / dt, β1 / dt, α2 / dt, β2 / dt + J = calc_J(integrator, cache) + if u isa Number + LU1 = -γdt * mass_matrix + J + LU2 = -(α1dt + β1dt * im) * mass_matrix + J + LU3 = -(α2dt + β2dt * im) * mass_matrix + J + else + LU1 = lu(-γdt * mass_matrix + J) + LU2 = lu(-(α1dt + β1dt * im) * mass_matrix + J) + LU3 = lu(-(α2dt + β2dt * im) * mass_matrix + J) + end + integrator.stats.nw += 1 + + # TODO better initial guess + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + z1 = map(zero, u) + z2 = map(zero, u) + z3 = map(zero, u) + z4 = map(zero, u) + z5 = map(zero, u) + w1 = map(zero, u) + w2 = map(zero, u) + w3 = map(zero, u) + w4 = map(zero, u) + w5 = map(zero, u) + integrator.k[3] = map(zero, u) + integrator.k[4] = map(zero, u) + integrator.k[5] = map(zero, u) + integrator.k[6] = map(zero, u) + integrator.k[7] = map(zero, u) + else + c5′ = dt / cache.dtprev + c1′ = c1 * c5′ + c2′ = c2 * c5′ + c3′ = c3 * c5′ + c4′ = c4 * c5′ + z1 = @.. c1′ * (k[3] + + (c1′-c4m1) * (k[4] + + (c1′ - c3m1) * (k[5] + + (c1′ - c2m1) * (k[6] + (c1′ - c1m1) * k[7])))) + z2 = @.. c2′ * (k[3] + + (c2′-c4m1) * (k[4] + + (c2′ - c3m1) * (k[5] + + (c2′ - c2m1) * (k[6] + (c2′ - c1m1) * k[7])))) + z3 = @.. c3′ * (k[3] + + (c3′-c4m1) * (k[4] + + (c3′ - c3m1) * (k[5] + + (c3′ - c2m1) * (k[6] + (c3′ - c1m1) * k[7])))) + z4 = @.. c4′ * (k[3] + + (c4′-c4m1) * (k[4] + + (c4′ - c3m1) * (k[5] + + (c4′ - c2m1) * (k[6] + (c4′ - c1m1) * k[7])))) + z5 = @.. c5′ * (k[3] + + (c5′-c4m1) * (k[4] + + (c5′ - c3m1) * (k[5] + (c5′ - c2m1) * (k[6] + (c5′ - c1m1) * k[7])))) + w1 = @.. TI11*z1+TI12*z2+TI13*z3+TI14*z4+TI15*z5 + w2 = @.. TI21*z1+TI22*z2+TI23*z3+TI24*z4+TI25*z5 + w3 = @.. TI31*z1+TI32*z2+TI33*z3+TI34*z4+TI35*z5 + w4 = @.. TI41*z1+TI42*z2+TI43*z3+TI44*z4+TI45*z5 + w5 = @.. TI51*z1+TI52*z2+TI53*z3+TI54*z4+TI55*z5 + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + + # evaluate function + ff1 = f(uprev + z1, p, t + c1 * dt) + ff2 = f(uprev + z2, p, t + c2 * dt) + ff3 = f(uprev + z3, p, t + c3 * dt) + ff4 = f(uprev + z4, p, t + c4 * dt) + ff5 = f(uprev + z5, p, t + dt) # c5 = 1 + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) + + fw1 = @.. TI11*ff1+TI12*ff2+TI13*ff3+TI14*ff4+TI15*ff5 + fw2 = @.. TI21*ff1+TI22*ff2+TI23*ff3+TI24*ff4+TI25*ff5 + fw3 = @.. TI31*ff1+TI32*ff2+TI33*ff3+TI34*ff4+TI35*ff5 + fw4 = @.. TI41*ff1+TI42*ff2+TI43*ff3+TI44*ff4+TI45*ff5 + fw5 = @.. TI51*ff1+TI52*ff2+TI53*ff3+TI54*ff4+TI55*ff5 + + if mass_matrix isa UniformScaling # `UniformScaling` doesn't play nicely with broadcast + Mw1 = @.. mass_matrix.λ*w1 + Mw2 = @.. mass_matrix.λ*w2 + Mw3 = @.. mass_matrix.λ*w3 + Mw4 = @.. mass_matrix.λ*w4 + Mw5 = @.. mass_matrix.λ*w5 + else + Mw1 = mass_matrix * w1 + Mw2 = mass_matrix * w2 + Mw3 = mass_matrix * w3 + Mw4 = mass_matrix * w4 + Mw5 = mass_matrix * w5 + end + + rhs1 = @.. fw1-γdt * Mw1 + rhs2 = @.. fw2 - α1dt * Mw2+β1dt * Mw3 + rhs3 = @.. fw3 - β1dt * Mw2-α1dt * Mw3 + rhs4 = @.. fw4 - α2dt * Mw4+β2dt * Mw5 + rhs5 = @.. fw5 - β2dt * Mw4-α2dt * Mw5 + dw1 = _reshape(LU1 \ _vec(rhs1), axes(u)) + dw23 = _reshape(LU2 \ _vec(@.. rhs2+rhs3 * im), axes(u)) + dw45 = _reshape(LU3 \ _vec(@.. rhs4+rhs5 * im), axes(u)) + integrator.stats.nsolve += 3 + dw2 = real(dw23) + dw3 = imag(dw23) + dw4 = real(dw45) + dw5 = imag(dw45) + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + atmp1 = calculate_residuals(dw1, uprev, u, atol, rtol, internalnorm, t) + atmp2 = calculate_residuals(dw2, uprev, u, atol, rtol, internalnorm, t) + atmp3 = calculate_residuals(dw3, uprev, u, atol, rtol, internalnorm, t) + atmp4 = calculate_residuals(dw4, uprev, u, atol, rtol, internalnorm, t) + atmp5 = calculate_residuals(dw5, uprev, u, atol, rtol, internalnorm, t) + ndw = internalnorm(atmp1, t) + internalnorm(atmp2, t) + internalnorm(atmp3, t) + + internalnorm(atmp4, t) + internalnorm(atmp5, t) + + # check divergence (not in initial step) + + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + w1 = @.. w1-dw1 + w2 = @.. w2-dw2 + w3 = @.. w3-dw3 + w4 = @.. w4-dw4 + w5 = @.. w5-dw5 + + # transform `w` to `z` + z1 = @.. T11*w1+T12*w2+T13*w3+T14*w4+T15*w5 + z2 = @.. T21*w1+T22*w2+T23*w3+T24*w4+T25*w5 + z3 = @.. T31*w1+T32*w2+T33*w3+T34*w4+T35*w5 + z4 = @.. T41*w1+T42*w2+T43*w3+T44*w4+T45*w5 + z5 = @.. T51*w1+w2+w4#= T52=1, T53=0, T54=1, T55=0 =# + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + return + end + #cache.ηold = η + #cache.iter = iter + + u = @.. uprev+z5 + + if integrator.EEst <= oneunit(integrator.EEst) + #cache.dtprev = dt + if alg.extrapolant != :constant + integrator.k[3] = (z4 - z5) / c4m1 # first derivative on [c4, 1] + tmp1 = @.. (z3 - z4) / c3mc4 # first derivative on [c3, c4] + integrator.k[4] = (tmp1 - integrator.k[3]) / c3m1 # second derivative on [c3, 1] + tmp2 = @.. (z2 - z3) / c2mc3 # first derivative on [c2, c3] + tmp3 = @.. (tmp2 - tmp1) / c2mc4 # second derivative on [c2, c4] + integrator.k[5] = (tmp3 - integrator.k[4]) / c2m1 # third derivative on [c2, 1] + tmp4 = @.. (z1 - z2) / c1mc2 # first derivative on [c1, c2] + tmp5 = @.. (tmp4 - tmp2) / c1mc3 # second derivative on [c1, c3] + tmp6 = @.. (tmp5 - tmp3) / c1mc4 # third derivative on [c1, c4] + integrator.k[6] = (tmp6 - integrator.k[5]) / c1m1 #fourth derivative on [c1, 1] + tmp7 = @.. z1 / c1 #first derivative on [0, c1] + tmp8 = @.. (tmp4 - tmp7) / c2 #second derivative on [0, c2] + tmp9 = @.. (tmp5 - tmp8) / c3 #third derivative on [0, c3] + tmp10 = @.. (tmp6 - tmp9) / c4 #fourth derivative on [0,c4] + integrator.k[7] = integrator.k[6] - tmp10 #fifth derivative on [0,1] + end + end + + integrator.fsallast = f(u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + integrator.u = u + return +end + +function _ode_addsteps!(integrator, cache::RadauIIA9Cache, repeat_step = false) + @unpack t, dt, uprev, u, f, p, fsallast, fslafirst, k = integrator + @unpack T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, + T33, T34, T35, T41, T42, T43, T44, T45, T51 = cache.tab#= T52 = 1, T53 = 0, T54 = 1, T55 = 0=# + @unpack TI11, + TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, + TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55 = cache.tab + @unpack c1, c2, c3, c4, γ, α1, β1, α2, β2, e1, e2, e3, e4, e5 = cache.tab + @unpack κ = cache + @unpack z1, z2, z3, z4, z5, w1, w2, w3, w4, w5 = cache + @unpack dw1, ubuff, dw23, dw45, cubuff1, cubuff2 = cache + @unpack k, k2, k3, k4, k5, fw1, fw2, fw3, fw4, fw5 = cache + @unpack J, W1, W2, W3 = cache + @unpack tmp, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, atmp, jac_config, + linsolve1, linsolve2, linsolve3, rtol, atol, step_limiter! = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations + c1m1 = c1 - 1 + c2m1 = c2 - 1 + c3m1 = c3 - 1 + c4m1 = c4 - 1 + c1mc2 = c1 - c2 + c1mc3 = c1 - c3 + c1mc4 = c1 - c4 + c2mc3 = c2 - c3 + c2mc4 = c2 - c4 + c3mc4 = c3 - c4 + + γdt, α1dt, β1dt, α2dt, β2dt = γ / dt, α1 / dt, β1 / dt, α2 / dt, β2 / dt + new_jac = false + if (new_W = do_newW(integrator, alg, new_jac, cache.W_γdt)) + @inbounds for II in CartesianIndices(J) + W1[II] = -γdt * mass_matrix[Tuple(II)...] + J[II] + W2[II] = -(α1dt + β1dt * im) * mass_matrix[Tuple(II)...] + J[II] + W3[II] = -(α2dt + β2dt * im) * mass_matrix[Tuple(II)...] + J[II] + end + integrator.stats.nw += 1 + end + + # TODO better initial guess + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = zero(eltype(u)) + @.. z1=uzero + @.. z2=uzero + @.. z3=uzero + @.. z4=uzero + @.. z5=uzero + @.. w1=uzero + @.. w2=uzero + @.. w3=uzero + @.. w4=uzero + @.. w5=uzero + @.. integrator.k[3]=uzero + @.. integrator.k[4]=uzero + @.. integrator.k[5]=uzero + @.. integrator.k[6]=uzero + @.. integrator.k[7]=uzero + else + c5′ = dt / cache.dtprev + c1′ = c1 * c5′ + c2′ = c2 * c5′ + c3′ = c3 * c5′ + c4′ = c4 * c5′ + @.. z1 = c1′ * (integrator.k[3] + + (c1′-c4m1) * (integrator.k[4] + + (c1′ - c3m1) * (integrator.k[5] + + (c1′ - c2m1) * (integrator.k[6] + (c1′ - c1m1) * integrator.k[7])))) + @.. z2 = c2′ * (integrator.k[3] + + (c2′-c4m1) * (integrator.k[4] + + (c2′ - c3m1) * (integrator.k[5] + + (c2′ - c2m1) * (integrator.k[6] + (c2′ - c1m1) * integrator.k[7])))) + @.. z3 = c3′ * (integrator.k[3] + + (c3′-c4m1) * (integrator.k[4] + + (c3′ - c3m1) * (integrator.k[5] + + (c3′ - c2m1) * (integrator.k[6] + (c3′ - c1m1) * integrator.k[7])))) + @.. z4 = c4′ * (integrator.k[3] + + (c4′-c4m1) * (integrator.k[4] + + (c4′ - c3m1) * (integrator.k[5] + + (c4′ - c2m1) * (integrator.k[6] + (c4′ - c1m1) * integrator.k[7])))) + @.. z5 = c5′ * (integrator.k[3] + + (c5′-c4m1) * (integrator.k[4] + + (c5′ - c3m1) * (integrator.k[5] + + (c5′ - c2m1) * (integrator.k[6] + (c5′ - c1m1) * integrator.k[7])))) + @.. w1 = TI11*z1+TI12*z2+TI13*z3+TI14*z4+TI15*z5 + @.. w2 = TI21*z1+TI22*z2+TI23*z3+TI24*z4+TI25*z5 + @.. w3 = TI31*z1+TI32*z2+TI33*z3+TI34*z4+TI35*z5 + @.. w4 = TI41*z1+TI42*z2+TI43*z3+TI44*z4+TI45*z5 + @.. w5 = TI51*z1+TI52*z2+TI53*z3+TI54*z4+TI55*z5 + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + + # evaluate function + @.. tmp=uprev + z1 + f(fsallast, tmp, p, t + c1 * dt) + @.. tmp=uprev + z2 + f(k2, tmp, p, t + c2 * dt) + @.. tmp=uprev + z3 + f(k3, tmp, p, t + c3 * dt) + @.. tmp=uprev + z4 + f(k4, tmp, p, t + c4 * dt) + @.. tmp=uprev + z5 + f(k5, tmp, p, t + dt) # c5 = 1 + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) + + @.. fw1=TI11 * fsallast + TI12 * k2 + TI13 * k3 + TI14 * k4 + + TI15 * k5 + @.. fw2=TI21 * fsallast + TI22 * k2 + TI23 * k3 + TI24 * k4 + + TI25 * k5 + @.. fw3=TI31 * fsallast + TI32 * k2 + TI33 * k3 + TI34 * k4 + + TI35 * k5 + @.. fw4=TI41 * fsallast + TI42 * k2 + TI43 * k3 + TI44 * k4 + + TI45 * k5 + @.. fw5=TI51 * fsallast + TI52 * k2 + TI53 * k3 + TI54 * k4 + + TI55 * k5 + + if mass_matrix === I + Mw1 = w1 + Mw2 = w2 + Mw3 = w3 + Mw4 = w4 + Mw5 = w5 + elseif mass_matrix isa UniformScaling + mul!(z1, mass_matrix.λ, w1) + mul!(z2, mass_matrix.λ, w2) + mul!(z3, mass_matrix.λ, w3) + mul!(z4, mass_matrix.λ, w4) + mul!(z5, mass_matrix.λ, w5) + Mw1 = z1 + Mw2 = z2 + Mw3 = z3 + Mw4 = z4 + Mw5 = z5 + else + mul!(z1, mass_matrix, w1) + mul!(z2, mass_matrix, w2) + mul!(z3, mass_matrix, w3) + mul!(z4, mass_matrix, w4) + mul!(z5, mass_matrix, w5) + Mw1 = z1 + Mw2 = z2 + Mw3 = z3 + Mw4 = z4 + Mw5 = z5 + end + + @.. ubuff=fw1 - γdt * Mw1 + needfactor = iter == 1 && new_W + + linsolve1 = cache.linsolve1 + + if needfactor + linres1 = dolinsolve( + integrator, linsolve1; A = W1, b = _vec(ubuff), linu = _vec(dw1)) + else + linres1 = dolinsolve( + integrator, linsolve1; A = nothing, b = _vec(ubuff), linu = _vec(dw1)) + end + + cache.linsolve1 = linres1.cache + + @.. cubuff1=complex( + fw2 - α1dt * Mw2 + β1dt * Mw3, fw3 - β1dt * Mw2 - α1dt * Mw3) + + linsolve2 = cache.linsolve2 + + if needfactor + linres2 = dolinsolve( + integrator, linsolve2; A = W2, b = _vec(cubuff1), linu = _vec(dw23)) + else + linres2 = dolinsolve( + integrator, linsolve2; A = nothing, b = _vec(cubuff1), linu = _vec(dw23)) + end + + cache.linsolve2 = linres2.cache + + @.. cubuff2=complex( + fw4 - α2dt * Mw4 + β2dt * Mw5, fw5 - β2dt * Mw4 - α2dt * Mw5) + + linsolve3 = cache.linsolve3 + + if needfactor + linres3 = dolinsolve( + integrator, linsolve3; A = W3, b = _vec(cubuff2), linu = _vec(dw45)) + else + linres3 = dolinsolve( + integrator, linsolve3; A = nothing, b = _vec(cubuff2), linu = _vec(dw45)) + end + + cache.linsolve3 = linres3.cache + integrator.stats.nsolve += 3 + dw2 = z2 + dw3 = z3 + @.. dw2=real(dw23) + @.. dw3=imag(dw23) + dw4 = z4 + dw5 = z5 + @.. dw4=real(dw45) + @.. dw5=imag(dw45) + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + calculate_residuals!(atmp, dw1, uprev, u, atol, rtol, internalnorm, t) + ndw1 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw2, uprev, u, atol, rtol, internalnorm, t) + ndw2 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw3, uprev, u, atol, rtol, internalnorm, t) + ndw3 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw4, uprev, u, atol, rtol, internalnorm, t) + ndw4 = internalnorm(atmp, t) + calculate_residuals!(atmp, dw5, uprev, u, atol, rtol, internalnorm, t) + ndw5 = internalnorm(atmp, t) + ndw = ndw1 + ndw2 + ndw3 + ndw4 + ndw5 + + # check divergence (not in initial step) + + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + @.. w1=w1 - dw1 + @.. w2=w2 - dw2 + @.. w3=w3 - dw3 + @.. w4=w4 - dw4 + @.. w5=w5 - dw5 + + # transform `w` to `z` + @.. z1=T11 * w1 + T12 * w2 + T13 * w3 + T14 * w4 + T15 * w5 + @.. z2=T21 * w1 + T22 * w2 + T23 * w3 + T24 * w4 + T25 * w5 + @.. z3=T31 * w1 + T32 * w2 + T33 * w3 + T34 * w4 + T35 * w5 + @.. z4=T41 * w1 + T42 * w2 + T43 * w3 + T44 * w4 + T45 * w5 + @.. z5=T51 * w1 + w2 + w4#= T52=1, T53=0, T54=1, T55=0 =# + + # check stopping criterion + + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + return + end + + cache.ηold = η + cache.iter = iter + + @.. u=uprev + z5 + + step_limiter!(u, integrator, p, t + dt) + + if alg.extrapolant != :constant + integrator.k[3] = (z4 - z5) / c4m1 # first derivative on [c4, 1] + @.. tmp = (z3 - z4) / c3mc4 # first derivative on [c3, c4] + integrator.k[4] = (tmp - integrator.k[3]) / c3m1 # second derivative on [c3, 1] + @.. tmp2 = (z2 - z3) / c2mc3 # first derivative on [c2, c3] + @.. tmp3 = (tmp2 - tmp) / c2mc4 # second derivative on [c2, c4] + integrator.k[5] = (tmp3 - integrator.k[4]) / c2m1 # third derivative on [c2, 1] + @.. tmp4 = (z1 - z2) / c1mc2 # first derivative on [c1, c2] + @.. tmp5 = (tmp4 - tmp2) / c1mc3 # second derivative on [c1, c3] + @.. tmp6 = (tmp5 - tmp3) / c1mc4 # third derivative on [c1, c4] + integrator.k[6] = (tmp6 - integrator.k[5]) / c1m1 #fourth derivative on [c1, 1] + @.. tmp7 = z1 / c1 #first derivative on [0, c1] + @.. tmp8 = (tmp4 - tmp7) / c2 #second derivative on [0, c2] + @.. tmp9 = (tmp5 - tmp8) / c3 #third derivative on [0, c3] + @.. tmp10 = (tmp6 - tmp9) / c4 #fourth derivative on [0,c4] + integrator.k[7] = integrator.k[6] - tmp10 #fifth derivative on [0,1] + end + + f(fsallast, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + return +end + +function _ode_addstep!(integrator, cache::AdaptiveRadauConstantCache, repeat_step = false) + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack tabs, num_stages, index = cache + tab = tabs[index] + @unpack T, TI, γ, α, β, c, e = tab + @unpack κ = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations rtol pow is (num stages + 1)/(2*num stages) + rtol = @.. reltol^((num_stages + 1) / (num_stages * 2))/10 + atol = @.. rtol*(abstol / reltol) + + γdt, αdt, βdt = γ / dt, α ./ dt, β ./ dt + J = calc_J(integrator, cache) + + if u isa Number + LU1 = -γdt * mass_matrix + J + tmp = -(αdt[1] + βdt[1] * im) * mass_matrix + J + else + LU1 = lu(-γdt * mass_matrix + J) + tmp = lu(-(αdt[1] + βdt[1] * im) * mass_matrix + J) + end + LU2 = Vector{typeof(tmp)}(undef, (num_stages - 1) ÷ 2) + LU2[1] = tmp + if u isa Number + for i in 2:((num_stages - 1) ÷ 2) + LU2[i] = -(αdt[i] + βdt[i] * im) * mass_matrix + J + end + else + for i in 2:((num_stages - 1) ÷ 2) + LU2[i] = lu(-(αdt[i] + βdt[i] * im) * mass_matrix + J) + end + end + + integrator.stats.nw += 1 + z = Vector{typeof(u)}(undef, num_stages) + w = Vector{typeof(u)}(undef, num_stages) + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + for i in 1:num_stages + z[i] = @.. map(zero, u) + w[i] = @.. map(zero, u) + integrator.k[i + 2] = map(zero, u) + end + else + c_prime = Vector{typeof(dt)}(undef, num_stages) #time stepping + c_prime[num_stages] = dt / cache.dtprev + for i in 1:(num_stages - 1) + c_prime[i] = c[i] * c_prime[num_stages] + end + for i in 1:num_stages # collocation polynomial + z[i] = @.. k[num_stages + 1] + k[num_stages + 2] * (c_prime[i] - c[1] + 1) + j = num_stages - 2 + while j > 0 + z[i] = @.. k[j + 2] + z[i] * (c_prime[i] - c[num_stages - j] + 1) + j = j - 1 + end + z[i] = @.. z[i] * c_prime[i] + end + #w = TI*z + for i in 1:num_stages + w[i] = @.. zero(u) + for j in 1:num_stages + w[i] = @.. w[i] + TI[i, j] * z[j] + end + end + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + + # evaluate function + #ff = Vector{typeof(u)}(undef, num_stages) + for i in 1:num_stages + z[i] = f(uprev + z[i], p, t + c[i] * dt) + end + OrdinaryDiffEqCore.increment_nf!(integrator.stats, num_stages) + + #fw = TI * ff + fw = Vector{typeof(u)}(undef, num_stages) + for i in 1:num_stages + fw[i] = @.. zero(u) + for j in 1:num_stages + fw[i] = @.. fw[i] + TI[i, j] * z[j] + end + end + + #Mw = Vector{typeof(u)}(undef, num_stages) + if mass_matrix isa UniformScaling # `UniformScaling` doesn't play nicely with broadcast + for i in 1:num_stages + z[i] = @.. mass_matrix.λ * w[i] #scaling by eigenvalue + end + else + z = mass_matrix * w #standard multiplication + end + + rhs = Vector{typeof(u)}(undef, num_stages) + rhs[1] = @.. fw[1] - γdt * z[1] + i = 2 + while i <= num_stages #block by block multiplication + rhs[i] = @.. fw[i] - αdt[i ÷ 2] * z[i] + βdt[i ÷ 2] * z[i + 1] + rhs[i + 1] = @.. fw[i + 1] - βdt[i ÷ 2] * z[i] - αdt[i ÷ 2] * z[i + 1] + i += 2 + end + + #dw = Vector{typeof(u)}(undef, num_stages) + z[1] = _reshape(LU1 \ _vec(rhs[1]), axes(u)) + for i in 2:((num_stages + 1) ÷ 2) + tmp = _reshape(LU2[i - 1] \ _vec(@.. rhs[2 * i - 2] + rhs[2 * i - 1] * im), axes(u)) + z[2 * i - 2] = @.. real(tmp) + z[2 * i - 1] = @.. imag(tmp) + end + integrator.stats.nsolve += (num_stages + 1) ÷ 2 + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + ndw = 0.0 + for i in 1:num_stages + ndw += internalnorm( + calculate_residuals( + z[i], uprev, u, atol, rtol, internalnorm, t), t) + end + + # check divergence (not in initial step) + + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + for i in 1:num_stages + w[i] = @.. w[i] - z[i] + end + + # transform `w` to `z` + #z = T * w + for i in 1:(num_stages - 1) + z[i] = @.. zero(u) + for j in 1:num_stages + z[i] = @.. z[i] + T[i, j] * w[j] + end + end + z[num_stages] = @.. T[num_stages, 1] * w[1] + i = 2 + while i < num_stages + z[num_stages] = @.. z[num_stages] + w[i] + i += 2 + end + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + return + end + cache.ηold = η + cache.iter = iter + + u = @.. uprev + z[num_stages] + + if integrator.EEst <= oneunit(integrator.EEst) + cache.dtprev = dt + if alg.extrapolant != :constant + derivatives = Matrix{typeof(u)}(undef, num_stages, num_stages) + derivatives[1, 1] = @.. z[1] / c[1] + for j in 2:num_stages + derivatives[1, j] = @.. (z[j - 1] - z[j]) / (c[j - 1] - c[j]) #first derivatives + end + for i in 2:num_stages + derivatives[i, i] = @.. (derivatives[i - 1, i] - + derivatives[i - 1, i - 1]) / c[i] + for j in (i + 1):num_stages + derivatives[i, j] = @.. (derivatives[i - 1, j - 1] - + derivatives[i - 1, j]) / (c[j - i] - c[j]) #all others + end + end + for i in 1:num_stages + integrator.k[i + 2] = @.. derivatives[i, num_stages] + end + end + end + + integrator.fsallast = f(u, p, t + dt) + integrator.stats.nf += 1 + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + integrator.u = u + return +end + +function _ode_addsteps!(integrator, cache::AdaptiveRadauCache, repeat_step = false) + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst, k = integrator + @unpack num_stages, tabs, index = cache + tab = tabs[index] + @unpack T, TI, γ, α, β, c, e = tab + @unpack κ, derivatives, z, w, c_prime, αdt, βdt = cache + @unpack dw1, ubuff, dw2, cubuff, dw = cache + @unpack ks, k, fw, J, W1, W2 = cache + @unpack tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol, step_limiter! = cache + @unpack internalnorm, abstol, reltol, adaptive = integrator.opts + alg = unwrap_alg(integrator, true) + @unpack maxiters = alg + mass_matrix = integrator.f.mass_matrix + + # precalculations + γdt = γ / dt + for i in 1:((num_stages - 1) ÷ 2) + αdt[i] = α[i]/dt + βdt[i] = β[i]/dt + end + + if integrator.opts.adaptive + @unpack abstol, reltol = integrator.opts + if reltol isa Number + cache.rtol = reltol^((num_stages + 1) / (2 * num_stages)) / 10 + cache.atol = cache.rtol * (abstol / reltol) + else + @.. cache.rtol=reltol^((num_stages + 1) / (2 * num_stages)) / 10 + @.. cache.atol=cache.rtol * (abstol / reltol) + end + end + + #no new J + new_jac = false + if (new_W = do_newW(integrator, alg, new_jac, cache.W_γdt)) + @inbounds for II in CartesianIndices(J) + W1[II] = -γdt * mass_matrix[Tuple(II)...] + J[II] + end + if !isthreaded(alg.threading) + @inbounds for II in CartesianIndices(J) + for i in 1:((num_stages - 1) ÷ 2) + W2[i][II] = -(αdt[i] + βdt[i] * im) * mass_matrix[Tuple(II)...] + J[II] + end + end + else + let W1 = W1, W2 = W2, γdt = γdt, αdt = αdt, βdt = βdt, + mass_matrix = mass_matrix, num_stages = num_stages, J = J + + @inbounds @threaded alg.threading for i in 1:((num_stages - 1) ÷ 2) + for II in CartesianIndices(J) + W2[i][II] = -(αdt[i] + βdt[i] * im) * mass_matrix[Tuple(II)...] + + J[II] + end + end + end + end + integrator.stats.nw += 1 + end + + # TODO better initial guess + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + for i in 1:num_stages + @.. z[i] = map(zero, u) + @.. w[i] = map(zero, u) + integrator.k[i + 2] = map(zero, u) + end + else + c_prime[num_stages] = dt + for i in 1:(num_stages - 1) + c_prime[i] = c[i] * c_prime[num_stages] + end + for i in 1:num_stages # collocation polynomial + @.. z[i] = k[num_stages + 2] * (c_prime[i] - c[1] + 1) + k[num_stages + 1] + j = num_stages - 2 + while j > 0 + @.. z[i] *= (c_prime[i] - c[num_stages - j] + 1) + @.. z[i] += k[j + 2] + j = j - 1 + end + @.. z[i] *= c_prime[i] + end + #mul!(w, TI, z) + for i in 1:num_stages + @.. w[i] = zero(u) + for j in 1:num_stages + @.. w[i] += TI[i, j] * z[j] + end + end + end + + # Newton iteration + local ndw + η = max(cache.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) + fail_convergence = true + iter = 0 + while iter < maxiters + iter += 1 + integrator.stats.nnonliniter += 1 + + # evaluate function + ks[1] = fsallast + for i in 1:num_stages + @.. tmp = uprev + z[i] + f(ks[i], tmp, p, t + c[i] * dt) + end + OrdinaryDiffEqCore.increment_nf!(integrator.stats, num_stages) + + #mul!(fw, TI, ks) + for i in 1:num_stages + @.. fw[i] = zero(u) + for j in 1:num_stages + @.. fw[i] += TI[i, j] * ks[j] + end + end + + if mass_matrix === I + Mw = w + elseif mass_matrix isa UniformScaling + for i in 1:num_stages + mul!(z[i], mass_matrix.λ, w[i]) + end + Mw = z + else + for i in 1:num_stages + mul!(z[i], mass_matrix, w[i]) + end + Mw = z + end + + @.. ubuff = fw[1] - γdt * Mw[1] + needfactor = iter == 1 && new_W + + if needfactor + cache.linsolve1 = dolinsolve( + integrator, linsolve1; A = W1, b = _vec(ubuff), linu = _vec(dw1)).cache + else + cache.linsolve1 = dolinsolve( + integrator, linsolve1; A = nothing, b = _vec(ubuff), linu = _vec(dw1)).cache + end + + if !isthreaded(alg.threading) + for i in 1:((num_stages - 1) ÷ 2) + @.. cubuff[i]=complex( + fw[2 * i] - αdt[i] * Mw[2 * i] + βdt[i] * Mw[2 * i + 1], + fw[2 * i + 1] - βdt[i] * Mw[2 * i] - αdt[i] * Mw[2 * i + 1]) + if needfactor + cache.linsolve2[i] = dolinsolve(integrator, linsolve2[i]; A = W2[i], + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + else + cache.linsolve2[i] = dolinsolve(integrator, linsolve2[i]; A = nothing, + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + end + end + else + let integrator = integrator, linsolve2 = linsolve2, fw = fw, αdt = αdt, + βdt = βdt, Mw = Mw, W1 = W1, W2 = W2, cubuff = cubuff, dw2 = dw2, + needfactor = needfactor + + @threaded alg.threading for i in 1:((num_stages - 1) ÷ 2) + @.. cubuff[i]=complex( + fw[2 * i] - αdt[i] * Mw[2 * i] + βdt[i] * Mw[2 * i + 1], + fw[2 * i + 1] - βdt[i] * Mw[2 * i] - αdt[i] * Mw[2 * i + 1]) + if needfactor + cache.linsolve2[i] = dolinsolve( + integrator, linsolve2[i]; A = W2[i], + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + else + cache.linsolve2[i] = dolinsolve( + integrator, linsolve2[i]; A = nothing, + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + end + end + end + end + + integrator.stats.nsolve += (num_stages + 1) / 2 + + for i in 1:((num_stages - 1) ÷ 2) + @.. dw[2 * i - 1] = real(dw2[i]) + @.. dw[2 * i] = imag(dw2[i]) + end + + # compute norm of residuals + iter > 1 && (ndwprev = ndw) + calculate_residuals!(atmp, dw1, uprev, u, atol, rtol, internalnorm, t) + ndw = internalnorm(atmp, t) + for i in 2:num_stages + calculate_residuals!(atmp, dw[i - 1], uprev, u, atol, rtol, internalnorm, t) + ndw += internalnorm(atmp, t) + end + + # check divergence (not in initial step) + + if iter > 1 + θ = ndw / ndwprev + (diverge = θ > 1) && (cache.status = Divergence) + (veryslowconvergence = ndw * θ^(maxiters - iter) > κ * (1 - θ)) && + (cache.status = VerySlowConvergence) + if diverge || veryslowconvergence + break + end + end + + @.. w[1] = w[1] - dw1 + for i in 2:num_stages + @.. w[i] = w[i] - dw[i - 1] + end + + # transform `w` to `z` + #mul!(z, T, w) + for i in 1:(num_stages - 1) + @.. z[i] = zero(u) + for j in 1:num_stages + @.. z[i] += T[i, j] * w[j] + end + end + @.. z[num_stages] = T[num_stages, 1] * w[1] + i = 2 + while i < num_stages + @.. z[num_stages] += w[i] + i += 2 + end + + # check stopping criterion + iter > 1 && (η = θ / (1 - θ)) + if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) + # Newton method converges + cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : + Convergence + fail_convergence = false + break + end + end + if fail_convergence + integrator.force_stepfail = true + integrator.stats.nnonlinconvfail += 1 + return + end + + cache.ηold = η + cache.iter = iter + + @.. u=uprev + z[num_stages] + + step_limiter!(u, integrator, p, t + dt) + + if integrator.EEst <= oneunit(integrator.EEst) + cache.dtprev = dt + if alg.extrapolant != :constant + @.. derivatives[1, 1] = z[1] / c[1] + for j in 2:num_stages + @.. derivatives[1, j] = (z[j - 1] - z[j]) / (c[j - 1] - c[j]) #first derivatives + end + for i in 2:num_stages + @.. derivatives[i, i] = (derivatives[i - 1, i] - + derivatives[i - 1, i - 1]) / c[i] + for j in (i + 1):num_stages + @.. derivatives[i, j] = (derivatives[i - 1, j - 1] - + derivatives[i - 1, j]) / (c[j - i] - c[j]) #all others + end + end + for i in 1:num_stages + integrator.k[i + 2] = derivatives[i, num_stages] + end + end + end + + f(fsallast, u, p, t + dt) + integrator.stats.nf += 1 + return +end diff --git a/lib/OrdinaryDiffEqFIRK/src/firk_caches.jl b/lib/OrdinaryDiffEqFIRK/src/firk_caches.jl index af6da2a282..6f99a62cf3 100644 --- a/lib/OrdinaryDiffEqFIRK/src/firk_caches.jl +++ b/lib/OrdinaryDiffEqFIRK/src/firk_caches.jl @@ -10,7 +10,6 @@ mutable struct RadauIIA3ConstantCache{F, Tab, Tol, Dt, U, JType} <: iter::Int cont1::U cont2::U - cont3::U dtprev::Dt W_γdt::Dt status::NLStatus @@ -28,7 +27,7 @@ function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, κ = convert(uToltype, 1 // 100) J = false .* _vec(rate_prototype) .* _vec(rate_prototype)' - RadauIIA3ConstantCache(uf, tab, κ, one(uToltype), 10000, u, u, u, dt, dt, + RadauIIA3ConstantCache(uf, tab, κ, one(uToltype), 10000, u, u, dt, dt, Convergence, J) end @@ -42,8 +41,6 @@ mutable struct RadauIIA3Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Ty w2::uType dw12::cuType cubuff::cuType - cont1::uType - cont2::uType du1::rateType fsalfirst::rateType k::rateType @@ -87,8 +84,6 @@ function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(dw12, false) cubuff = similar(u, Complex{eltype(u)}) recursivefill!(cubuff, false) - cont1 = zero(u) - cont2 = zero(u) fsalfirst = zero(rate_prototype) k = zero(rate_prototype) @@ -96,19 +91,20 @@ function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, fw1 = zero(rate_prototype) fw2 = zero(rate_prototype) - J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) - W1 = similar(J, Complex{eltype(W1)}) - recursivefill!(W1, false) - du1 = zero(rate_prototype) tmp = zero(u) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) - jac_config = jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dw12) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dw12) + + J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + W1 = similar(J, Complex{eltype(W1)}) + recursivefill!(W1, false) linprob = LinearProblem(W1, _vec(cubuff); u0 = _vec(dw12)) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) @@ -118,7 +114,7 @@ function alg_cache(alg::RadauIIA3, u, rate_prototype, ::Type{uEltypeNoUnits}, RadauIIA3Cache(u, uprev, z1, z2, w1, w2, - dw12, cubuff, cont1, cont2, + dw12, cubuff, du1, fsalfirst, k, k2, fw1, fw2, J, W1, uf, tab, κ, one(uToltype), 10000, @@ -172,9 +168,6 @@ mutable struct RadauIIA5Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Ty ubuff::uType dw23::cuType cubuff::cuType - cont1::uType - cont2::uType - cont3::uType du1::rateType fsalfirst::rateType k::rateType @@ -226,9 +219,6 @@ function alg_cache(alg::RadauIIA5, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(dw23, false) cubuff = similar(u, Complex{eltype(u)}) recursivefill!(cubuff, false) - cont1 = zero(u) - cont2 = zero(u) - cont3 = zero(u) fsalfirst = zero(rate_prototype) k = zero(rate_prototype) @@ -238,13 +228,6 @@ function alg_cache(alg::RadauIIA5, u, rate_prototype, ::Type{uEltypeNoUnits}, fw2 = zero(rate_prototype) fw3 = zero(rate_prototype) - J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) - if J isa AbstractSciMLOperator - error("Non-concrete Jacobian not yet supported by RadauIIA5.") - end - W2 = similar(J, Complex{eltype(W1)}) - recursivefill!(W2, false) - du1 = zero(rate_prototype) tmp = zero(u) @@ -252,13 +235,22 @@ function alg_cache(alg::RadauIIA5, u, rate_prototype, ::Type{uEltypeNoUnits}, recursivefill!(atmp, false) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dw1) + J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + if J isa AbstractSciMLOperator + error("Non-concrete Jacobian not yet supported by RadauIIA5.") + end + W2 = similar(J, Complex{eltype(W1)}) + recursivefill!(W2, false) + linprob = LinearProblem(W1, _vec(ubuff); u0 = _vec(dw1)) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) linprob = LinearProblem(W2, _vec(cubuff); u0 = _vec(dw23)) - linsolve2 = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve2 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) @@ -268,7 +260,7 @@ function alg_cache(alg::RadauIIA5, u, rate_prototype, ::Type{uEltypeNoUnits}, RadauIIA5Cache(u, uprev, z1, z2, z3, w1, w2, w3, - dw1, ubuff, dw23, cubuff, cont1, cont2, cont3, + dw1, ubuff, dw23, cubuff, du1, fsalfirst, k, k2, k3, fw1, fw2, fw3, J, W1, W2, uf, tab, κ, one(uToltype), 10000, @@ -330,11 +322,6 @@ mutable struct RadauIIA9Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Ty dw45::cuType cubuff1::cuType cubuff2::cuType - cont1::uType - cont2::uType - cont3::uType - cont4::uType - cont5::uType du1::rateType fsalfirst::rateType k::rateType @@ -362,6 +349,10 @@ mutable struct RadauIIA9Cache{uType, cuType, uNoUnitsType, rateType, JType, W1Ty tmp4::uType tmp5::uType tmp6::uType + tmp7::uType + tmp8::uType + tmp9::uType + tmp10::uType atmp::uNoUnitsType jac_config::JC linsolve1::F1 @@ -405,11 +396,6 @@ function alg_cache(alg::RadauIIA9, u, rate_prototype, ::Type{uEltypeNoUnits}, cubuff2 = similar(u, Complex{eltype(u)}) recursivefill!(cubuff1, false) recursivefill!(cubuff2, false) - cont1 = zero(u) - cont2 = zero(u) - cont3 = zero(u) - cont4 = zero(u) - cont5 = zero(u) fsalfirst = zero(rate_prototype) k = zero(rate_prototype) @@ -423,15 +409,6 @@ function alg_cache(alg::RadauIIA9, u, rate_prototype, ::Type{uEltypeNoUnits}, fw4 = zero(rate_prototype) fw5 = zero(rate_prototype) - J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) - if J isa AbstractSciMLOperator - error("Non-concrete Jacobian not yet supported by RadauIIA5.") - end - W2 = similar(J, Complex{eltype(W1)}) - W3 = similar(J, Complex{eltype(W1)}) - recursivefill!(W2, false) - recursivefill!(W3, false) - du1 = zero(rate_prototype) tmp = zero(u) @@ -440,22 +417,38 @@ function alg_cache(alg::RadauIIA9, u, rate_prototype, ::Type{uEltypeNoUnits}, tmp4 = zero(u) tmp5 = zero(u) tmp6 = zero(u) + tmp7 = zero(u) + tmp8 = zero(u) + tmp9 = zero(u) + tmp10 = zero(u) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, dw1) + J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + if J isa AbstractSciMLOperator + error("Non-concrete Jacobian not yet supported by RadauIIA5.") + end + W2 = similar(J, Complex{eltype(W1)}) + W3 = similar(J, Complex{eltype(W1)}) + recursivefill!(W2, false) + recursivefill!(W3, false) + linprob = LinearProblem(W1, _vec(ubuff); u0 = _vec(dw1)) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) linprob = LinearProblem(W2, _vec(cubuff1); u0 = _vec(dw23)) - linsolve2 = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve2 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) linprob = LinearProblem(W3, _vec(cubuff2); u0 = _vec(dw45)) - linsolve3 = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve3 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) #Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), #Pr = Diagonal(_vec(weight))) @@ -465,19 +458,19 @@ function alg_cache(alg::RadauIIA9, u, rate_prototype, ::Type{uEltypeNoUnits}, RadauIIA9Cache(u, uprev, z1, z2, z3, z4, z5, w1, w2, w3, w4, w5, - dw1, ubuff, dw23, dw45, cubuff1, cubuff2, cont1, cont2, cont3, cont4, cont5, + dw1, ubuff, dw23, dw45, cubuff1, cubuff2, du1, fsalfirst, k, k2, k3, k4, k5, fw1, fw2, fw3, fw4, fw5, J, W1, W2, W3, uf, tab, κ, one(uToltype), 10000, - tmp, tmp2, tmp3, tmp4, tmp5, tmp6, atmp, jac_config, + tmp, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, atmp, jac_config, linsolve1, linsolve2, linsolve3, rtol, atol, dt, dt, Convergence, alg.step_limiter!) end mutable struct AdaptiveRadauConstantCache{F, Tab, Tol, Dt, U, JType} <: - OrdinaryDiffEqConstantCache + OrdinaryDiffEqConstantCache uf::F - tab::Tab + tabs::Vector{Tab} κ::Tol ηold::Tol iter::Int @@ -486,6 +479,10 @@ mutable struct AdaptiveRadauConstantCache{F, Tab, Tol, Dt, U, JType} <: W_γdt::Dt status::NLStatus J::JType + num_stages::Int + step::Int + hist_iter::Float64 + index::Int end function alg_cache(alg::AdaptiveRadau, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -494,33 +491,35 @@ function alg_cache(alg::AdaptiveRadau, u, rate_prototype, ::Type{uEltypeNoUnits} ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} uf = UDerivativeWrapper(f, t, p) uToltype = constvalue(uBottomEltypeNoUnits) - num_stages = alg.num_stages - - if (num_stages == 3) - tab = BigRadauIIA5Tableau(uToltype, constvalue(tTypeNoUnits)) - elseif (num_stages == 5) - tab = BigRadauIIA9Tableau(uToltype, constvalue(tTypeNoUnits)) - elseif (num_stages == 7) - tab = BigRadauIIA13Tableau(uToltype, constvalue(tTypeNoUnits)) - elseif iseven(num_stages) || num_stages <3 - error("num_stages must be odd and 3 or greater") - else - tab = adaptiveRadauTableau(uToltype, constvalue(tTypeNoUnits), num_stages) + + max_order = alg.max_order + min_order = alg.min_order + max_stages = (max_order - 1) ÷ 4 * 2 + 1 + min_stages = (min_order - 1) ÷ 4 * 2 + 1 + if (alg.min_order < 5) + error("min_order choice $min_order below 5 is not compatible with the algorithm") + elseif (max_stages < min_stages) + error("max_order $max_order is below min_order $min_order") end + num_stages = min_stages - cont = Vector{typeof(u)}(undef, num_stages) - for i in 1: num_stages + tabs = [RadauIIATableau(uToltype, constvalue(tTypeNoUnits), i) + for i in min_stages:2:max_stages] + cont = Vector{typeof(u)}(undef, max_stages) + for i in 1:max_stages cont[i] = zero(u) end + index = 1 + κ = alg.κ !== nothing ? convert(uToltype, alg.κ) : convert(uToltype, 1 // 100) J = false .* _vec(rate_prototype) .* _vec(rate_prototype)' - - AdaptiveRadauConstantCache(uf, tab, κ, one(uToltype), 10000, cont, dt, dt, - Convergence, J) + AdaptiveRadauConstantCache(uf, tabs, κ, one(uToltype), 10000, cont, dt, dt, + Convergence, J, num_stages, 1, 0.0, index) end -mutable struct AdaptiveRadauCache{uType, cuType, tType, uNoUnitsType, rateType, JType, W1Type, W2Type, +mutable struct AdaptiveRadauCache{ + uType, cuType, tType, uNoUnitsType, rateType, JType, W1Type, W2Type, UF, JC, F1, F2, Tab, Tol, Dt, rTol, aTol, StepLimiter} <: FIRKMutableCache u::uType @@ -528,13 +527,14 @@ mutable struct AdaptiveRadauCache{uType, cuType, tType, uNoUnitsType, rateType, z::Vector{uType} w::Vector{uType} c_prime::Vector{tType} + αdt::Vector{tType} + βdt::Vector{tType} dw1::uType ubuff::uType dw2::Vector{cuType} cubuff::Vector{cuType} dw::Vector{uType} - cont::Vector{uType} - derivatives:: Matrix{uType} + derivatives::Matrix{uType} du1::rateType fsalfirst::rateType ks::Vector{rateType} @@ -544,7 +544,7 @@ mutable struct AdaptiveRadauCache{uType, cuType, tType, uNoUnitsType, rateType, W1::W1Type #real W2::Vector{W2Type} #complex uf::UF - tab::Tab + tabs::Vector{Tab} κ::Tol ηold::Tol iter::Int @@ -559,6 +559,10 @@ mutable struct AdaptiveRadauCache{uType, cuType, tType, uNoUnitsType, rateType, W_γdt::Dt status::NLStatus step_limiter!::StepLimiter + num_stages::Int + step::Int + hist_iter::Float64 + index::Int end function alg_cache(alg::AdaptiveRadau, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -567,63 +571,58 @@ function alg_cache(alg::AdaptiveRadau, u, rate_prototype, ::Type{uEltypeNoUnits} ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} uf = UJacobianWrapper(f, t, p) uToltype = constvalue(uBottomEltypeNoUnits) - num_stages = alg.num_stages - - if (num_stages == 3) - tab = BigRadauIIA5Tableau(uToltype, constvalue(tTypeNoUnits)) - elseif (num_stages == 5) - tab = BigRadauIIA9Tableau(uToltype, constvalue(tTypeNoUnits)) - elseif (num_stages == 7) - tab = BigRadauIIA13Tableau(uToltype, constvalue(tTypeNoUnits)) - elseif iseven(num_stages) || num_stages < 3 - error("num_stages must be odd and 3 or greater") - else - tab = adaptiveRadauTableau(uToltype, constvalue(tTypeNoUnits), num_stages) + + max_order = alg.max_order + min_order = alg.min_order + max_stages = (max_order - 1) ÷ 4 * 2 + 1 + min_stages = (min_order - 1) ÷ 4 * 2 + 1 + if (alg.min_order < 5) + error("min_order choice $min_order below 5 is not compatible with the algorithm") + elseif (max_stages < min_stages) + error("max_order $max_order is below min_order $min_order") end + num_stages = min_stages + + tabs = [RadauIIATableau(uToltype, constvalue(tTypeNoUnits), i) + for i in min_stages:2:max_stages] + + index = 1 κ = alg.κ !== nothing ? convert(uToltype, alg.κ) : convert(uToltype, 1 // 100) - z = Vector{typeof(u)}(undef, num_stages) - w = Vector{typeof(u)}(undef, num_stages) - for i in 1 : num_stages - z[i] = w[i] = zero(u) + z = Vector{typeof(u)}(undef, max_stages) + w = Vector{typeof(u)}(undef, max_stages) + for i in 1:max_stages + z[i] = zero(u) + w[i] = zero(u) end - c_prime = Vector{typeof(t)}(undef, num_stages) #time stepping + αdt = [zero(t) for i in 1:max_stages] + βdt = [zero(t) for i in 1:max_stages] + c_prime = Vector{typeof(t)}(undef, max_stages) #time stepping + for i in 1:max_stages + c_prime[i] = zero(t) + end dw1 = zero(u) ubuff = zero(u) - dw2 = [similar(u, Complex{eltype(u)}) for _ in 1 : (num_stages - 1) ÷ 2] + dw2 = [similar(u, Complex{eltype(u)}) for _ in 1:((max_stages - 1) ÷ 2)] recursivefill!.(dw2, false) - cubuff = [similar(u, Complex{eltype(u)}) for _ in 1 : (num_stages - 1) ÷ 2] + cubuff = [similar(u, Complex{eltype(u)}) for _ in 1:((max_stages - 1) ÷ 2)] recursivefill!.(cubuff, false) - dw = Vector{typeof(u)}(undef, num_stages - 1) + dw = [zero(u) for i in 1:max_stages] - cont = Vector{typeof(u)}(undef, num_stages) - for i in 1 : num_stages - cont[i] = zero(u) - end + derivatives = Matrix{typeof(u)}(undef, max_stages, max_stages) + for i in 1:max_stages, j in 1:max_stages - derivatives = Matrix{typeof(u)}(undef, num_stages, num_stages) - for i in 1 : num_stages, j in 1 : num_stages derivatives[i, j] = zero(u) end fsalfirst = zero(rate_prototype) - fw = Vector{typeof(rate_prototype)}(undef, num_stages) - ks = Vector{typeof(rate_prototype)}(undef, num_stages) - for i in 1: num_stages - ks[i] = fw[i] = zero(rate_prototype) - end - k = ks[1] - - J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) - if J isa AbstractSciMLOperator - error("Non-concrete Jacobian not yet supported by AdaptiveRadau.") - end + fw = [zero(rate_prototype) for i in 1:max_stages] + ks = [zero(rate_prototype) for i in 1:max_stages] - W2 = [similar(J, Complex{eltype(W1)}) for _ in 1 : (num_stages - 1) ÷ 2] - recursivefill!.(W2, false) + k = ks[1] du1 = zero(rate_prototype) @@ -634,24 +633,34 @@ function alg_cache(alg::AdaptiveRadau, u, rate_prototype, ::Type{uEltypeNoUnits} jac_config = build_jac_config(alg, f, uf, du1, uprev, u, zero(u), dw1) + J, W1 = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + if J isa AbstractSciMLOperator + error("Non-concrete Jacobian not yet supported by AdaptiveRadau.") + end + + W2 = [similar(J, Complex{eltype(W1)}) for _ in 1:((max_stages - 1) ÷ 2)] + recursivefill!.(W2, false) + linprob = LinearProblem(W1, _vec(ubuff); u0 = _vec(dw1)) - linsolve1 = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve1 = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), assumptions = LinearSolve.OperatorAssumptions(true)) - linsolve2 = [ - init(LinearProblem(W2[i], _vec(cubuff[i]); u0 = _vec(dw2[i])), alg.linsolve, alias_A = true, alias_b = true, - assumptions = LinearSolve.OperatorAssumptions(true)) for i in 1 : (num_stages - 1) ÷ 2] + linsolve2 = [init(LinearProblem(W2[i], _vec(cubuff[i]); u0 = _vec(dw2[i])), + alg.linsolve, alias = LinearAliasSpecifier( + alias_A = true, alias_b = true), + assumptions = LinearSolve.OperatorAssumptions(true)) + for i in 1:((max_stages - 1) ÷ 2)] rtol = reltol isa Number ? reltol : zero(reltol) atol = reltol isa Number ? reltol : zero(reltol) AdaptiveRadauCache(u, uprev, - z, w, c_prime, dw1, ubuff, dw2, cubuff, dw, cont, derivatives, + z, w, c_prime, αdt, βdt, dw1, ubuff, dw2, cubuff, dw, derivatives, du1, fsalfirst, ks, k, fw, J, W1, W2, - uf, tab, κ, one(uToltype), 10000, tmp, + uf, tabs, κ, one(uToltype), 10000, tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol, dt, dt, - Convergence, alg.step_limiter!) + Convergence, alg.step_limiter!, num_stages, 1, 0.0, index) end - diff --git a/lib/OrdinaryDiffEqFIRK/src/firk_interpolants.jl b/lib/OrdinaryDiffEqFIRK/src/firk_interpolants.jl new file mode 100644 index 0000000000..80bbb165df --- /dev/null +++ b/lib/OrdinaryDiffEqFIRK/src/firk_interpolants.jl @@ -0,0 +1,107 @@ +FIRK_WITH_INTERPOLATIONS = Union{ + RadauIIA3ConstantCache, RadauIIA3Cache, RadauIIA5ConstantCache, RadauIIA5Cache, + RadauIIA9ConstantCache, RadauIIA9Cache, AdaptiveRadauConstantCache, AdaptiveRadauCache} + +@muladd function _ode_interpolant( + Θ, dt, y₀, y₁, k, cache::Union{RadauIIA3ConstantCache, RadauIIA3Cache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack cont1, cont2 = cache + @unpack c1 = cache.tab + c1m1 = c1 - 1 + Θdt = 1 - Θ + @.. y₁ - Θdt * (k[3] - (Θdt + c1m1) * k[4]) +end + +@muladd function _ode_interpolant!( + out, Θ, dt, y₀, y₁, k, cache::Union{RadauIIA3ConstantCache, RadauIIA3Cache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack c1 = cache.tab + c1m1 = c1 - 1 + Θdt = 1 - Θ + @.. out = y₁ - Θdt * (k[3] - (Θdt + c1m1) * k[4]) +end + +@muladd function _ode_interpolant( + Θ, dt, y₀, y₁, k, cache::Union{RadauIIA5ConstantCache, RadauIIA5Cache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack c1, c2 = cache.tab + c1m1 = c1 - 1 + c2m1 = c2 - 1 + Θdt = 1-Θ + @.. y₁ - Θdt * (k[3] - (Θdt + c2m1) * (k[4] - (Θdt + c1m1) * k[5])) +end + +@muladd function _ode_interpolant!( + out, Θ, dt, y₀, y₁, k, cache::Union{RadauIIA5ConstantCache, RadauIIA5Cache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack c1, c2 = cache.tab + @unpack dtprev = cache + c1m1 = c1 - 1 + c2m1 = c2 - 1 + Θdt = 1 - Θ + @.. out = y₁ - Θdt * (k[3] - (Θdt + c2m1) * (k[4] - (Θdt + c1m1) * k[5])) +end + +@muladd function _ode_interpolant( + Θ, dt, y₀, y₁, k, cache::Union{RadauIIA9ConstantCache, RadauIIA9Cache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack c1, c2, c3, c4 = cache.tab + c1m1 = c1 - 1 + c2m1 = c2 - 1 + c3m1 = c3 - 1 + c4m1 = c4 - 1 + Θdt = 1 - Θ + @.. y₁ - + Θdt * (k[3] - + (Θdt + c4m1) * + (k[4] - (Θdt + c3m1) * (k[5] - (Θdt + c2m1) * (k[6] - (Θdt + c1m1) * k[7])))) +end + +@muladd function _ode_interpolant!( + out, Θ, dt, y₀, y₁, k, cache::Union{RadauIIA9ConstantCache, RadauIIA9Cache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack c1, c2, c3, c4 = cache.tab + c1m1 = c1 - 1 + c2m1 = c2 - 1 + c3m1 = c3 - 1 + c4m1 = c4 - 1 + Θdt = 1 - Θ + @.. out = y₁ - + Θdt * (k[3] - + (Θdt + c4m1) * + (k[4] - (Θdt + c3m1) * (k[5] - (Θdt + c2m1) * (k[6] - (Θdt + c1m1) * k[7])))) +end + +@muladd function _ode_interpolant( + Θ, dt, y₀, y₁, k, cache::Union{AdaptiveRadauConstantCache, AdaptiveRadauCache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack num_stages, index = cache + @unpack c = cache.tabs[index] + Θdt = 1 - Θ + tmp = k[num_stages + 1] - k[num_stages + 2] * (Θdt + c[1] - 1) + j = num_stages - 2 + while j > 0 + tmp *= (Θdt + c[num_stages - j] - 1) + tmp = k[j + 2] - tmp + j = j - 1 + end + tmp *= Θdt + @.. y₁ - tmp +end + +@muladd function _ode_interpolant!( + out, Θ, dt, y₀, y₁, k, cache::Union{AdaptiveRadauConstantCache, AdaptiveRadauCache}, + idxs::Nothing, T::Type{Val{0}}, differential_vars) + @unpack num_stages, index = cache + @unpack c = cache.tabs[index] + Θdt = 1 - Θ + tmp = k[num_stages + 1] - k[num_stages + 2] * (Θdt + c[1] - 1) + j = num_stages - 2 + while j > 0 + tmp *= (Θdt + c[num_stages - j] - 1) + tmp = k[j + 2] - tmp + j = j - 1 + end + tmp *= Θdt + @.. out = y₁ - tmp +end diff --git a/lib/OrdinaryDiffEqFIRK/src/firk_perform_step.jl b/lib/OrdinaryDiffEqFIRK/src/firk_perform_step.jl index 044257afad..cc87d08b6b 100644 --- a/lib/OrdinaryDiffEqFIRK/src/firk_perform_step.jl +++ b/lib/OrdinaryDiffEqFIRK/src/firk_perform_step.jl @@ -26,8 +26,8 @@ function do_newW(integrator, nlsolver, new_jac, W_dt)::Bool # for FIRK return !smallstepchange end -function initialize!(integrator, cache::Union{RadauIIA3ConstantCache, RadauIIA5ConstantCache, RadauIIA9ConstantCache,AdaptiveRadauConstantCache}) - integrator.kshortsize = 2 +function initialize!(integrator, cache::RadauIIA3ConstantCache) + integrator.kshortsize = 4 integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -40,20 +40,51 @@ function initialize!(integrator, cache::Union{RadauIIA3ConstantCache, RadauIIA5C end function initialize!(integrator, cache::RadauIIA3Cache) - integrator.kshortsize = 2 + integrator.kshortsize = 4 #2 for fsalfirst and fsallast and 3 for the collocation terms resize!(integrator.k, integrator.kshortsize) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + integrator.k[3] = zero(integrator.fsallast) + integrator.k[4] = zero(integrator.fsallast) integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + if integrator.opts.adaptive + @unpack abstol, reltol = integrator.opts + if reltol isa Number + cache.rtol = reltol^(2 / 3) / 10 + cache.atol = cache.rtol * (abstol / reltol) + else + @.. cache.rtol=reltol^(2 / 3) / 10 + @.. cache.atol=cache.rtol * (abstol / reltol) + end + end + nothing +end + +function initialize!(integrator, cache::RadauIIA5ConstantCache) + integrator.kshortsize = 5 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + + # Avoid undefined entries if k is an array of arrays + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + integrator.k[3] = zero(integrator.fsalfirst) + integrator.k[4] = zero(integrator.fsalfirst) + integrator.k[5] = zero(integrator.fsalfirst) nothing end function initialize!(integrator, cache::RadauIIA5Cache) - integrator.kshortsize = 2 + integrator.kshortsize = 5 #2 for fsalfirst and fsallast and 3 for the collocation terms resize!(integrator.k, integrator.kshortsize) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + integrator.k[3] = zero(integrator.fsallast) + integrator.k[4] = zero(integrator.fsallast) + integrator.k[5] = zero(integrator.fsallast) integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) if integrator.opts.adaptive @@ -62,18 +93,41 @@ function initialize!(integrator, cache::RadauIIA5Cache) cache.rtol = reltol^(2 / 3) / 10 cache.atol = cache.rtol * (abstol / reltol) else - @.. broadcast=false cache.rtol=reltol^(2 / 3) / 10 - @.. broadcast=false cache.atol=cache.rtol * (abstol / reltol) + @.. cache.rtol=reltol^(2 / 3) / 10 + @.. cache.atol=cache.rtol * (abstol / reltol) end end nothing end +function initialize!(integrator, cache::RadauIIA9ConstantCache) + integrator.kshortsize = 7 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + + # Avoid undefined entries if k is an array of arrays + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + integrator.k[3] = zero(integrator.fsalfirst) + integrator.k[4] = zero(integrator.fsalfirst) + integrator.k[5] = zero(integrator.fsalfirst) + integrator.k[6] = zero(integrator.fsalfirst) + integrator.k[7] = zero(integrator.fsalfirst) + nothing +end + function initialize!(integrator, cache::RadauIIA9Cache) - integrator.kshortsize = 2 + integrator.kshortsize = 7 resize!(integrator.k, integrator.kshortsize) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + integrator.k[3] = similar(integrator.fsallast) + integrator.k[4] = similar(integrator.fsallast) + integrator.k[5] = similar(integrator.fsallast) + integrator.k[6] = similar(integrator.fsallast) + integrator.k[7] = similar(integrator.fsallast) integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) if integrator.opts.adaptive @@ -82,40 +136,49 @@ function initialize!(integrator, cache::RadauIIA9Cache) cache.rtol = reltol^(3 / 5) / 10 cache.atol = cache.rtol * (abstol / reltol) else - @.. broadcast=false cache.rtol=reltol^(3 / 5) / 10 - @.. broadcast=false cache.atol=cache.rtol * (abstol / reltol) + @.. cache.rtol=reltol^(3 / 5) / 10 + @.. cache.atol=cache.rtol * (abstol / reltol) end end nothing end +function initialize!(integrator, cache::AdaptiveRadauConstantCache) + max_stages = (integrator.alg.max_order - 1) ÷ 4 * 2 + 1 + integrator.kshortsize = max_stages + 2 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + + # Avoid undefined entries if k is an array of arrays + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[2] = integrator.fsallast + for i in 3:(max_stages + 2) + integrator.k[i] = zero(integrator.fsallast) + end + nothing +end + function initialize!(integrator, cache::AdaptiveRadauCache) - @unpack num_stages = cache.tab - integrator.kshortsize = 2 + max_stages = (integrator.alg.max_order - 1) ÷ 4 * 2 + 1 + integrator.kshortsize = max_stages + 2 resize!(integrator.k, integrator.kshortsize) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + for i in 3:(max_stages + 2) + integrator.k[i] = similar(integrator.fsallast) + end integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - if integrator.opts.adaptive - @unpack abstol, reltol = integrator.opts - if reltol isa Number - cache.rtol = reltol^((num_stages + 1) / (2 * num_stages)) / 10 - cache.atol = cache.rtol * (abstol / reltol) - else - @.. broadcast=false cache.rtol=reltol^((num_stages + 1) / (2 * num_stages)) / 10 - @.. broadcast=false cache.atol=cache.rtol * (abstol / reltol) - end - end nothing end - @muladd function perform_step!(integrator, cache::RadauIIA3ConstantCache) - @unpack t, dt, uprev, u, f, p = integrator + @unpack t, dt, uprev, u, f, p, k = integrator @unpack T11, T12, T21, T22, TI11, TI12, TI21, TI22 = cache.tab @unpack c1, c2, α, β, e1, e2 = cache.tab - @unpack κ, cont1, cont2 = cache + @unpack κ = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @unpack maxiters = alg @@ -127,11 +190,24 @@ end αdt, βdt = α / dt, β / dt J = calc_J(integrator, cache) - cache.dtprev = one(cache.dtprev) - z1 = w1 = map(zero, u) - z2 = w2 = map(zero, u) - cache.cont1 = map(zero, u) - cache.cont2 = map(zero, u) + c1m1 = c1 - 1 + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = map(zero, u) + z1 = @.. uzero + z2 = @.. uzero + w1 = @.. uzero + w2 = @.. uzero + integrator.k[3] = uzero + integrator.k[4] = uzero + else + c2′ = dt / cache.dtprev + c1′ = c1 * c2′ + z1 = @.. c1′ * (integrator.k[3] + (c1′ - c1m1) * integrator.k[4]) + z2 = @.. c2′ * (integrator.k[3] + (c2′ - c1m1) * integrator.k[4]) + w1 = @.. TI11 * z1 + TI12 * z2 + w2 = @.. TI21 * z1 + TI22 * z2 + end if u isa Number LU1 = -(αdt + βdt * im) * mass_matrix + J @@ -217,6 +293,14 @@ end integrator.EEst = internalnorm(atmp, t) end + if integrator.EEst <= oneunit(integrator.EEst) + cache.dtprev = dt + if alg.extrapolant != :constant + integrator.k[3] = (z1 - z2) / c1m1 + integrator.k[4] = integrator.k[3] - (z1 / c1) + end + end + integrator.fsallast = f(u, p, t + dt) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast @@ -225,10 +309,10 @@ end end @muladd function perform_step!(integrator, cache::RadauIIA3Cache, repeat_step = false) - @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst = integrator + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst, k = integrator @unpack T11, T12, T21, T22, TI11, TI12, TI21, TI22 = cache.tab @unpack c1, c2, α, β, e1, e2 = cache.tab - @unpack κ, cont1, cont2 = cache + @unpack κ = cache @unpack z1, z2, w1, w2, dw12, cubuff, k, k2, fw1, fw2, @@ -249,14 +333,24 @@ end integrator.stats.nw += 1 end - #better initial guess - uzero = zero(eltype(z1)) - @. z1 = uzero - @. z2 = uzero - @. w1 = uzero - @. w2 = uzero - @. cache.cont1 = uzero - @. cache.cont2 = uzero + c1m1 = c1 - 1 + if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant + cache.dtprev = one(cache.dtprev) + uzero = zero(eltype(u)) + @.. z1=uzero + @.. z2=uzero + @.. w1=uzero + @.. w2=uzero + @.. integrator.k[3]=uzero + @.. integrator.k[4]=uzero + else + c2′ = dt / cache.dtprev + c1′ = c1 * c2′ + @.. z1=c1′ * (integrator.k[3] + (c1′ - c1m1) * integrator.k[4]) + @.. z2=c2′ * (integrator.k[3] + (c2′ - c1m1) * integrator.k[4]) + @.. w1=TI11 * z1 + TI12 * z2 + @.. w2=TI21 * z1 + TI22 * z2 + end # Newton iteration local ndw @@ -361,6 +455,15 @@ end calculate_residuals!(atmp, utilde, uprev, u, atol, rtol, internalnorm, t) integrator.EEst = internalnorm(atmp, t) end + + if integrator.EEst <= oneunit(integrator.EEst) + cache.dtprev = dt + if alg.extrapolant != :constant + integrator.k[3] = (z1 - z2) / c1m1 + integrator.k[4] = integrator.k[3] - (z1 / c1) + end + end + f(fsallast, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) return @@ -368,8 +471,9 @@ end @muladd function perform_step!(integrator, cache::RadauIIA5ConstantCache, repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack T11, T12, T13, T21, T22, T23, T31, TI11, TI12, TI13, TI21, TI22, TI23, TI31, TI32, TI33 = cache.tab + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack T11, T12, T13, T21, T22, T23, T31, TI11, TI12, TI13, + TI21, TI22, TI23, TI31, TI32, TI33 = cache.tab @unpack c1, c2, γ, α, β, e1, e2, e3 = cache.tab @unpack κ, cont1, cont2, cont3 = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts @@ -378,8 +482,8 @@ end mass_matrix = integrator.f.mass_matrix # precalculations - rtol = @.. broadcast=false reltol^(2 / 3)/10 - atol = @.. broadcast=false rtol*(abstol / reltol) + rtol = @.. reltol^(2 / 3)/10 + atol = @.. rtol*(abstol / reltol) c1m1 = c1 - 1 c2m1 = c2 - 1 c1mc2 = c1 - c2 @@ -397,22 +501,26 @@ end # TODO better initial guess if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant cache.dtprev = one(cache.dtprev) - z1 = w1 = map(zero, u) - z2 = w2 = map(zero, u) - z3 = w3 = map(zero, u) - cache.cont1 = map(zero, u) - cache.cont2 = map(zero, u) - cache.cont3 = map(zero, u) + uzero = map(zero, u) + z1 = @.. uzero + z2 = @.. uzero + z3 = @.. uzero + w1 = @.. uzero + w2 = @.. uzero + w3 = @.. uzero + integrator.k[3] = uzero + integrator.k[4] = uzero + integrator.k[5] = uzero else c3′ = dt / cache.dtprev c1′ = c1 * c3′ c2′ = c2 * c3′ - z1 = @.. broadcast=false c1′*(cont1 + (c1′ - c2m1) * (cont2 + (c1′ - c1m1) * cont3)) - z2 = @.. broadcast=false c2′*(cont1 + (c2′ - c2m1) * (cont2 + (c2′ - c1m1) * cont3)) - z3 = @.. broadcast=false c3′*(cont1 + (c3′ - c2m1) * (cont2 + (c3′ - c1m1) * cont3)) - w1 = @.. broadcast=false TI11*z1+TI12*z2+TI13*z3 - w2 = @.. broadcast=false TI21*z1+TI22*z2+TI23*z3 - w3 = @.. broadcast=false TI31*z1+TI32*z2+TI33*z3 + z1 = @.. c1′ * (k[3] + (c1′ - c2m1) * (k[4] + (c1′ - c1m1) * k[5])) + z2 = @.. c2′ * (k[3] + (c2′ - c2m1) * (k[4] + (c2′ - c1m1) * k[5])) + z3 = @.. c3′ * (k[3] + (c3′ - c2m1) * (k[4] + (c3′ - c1m1) * k[5])) + w1 = @.. TI11*z1+TI12*z2+TI13*z3 + w2 = @.. TI21*z1+TI22*z2+TI23*z3 + w3 = @.. TI31*z1+TI32*z2+TI33*z3 end # Newton iteration @@ -430,25 +538,25 @@ end ff3 = f(uprev + z3, p, t + dt) # c3 = 1 OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) - fw1 = @.. broadcast=false TI11*ff1+TI12*ff2+TI13*ff3 - fw2 = @.. broadcast=false TI21*ff1+TI22*ff2+TI23*ff3 - fw3 = @.. broadcast=false TI31*ff1+TI32*ff2+TI33*ff3 + fw1 = @.. TI11*ff1+TI12*ff2+TI13*ff3 + fw2 = @.. TI21*ff1+TI22*ff2+TI23*ff3 + fw3 = @.. TI31*ff1+TI32*ff2+TI33*ff3 if mass_matrix isa UniformScaling # `UniformScaling` doesn't play nicely with broadcast - Mw1 = @.. broadcast=false mass_matrix.λ*w1 - Mw2 = @.. broadcast=false mass_matrix.λ*w2 - Mw3 = @.. broadcast=false mass_matrix.λ*w3 + Mw1 = @.. mass_matrix.λ*w1 + Mw2 = @.. mass_matrix.λ*w2 + Mw3 = @.. mass_matrix.λ*w3 else Mw1 = mass_matrix * w1 Mw2 = mass_matrix * w2 Mw3 = mass_matrix * w3 end - rhs1 = @.. broadcast=false fw1-γdt * Mw1 - rhs2 = @.. broadcast=false fw2 - αdt * Mw2+βdt * Mw3 - rhs3 = @.. broadcast=false fw3 - βdt * Mw2-αdt * Mw3 + rhs1 = @.. fw1-γdt * Mw1 + rhs2 = @.. fw2 - αdt * Mw2+βdt * Mw3 + rhs3 = @.. fw3 - βdt * Mw2-αdt * Mw3 dw1 = _reshape(LU1 \ _vec(rhs1), axes(u)) - dw23 = _reshape(LU2 \ _vec(@.. broadcast=false rhs2+rhs3 * im), axes(u)) + dw23 = _reshape(LU2 \ _vec(@.. rhs2+rhs3 * im), axes(u)) integrator.stats.nsolve += 2 dw2 = real(dw23) dw3 = imag(dw23) @@ -470,14 +578,14 @@ end end end - w1 = @.. broadcast=false w1-dw1 - w2 = @.. broadcast=false w2-dw2 - w3 = @.. broadcast=false w3-dw3 + w1 = @.. w1-dw1 + w2 = @.. w2-dw2 + w3 = @.. w3-dw3 # transform `w` to `z` - z1 = @.. broadcast=false T11*w1+T12*w2+T13*w3 - z2 = @.. broadcast=false T21*w1+T22*w2+T23*w3 - z3 = @.. broadcast=false T31 * w1+w2 # T32 = 1, T33 = 0 + z1 = @.. T11*w1+T12*w2+T13*w3 + z2 = @.. T21*w1+T22*w2+T23*w3 + z3 = @.. T31 * w1+w2 # T32 = 1, T33 = 0 # check stopping criterion iter > 1 && (η = θ / (1 - θ)) @@ -497,13 +605,13 @@ end cache.ηold = η cache.iter = iter - u = @.. broadcast=false uprev+z3 + u = @.. uprev+z3 if adaptive e1dt, e2dt, e3dt = e1 / dt, e2 / dt, e3 / dt - tmp = @.. broadcast=false e1dt*z1+e2dt*z2+e3dt*z3 + tmp = @.. e1dt*z1+e2dt*z2+e3dt*z3 mass_matrix != I && (tmp = mass_matrix * tmp) - utilde = @.. broadcast=false integrator.fsalfirst+tmp + utilde = @.. integrator.fsalfirst+tmp if alg.smooth_est utilde = _reshape(LU1 \ _vec(utilde), axes(u)) integrator.stats.nsolve += 1 @@ -517,7 +625,7 @@ end integrator.u_modified f0 = f(uprev .+ utilde, p, t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - utilde = @.. broadcast=false f0+tmp + utilde = @.. f0+tmp alg.smooth_est && (utilde = LU1 \ utilde; integrator.stats.nsolve += 1) atmp = calculate_residuals(utilde, uprev, u, atol, rtol, internalnorm, t) integrator.EEst = internalnorm(atmp, t) @@ -527,10 +635,10 @@ end if integrator.EEst <= oneunit(integrator.EEst) cache.dtprev = dt if alg.extrapolant != :constant - cache.cont1 = @.. broadcast=false (z2 - z3)/c2m1 - tmp = @.. broadcast=false (z1 - z2)/c1mc2 - cache.cont2 = @.. broadcast=false (tmp - cache.cont1)/c1m1 - cache.cont3 = @.. broadcast=false cache.cont2-(tmp - z1 / c1) / c2 + integrator.k[3] = (z2 - z3)/c2m1 + tmp = @.. (z1 - z2)/c1mc2 + integrator.k[4] = (tmp - integrator.k[3])/c1m1 + integrator.k[5] = integrator.k[4]-(tmp - z1 / c1) / c2 end end @@ -543,10 +651,11 @@ end end @muladd function perform_step!(integrator, cache::RadauIIA5Cache, repeat_step = false) - @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst = integrator - @unpack T11, T12, T13, T21, T22, T23, T31, TI11, TI12, TI13, TI21, TI22, TI23, TI31, TI32, TI33 = cache.tab + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst, k = integrator + @unpack T11, T12, T13, T21, T22, T23, T31, TI11, TI12, TI13, + TI21, TI22, TI23, TI31, TI32, TI33 = cache.tab @unpack c1, c2, γ, α, β, e1, e2, e3 = cache.tab - @unpack κ, cont1, cont2, cont3 = cache + @unpack κ = cache @unpack z1, z2, z3, w1, w2, w3, dw1, ubuff, dw23, cubuff, k, k2, k3, fw1, fw2, fw3, @@ -576,25 +685,28 @@ end if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant cache.dtprev = one(cache.dtprev) uzero = zero(eltype(u)) - @.. broadcast=false z1=uzero - @.. broadcast=false z2=uzero - @.. broadcast=false z3=uzero - @.. broadcast=false w1=uzero - @.. broadcast=false w2=uzero - @.. broadcast=false w3=uzero - @.. broadcast=false cache.cont1=uzero - @.. broadcast=false cache.cont2=uzero - @.. broadcast=false cache.cont3=uzero + @.. z1=uzero + @.. z2=uzero + @.. z3=uzero + @.. w1=uzero + @.. w2=uzero + @.. w3=uzero + @.. integrator.k[3]=uzero + @.. integrator.k[4]=uzero + @.. integrator.k[5]=uzero else c3′ = dt / cache.dtprev c1′ = c1 * c3′ c2′ = c2 * c3′ - @.. broadcast=false z1=c1′ * (cont1 + (c1′ - c2m1) * (cont2 + (c1′ - c1m1) * cont3)) - @.. broadcast=false z2=c2′ * (cont1 + (c2′ - c2m1) * (cont2 + (c2′ - c1m1) * cont3)) - @.. broadcast=false z3=c3′ * (cont1 + (c3′ - c2m1) * (cont2 + (c3′ - c1m1) * cont3)) - @.. broadcast=false w1=TI11 * z1 + TI12 * z2 + TI13 * z3 - @.. broadcast=false w2=TI21 * z1 + TI22 * z2 + TI23 * z3 - @.. broadcast=false w3=TI31 * z1 + TI32 * z2 + TI33 * z3 + @.. z1=c1′ * (integrator.k[3] + + (c1′ - c2m1) * (integrator.k[4] + (c1′ - c1m1) * integrator.k[5])) + @.. z1=c2′ * (integrator.k[3] + + (c2′ - c2m1) * (integrator.k[4] + (c2′ - c1m1) * integrator.k[5])) + @.. z1=c3′ * (integrator.k[3] + + (c3′ - c2m1) * (integrator.k[4] + (c3′ - c1m1) * integrator.k[5])) + @.. w1=TI11 * z1 + TI12 * z2 + TI13 * z3 + @.. w2=TI21 * z1 + TI22 * z2 + TI23 * z3 + @.. w3=TI31 * z1 + TI32 * z2 + TI33 * z3 end # Newton iteration @@ -607,17 +719,17 @@ end integrator.stats.nnonliniter += 1 # evaluate function - @.. broadcast=false tmp=uprev + z1 + @.. tmp=uprev + z1 f(fsallast, tmp, p, t + c1 * dt) - @.. broadcast=false tmp=uprev + z2 + @.. tmp=uprev + z2 f(k2, tmp, p, t + c2 * dt) - @.. broadcast=false tmp=uprev + z3 + @.. tmp=uprev + z3 f(k3, tmp, p, t + dt) # c3 = 1 OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) - @.. broadcast=false fw1=TI11 * fsallast + TI12 * k2 + TI13 * k3 - @.. broadcast=false fw2=TI21 * fsallast + TI22 * k2 + TI23 * k3 - @.. broadcast=false fw3=TI31 * fsallast + TI32 * k2 + TI33 * k3 + @.. fw1=TI11 * fsallast + TI12 * k2 + TI13 * k3 + @.. fw2=TI21 * fsallast + TI22 * k2 + TI23 * k3 + @.. fw3=TI31 * fsallast + TI32 * k2 + TI33 * k3 if mass_matrix === I Mw1 = w1 @@ -639,7 +751,7 @@ end Mw3 = z3 end - @.. broadcast=false ubuff=fw1 - γdt * Mw1 + @.. ubuff=fw1 - γdt * Mw1 needfactor = iter == 1 && new_W linsolve1 = cache.linsolve1 @@ -654,7 +766,7 @@ end cache.linsolve1 = linres1.cache - @.. broadcast=false cubuff=complex(fw2 - αdt * Mw2 + βdt * Mw3, + @.. cubuff=complex(fw2 - αdt * Mw2 + βdt * Mw3, fw3 - βdt * Mw2 - αdt * Mw3) linsolve2 = cache.linsolve2 @@ -672,8 +784,8 @@ end integrator.stats.nsolve += 2 dw2 = z2 dw3 = z3 - @.. broadcast=false dw2=real(dw23) - @.. broadcast=false dw3=imag(dw23) + @.. dw2=real(dw23) + @.. dw3=imag(dw23) # compute norm of residuals iter > 1 && (ndwprev = ndw) @@ -696,14 +808,14 @@ end end end - @.. broadcast=false w1=w1 - dw1 - @.. broadcast=false w2=w2 - dw2 - @.. broadcast=false w3=w3 - dw3 + @.. w1=w1 - dw1 + @.. w2=w2 - dw2 + @.. w3=w3 - dw3 # transform `w` to `z` - @.. broadcast=false z1=T11 * w1 + T12 * w2 + T13 * w3 - @.. broadcast=false z2=T21 * w1 + T22 * w2 + T23 * w3 - @.. broadcast=false z3=T31 * w1 + w2 # T32 = 1, T33 = 0 + @.. z1=T11 * w1 + T12 * w2 + T13 * w3 + @.. z2=T21 * w1 + T22 * w2 + T23 * w3 + @.. z3=T31 * w1 + w2 # T32 = 1, T33 = 0 # check stopping criterion iter > 1 && (η = θ / (1 - θ)) @@ -723,15 +835,15 @@ end cache.ηold = η cache.iter = iter - @.. broadcast=false u=uprev + z3 + @.. u=uprev + z3 step_limiter!(u, integrator, p, t + dt) if adaptive utilde = w2 e1dt, e2dt, e3dt = e1 / dt, e2 / dt, e3 / dt - @.. broadcast=false tmp=e1dt * z1 + e2dt * z2 + e3dt * z3 + @.. tmp=e1dt * z1 + e2dt * z2 + e3dt * z3 mass_matrix != I && (mul!(w1, mass_matrix, tmp); copyto!(tmp, w1)) - @.. broadcast=false ubuff=integrator.fsalfirst + tmp + @.. ubuff=integrator.fsalfirst + tmp if alg.smooth_est linres1 = dolinsolve(integrator, linres1.cache; b = _vec(ubuff), @@ -747,10 +859,10 @@ end if !(integrator.EEst < oneunit(integrator.EEst)) && integrator.iter == 1 || integrator.u_modified - @.. broadcast=false utilde=uprev + utilde + @.. utilde=uprev + utilde f(fsallast, utilde, p, t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false ubuff=fsallast + tmp + @.. ubuff=fsallast + tmp if alg.smooth_est linres1 = dolinsolve(integrator, linres1.cache; b = _vec(ubuff), @@ -767,10 +879,10 @@ end if integrator.EEst <= oneunit(integrator.EEst) cache.dtprev = dt if alg.extrapolant != :constant - @.. broadcast=false cache.cont1=(z2 - z3) / c2m1 - @.. broadcast=false tmp=(z1 - z2) / c1mc2 - @.. broadcast=false cache.cont2=(tmp - cache.cont1) / c1m1 - @.. broadcast=false cache.cont3=cache.cont2 - (tmp - z1 / c1) / c2 + integrator.k[3] = (z2 - z3) / c2m1 # (c2, z2) and (1, z3) + @.. tmp = (z1 - z2) / c1mc2 + integrator.k[4] = (tmp - integrator.k[3]) / c1m1 + integrator.k[5] = integrator.k[4] - (tmp - z1 / c1) / c2 end end @@ -781,19 +893,22 @@ end @muladd function perform_step!(integrator, cache::RadauIIA9ConstantCache, repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, T33, T34, T35, T41, T42, T43, T44, T45, T51 = cache.tab #= T52 = 1, T53 = 0, T54 = 1, T55 = 0=# - @unpack TI11, TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55 = cache.tab + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, + T33, T34, T35, T41, T42, T43, T44, T45, T51 = cache.tab#= T52 = 1, T53 = 0, T54 = 1, T55 = 0=# + @unpack TI11, + TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, + TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55 = cache.tab @unpack c1, c2, c3, c4, γ, α1, β1, α2, β2, e1, e2, e3, e4, e5 = cache.tab - @unpack κ, cont1, cont2, cont3, cont4, cont5 = cache + @unpack κ = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @unpack maxiters = alg mass_matrix = integrator.f.mass_matrix # precalculations rtol pow is (num stages + 1)/(2*num stages) - rtol = @.. broadcast=false reltol^(3 / 5)/10 - atol = @.. broadcast=false rtol*(abstol / reltol) + rtol = @.. reltol^(3 / 5)/10 + atol = @.. rtol*(abstol / reltol) c1m1 = c1 - 1 c2m1 = c2 - 1 c3m1 = c3 - 1 @@ -821,46 +936,51 @@ end # TODO better initial guess if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant cache.dtprev = one(cache.dtprev) - z1 = w1 = map(zero, u) - z2 = w2 = map(zero, u) - z3 = w3 = map(zero, u) - z4 = w4 = map(zero, u) - z5 = w5 = map(zero, u) - cache.cont1 = map(zero, u) - cache.cont2 = map(zero, u) - cache.cont3 = map(zero, u) - cache.cont4 = map(zero, u) - cache.cont5 = map(zero, u) + z1 = map(zero, u) + z2 = map(zero, u) + z3 = map(zero, u) + z4 = map(zero, u) + z5 = map(zero, u) + w1 = map(zero, u) + w2 = map(zero, u) + w3 = map(zero, u) + w4 = map(zero, u) + w5 = map(zero, u) + integrator.k[3] = map(zero, u) + integrator.k[4] = map(zero, u) + integrator.k[5] = map(zero, u) + integrator.k[6] = map(zero, u) + integrator.k[7] = map(zero, u) else c5′ = dt / cache.dtprev c1′ = c1 * c5′ c2′ = c2 * c5′ c3′ = c3 * c5′ c4′ = c4 * c5′ - z1 = @.. c1′ * (cont1 + - (c1′-c4m1) * (cont2 + - (c1′ - c3m1) * (cont3 + - (c1′ - c2m1) * (cont4 + (c1′ - c1m1) * cont5)))) - z2 = @.. c2′ * (cont1 + - (c2′-c4m1) * (cont2 + - (c2′ - c3m1) * (cont3 + - (c2′ - c2m1) * (cont4 + (c2′ - c1m1) * cont5)))) - z3 = @.. c3′ * (cont1 + - (c3′-c4m1) * (cont2 + - (c3′ - c3m1) * (cont3 + - (c3′ - c2m1) * (cont4 + (c3′ - c1m1) * cont5)))) - z4 = @.. c4′ * (cont1 + - (c4′-c4m1) * (cont2 + - (c4′ - c3m1) * (cont3 + - (c4′ - c2m1) * (cont4 + (c4′ - c1m1) * cont5)))) - z5 = @.. c5′ * (cont1 + - (c5′-c4m1) * (cont2 + - (c5′ - c3m1) * (cont3 + (c5′ - c2m1) * (cont4 + (c5′ - c1m1) * cont5)))) - w1 = @.. broadcast=false TI11*z1+TI12*z2+TI13*z3+TI14*z4+TI15*z5 - w2 = @.. broadcast=false TI21*z1+TI22*z2+TI23*z3+TI24*z4+TI25*z5 - w3 = @.. broadcast=false TI31*z1+TI32*z2+TI33*z3+TI34*z4+TI35*z5 - w4 = @.. broadcast=false TI41*z1+TI42*z2+TI43*z3+TI44*z4+TI45*z5 - w5 = @.. broadcast=false TI51*z1+TI52*z2+TI53*z3+TI54*z4+TI55*z5 + z1 = @.. c1′ * (k[3] + + (c1′-c4m1) * (k[4] + + (c1′ - c3m1) * (k[5] + + (c1′ - c2m1) * (k[6] + (c1′ - c1m1) * k[7])))) + z2 = @.. c2′ * (k[3] + + (c2′-c4m1) * (k[4] + + (c2′ - c3m1) * (k[5] + + (c2′ - c2m1) * (k[6] + (c2′ - c1m1) * k[7])))) + z3 = @.. c3′ * (k[3] + + (c3′-c4m1) * (k[4] + + (c3′ - c3m1) * (k[5] + + (c3′ - c2m1) * (k[6] + (c3′ - c1m1) * k[7])))) + z4 = @.. c4′ * (k[3] + + (c4′-c4m1) * (k[4] + + (c4′ - c3m1) * (k[5] + + (c4′ - c2m1) * (k[6] + (c4′ - c1m1) * k[7])))) + z5 = @.. c5′ * (k[3] + + (c5′-c4m1) * (k[4] + + (c5′ - c3m1) * (k[5] + (c5′ - c2m1) * (k[6] + (c5′ - c1m1) * k[7])))) + w1 = @.. TI11*z1+TI12*z2+TI13*z3+TI14*z4+TI15*z5 + w2 = @.. TI21*z1+TI22*z2+TI23*z3+TI24*z4+TI25*z5 + w3 = @.. TI31*z1+TI32*z2+TI33*z3+TI34*z4+TI35*z5 + w4 = @.. TI41*z1+TI42*z2+TI43*z3+TI44*z4+TI45*z5 + w5 = @.. TI51*z1+TI52*z2+TI53*z3+TI54*z4+TI55*z5 end # Newton iteration @@ -880,18 +1000,18 @@ end ff5 = f(uprev + z5, p, t + dt) # c5 = 1 OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) - fw1 = @.. broadcast=false TI11*ff1+TI12*ff2+TI13*ff3+TI14*ff4+TI15*ff5 - fw2 = @.. broadcast=false TI21*ff1+TI22*ff2+TI23*ff3+TI24*ff4+TI25*ff5 - fw3 = @.. broadcast=false TI31*ff1+TI32*ff2+TI33*ff3+TI34*ff4+TI35*ff5 - fw4 = @.. broadcast=false TI41*ff1+TI42*ff2+TI43*ff3+TI44*ff4+TI45*ff5 - fw5 = @.. broadcast=false TI51*ff1+TI52*ff2+TI53*ff3+TI54*ff4+TI55*ff5 + fw1 = @.. TI11*ff1+TI12*ff2+TI13*ff3+TI14*ff4+TI15*ff5 + fw2 = @.. TI21*ff1+TI22*ff2+TI23*ff3+TI24*ff4+TI25*ff5 + fw3 = @.. TI31*ff1+TI32*ff2+TI33*ff3+TI34*ff4+TI35*ff5 + fw4 = @.. TI41*ff1+TI42*ff2+TI43*ff3+TI44*ff4+TI45*ff5 + fw5 = @.. TI51*ff1+TI52*ff2+TI53*ff3+TI54*ff4+TI55*ff5 if mass_matrix isa UniformScaling # `UniformScaling` doesn't play nicely with broadcast - Mw1 = @.. broadcast=false mass_matrix.λ*w1 - Mw2 = @.. broadcast=false mass_matrix.λ*w2 - Mw3 = @.. broadcast=false mass_matrix.λ*w3 - Mw4 = @.. broadcast=false mass_matrix.λ*w4 - Mw5 = @.. broadcast=false mass_matrix.λ*w5 + Mw1 = @.. mass_matrix.λ*w1 + Mw2 = @.. mass_matrix.λ*w2 + Mw3 = @.. mass_matrix.λ*w3 + Mw4 = @.. mass_matrix.λ*w4 + Mw5 = @.. mass_matrix.λ*w5 else Mw1 = mass_matrix * w1 Mw2 = mass_matrix * w2 @@ -900,14 +1020,14 @@ end Mw5 = mass_matrix * w5 end - rhs1 = @.. broadcast=false fw1-γdt * Mw1 - rhs2 = @.. broadcast=false fw2 - α1dt * Mw2+β1dt * Mw3 - rhs3 = @.. broadcast=false fw3 - β1dt * Mw2-α1dt * Mw3 - rhs4 = @.. broadcast=false fw4 - α2dt * Mw4+β2dt * Mw5 - rhs5 = @.. broadcast=false fw5 - β2dt * Mw4-α2dt * Mw5 + rhs1 = @.. fw1-γdt * Mw1 + rhs2 = @.. fw2 - α1dt * Mw2+β1dt * Mw3 + rhs3 = @.. fw3 - β1dt * Mw2-α1dt * Mw3 + rhs4 = @.. fw4 - α2dt * Mw4+β2dt * Mw5 + rhs5 = @.. fw5 - β2dt * Mw4-α2dt * Mw5 dw1 = _reshape(LU1 \ _vec(rhs1), axes(u)) - dw23 = _reshape(LU2 \ _vec(@.. broadcast=false rhs2+rhs3 * im), axes(u)) - dw45 = _reshape(LU3 \ _vec(@.. broadcast=false rhs4+rhs5 * im), axes(u)) + dw23 = _reshape(LU2 \ _vec(@.. rhs2+rhs3 * im), axes(u)) + dw45 = _reshape(LU3 \ _vec(@.. rhs4+rhs5 * im), axes(u)) integrator.stats.nsolve += 3 dw2 = real(dw23) dw3 = imag(dw23) @@ -936,18 +1056,18 @@ end end end - w1 = @.. broadcast=false w1-dw1 - w2 = @.. broadcast=false w2-dw2 - w3 = @.. broadcast=false w3-dw3 - w4 = @.. broadcast=false w4-dw4 - w5 = @.. broadcast=false w5-dw5 + w1 = @.. w1-dw1 + w2 = @.. w2-dw2 + w3 = @.. w3-dw3 + w4 = @.. w4-dw4 + w5 = @.. w5-dw5 # transform `w` to `z` - z1 = @.. broadcast=false T11*w1+T12*w2+T13*w3+T14*w4+T15*w5 - z2 = @.. broadcast=false T21*w1+T22*w2+T23*w3+T24*w4+T25*w5 - z3 = @.. broadcast=false T31*w1+T32*w2+T33*w3+T34*w4+T35*w5 - z4 = @.. broadcast=false T41*w1+T42*w2+T43*w3+T44*w4+T45*w5 - z5 = @.. broadcast=false T51*w1+w2+w4 #= T52=1, T53=0, T54=1, T55=0 =# + z1 = @.. T11*w1+T12*w2+T13*w3+T14*w4+T15*w5 + z2 = @.. T21*w1+T22*w2+T23*w3+T24*w4+T25*w5 + z3 = @.. T31*w1+T32*w2+T33*w3+T34*w4+T35*w5 + z4 = @.. T41*w1+T42*w2+T43*w3+T44*w4+T45*w5 + z5 = @.. T51*w1+w2+w4#= T52=1, T53=0, T54=1, T55=0 =# # check stopping criterion iter > 1 && (η = θ / (1 - θ)) @@ -968,13 +1088,13 @@ end cache.ηold = η cache.iter = iter - u = @.. broadcast=false uprev+z5 + u = @.. uprev+z5 if adaptive e1dt, e2dt, e3dt, e4dt, e5dt = e1 / dt, e2 / dt, e3 / dt, e4 / dt, e5 / dt - tmp = @.. broadcast=false e1dt*z1+e2dt*z2+e3dt*z3+e4dt*z4+e5dt*z5 + tmp = @.. e1dt*z1+e2dt*z2+e3dt*z3+e4dt*z4+e5dt*z5 mass_matrix != I && (tmp = mass_matrix * tmp) - utilde = @.. broadcast=false integrator.fsalfirst+tmp + utilde = @.. integrator.fsalfirst+tmp if alg.smooth_est utilde = _reshape(LU1 \ _vec(utilde), axes(u)) integrator.stats.nsolve += 1 @@ -986,7 +1106,7 @@ end integrator.u_modified f0 = f(uprev .+ utilde, p, t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - utilde = @.. broadcast=false f0+tmp + utilde = @.. f0+tmp alg.smooth_est && (utilde = LU1 \ utilde; integrator.stats.nsolve += 1) atmp = calculate_residuals(utilde, uprev, u, atol, rtol, internalnorm, t) integrator.EEst = internalnorm(atmp, t) @@ -996,21 +1116,21 @@ end if integrator.EEst <= oneunit(integrator.EEst) cache.dtprev = dt if alg.extrapolant != :constant - cache.cont1 = @.. (z4 - z5) / c4m1 # first derivative on [c4, 1] + integrator.k[3] = (z4 - z5) / c4m1 # first derivative on [c4, 1] tmp1 = @.. (z3 - z4) / c3mc4 # first derivative on [c3, c4] - cache.cont2 = @.. (tmp1 - cache.cont1) / c3m1 # second derivative on [c3, 1] + integrator.k[4] = (tmp1 - integrator.k[3]) / c3m1 # second derivative on [c3, 1] tmp2 = @.. (z2 - z3) / c2mc3 # first derivative on [c2, c3] tmp3 = @.. (tmp2 - tmp1) / c2mc4 # second derivative on [c2, c4] - cache.cont3 = @.. (tmp3 - cache.cont2) / c2m1 # third derivative on [c2, 1] + integrator.k[5] = (tmp3 - integrator.k[4]) / c2m1 # third derivative on [c2, 1] tmp4 = @.. (z1 - z2) / c1mc2 # first derivative on [c1, c2] tmp5 = @.. (tmp4 - tmp2) / c1mc3 # second derivative on [c1, c3] tmp6 = @.. (tmp5 - tmp3) / c1mc4 # third derivative on [c1, c4] - cache.cont4 = @.. (tmp6 - cache.cont3) / c1m1 #fourth derivative on [c1, 1] + integrator.k[6] = (tmp6 - integrator.k[5]) / c1m1 #fourth derivative on [c1, 1] tmp7 = @.. z1 / c1 #first derivative on [0, c1] tmp8 = @.. (tmp4 - tmp7) / c2 #second derivative on [0, c2] tmp9 = @.. (tmp5 - tmp8) / c3 #third derivative on [0, c3] tmp10 = @.. (tmp6 - tmp9) / c4 #fourth derivative on [0,c4] - cache.cont5 = @.. cache.cont4 - tmp10 #fifth derivative on [0,1] + integrator.k[7] = integrator.k[6] - tmp10 #fifth derivative on [0,1] end end @@ -1023,16 +1143,20 @@ end end @muladd function perform_step!(integrator, cache::RadauIIA9Cache, repeat_step = false) - @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst = integrator - @unpack T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, T33, T34, T35, T41, T42, T43, T44, T45, T51 = cache.tab #= T52 = 1, T53 = 0, T54 = 1, T55 = 0=# - @unpack TI11, TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55 = cache.tab + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst, k = integrator + @unpack T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, + T33, T34, T35, T41, T42, T43, T44, T45, T51 = cache.tab#= T52 = 1, T53 = 0, T54 = 1, T55 = 0=# + @unpack TI11, + TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, + TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55 = cache.tab @unpack c1, c2, c3, c4, γ, α1, β1, α2, β2, e1, e2, e3, e4, e5 = cache.tab - @unpack κ, cont1, cont2, cont3, cont4, cont5 = cache + @unpack κ = cache @unpack z1, z2, z3, z4, z5, w1, w2, w3, w4, w5 = cache @unpack dw1, ubuff, dw23, dw45, cubuff1, cubuff2 = cache @unpack k, k2, k3, k4, k5, fw1, fw2, fw3, fw4, fw5 = cache @unpack J, W1, W2, W3 = cache - @unpack tmp, tmp2, tmp3, tmp4, tmp5, tmp6, atmp, jac_config, linsolve1, linsolve2, linsolve3, rtol, atol, step_limiter! = cache + @unpack tmp, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, atmp, jac_config, + linsolve1, linsolve2, linsolve3, rtol, atol, step_limiter! = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @unpack maxiters = alg @@ -1066,51 +1190,52 @@ end if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant cache.dtprev = one(cache.dtprev) uzero = zero(eltype(u)) - @.. broadcast=false z1=uzero - @.. broadcast=false z2=uzero - @.. broadcast=false z3=uzero - @.. broadcast=false z4=uzero - @.. broadcast=false z5=uzero - @.. broadcast=false w1=uzero - @.. broadcast=false w2=uzero - @.. broadcast=false w3=uzero - @.. broadcast=false w4=uzero - @.. broadcast=false w5=uzero - @.. broadcast=false cache.cont1=uzero - @.. broadcast=false cache.cont2=uzero - @.. broadcast=false cache.cont3=uzero - @.. broadcast=false cache.cont4=uzero - @.. broadcast=false cache.cont5=uzero + @.. z1=uzero + @.. z2=uzero + @.. z3=uzero + @.. z4=uzero + @.. z5=uzero + @.. w1=uzero + @.. w2=uzero + @.. w3=uzero + @.. w4=uzero + @.. w5=uzero + integrator.k[3] = map(zero, u) + integrator.k[4] = map(zero, u) + integrator.k[5] = map(zero, u) + integrator.k[6] = map(zero, u) + integrator.k[7] = map(zero, u) else c5′ = dt / cache.dtprev c1′ = c1 * c5′ c2′ = c2 * c5′ c3′ = c3 * c5′ c4′ = c4 * c5′ - z1 = @.. c1′ * (cont1 + - (c1′-c4m1) * (cont2 + - (c1′ - c3m1) * (cont3 + - (c1′ - c2m1) * (cont4 + (c1′ - c1m1) * cont5)))) - z2 = @.. c2′ * (cont1 + - (c2′-c4m1) * (cont2 + - (c2′ - c3m1) * (cont3 + - (c2′ - c2m1) * (cont4 + (c2′ - c1m1) * cont5)))) - z3 = @.. c3′ * (cont1 + - (c3′-c4m1) * (cont2 + - (c3′ - c3m1) * (cont3 + - (c3′ - c2m1) * (cont4 + (c3′ - c1m1) * cont5)))) - z4 = @.. c4′ * (cont1 + - (c4′-c4m1) * (cont2 + - (c4′ - c3m1) * (cont3 + - (c4′ - c2m1) * (cont4 + (c4′ - c1m1) * cont5)))) - z5 = @.. c5′ * (cont1 + - (c5′-c4m1) * (cont2 + - (c5′ - c3m1) * (cont3 + (c5′ - c2m1) * (cont4 + (c5′ - c1m1) * cont5)))) - w1 = @.. broadcast=false TI11*z1+TI12*z2+TI13*z3+TI14*z4+TI15*z5 - w2 = @.. broadcast=false TI21*z1+TI22*z2+TI23*z3+TI24*z4+TI25*z5 - w3 = @.. broadcast=false TI31*z1+TI32*z2+TI33*z3+TI34*z4+TI35*z5 - w4 = @.. broadcast=false TI41*z1+TI42*z2+TI43*z3+TI44*z4+TI45*z5 - w5 = @.. broadcast=false TI51*z1+TI52*z2+TI53*z3+TI54*z4+TI55*z5 + @.. z1 = c1′ * (integrator.k[3] + + (c1′-c4m1) * (integrator.k[4] + + (c1′ - c3m1) * (integrator.k[5] + + (c1′ - c2m1) * (integrator.k[6] + (c1′ - c1m1) * integrator.k[7])))) + @.. z2 = c2′ * (integrator.k[3] + + (c2′-c4m1) * (integrator.k[4] + + (c2′ - c3m1) * (integrator.k[5] + + (c2′ - c2m1) * (integrator.k[6] + (c2′ - c1m1) * integrator.k[7])))) + @.. z3 = c3′ * (integrator.k[3] + + (c3′-c4m1) * (integrator.k[4] + + (c3′ - c3m1) * (integrator.k[5] + + (c3′ - c2m1) * (integrator.k[6] + (c3′ - c1m1) * integrator.k[7])))) + @.. z4 = c4′ * (integrator.k[3] + + (c4′-c4m1) * (integrator.k[4] + + (c4′ - c3m1) * (integrator.k[5] + + (c4′ - c2m1) * (integrator.k[6] + (c4′ - c1m1) * integrator.k[7])))) + @.. z5 = c5′ * (integrator.k[3] + + (c5′-c4m1) * (integrator.k[4] + + (c5′ - c3m1) * (integrator.k[5] + + (c5′ - c2m1) * (integrator.k[6] + (c5′ - c1m1) * integrator.k[7])))) + @.. w1 = TI11*z1+TI12*z2+TI13*z3+TI14*z4+TI15*z5 + @.. w2 = TI21*z1+TI22*z2+TI23*z3+TI24*z4+TI25*z5 + @.. w3 = TI31*z1+TI32*z2+TI33*z3+TI34*z4+TI35*z5 + @.. w4 = TI41*z1+TI42*z2+TI43*z3+TI44*z4+TI45*z5 + @.. w5 = TI51*z1+TI52*z2+TI53*z3+TI54*z4+TI55*z5 end # Newton iteration @@ -1123,28 +1248,28 @@ end integrator.stats.nnonliniter += 1 # evaluate function - @.. broadcast=false tmp=uprev + z1 + @.. tmp=uprev + z1 f(fsallast, tmp, p, t + c1 * dt) - @.. broadcast=false tmp=uprev + z2 + @.. tmp=uprev + z2 f(k2, tmp, p, t + c2 * dt) - @.. broadcast=false tmp=uprev + z3 + @.. tmp=uprev + z3 f(k3, tmp, p, t + c3 * dt) - @.. broadcast=false tmp=uprev + z4 + @.. tmp=uprev + z4 f(k4, tmp, p, t + c4 * dt) - @.. broadcast=false tmp=uprev + z5 + @.. tmp=uprev + z5 f(k5, tmp, p, t + dt) # c5 = 1 OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) - @.. broadcast=false fw1=TI11 * fsallast + TI12 * k2 + TI13 * k3 + TI14 * k4 + - TI15 * k5 - @.. broadcast=false fw2=TI21 * fsallast + TI22 * k2 + TI23 * k3 + TI24 * k4 + - TI25 * k5 - @.. broadcast=false fw3=TI31 * fsallast + TI32 * k2 + TI33 * k3 + TI34 * k4 + - TI35 * k5 - @.. broadcast=false fw4=TI41 * fsallast + TI42 * k2 + TI43 * k3 + TI44 * k4 + - TI45 * k5 - @.. broadcast=false fw5=TI51 * fsallast + TI52 * k2 + TI53 * k3 + TI54 * k4 + - TI55 * k5 + @.. fw1=TI11 * fsallast + TI12 * k2 + TI13 * k3 + TI14 * k4 + + TI15 * k5 + @.. fw2=TI21 * fsallast + TI22 * k2 + TI23 * k3 + TI24 * k4 + + TI25 * k5 + @.. fw3=TI31 * fsallast + TI32 * k2 + TI33 * k3 + TI34 * k4 + + TI35 * k5 + @.. fw4=TI41 * fsallast + TI42 * k2 + TI43 * k3 + TI44 * k4 + + TI45 * k5 + @.. fw5=TI51 * fsallast + TI52 * k2 + TI53 * k3 + TI54 * k4 + + TI55 * k5 if mass_matrix === I Mw1 = w1 @@ -1176,53 +1301,59 @@ end Mw5 = z5 end - @.. broadcast=false ubuff=fw1 - γdt * Mw1 + @.. ubuff=fw1 - γdt * Mw1 needfactor = iter == 1 && new_W linsolve1 = cache.linsolve1 if needfactor - linres1 = dolinsolve(integrator, linsolve1; A = W1, b = _vec(ubuff), linu = _vec(dw1)) + linres1 = dolinsolve( + integrator, linsolve1; A = W1, b = _vec(ubuff), linu = _vec(dw1)) else - linres1 = dolinsolve(integrator, linsolve1; A = nothing, b = _vec(ubuff), linu = _vec(dw1)) + linres1 = dolinsolve( + integrator, linsolve1; A = nothing, b = _vec(ubuff), linu = _vec(dw1)) end cache.linsolve1 = linres1.cache - @.. broadcast=false cubuff1=complex( + @.. cubuff1=complex( fw2 - α1dt * Mw2 + β1dt * Mw3, fw3 - β1dt * Mw2 - α1dt * Mw3) linsolve2 = cache.linsolve2 if needfactor - linres2 = dolinsolve(integrator, linsolve2; A = W2, b = _vec(cubuff1), linu = _vec(dw23)) + linres2 = dolinsolve( + integrator, linsolve2; A = W2, b = _vec(cubuff1), linu = _vec(dw23)) else - linres2 = dolinsolve(integrator, linsolve2; A = nothing, b = _vec(cubuff1), linu = _vec(dw23)) + linres2 = dolinsolve( + integrator, linsolve2; A = nothing, b = _vec(cubuff1), linu = _vec(dw23)) end cache.linsolve2 = linres2.cache - @.. broadcast=false cubuff2=complex( + @.. cubuff2=complex( fw4 - α2dt * Mw4 + β2dt * Mw5, fw5 - β2dt * Mw4 - α2dt * Mw5) linsolve3 = cache.linsolve3 if needfactor - linres3 = dolinsolve(integrator, linsolve3; A = W3, b = _vec(cubuff2), linu = _vec(dw45)) + linres3 = dolinsolve( + integrator, linsolve3; A = W3, b = _vec(cubuff2), linu = _vec(dw45)) else - linres3 = dolinsolve(integrator, linsolve3; A = nothing, b = _vec(cubuff2), linu = _vec(dw45)) + linres3 = dolinsolve( + integrator, linsolve3; A = nothing, b = _vec(cubuff2), linu = _vec(dw45)) end cache.linsolve3 = linres3.cache integrator.stats.nsolve += 3 dw2 = z2 dw3 = z3 - @.. broadcast=false dw2=real(dw23) - @.. broadcast=false dw3=imag(dw23) + @.. dw2=real(dw23) + @.. dw3=imag(dw23) dw4 = z4 dw5 = z5 - @.. broadcast=false dw4=real(dw45) - @.. broadcast=false dw5=imag(dw45) + @.. dw4=real(dw45) + @.. dw5=imag(dw45) # compute norm of residuals iter > 1 && (ndwprev = ndw) @@ -1250,18 +1381,18 @@ end end end - @.. broadcast=false w1=w1 - dw1 - @.. broadcast=false w2=w2 - dw2 - @.. broadcast=false w3=w3 - dw3 - @.. broadcast=false w4=w4 - dw4 - @.. broadcast=false w5=w5 - dw5 + @.. w1=w1 - dw1 + @.. w2=w2 - dw2 + @.. w3=w3 - dw3 + @.. w4=w4 - dw4 + @.. w5=w5 - dw5 # transform `w` to `z` - @.. broadcast=false z1=T11 * w1 + T12 * w2 + T13 * w3 + T14 * w4 + T15 * w5 - @.. broadcast=false z2=T21 * w1 + T22 * w2 + T23 * w3 + T24 * w4 + T25 * w5 - @.. broadcast=false z3=T31 * w1 + T32 * w2 + T33 * w3 + T34 * w4 + T35 * w5 - @.. broadcast=false z4=T41 * w1 + T42 * w2 + T43 * w3 + T44 * w4 + T45 * w5 - @.. broadcast=false z5=T51 * w1 + w2 + w4 #= T52=1, T53=0, T54=1, T55=0 =# + @.. z1=T11 * w1 + T12 * w2 + T13 * w3 + T14 * w4 + T15 * w5 + @.. z2=T21 * w1 + T22 * w2 + T23 * w3 + T24 * w4 + T25 * w5 + @.. z3=T31 * w1 + T32 * w2 + T33 * w3 + T34 * w4 + T35 * w5 + @.. z4=T41 * w1 + T42 * w2 + T43 * w3 + T44 * w4 + T45 * w5 + @.. z5=T51 * w1 + w2 + w4#= T52=1, T53=0, T54=1, T55=0 =# # check stopping criterion @@ -1283,16 +1414,16 @@ end cache.ηold = η cache.iter = iter - @.. broadcast=false u=uprev + z5 + @.. u=uprev + z5 step_limiter!(u, integrator, p, t + dt) if adaptive utilde = w2 e1dt, e2dt, e3dt, e4dt, e5dt = e1 / dt, e2 / dt, e3 / dt, e4 / dt, e5 / dt - @.. broadcast=false tmp=e1dt * z1 + e2dt * z2 + e3dt * z3 + e4dt * z4 + e5dt * z5 + @.. tmp=e1dt * z1 + e2dt * z2 + e3dt * z3 + e4dt * z4 + e5dt * z5 mass_matrix != I && (mul!(w1, mass_matrix, tmp); copyto!(tmp, w1)) - @.. broadcast=false ubuff=integrator.fsalfirst + tmp + @.. ubuff=integrator.fsalfirst + tmp if alg.smooth_est linres1 = dolinsolve(integrator, linres1.cache; b = _vec(ubuff), @@ -1308,10 +1439,10 @@ end if !(integrator.EEst < oneunit(integrator.EEst)) && integrator.iter == 1 || integrator.u_modified - @.. broadcast=false utilde=uprev + utilde + @.. utilde=uprev + utilde f(fsallast, utilde, p, t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - @.. broadcast=false ubuff=fsallast + tmp + @.. ubuff=fsallast + tmp if alg.smooth_est linres1 = dolinsolve(integrator, linres1.cache; b = _vec(ubuff), @@ -1328,21 +1459,21 @@ end if integrator.EEst <= oneunit(integrator.EEst) cache.dtprev = dt if alg.extrapolant != :constant - cache.cont1 = @.. (z4 - z5) / c4m1 # first derivative on [c4, 1] - tmp1 = @.. (z3 - z4) / c3mc4 # first derivative on [c3, c4] - cache.cont2 = @.. (tmp1 - cache.cont1) / c3m1 # second derivative on [c3, 1] - tmp2 = @.. (z2 - z3) / c2mc3 # first derivative on [c2, c3] - tmp3 = @.. (tmp2 - tmp1) / c2mc4 # second derivative on [c2, c4] - cache.cont3 = @.. (tmp3 - cache.cont2) / c2m1 # third derivative on [c2, 1] - tmp4 = @.. (z1 - z2) / c1mc2 # first derivative on [c1, c2] - tmp5 = @.. (tmp4 - tmp2) / c1mc3 # second derivative on [c1, c3] - tmp6 = @.. (tmp5 - tmp3) / c1mc4 # third derivative on [c1, c4] - cache.cont4 = @.. (tmp6 - cache.cont3) / c1m1 #fourth derivative on [c1, 1] - tmp7 = @.. z1 / c1 #first derivative on [0, c1] - tmp8 = @.. (tmp4 - tmp7) / c2 #second derivative on [0, c2] - tmp9 = @.. (tmp5 - tmp8) / c3 #third derivative on [0, c3] - tmp10 = @.. (tmp6 - tmp9) / c4 #fourth derivative on [0,c4] - cache.cont5 = @.. cache.cont4 - tmp10 #fifth derivative on [0,1] + integrator.k[3] = (z4 - z5) / c4m1 # first derivative on [c4, 1] + @.. tmp = (z3 - z4) / c3mc4 # first derivative on [c3, c4] + integrator.k[4] = (tmp - integrator.k[3]) / c3m1 # second derivative on [c3, 1] + @.. tmp2 = (z2 - z3) / c2mc3 # first derivative on [c2, c3] + @.. tmp3 = (tmp2 - tmp) / c2mc4 # second derivative on [c2, c4] + integrator.k[5] = (tmp3 - integrator.k[4]) / c2m1 # third derivative on [c2, 1] + @.. tmp4 = (z1 - z2) / c1mc2 # first derivative on [c1, c2] + @.. tmp5 = (tmp4 - tmp2) / c1mc3 # second derivative on [c1, c3] + @.. tmp6 = (tmp5 - tmp3) / c1mc4 # third derivative on [c1, c4] + integrator.k[6] = (tmp6 - integrator.k[5]) / c1m1 #fourth derivative on [c1, 1] + @.. tmp7 = z1 / c1 #first derivative on [0, c1] + @.. tmp8 = (tmp4 - tmp7) / c2 #second derivative on [0, c2] + @.. tmp9 = (tmp5 - tmp8) / c3 #third derivative on [0, c3] + @.. tmp10 = (tmp6 - tmp9) / c4 #fourth derivative on [0,c4] + integrator.k[7] = integrator.k[6] - tmp10 #fifth derivative on [0,1] end end @@ -1352,18 +1483,20 @@ end end @muladd function perform_step!(integrator, cache::AdaptiveRadauConstantCache, - repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack T, TI, γ, α, β, c, e, num_stages = cache.tab - @unpack κ, cont = cache + repeat_step = false) + @unpack t, dt, uprev, u, f, p, k = integrator + @unpack tabs, num_stages, index = cache + tab = tabs[index] + @unpack T, TI, γ, α, β, c, e = tab + @unpack κ = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @unpack maxiters = alg mass_matrix = integrator.f.mass_matrix # precalculations rtol pow is (num stages + 1)/(2*num stages) - rtol = @.. broadcast=false reltol^((num_stages + 1) / (num_stages * 2))/10 - atol = @.. broadcast=false rtol*(abstol / reltol) + rtol = @.. reltol^((num_stages + 1) / (num_stages * 2))/10 + atol = @.. rtol*(abstol / reltol) γdt, αdt, βdt = γ / dt, α ./ dt, β ./ dt @@ -1375,14 +1508,14 @@ end LU1 = lu(-γdt * mass_matrix + J) tmp = lu(-(αdt[1] + βdt[1] * im) * mass_matrix + J) end - LU2 = Vector{typeof(tmp)}(undef, (num_stages - 1) ÷ 2) + LU2 = Vector{typeof(tmp)}(undef, (num_stages - 1) ÷ 2) LU2[1] = tmp if u isa Number - for i in 2 : (num_stages - 1) ÷ 2 + for i in 2:((num_stages - 1) ÷ 2) LU2[i] = -(αdt[i] + βdt[i] * im) * mass_matrix + J end else - for i in 2 : (num_stages - 1) ÷ 2 + for i in 2:((num_stages - 1) ÷ 2) LU2[i] = lu(-(αdt[i] + βdt[i] * im) * mass_matrix + J) end end @@ -1392,22 +1525,22 @@ end w = Vector{typeof(u)}(undef, num_stages) if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant cache.dtprev = one(cache.dtprev) - for i in 1 : num_stages + for i in 1:num_stages z[i] = @.. map(zero, u) w[i] = @.. map(zero, u) - cache.cont[i] = @.. map(zero, u) + integrator.k[i + 2] = map(zero, u) end else - c_prime = Vector{typeof(u)}(undef, num_stages) #time stepping - c_prime[num_stages] = @.. dt / cache.dtprev - for i in 1 : num_stages - 1 - c_prime[i] = @.. c[i] * c_prime[num_stages] + c_prime = Vector{typeof(dt)}(undef, num_stages) #time stepping + c_prime[num_stages] = dt / cache.dtprev + for i in 1:(num_stages - 1) + c_prime[i] = c[i] * c_prime[num_stages] end - for i in 1 : num_stages # collocation polynomial - z[i] = @.. cont[num_stages] * (c_prime[i] - c[1] + 1) + cont[num_stages - 1] + for i in 1:num_stages # collocation polynomial + z[i] = @.. k[num_stages + 1] + k[num_stages + 2] * (c_prime[i] - c[1] + 1) j = num_stages - 2 while j > 0 - z[i] = @.. z[i] * (c_prime[i] - c[num_stages - j] + 1) + cont[j] + z[i] = @.. k[j + 2] + z[i] * (c_prime[i] - c[num_stages - j] + 1) j = j - 1 end z[i] = @.. z[i] * c_prime[i] @@ -1416,7 +1549,7 @@ end for i in 1:num_stages w[i] = @.. zero(u) for j in 1:num_stages - w[i] = @.. w[i] + TI[i,j] * z[j] + w[i] = @.. w[i] + TI[i, j] * z[j] end end end @@ -1431,53 +1564,55 @@ end integrator.stats.nnonliniter += 1 # evaluate function - ff = Vector{typeof(u)}(undef, num_stages) - for i in 1 : num_stages - ff[i] = f(uprev + z[i], p, t + c[i] * dt) + #ff = Vector{typeof(u)}(undef, num_stages) + for i in 1:num_stages + z[i] = f(uprev + z[i], p, t + c[i] * dt) end - integrator.stats.nf += num_stages + OrdinaryDiffEqCore.increment_nf!(integrator.stats, num_stages) #fw = TI * ff fw = Vector{typeof(u)}(undef, num_stages) - for i in 1 : num_stages + for i in 1:num_stages fw[i] = @.. zero(u) for j in 1:num_stages - fw[i] = @.. fw[i] + TI[i,j] * ff[j] + fw[i] = @.. fw[i] + TI[i, j] * z[j] end end - Mw = Vector{typeof(u)}(undef, num_stages) + #Mw = Vector{typeof(u)}(undef, num_stages) if mass_matrix isa UniformScaling # `UniformScaling` doesn't play nicely with broadcast - for i in 1 : num_stages - Mw[i] = @.. mass_matrix.λ * w[i] #scaling by eigenvalue + for i in 1:num_stages + z[i] = @.. mass_matrix.λ * w[i] #scaling by eigenvalue end else - Mw = mass_matrix * w #standard multiplication + z = mass_matrix * w #standard multiplication end rhs = Vector{typeof(u)}(undef, num_stages) - rhs[1] = @.. fw[1] - γdt * Mw[1] + rhs[1] = @.. fw[1] - γdt * z[1] i = 2 while i <= num_stages #block by block multiplication - rhs[i] = @.. fw[i] - αdt[i ÷ 2] * Mw[i] + βdt[i ÷ 2] * Mw[i + 1] - rhs[i + 1] = @.. fw[i + 1] - βdt[i ÷ 2] * Mw[i] - αdt[i ÷ 2] * Mw[i + 1] + rhs[i] = @.. fw[i] - αdt[i ÷ 2] * z[i] + βdt[i ÷ 2] * z[i + 1] + rhs[i + 1] = @.. fw[i + 1] - βdt[i ÷ 2] * z[i] - αdt[i ÷ 2] * z[i + 1] i += 2 end - dw = Vector{typeof(u)}(undef, num_stages) - dw[1] = _reshape(LU1 \ _vec(rhs[1]), axes(u)) - for i in 2 :(num_stages + 1) ÷ 2 - tmp = _reshape(LU2[i - 1] \ _vec(@.. rhs[2 * i - 2] + rhs[2 * i - 1] * im), axes(u)) - dw[2 * i - 2] = @.. real(tmp) - dw[2 * i - 1] = @.. imag(tmp) + #dw = Vector{typeof(u)}(undef, num_stages) + z[1] = _reshape(LU1 \ _vec(rhs[1]), axes(u)) + for i in 2:((num_stages + 1) ÷ 2) + tmp = _reshape( + LU2[i - 1] \ _vec(@.. rhs[2 * i - 2] + rhs[2 * i - 1] * im), axes(u)) + z[2 * i - 2] = @.. real(tmp) + z[2 * i - 1] = @.. imag(tmp) end - integrator.stats.nsolve +=(num_stages + 1) ÷ 2 + integrator.stats.nsolve += (num_stages + 1) ÷ 2 # compute norm of residuals iter > 1 && (ndwprev = ndw) ndw = 0.0 - for i in 1 : num_stages - ndw += internalnorm(calculate_residuals(dw[i], uprev, u, atol, rtol, internalnorm, t), t) + for i in 1:num_stages + ndw += internalnorm( + calculate_residuals(z[i], uprev, u, atol, rtol, internalnorm, t), t) end # check divergence (not in initial step) @@ -1491,17 +1626,17 @@ end break end end - - for i in 1 : num_stages - w[i] = @.. w[i] - dw[i] + + for i in 1:num_stages + w[i] = @.. w[i] - z[i] end # transform `w` to `z` #z = T * w - for i in 1:num_stages - 1 + for i in 1:(num_stages - 1) z[i] = @.. zero(u) for j in 1:num_stages - z[i] = @.. z[i] + T[i,j] * w[j] + z[i] = @.. z[i] + T[i, j] * w[j] end end z[num_stages] = @.. T[num_stages, 1] * w[1] @@ -1511,13 +1646,12 @@ end i += 2 end - # check stopping criterion iter > 1 && (η = θ / (1 - θ)) if η * ndw < κ && (iter > 1 || iszero(ndw) || !iszero(integrator.success_iter)) # Newton method converges cache.status = η < alg.fast_convergence_cutoff ? FastConvergence : - Convergence + Convergence fail_convergence = false break end @@ -1532,12 +1666,15 @@ end cache.iter = iter u = @.. uprev + z[num_stages] - + if adaptive - edt = e ./ dt - tmp = dot(edt, z) + tmp = 0 + for i in 1:num_stages + tmp = @.. tmp + e[i] / dt * z[i] + end mass_matrix != I && (tmp = mass_matrix * tmp) - utilde = @.. broadcast=false 1 / γ * dt * integrator.fsalfirst+tmp + #utilde = @.. 1 / γ * dt * integrator.fsalfirst + tmp + utilde = @.. integrator.fsalfirst+tmp if alg.smooth_est utilde = _reshape(LU1 \ _vec(utilde), axes(u)) integrator.stats.nsolve += 1 @@ -1546,10 +1683,11 @@ end integrator.EEst = internalnorm(atmp, t) if !(integrator.EEst < oneunit(integrator.EEst)) && integrator.iter == 1 || - integrator.u_modified + integrator.u_modified f0 = f(uprev .+ utilde, p, t) - integrator.stats.nf += 1 - utilde = @.. broadcast=false 1 / γ * dt * f0 + tmp + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + #utilde = @.. 1 / γ * dt * f0 + tmp + utilde = @.. f0+tmp if alg.smooth_est utilde = _reshape(LU1 \ _vec(utilde), axes(u)) integrator.stats.nsolve += 1 @@ -1563,18 +1701,20 @@ end cache.dtprev = dt if alg.extrapolant != :constant derivatives = Matrix{typeof(u)}(undef, num_stages, num_stages) - derivatives[1, 1] = @.. z[1] / c[1] - for j in 2 : num_stages + derivatives[1, 1] = @.. z[1] / c[1] + for j in 2:num_stages derivatives[1, j] = @.. (z[j - 1] - z[j]) / (c[j - 1] - c[j]) #first derivatives end - for i in 2 : num_stages - derivatives[i, i] = @.. (derivatives[i - 1, i] - derivatives[i - 1, i - 1]) / c[i] - for j in i+1 : num_stages - derivatives[i, j] = @.. (derivatives[i - 1, j - 1] - derivatives[i - 1, j]) / (c[j - i] - c[j]) #all others + for i in 2:num_stages + derivatives[i, i] = @.. (derivatives[i - 1, i] - + derivatives[i - 1, i - 1]) / c[i] + for j in (i + 1):num_stages + derivatives[i, j] = @.. (derivatives[i - 1, j - 1] - + derivatives[i - 1, j]) / (c[j - i] - c[j]) #all others end end - for i in 1 : num_stages - cache.cont[i] = @.. derivatives[i, num_stages] + for i in 1:num_stages + integrator.k[i + 2] = derivatives[i, num_stages] end end end @@ -1588,11 +1728,13 @@ end end @muladd function perform_step!(integrator, cache::AdaptiveRadauCache, repeat_step = false) - @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst = integrator - @unpack T, TI, γ, α, β, c, e, num_stages = cache.tab - @unpack κ, cont, derivatives, z, w, c_prime = cache + @unpack t, dt, uprev, u, f, p, fsallast, fsalfirst, k = integrator + @unpack num_stages, tabs, index = cache + tab = tabs[index] + @unpack T, TI, γ, α, β, c, e = tab + @unpack κ, derivatives, z, w, c_prime, αdt, βdt = cache @unpack dw1, ubuff, dw2, cubuff, dw = cache - @unpack ks, k, fw, J, W1, W2 = cache + @unpack ks, fw, J, W1, W2 = cache @unpack tmp, atmp, jac_config, linsolve1, linsolve2, rtol, atol, step_limiter! = cache @unpack internalnorm, abstol, reltol, adaptive = integrator.opts alg = unwrap_alg(integrator, true) @@ -1600,14 +1742,45 @@ end mass_matrix = integrator.f.mass_matrix # precalculations - γdt, αdt, βdt = γ / dt, α ./ dt, β ./ dt + γdt = γ / dt + for i in 1:((num_stages - 1) ÷ 2) + αdt[i] = α[i] / dt + βdt[i] = β[i] / dt + end + + if integrator.opts.adaptive + @unpack abstol, reltol = integrator.opts + if reltol isa Number + cache.rtol = reltol^((num_stages + 1) / (2 * num_stages)) / 10 + cache.atol = cache.rtol * (abstol / reltol) + else + @.. cache.rtol=reltol^((num_stages + 1) / (2 * num_stages)) / 10 + @.. cache.atol=cache.rtol * (abstol / reltol) + end + end + (new_jac = do_newJ(integrator, alg, cache, repeat_step)) && (calc_J!(J, integrator, cache); cache.W_γdt = dt) if (new_W = do_newW(integrator, alg, new_jac, cache.W_γdt)) @inbounds for II in CartesianIndices(J) W1[II] = -γdt * mass_matrix[Tuple(II)...] + J[II] - for i in 1 :(num_stages - 1) ÷ 2 - W2[i][II] = -(αdt[i] + βdt[i] * im) * mass_matrix[Tuple(II)...] + J[II] + end + if !isthreaded(alg.threading) + @inbounds for II in CartesianIndices(J) + for i in 1:((num_stages - 1) ÷ 2) + W2[i][II] = -(αdt[i] + βdt[i] * im) * mass_matrix[Tuple(II)...] + J[II] + end + end + else + let W1 = W1, W2 = W2, γdt = γdt, αdt = αdt, βdt = βdt, + mass_matrix = mass_matrix, num_stages = num_stages, J = J + + @inbounds @threaded alg.threading for i in 1:((num_stages - 1) ÷ 2) + for II in CartesianIndices(J) + W2[i][II] = -(αdt[i] + βdt[i] * im) * mass_matrix[Tuple(II)...] + + J[II] + end + end end end integrator.stats.nw += 1 @@ -1616,21 +1789,22 @@ end # TODO better initial guess if integrator.iter == 1 || integrator.u_modified || alg.extrapolant == :constant cache.dtprev = one(cache.dtprev) - for i in 1 : num_stages + for i in 1:num_stages @.. z[i] = map(zero, u) @.. w[i] = map(zero, u) - @.. cache.cont[i] = map(zero, u) + integrator.k[i + 2] = map(zero, u) end else c_prime[num_stages] = dt / cache.dtprev - for i in 1 : num_stages - 1 + for i in 1:(num_stages - 1) c_prime[i] = c[i] * c_prime[num_stages] end - for i in 1 : num_stages # collocation polynomial - @.. z[i] = cont[num_stages] * (c_prime[i] - c[1] + 1) + cont[num_stages - 1] + for i in 1:num_stages # collocation polynomial + @.. z[i] = k[num_stages + 2] * (c_prime[i] - c[1] + 1) + k[num_stages + 1] j = num_stages - 2 while j > 0 - @.. z[i] *= (c_prime[i] - c[num_stages - j] + 1) + cont[j] + @.. z[i] *= (c_prime[i] - c[num_stages - j] + 1) + @.. z[i] += k[j + 2] j = j - 1 end @.. z[i] *= c_prime[i] @@ -1639,7 +1813,7 @@ end for i in 1:num_stages @.. w[i] = zero(u) for j in 1:num_stages - @.. w[i] += TI[i,j] * z[j] + @.. w[i] += TI[i, j] * z[j] end end end @@ -1655,29 +1829,29 @@ end # evaluate function ks[1] = fsallast - for i in 1 : num_stages + for i in 1:num_stages @.. tmp = uprev + z[i] f(ks[i], tmp, p, t + c[i] * dt) end - integrator.stats.nf += num_stages + OrdinaryDiffEqCore.increment_nf!(integrator.stats, num_stages) #mul!(fw, TI, ks) for i in 1:num_stages - fw[i] = @.. zero(u) + @.. fw[i] = zero(u) for j in 1:num_stages - fw[i] = @.. fw[i] + TI[i,j] * ks[j] + @.. fw[i] += TI[i, j] * ks[j] end end if mass_matrix === I Mw = w elseif mass_matrix isa UniformScaling - for i in 1 : num_stages - mul!(z[i], mass_matrix.λ, w[i]) + for i in 1:num_stages + mul!(z[i], mass_matrix.λ, w[i]) end Mw = z else - for i in 1 : num_stages + for i in 1:num_stages mul!(z[i], mass_matrix, w[i]) end Mw = z @@ -1686,42 +1860,61 @@ end @.. ubuff = fw[1] - γdt * Mw[1] needfactor = iter == 1 && new_W - linsolve1 = cache.linsolve1 if needfactor - linres = dolinsolve(integrator, linsolve1; A = W1, b = _vec(ubuff), linu = _vec(dw1)) + cache.linsolve1 = dolinsolve( + integrator, linsolve1; A = W1, b = _vec(ubuff), linu = _vec(dw1)).cache else - linres = dolinsolve(integrator, linsolve1; A = nothing, b = _vec(ubuff), linu = _vec(dw1)) - end - - cache.linsolve1 = linres.cache - - linres2 = Vector{Any}(undef,(num_stages - 1) ÷ 2) - - for i in 1 :(num_stages - 1) ÷ 2 - @.. cubuff[i]=complex( - fw[2 * i] - αdt[i] * Mw[2 * i] + βdt[i] * Mw[2 * i + 1], fw[2 * i + 1] - βdt[i] * Mw[2 * i] - αdt[i] * Mw[2 * i + 1]) - if needfactor - linres2[i] = dolinsolve(integrator, linsolve2[i]; A = W2[i], b = _vec(cubuff[i]), linu = _vec(dw2[i])) - else - linres2[i] = dolinsolve(integrator, linsolve2[i]; A = nothing, b = _vec(cubuff[i]), linu = _vec(dw2[i])) + cache.linsolve1 = dolinsolve( + integrator, linsolve1; A = nothing, b = _vec(ubuff), linu = _vec(dw1)).cache + end + + if !isthreaded(alg.threading) + for i in 1:((num_stages - 1) ÷ 2) + @.. cubuff[i] = complex( + fw[2 * i] - αdt[i] * Mw[2 * i] + βdt[i] * Mw[2 * i + 1], + fw[2 * i + 1] - βdt[i] * Mw[2 * i] - αdt[i] * Mw[2 * i + 1]) + if needfactor + cache.linsolve2[i] = dolinsolve(integrator, linsolve2[i]; A = W2[i], + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + else + cache.linsolve2[i] = dolinsolve(integrator, linsolve2[i]; A = nothing, + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + end + end + else + let integrator = integrator, linsolve2 = linsolve2, fw = fw, αdt = αdt, + βdt = βdt, Mw = Mw, W1 = W1, W2 = W2, cubuff = cubuff, dw2 = dw2, + needfactor = needfactor + + @threaded alg.threading for i in 1:((num_stages - 1) ÷ 2) + @.. cubuff[i] = complex( + fw[2 * i] - αdt[i] * Mw[2 * i] + βdt[i] * Mw[2 * i + 1], + fw[2 * i + 1] - βdt[i] * Mw[2 * i] - αdt[i] * Mw[2 * i + 1]) + if needfactor + cache.linsolve2[i] = dolinsolve( + integrator, linsolve2[i]; A = W2[i], + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + else + cache.linsolve2[i] = dolinsolve( + integrator, linsolve2[i]; A = nothing, + b = _vec(cubuff[i]), linu = _vec(dw2[i])).cache + end + end end - cache.linsolve2[i] = linres2[i].cache end integrator.stats.nsolve += (num_stages + 1) / 2 - for i in 1 : (num_stages - 1) ÷ 2 - dw[2 * i - 1] = z[2 * i - 1] - dw[2 * i] = z[2 * i] - dw[2 * i - 1] = real(dw2[i]) - dw[2 * i] = imag(dw2[i]) + for i in 1:((num_stages - 1) ÷ 2) + @.. dw[2 * i - 1] = real(dw2[i]) + @.. dw[2 * i] = imag(dw2[i]) end # compute norm of residuals iter > 1 && (ndwprev = ndw) calculate_residuals!(atmp, dw1, uprev, u, atol, rtol, internalnorm, t) ndw = internalnorm(atmp, t) - for i in 2 : num_stages + for i in 2:num_stages calculate_residuals!(atmp, dw[i - 1], uprev, u, atol, rtol, internalnorm, t) ndw += internalnorm(atmp, t) end @@ -1738,23 +1931,23 @@ end end end - @.. w[1] = w[1] - dw1 - for i in 2 : num_stages + @.. w[1] = w[1] - dw1 + for i in 2:num_stages @.. w[i] = w[i] - dw[i - 1] end # transform `w` to `z` #mul!(z, T, w) - for i in 1:num_stages - 1 - z[i] = @.. zero(u) + for i in 1:(num_stages - 1) + @.. z[i] = zero(u) for j in 1:num_stages - z[i] = @.. z[i] + T[i,j] * w[j] + @.. z[i] += T[i, j] * w[j] end end - z[num_stages] = @.. T[num_stages, 1] * w[1] + @.. z[num_stages] = T[num_stages, 1] * w[1] i = 2 while i < num_stages - z[num_stages] = @.. z[num_stages] + w[i] + @.. z[num_stages] += w[i] i += 2 end @@ -1777,21 +1970,23 @@ end cache.ηold = η cache.iter = iter - @.. broadcast=false u=uprev + z[num_stages] + @.. u=uprev + z[num_stages] step_limiter!(u, integrator, p, t + dt) - + if adaptive - utilde = w2 - edt = e./dt - @.. tmp = dot(edt, z) + 1 / γ * dt * fsalfirst - mass_matrix != I && (mul!(w1, mass_matrix, tmp); copyto!(tmp, w1)) + utilde = w[2] + @.. tmp = 0 + for i in 1:num_stages + @.. tmp += e[i] / dt * z[i] + end + mass_matrix != I && (mul!(w[1], mass_matrix, tmp); copyto!(tmp, w[1])) + #@.. ubuff=1 / γ * dt * integrator.fsalfirst + tmp @.. ubuff=integrator.fsalfirst + tmp if alg.smooth_est - linres1 = dolinsolve(integrator, linres1.cache; b = _vec(ubuff), - linu = _vec(utilde)) - cache.linsolve1 = linres1.cache + cache.linsolve1 = dolinsolve(integrator, linsolve1; b = _vec(ubuff), + linu = _vec(utilde)).cache integrator.stats.nsolve += 1 end @@ -1802,15 +1997,15 @@ end if !(integrator.EEst < oneunit(integrator.EEst)) && integrator.iter == 1 || integrator.u_modified - @.. broadcast=false utilde=uprev + utilde + @.. utilde=uprev + utilde f(fsallast, utilde, p, t) - integrator.stats.nf += 1 - @.. broadcast=false ubuff=fsallast + tmp + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + #@.. ubuff = 1 / γ * dt * fsallast + tmp + @.. ubuff=fsallast + tmp if alg.smooth_est - linres1 = dolinsolve(integrator, linres1.cache; b = _vec(ubuff), - linu = _vec(utilde)) - cache.linsolve1 = linres1.cache + cache.linsolve1 = dolinsolve(integrator, linsolve1; b = _vec(ubuff), + linu = _vec(utilde)).cache integrator.stats.nsolve += 1 end @@ -1823,17 +2018,19 @@ end cache.dtprev = dt if alg.extrapolant != :constant @.. derivatives[1, 1] = z[1] / c[1] - for j in 2 : num_stages + for j in 2:num_stages @.. derivatives[1, j] = (z[j - 1] - z[j]) / (c[j - 1] - c[j]) #first derivatives end - for i in 2 : num_stages - @.. derivatives[i, i] = (derivatives[i - 1, i] - derivatives[i - 1, i - 1]) / c[i] - for j in i+1 : num_stages - @.. derivatives[i, j] = (derivatives[i - 1, j - 1] - derivatives[i - 1, j]) / (c[j - i] - c[j]) #all others + for i in 2:num_stages + @.. derivatives[i, i] = (derivatives[i - 1, i] - + derivatives[i - 1, i - 1]) / c[i] + for j in (i + 1):num_stages + @.. derivatives[i, j] = (derivatives[i - 1, j - 1] - + derivatives[i - 1, j]) / (c[j - i] - c[j]) #all others end end - for i in 1 : num_stages - cache.cont[i] = derivatives[i, num_stages] + for i in 1:num_stages + integrator.k[i + 2] = derivatives[i, num_stages] end end end diff --git a/lib/OrdinaryDiffEqFIRK/src/firk_tableaus.jl b/lib/OrdinaryDiffEqFIRK/src/firk_tableaus.jl index 750a9a0b34..73e25c9d2a 100644 --- a/lib/OrdinaryDiffEqFIRK/src/firk_tableaus.jl +++ b/lib/OrdinaryDiffEqFIRK/src/firk_tableaus.jl @@ -43,7 +43,7 @@ struct RadauIIA5Tableau{T, T2} T22::T T23::T T31::T - #T32::T + #T32::T #T33::T TI11::T TI12::T @@ -104,148 +104,15 @@ function RadauIIA5Tableau(T, T2) e1 = convert(T, -(13 + 7 * sqrt6) / 3) e2 = convert(T, (-13 + 7 * sqrt6) / 3) e3 = convert(T, -1 / 3) - RadauIIA5Tableau{T, T2}(T11, T12, T13, T21, T22, T23, T31, #= T33 = 0 =# + RadauIIA5Tableau{T, T2}(T11, T12, T13, T21, T22, T23, T31, + #= T33 = 0 =# TI11, TI12, TI13, TI21, TI22, TI23, TI31, TI32, TI33, - c1, c2, #= c3 = 1 =# + c1, c2, + #= c3 = 1 =# γ, α, β, e1, e2, e3) end -struct RadauIIATableau{T1, T2} - T::Matrix{T1} - TI::Matrix{T1} - c::Vector{T2} - γ::T1 - α::Vector{T1} - β::Vector{T1} - e::Vector{T1} - num_stages::Int -end - -function BigRadauIIA5Tableau(T1, T2) - γ = convert(T1, big"3.63783425274449573220841851357777579794593608687391153215117488565841871456727143375130115708511223004183651123208497057248238260532214672028700625775335843") - α = Vector{T1}(undef, 1) - β = Vector{T1}(undef, 1) - α[1] = big"2.68108287362775213389579074321111210102703195656304423392441255717079064271636428312434942145744388497908174438395751471375880869733892663985649687112332242" - β[1] = big"3.05043019924741056942637762478756790444070419917947659226291744751211727051786694870515117615266028855554735929171362769761399150862332538376382934625577549" - - c = Vector{T2}(undef, 3) - c[1] = big"0.155051025721682190180271592529410860803405251934332987156730743274903962254268497346014056689535976518140539877338581087514113454016224265837421604876272084" - c[2] = big"0.644948974278317809819728407470589139196594748065667012843269256725096037745731502653985943310464023481859460122661418912485886545983775734162578395123729143" - c[3] = big"1" - - e = Vector{T1}(undef, 3) - e[1] = big"-0.428298294115368098113417591057340987284723986878723769598436582629558514867595819404541110575367601847354683220540647741034052880983125451920841851066713815" - e[2] = big"0.245039074384916438547779982042524963814308131639809054920681599475247366387530452311400517264433163448821319862243292031101333835037542080594323438762615605" - e[3] = big"-0.0916296098652259003910911359018870983677439465358993542342383692664256286871842771687905889462502859518430848371143253189423645209875225522045944109790661043" - - TI = Matrix{T1}(undef, 3, 3) - TI[1, 1] = big"4.32557989006315535102435095295614882731995158490590784287320458848019483341979047442263696495019938973156007686663488090615420049217658854859024016717169837" - TI[1, 2] = big"0.339199251815809869542824974053410987511771566126056902312311333553438988409693737874718833892037643701271502187763370262948704203562215007824701228014200056" - TI[1, 3] = big"0.541770539935874871186523033492089631898841317849243944095021379289933921771713116368931784890546144473788347538203807242114936998948954098533375649163016612" - TI[2, 1] = big"-4.17871859155190472734646265851205623000038388214686525896709481539843195209360778128456932548583273459040707932166364293012713818843609182148794380267482041" - TI[2, 2] = big"-0.327682820761062387082533272429616234245791838308340887801415258608836530255609335712523838667242449344879454518796849992049787172023800373390124427898159896" - TI[2, 3] = big"0.476623554500550451960069084091012497939942928625055897109833707684876604712862299049343675491204859381277636585708398915065951363736337328178192801074535132" - TI[3, 1] = big"-0.502872634945786875951247343139544292859248429570937886791036339034110181540695221500843782634464164585836226038438397328726973424362168221527501738985822875" - TI[3, 2] = big"2.57192694985560542918678535360167505469448742842178326395573566888176471664393761903447163100353067504020263109067033226021288356347565113471227052083596358" - TI[3, 3] = big"-0.596039204828224924968821911099302403289857517521591823052174732952989090998130905722763344484798508456930766594977798579939415052669401095404149917833710127" - - T = Matrix{T1}(undef, 3, 3) - T[1, 1] = big"0.091232394870892942791548135249436196118684699372210280712184363514099824021240149574725365814781580305065489937969163922775110463056339192206701819661425186" - T[1, 2] = big"-0.141255295020954208427990383807797309409263248498594798844289981408804297900674604638610419147468875667691398225003133444988034605081071965848437945842767211" - T[1 ,3] = big"-0.0300291941051474244918611170890538666683842974606300802563717702200388818691214144173874588956764952224874407424115249418136547481236684478531215095064078994" - T[2, 1] = big"0.241717932707107018957474779310148232884879540532595279746187345714229132659465207414913313803429072060469564350914390845001169448350326344874859416624577348" - T[2, 2] = big"0.204129352293799931995990810298338174086540402523315938937516234649384944528706774788799548853122282827246947911905379230680096946800308693162079538975632443" - T[2, 3] = big"0.382942112757261937795438233599873210357792575012007744255205163027042915338009760005422153613194350161760232119048691964499888989151661861236831969497483828" - T[3, 1] = big"0.966048182615092936190567080794590794996748754810883844283183333914131408744555961195911605614405476210484499875001737558078500322423463946527349731087504518" - T[3, 2] = big"1.0" - T[3, 3] = big"0.0" - RadauIIATableau{T1, T2}(T, TI, - c, γ, α, β, e, 3) -end - -function BigRadauIIA9Tableau(T1, T2) - γ = convert(T1, big"6.28670475172927664517315334186940904959068186655567041187229167532923622489525703260842273089261139845280626287956099768662193453067483410165932355981736786") - α = Vector{T1}(undef, 2) - β = Vector{T1}(undef, 2) - α[1] = big"3.65569432546357225824320796009543385435699888857815445045567025741630720509235614026228963385258117304229337679733945535812317372403535763551850772878775217" - α[2] = big"5.70095329867178941917021536896986162084766017814401034360818390491907468246001534343349900070111312773130349176288004579856585901062722531365183049130382405" - β[1] = big"6.5437368993600772940210715093936863183637851728134458820202187133882261290012752452972782843700946890488789462524897903624959996932392239962196563965573345" - β[2] = big"3.21026560030854988842501065297211721232153653493981008029923647488964744732168461657389754087826565709085773529539707072244537983491480773006949966789260925" - - c = Vector{T2}(undef, 5) - c[1] = big"0.0571041961145176821931211925541156212350779455987501643278082929309346782020731645861138168198427368635148018903413155731609901559772929443100370500757072557" - c[2] = big"0.276843013638123827680045997685625141110889169695030468349442048831121339683708036772541528564051130879197377136636984534220758899839905855114024309075271826" - c[3] = big"0.583590432368916820056697668662917248693432639896771640176293841831747501961831012005632277467456299345321045569611992496682381919275766424103024358378365496" - c[4] = big"0.8602401356562194478479129188751197667383780225872255049242335941839742579301655644134901549264276106897445531811874851737136468026848125542506920602484255" - c[5] = big"1.0" - - e = Vector{T1}(undef, 5) - e[1] = big"-0.239909571163200476817707991076962793618683493830916562279975225042872448414819259070978815977101189851237591634144816820425592764432710089981892023441549743" - e[2] = big"0.125293484229223300606887443525929336197638450194973243323835481816625682669684634271160851996902445722310139152840852195000603355301430153561918341655137084" - e[3] = big"-0.0688288849083782089370741375422279772873399871312158026536514369967825732836040693366396751988019623495452730460577336089848105495733304937016477629621990433" - e[4] = big"0.0372433600301293198267284480468961585078575499935477902539140092558239369583143189611737274891328175087350382605569395937945872776839987254373869550943049195" - e[5] = big"-0.012863950751139890646895902730137465239579845437088427263654957605488133042638147254426913683751171160691603649073170415735165315443538347036196755548109703" - - TI = Matrix{T1}(undef, 5, 5) - TI[1, 1] = big"30.0415677215444016277146611632467970747634862837368422955138470463852339244593400023985957753164599415374157317627305099177616927640413043608408838747985125" - TI[1, 2] = big"13.8651078562714131651762946846279728486098595017962436746405940971751244384714668104145151259298432908422191238542910724677205181071665482818120092330632702" - TI[1 ,3] = big"3.48000277479518556182840016971955819123081637245954095062693470191383865922357339844125383481645392882289968250993872221445874555610460465838129969397069557" - TI[1, 4] = big"-1.03200879782526342277108071214631493513824682491749273908106331923801396656058254294323988505859654767877050109789490714699847664805679842903430004696170252" - TI[1, 5] = big"0.804303045073989917475330383606196086089578671788707543063308602519859970319818304759856653218877415405946945572102875643297890954688508528143272905631829894" - TI[2, 1] = big"5.34418643783491159889531030409736033885455686563071401172022718575590068536629704134603404624953791012861634674294690788961703408019660066685859393456498931" - TI[2, 2] = big"4.59361556775916100445407449817656238428260055301676371438973411021009514435572975394999086474831271997070798032181411537895658457000537727156665947774751386" - TI[2, 3] = big"-3.03636032345942429864615756872018980250277648141683630832856906288036929718223473102394179699607901856890769270810252103326382063852039607285826867723587514" - TI[2, 4] = big"1.05066019023145886385983615715299311307615150447133905233370933194949591737765763708886464382722316727972166443876395823044171403663404254906698768838255919" - TI[2, 5] = big"-0.272778611864296270538614649997366804891835224042737605275699398413256470423268908248569612750117948720141667949532252500428432062582365619208502333677907158" - TI[3, 1] = big"3.74805980743980486005103450189256983678052751095791526209741655305580351377124372457009580386663275146166007984852101733055495783906881063060757645038080343" - TI[3, 2] = big"-3.98496573634388466725226385805351110838575115293851360514636734529255361185420464416807882769853298186283398369873418552760618971047757002216338511286260041" - TI[3, 3] = big"-1.04441564160801879294224732309562532189841624726401645191058551173485917137499204844819781779667611903670073971659834929382224472890100209497741235960707456" - TI[3, 4] = big"1.18409856813794848723102038838340482030291345603197522521517834943166421242518751666675199211369552058487095283489346390066317584532997854692445653563909898" - TI[3, 5] = big"-0.449917770156780368898811918314095435942113881883174152777026977062686286863549565130412864190301081537983106397709991028107600781961279985605930655683680139" - TI[4, 1] = big"-33.0418802135190000080614469426109507742858088371383868670878639187564531424382858814386742148456699143328462132296293097447566408853495288807407929988004676" - TI[4, 2] = big"-17.3769534790635670194549806058987105852733409102703844354448800193942184746909147697382687117638715195698950138089979798321855885541817752366521518811413713" - TI[4, 3] = big"-0.172129063254005561151528806427751383749451500597823574207174433146207178559871803504021077429693091164540897873472803934375603405253541639437370184767553293" - TI[4, 4] = big"-0.0991697779825426425881662214017368584726354746776989845479783944003623924121748016326495070834800297497011104846871751430208559227945252758721362340763610828" - TI[4, 5] = big"0.531228115838306667184911422606024795426589562580669892779793097035561488973256023529352389498509937781553683467106048413485632583844632286562240161995145055" - TI[5, 1] = big"-8.61144397987529197770008251257034851950485933115010902789613925540488896812417081206983938638600226846804467531843522104806738090683710882069500386691775154" - TI[5, 2] = big"9.69999140952880823133589405342003266497120753048627084327055311528684684237122654108691149692242002085965723391934376924400492239317026460192827344970015484" - TI[5, 3] = big"1.91472863969687428485137560339172471528025297511003983469957355306260543484472462223194401768126877615795915146192537091374017807611943419264038682143890747" - TI[5, 4] = big"2.41869200608494002642656343408298350771199306961305597858229870375990977712805399625496435641846363295393762353024017195444763964531237381728801981679934304" - TI[5, 5] = big"-1.0474634879353374186944329992117360176590042540536055452919974336199826846201614544718272622833822842591012529895091659029452542118642301415759073410771819" - - T = Matrix{T1}(undef, 5, 5) - T[1, 1] = big"0.0125175862205010458901356760368001462557655123420858705973577952199246108029451084239310924615007306721702298573083400752464277227557045438770401832498107968" - T[1, 2] = big"-0.0102420478179088270700863300668590125015813934827825923708366359399562125950804289592272678367034071306578383319296130180550178248531589487456925441921649293" - T[1 ,3] = big"0.0476738772902957238631839478592069782970238490568258436986723993118380988311441474394156362952631834786373081794857384127209450988829840886524135970873769918" - T[1, 4] = big"-0.0114785152552295147079415554121555049385506204591245712490409384029671974157542450636658532835395855844059342442518520033304129991000509527123870917346017759" - T[1, 5] = big"-0.0140198588928754102810778942934959307831026572823203692568448424056201483917805257790275956734469193171917730378117501915144713896813544630288006687542182225" - T[2, 1] = big"0.00149167015189538242900444775236282223594625052328927847572623038484966999313257893341818287477809424303168766872838075463220122499449382436194198620498144296" - T[2, 2] = big"0.050172864517371058162991380262646513853120568882725793734131676894272706020317186004736779675826101816279321643304301437029912742375638648226701787880031719" - T[2, 3] = big"-0.0943318191816114369806569003363724471884924328367212069321438749304281980331334016578193750445513659941246363262225907407726099492713722343006925656625258579" - T[2, 4] = big"-0.00766883074918016288515687679203608074116106558796378201472238095295554979920808799930579174190884587422912077296093093698836937450535804218413704866981728518" - T[2, 5] = big"0.024708578426518526812525205377780382655366504554979744093019395818934704623702078004474076773426928900579988063099593288435684744957695210778788200213260272" - T[3, 1] = big"0.072981876388087148622657299703669587832652508881663282287850495621401398441897288250625556038835308015912409648841893161563884759791665776933761278383553608" - T[3, 2] = big"-0.230539534043417946721421862180000422679228296568599014834226319726930529322581417981617275287468418138394077987361681288909676234537699721082090802790143303" - T[3, 3] = big"0.102703045380125899792210456947141185148813233939327773583525878521508211077874610560448598369259541346968946573971195783374996178436435357335759255990489434" - T[3, 4] = big"0.0193984639988289509112232896408330872285824216708905773930244363652651247181543158008567311548336143384128605013911312875018664026371225431993252265128272262" - T[3, 5] = big"0.0818003537037511708363908122287572533071340646031113975848869261019231448226334426630664318901554550460201409321555775999869184033436795623062614812355590017" - T[4, 1] = big"0.380091440003568104126439184355215575526619121262253024859378518379910007234696730891540745160675744992320824590679292148769326540463161583672773762554445506" - T[4, 2] = big"0.377893902248861249543862293745933995234687511602719536459666284734445918178134851270924212812363352965391508894581698067329905034837778770261095647458874628" - T[4, 3] = big"0.466744130332494359289559582964906703283968612669234331018678042733321473730897217606173184300477207393539851157929838664168404778962779344509707214938022808" - T[4, 4] = big"0.40760117128019906662166237021895987274626181127101561893104166874567447589187790736078997321464949349935802836110699884016973990503134772720646054039223561" - T[4, 5] = big"0.199682427886802525936540566022390695167018315867216115995143539347975271751460199398235415129329119718414206048034051939441434136353381864781262773401023899" - T[5, 1] = big"0.921978973681210488488254647415676321266345412943047462855852351388222898143904205962703147998267738964059170225806964893009202287585991334322032058414768529" - T[5, 2] = big"1.0" - T[5, 3] = big"0.0" - T[5, 4] = big"1.0" - T[5, 5] = big"0.0" - - RadauIIATableau{T1, T2}(T, TI, - c, γ, α, β, e, 5) -end - - struct RadauIIA9Tableau{T, T2} T11::T T12::T @@ -368,8 +235,7 @@ function RadauIIA9Tableau(T, T2) c1 = convert(T2, 5.710419611451768219312e-2) c2 = convert(T2, 2.768430136381238276800e-1) c3 = convert(T2, 5.835904323689168200567e-1) - c4 = convert(T2, 8.602401356562194478479e-1) - #= c5 = convert(T2, 1) =# + c4 = convert(T2, 8.602401356562194478479e-1)#= c5 = convert(T2, 1) =# γ = convert(T, 6.286704751729276645173e0) α1 = convert(T, 3.655694325463572258243e0) @@ -385,249 +251,93 @@ function RadauIIA9Tableau(T, T2) RadauIIA9Tableau{T, T2}(T11, T12, T13, T14, T15, T21, T22, T23, T24, T25, T31, T32, T33, T34, T35, - T41, T42, T43, T44, T45, T51, #=T52, T53, T54, T55=# + T41, T42, T43, T44, T45, T51, + #=T52, T53, T54, T55=# TI11, TI12, TI13, TI14, TI15, TI21, TI22, TI23, TI24, TI25, TI31, TI32, TI33, TI34, TI35, TI41, TI42, TI43, TI44, TI45, TI51, TI52, TI53, TI54, TI55, - c1, c2, c3, c4, #= c5 = 1 =# + c1, c2, c3, c4, + #= c5 = 1 =# γ, α1, β1, α2, β2, e1, e2, e3, e4, e5) end -function BigRadauIIA13Tableau(T1, T2) - γ = convert(T1, big"8.93683278840521633730209691330107970355008194433956657198414191417624969654351559268800871286734194720118970058657997472527299153742511021973612156231867783") - α = Vector{T1}(undef, 3) - β = Vector{T1}(undef, 3) - α[1] = big"4.37869356150680600252334919268856129165763746518197948235657247177701087073069907016715245914093899486193202405685779803686971216417800783050995450529391908" - α[2] = big"7.14105521918764010577498142571556804318193862372238812855726792587872300446315860222917039505087745633962330233504078264632719519730762016919715839787116038" - α[3] = big"8.51183482510294572305062092494533081338538293892584910309408864525614127653438453125967278937451257519784982331481143195416659686980181689042482631568989031" - β[1] = big"10.1696932837950116273183544188477298930096536824510223588525334625762336174947183926243705927725260475934351162622185429326813205432867247703480391692806137" - β[2] = big"6.62304592263927597062055811591186110468148199066707542227575094761515104946479159063603447729283770429494038962408904312215452856333028405675512985803584472" - β[3] = big"3.2810136243250588300359425270393915846791621918405321383787427650552081712406957205287551182809705166989352673500472974040971593568323836675590314648604458" - - c = Vector{T2}(undef, 7) - c[1] = big"0.0293164271597848919720502769131649103737303925637149277869106839449360382416657787486309483651843695097273923248526200112627747993405898353736305552306269904" - c[2] = big"0.148078599668484291849976852495979212230248774808594461412594641801598386090878321806369397661747576057906341132861865305306667654594593138746653233717241913" - c[3] = big"0.336984690281154299097052972080775705197568750028473347122562968073691350512784060852409141173654482529393236826516171319486086447256539582972346127980810124" - c[4] = big"0.558671518771550132081393341805521940074368288965407825555747226117350122897421078323820052012282581935200398463518265914564420109615277886000739200777932339" - c[5] = big"0.769233862030054500916883360115645451837142143322295416166948169636548130573953285685200211542774367652885154701431860087378103033801830280742146083476036669" - c[6] = big"0.926945671319741114851873965819682011056172419542283252724467079656645202452528243814339480013587391545656707320049986592771178724621938506933715568048004783" - c[7] = big"1.0" - - e = Vector{T1}(undef, 7) - e[1] = big"-0.171003707892600662399316289094713451418682228802554671094543075316220821099884263713032871578607576486535539488632407200766379971279557791263375813632287147" - e[2] = big"0.0934967172358652400317534533028674569308657324394316331629203486361371292312231403973668315582870547753526899857449840409175610009437530537219068836721686211" - e[3] = big"-0.0538908303114758775848180855518003793385120454908028879947132475960997563222416509683480350817114056356343433378213334826358824351525243402758389616051172681" - e[4] = big"0.03036786965048439581219923157368590250090409822952169396779792168990510618756404452728392288892998298088147691907128776816545685599760715439221674418662785" - e[5] = big"-0.0169792974425458224044481617230998766694942329759644144506911809530904808476835739189122151558601434810772520378036293579816345384682687602578758514350075723" - e[6] = big"0.00942688256820236884916415666439281573527695349338346787075550606528435808025071461023926432308932314282041885090975780812273515256740094297311541275151861292" - e[7] = big"-0.00331409873565629283448601269346047459594635696619041493081994712789731442072563377354737487903843138987115421498455722938021358621090485566426506726181005806" - - TI = Matrix{T1}(undef, 7, 7) - TI[1, 1] = big"258.131926319982229276108947425184471333411128774462923076434633414645220927977539758484670571338176678808837829326061674950321562391576244286310404028770676" - TI[1, 2] = big"189.073763081398508951976143411165126555759459745371576264125287430947886413126866952443113984840310549596923934762141954737541643761162558070450614795561734" - TI[1, 3] = big"49.0873148179301311944474703372633419330229683717897887664283914712555334645741343066714059043135343948204451450061803442374878045458955826422757210762412997" - TI[1, 4] = big"4.11064746966142841811238518636124668078589358089581133578005291508858571621836624121708112101643343488669794287298806656198949715476379639435093560435010553" - TI[1, 5] = big"4.05344788931556330417512803837862541661144275947069236866476426664242632965376171604053865483440478823853326237912519148507906655855071507442222711969825069" - TI[1, 6] = big"-3.11275536660734607655357698925636361735741304308245452106573904595716690770542970584435712650159533448326091358879097717388530116398450168049097806992817596" - TI[1, 7] = big"1.64677491355844465016894934800942442334612077828885771793164268655566366462165061862443368822544695623147966149765223644798045399342853834086413561960176148" - TI[2, 1] = big"-3.00739016945129213173149353792169083141834116044470099212013728771587881480191343754504173052952073006187734389002396348355357273701343509199048972794392147" - TI[2, 2] = big"-11.0158660787657713291120393664792067595453921824881213620299497076376976067619617086470844707815815293102862568459526162951253770377715406520772358338647188" - TI[2, 3] = big"1.48779945613165628148618248664965038886474377325027865838645297753993182317594482435706956176392903188004580583104018591540474622009639200188521283880201225" - TI[2, 4] = big"2.13038815955928245943197208332824475219642634294808813866153957342980992047877237670079423767538654092424134276380826377135080667266661637001176204430488753" - TI[2, 5] = big"-1.81614108681756562482220455159496741723359999245934818387747079566312917815672128128449281415737713177900591942282975861961228230314168417307836619006791605" - TI[2, 6] = big"1.13432558789516110008277908420532415765361628740656810686297793967986689714948610119162966211301325316623863222505219543867472186257492829970663316956377323" - TI[2, 7] = big"-0.414699045943303531993049422295928526684402022493736427543557958358387925728160703636844863663828153394608981043415378230601486738224597324364079320598162815" - TI[3, 1] = big"-8.44196318832108468175691559413731210343158392484322786670758421404507417209484447031645790366021837365786640573614305718894911853549168061902141351516580451" - TI[3, 2] = big"-0.650525274057515002816904045893485631294530894981669254094573985727348985809697093879080285963063573837365484483755274668080611163704039179328960851461387071" - TI[3, 3] = big"6.94067073036987647880408175445008301222030789462375109942012235845495260572570799226646472429196555932436186979400567616504159564738984233922289782922787445" - TI[3, 4] = big"-3.20504752559789843156502799159713971965747774043426947358779973217345866996463287674334224123932879873323284636947452187683408110992957222808611161423213549" - TI[3, 5] = big"1.07128094354647858978279562700457911254627057919002861801894953308482120936700881726232902304000322718645130593907512149815870969208873216470962770569998532" - TI[3, 6] = big"-0.354850749121622187972972761073874956531274189535504546398851680169235702590362534883357256681588685608802983372517893712333972644320006895019178184808028042" - TI[3, 7] = big"0.0919854913278655415440864884207305663999562250023079120516746551750254082665966708567906888946992351083964961208132558221142585217674963218388224937302473142" - TI[4, 1] = big"74.6783322350226997715286176267232500441551583987525066913719852490109364599462546293112601362342028584101507709386240000804692470037564789980905370400509214" - TI[4, 2] = big"87.4085889799008164020396362924136436577534600993283836959398121813667403209890699914314446222016952621954817633686823685774595935180374571416781238038364186" - TI[4, 3] = big"4.02415873737999787701407840793921059156554118449220356776918749072220128918152906578385457943212213189933447495921754693186811343717296680238755923076427455" - TI[4, 4] = big"-3.7148063151583641866387382381081795406061842159003055897302686185198568522128509989890869602984467843559169959313018612449354703104270603001605170037725663" - TI[4, 5] = big"-3.43009398598231735074090769130593476067104938465255451803266927011738721835297930406017172365070584279715308905584391225176154776278518922912169890517961929" - TI[4, 6] = big"2.69660480976531237885262500230842013033719691844775548640355919138284680959979836353143310081338215041119022648809147361433752919265159399610746756470853959" - TI[4, 7] = big"-0.938692743607546193356785681771531136814109179879957291315724533839534255667763099330792864148293396694586387338161584706252944483821135344465739888811338788" - TI[5, 1] = big"58.3565288519065772423731088606544342599129168115273649928818622008651860145833895668543250775742899696760389837877193028417145182338484929599333810581515993" - TI[5, 2] = big"-10.0687739578001809632495544545749228539542767485211306078205622876595603032162891608453826862136355989387474454697691529766293644115682409173741730758425432" - TI[5, 3] = big"-30.3663888425666712081087189214021522992426235463582449811325590575576319489955157279473313224901192335775884848736150180108985558310423628914140477437063457" - TI[5, 4] = big"-1.02002086518486598502718784312141857841892430616701325398305811243769008274372077411348691412296276168896198187688441456921700292037247387330560786140723416" - TI[5, 5] = big"-0.112417500378424962126670249921897816128157398591725875330925039631874967429838848482089690872916638698820411392685501889126627650123714184027159547685248056" - TI[5, 6] = big"1.89064083100037762279966919417932484200269828564004442737723486475878958135985745266991261770924069476112679285337233931312540904735632744873728510014970829" - TI[5, 7] = big"-0.971648639383148228217233127548943147296423534674266405843322723719694664032217172325052282800290275002731997713145411340983758516166807609661717915219518127" - TI[6, 1] = big"-299.18624802825209667863642523944728107942141534516550178278869311293354511449399684666660494133688445719285752471650937062695632169114367079856135650539072" - TI[6, 2] = big"-243.040745368744791181900565230083092669143049316165122405971394775932180012728275256467636352341415340547177922968547123544546515287229215470481168446631934" - TI[6, 3] = big"-48.7771040780378692121909344887388032694629956594617430615510915251995189158287187599892740037773277403958100797917560590738598108409472582147091119440886778" - TI[6, 4] = big"-2.03867190574193440528015205293433905622043272233073734690244789947707827347049413187234402189062846366658963666461334786306660732097114011309282331323116958" - TI[6, 5] = big"1.67356023986108494426829042309213202110891938292923077616474877079402040904687073610625868939896244842053999572446723558562427506280564629528151134946587118" - TI[6, 6] = big"-1.0873740320571061644555969255032311107358443063278089996181949045168433801494845898897631535619158410753032807069032950523487601457868753453652745002841107" - TI[6, 7] = big"0.901938249296099373842715514839004052963355800714627971724094542443991299921284427589690820402982448873149676210397055957126153220340909284180014056386791594" - TI[7, 1] = big"-93.076502897435305911571945263737383854569504715670989865831914555937966339933932282945955570244055882294556430466422133231853008314991630740535709028417842" - TI[7, 2] = big"23.8816310562811442770319002318043863376962876994405756649585750650966186536576789769674007990310112890015051984278059899811178135726914390958188405071290871" - TI[7, 3] = big"39.2788807308138438271015646136760366834412493325456249795727722130258444051594274416196392795817449902122139076648927894476044063388859377757097127385794539" - TI[7, 4] = big"14.3889156854910800698761307424979534708984169042483973564042387223013868069040933228077604321320066763752720714195604903398768371784013771964086553618150626" - TI[7, 5] = big"-3.51043839939936122108708432480845734972162782563284715495715984978907792386567906732993553255070093796782368160341757151292477304975079070782335737053297468" - TI[7, 6] = big"4.86328488556618070121491058699734313503568312572977577331134555924656926935558698308076704662503608259898740028814153544991114426972747448736702277116049277" - TI[7, 7] = big"-2.24648272959123991640046924839711232278867381637608763335081676684616443569602032178385937243819174902544136208243971053224668691848283004752869023074006745" +struct RadauIIATableau{T1, T2} + T::Matrix{T1} + TI::Matrix{T1} + c::Vector{T2} + γ::T1 + α::Vector{T1} + β::Vector{T1} + e::Vector{T1} +end - T = Matrix{T1}(undef, 7, 7) - T[1, 1] = big"0.00215375462731052642282751906550204337272018200721827917615061640312650856312529840445028048591986867096756005142895325420603307041594804305862850861253757163" - T[1, 2] = big"0.021567551351320773386914226953811992365459277376204369162736830595700124529879508417849062386878143122032508776691627063229415272329484156789207145821702462" - T[1, 3] = big"0.00878356792514414440732555660043326940873333657406338685620618347939710728032290406426688328221296324998146697730909767495361893387567339044816921837538988154" - T[1, 4] = big"-0.00405516145233102389819844704090310382485225922827010954643577855973533421255114497764957587851178840064428149215351434824919490696577563849929483184955933965" - T[1, 5] = big"0.00442723275326828547967807873499027629097834766201549949492135358632150336069311115075327876323707841703727317338755331613570950287342825020738596326021052902" - T[1, 6] = big"-0.00123864618795287405637686870391105285581324510790128485733529975336279476721707053186563729417080236061385260749762448518679294700311105630290083016823761156" - T[1, 7] = big"-0.00276061748054385249954800379096675592021481213358861974911688001011761550911589157738523818859000828996335817774948428177282421412491830529445501318154035024" - T[2, 1] = big"-0.00160002507788042852683067347985080829550105638728462477214069614397009338180775134535418790113854904464693278677067195562013777079470430165035085043732753352" - T[2, 2] = big"-0.0381316481344115466944201512445271892551007922443248010648630183723114657457789198582213862424187595732944781586531399310738197517976083499508550510483478779" - T[2, 3] = big"-0.0215255605940068755238494349163503963236812065771639056145559371805737876208350036328339608215271680572576146954552666030277743869132676140541472724370558091" - T[2, 4] = big"0.00841556827655958923717700333156546206587781542530241328710392714333753219743181540077241302321588065650704924760060316717877095134935044662592211744890794666" - T[2, 5] = big"-0.00403194957022454949230429372587008587329606687054571010486662485715979240183165499902791387008699068626978608835015342675934092134962673636484308565473356683" - T[2, 6] = big"-6.6666353393963381817604789740257628821376819567901071737415235834331307484818353061850936507762955342131861918219584166678095273744210157164382779907235669e-05" - T[2, 7] = big"0.00318547482516620984874835878222687621122035448401205459368674257818574765593899794870819769668503869906022860261901897250913569265553156976061140932045107432" - T[3, 1] = big"0.00405910730194768309165024146216588597640781263680870767202041411242133338742562561902630276038676420444232405079851555753917806998064489819308813790494788924" - T[3, 2] = big"0.0573965089393817153975680203880753938458832782600090443030839643350468249623833638779578474891654213594195393636829414422184571666256857425091138479371917574" - T[3, 3] = big"0.0588505292084267910561208969865829735901655409220388105109199298038946675765714122525765330769443473927581930134049676200572930797370286476504623214740871248" - T[3, 4] = big"-0.00856043106160343206017727185390754992573940897343949944649743606465705403614377469754987858631901604547097801042861815249197647886051332362774581709381720893" - T[3, 5] = big"-0.00692321266502390892414068519049460069371592099748070119636478595631451405094203293036429762819458535062492059219566837532157551782305886338773933077463475632" - T[3, 6] = big"-0.00235218098294333834053519532555529491776729377182703234025085030409255592197086839142988525473684138901264206886166295186155491132922909402254443843846019141" - T[3, 7] = big"0.00041690777252975626914088803059940941342549922756308931704215701350026719541939053570614368159222367707113801117750298289694571643601584878405615892432648487" - T[4, 1] = big"0.0157504880793768442034586734054915501004520506405808322686493022779655453114657621318660532381583918124125360276320121127974912393389579826125529804830864399" - T[4, 2] = big"-0.0382146935969683504846411337659300127514788882892071252172987515109399372135899067290947441850340146027892665775682097051548343529370733593281856326317259999" - T[4, 3] = big"-0.165736811272943851241241116255535218556011122333381899790277357803281567727036568454939356458468926429537927937619042817050400333625919290585510785057955509" - T[4, 4] = big"-0.0373712423023844574190702119163246888117181457309185176497005310822879226235861373253125139016964433591381638592353617347369492240160809914228784174846477722" - T[4, 5] = big"0.00823900729850771940449868235563938395546999707236910359131464615707125576979409087864780171789078059526539789661318173387826643385244974406562622466790754233" - T[4, 6] = big"0.00311507115234617525272547086289315208054441921705361129575617631104650731644437585122142710666234276633544335552925569262424677362146587776195531866754755781" - T[4, 7] = big"0.025116604913438821928363823471446698278976101918753236732238210724710282378748917637317846485853317873304329580245705683618093593158791190832004186288367408" - T[5, 1] = big"0.112977661024220807608615842313106352633973778091080400075534257952348289641328709240673869677499013004285003126194992176632265223545565047727637631580337111" - T[5, 2] = big"-0.249174212465263686330825594009221950347570740813751325091913985975498424569678307894304962660904874986611526140914403971840496728150916599999921976188547708" - T[5, 3] = big"0.273563305798662321213236935135336593478278696397012151365678540099566245199777083242808233574654642014215983653810819494932091426330017240672955510133726276" - T[5, 4] = big"0.00536676137918177009427930181087914853701809128264121101773394730339300080525157052081366996826642003169044168721911822166683675089051631342776752635189343996" - T[5, 5] = big"0.193211116101262014431211225620266980060733605289133050251158448403922545905872373640500736693735926480983370235582910255756813799388364741420161359961401418" - T[5, 6] = big"0.101717732481715146808078931323995112561027763392448195424858681165964478003318758266672250034474900552688318026734856778296896546916272032434282368222825518" - T[5, 7] = big"0.0950450203560462282103892144485647895183175432965514336285840628832838918715022627077373617151475963061484489345238022187829573892306346658797861719620799413" - T[6, 1] = big"0.458381043183931501028085939964292092908293295595258886425372669820276128937720150467378912424378376379185138190017965370589550781979145790869568608776861466" - T[6, 2] = big"0.5315846490836284292050500994300107341125728347976407285397462896004659632807779347307732180848765709277026749725126234633983063167374333425454720010026876" - T[6, 3] = big"0.486322836617572894056685295353340203321316764127126557475136642083389075853199222650975554544550110757249234979120491845825690852575400863926535437662617201" - T[6, 4] = big"0.526574226458449262914091192639271913456008564881594253716678163127743947224108435833618497118891017505982561930788522171455486058320589875335702474378251931" - T[6, 5] = big"0.275534394989625814192875938762525038291639319966986287664787801569471609648366101593885546008609962622035890891754680149203464179471952105174480329668882489" - T[6, 6] = big"0.521751945274765285294609453181807034209434470364856664246194441011327338299794536726049398636575212016960129143954076748520870645966241492966592488607495009" - T[6, 7] = big"0.128071944635543894414114939510913357662538610722706228789484435811417614332529416514635125851744500940930818246509599119254761178392202724896572159336577251" - T[7, 1] = big"0.881391578353818376313498879127399181693003124999819194603124949551827789004545406999549226388170693806014968936224161749923163222614460424501073405017519348" - T[7, 2] = big"1.0" - T[7, 3] = big"0.0" - T[7, 4] = big"1.0" - T[7, 5] = big"0.0" - T[7, 6] = big"1.0" - T[7, 7] = big"0.0" +import LinearAlgebra: eigen +import FastGaussQuadrature: gaussradau - RadauIIATableau{T1, T2}(T, TI, - c, γ, α, β, e, 7) +function RadauIIATableau{T1, T2}(tab::RadauIIATableau{T1, T2}) where {T1, T2} + RadauIIATableau{T1, T2}(tab.T, tab.TI, tab.c, tab.γ, tab.α, tab.β, tab.e) end -using Polynomials, LinearAlgebra, GenericSchur, RootedTrees, Symbolics -using Symbolics: variables, variable, unwrap - -function adaptiveRadauTableau(T1, T2, num_stages::Int) - tmp = Vector{BigFloat}(undef, num_stages - 1) - for i in 1:(num_stages - 1) - tmp[i] = 0 - end - tmp2 = Vector{BigFloat}(undef, num_stages + 1) - for i in 1:(num_stages + 1) - tmp2[i]=(-1)^(num_stages + 1 - i) * binomial(num_stages , num_stages + 1 - i) +function RadauIIATableau(T1, T2, num_stages::Int) + tab = get(RadauIIATableauCache, (T1, T2, num_stages)) do + tab = generateRadauTableau(T1, T2, num_stages) + RadauIIATableauCache[T1, T2, num_stages] = tab + tab end - radau_p = Polynomial{BigFloat}([tmp; tmp2]) - for i in 1:(num_stages - 1) - radau_p = derivative(radau_p) + return RadauIIATableau{T1, T2}(tab) +end + +function generateRadauTableau(T1, T2, num_stages::Int) + c = reverse!(1 .- gaussradau(num_stages, T1)[1]) ./ 2 + if T1 == T2 + c2 = c + else + c2 = reverse!(1 .- gaussradau(num_stages, T2)[1]) ./ 2 end - c = real(roots(radau_p)) - c[num_stages] = 1 - c_powers = Matrix{BigFloat}(undef, num_stages, num_stages) - for i in 1 : num_stages - for j in 1 : num_stages - c_powers[i,j] = c[i]^(j - 1) + + c_powers = Matrix{T1}(undef, num_stages, num_stages) + for i in 1:num_stages + c_powers[i, 1] = 1 + for j in 2:num_stages + c_powers[i, j] = c[i] * c_powers[i, j - 1] end end - inverse_c_powers = inv(c_powers) - c_q = Matrix{BigFloat}(undef, num_stages, num_stages) - for i in 1 : num_stages - for j in 1 : num_stages - c_q[i,j] = c[i]^(j) / j + c_q = Matrix{T1}(undef, num_stages, num_stages) + for i in 1:num_stages + for j in 1:num_stages + c_q[i, j] = c_powers[i, j] * c[i] / j end end - a = c_q * inverse_c_powers - a_inverse = inv(a) - b = Vector{BigFloat}(undef, num_stages) - for i in 1 : num_stages - b[i] = a[num_stages, i] - end - vals = eigvals(a_inverse) - γ = real(vals[num_stages]) - α = Vector{BigFloat}(undef, floor(Int, num_stages/2)) - β = Vector{BigFloat}(undef, floor(Int, num_stages/2)) - index = 1 - i = 1 - while i <= (num_stages - 1) - α[index] = real(vals[i]) - β[index] = imag(vals[i + 1]) - index = index + 1 - i = i + 2 - end - eigvec = eigvecs(a) - vecs = Vector{Vector{BigFloat}}(undef, num_stages) - i = 1 - index = 2 - while i < num_stages - vecs[index] = real(eigvec[:, i] ./ eigvec[num_stages, i]) - vecs[index + 1] = -imag(eigvec[:, i] ./ eigvec[num_stages, i]) - index += 2 - i += 2 + a = c_q / c_powers + + local eigval, eigvec + try + eigval, eigvec = eigen(a) + catch + throw(ArgumentError("Solving ODEs with AdaptiveRadau with $T1 eltype and max_order >=17 requires loading GenericSchur.jl")) end - vecs[1] = real(eigvec[:, num_stages]) - tmp3 = vcat(vecs) - T = Matrix{BigFloat}(undef, num_stages, num_stages) - for j in 1 : num_stages - for i in 1 : num_stages - T[i, j] = tmp3[j][i] - end + # α, β, and γ come from eigvals(inv(a)) which are equal to inv.(eivals(a)) + eigval .= inv.(eigval) + α = [real(eigval[i]) for i in 1:2:(num_stages - 1)] + β = [imag(eigval[i]) for i in 1:2:(num_stages - 1)] + γ = real(eigval[num_stages]) + + T = Matrix{T1}(undef, num_stages, num_stages) + @views for i in 2:2:num_stages + T[:, i] .= real.(eigvec[:, i] ./ eigvec[num_stages, i]) + T[:, i + 1] .= imag.(eigvec[:, i] ./ eigvec[num_stages, i]) end + @views T[:, 1] .= real.(eigvec[:, num_stages]) TI = inv(T) - - if (num_stages == 9) - e = Vector{BigFloat}(undef, 9) - e[1] = big"-0.133101731359431287515066981129913748644705107621439651956220186897253838380345034218235538734967567153163030284540660584311040323114847240173627907922903296" - e[2] = big"0.0754476228408557299650196603226967248368445025181771896522057250989188754588885465998346476425502117889420021664297319179240040109156780754680742172762707621" - e[3] = big"-0.0458369394236156144604575482137179697005739995740615341890112217655441769701945378217626766299683076189687755618065050383493055018324395934911567207485032988" - e[4] = big"0.0271430329153098694457979735602502142083095152399102869109830450899844979409229538982100527256348792152825816553434603418662939944133319974874915933773657075" - e[5] = big"-0.0156126300301219212217568535995825232086423550686814635293876744035364259647929167763641353639085929285192729729570945658304937255929114458885296622493040224" - e[6] = big"0.00890598154557403928205152521539967562877335780940124672915181111908317890891659158654221736499522823959933517986673010006749138291836676520080172845444352328" - e[7] = big"-0.00514824122639241252178399021479378841872099572255461304439292434131750195489022869965968028106854978547414579491205935930595041763060069987112580994637398395" - e[8] = big"0.00296533914055503317169967748114188676589522458557982039693426239853498956125735811263087631479968309978854200615027412311940897061471388689986239742919640848" - e[9] = big"-0.0010634368308888065260482548541946175520274736959410047497431569257848032902381738362547705844630238841535652230832162703806430112125115777122361837311714267" - else - p = num_stages - eb = variables(:b, 1:num_stages + 1) - @variables y - zz = zeros(size(a, 1) + 1) - zz2 = zeros(size(a, 1)) - eA = [zz' - zz2 a] - ec = [0; c] - constraints = map(Iterators.flatten(RootedTreeIterator(i) for i in 1:2*p-3)) do t - residual_order_condition(t, RungeKuttaMethod(eA, eb, ec)) - end - AA, bb, islinear = Symbolics.linear_expansion(Symbolics.substitute.(constraints, (eb[1]=>1/γ,)), eb[2:end]) - AA = Float64.(map(unwrap, AA)) - idxs = qr(AA', ColumnNorm()).p[1:num_stages] - @assert rank(AA[idxs, :]) == num_stages - @assert islinear - b_hat = Symbolics.expand.((AA \ -bb)) - e = [Symbolics.symbolic_to_float(b_hat[i] - b[i]) for i in 1 : num_stages] - end - RadauIIATableau{T1, T2}(T, TI, c, γ, α, β, e, num_stages) + A = c_powers' ./ (1:num_stages) + b = vcat(-(num_stages)^2, -0.5, zeros(num_stages - 2)) + e = A \ b + tab = RadauIIATableau{T1, T2}(T, TI, c2, γ, α, β, e) end + +const RadauIIATableauCache = Dict{ + Tuple{Type, Type, Int}, RadauIIATableau{T1, T2} where {T1, T2}}( + (Float64, Float64, 3) => generateRadauTableau(Float64, Float64, 3), + (Float64, Float64, 5) => generateRadauTableau(Float64, Float64, 5), + (Float64, Float64, 7) => generateRadauTableau(Float64, Float64, 7)) diff --git a/lib/OrdinaryDiffEqFIRK/src/integrator_interface.jl b/lib/OrdinaryDiffEqFIRK/src/integrator_interface.jl index dc4bbb1e88..6670c6b7f2 100644 --- a/lib/OrdinaryDiffEqFIRK/src/integrator_interface.jl +++ b/lib/OrdinaryDiffEqFIRK/src/integrator_interface.jl @@ -1,4 +1,5 @@ -@inline function DiffEqBase.get_tmp_cache(integrator, alg::Union{RadauIIA3, RadauIIA5, RadauIIA9, AdaptiveRadau}, +@inline function SciMLBase.get_tmp_cache( + integrator, alg::Union{RadauIIA3, RadauIIA5, RadauIIA9, AdaptiveRadau}, cache::OrdinaryDiffEqMutableCache) (cache.tmp, cache.atmp) end diff --git a/lib/OrdinaryDiffEqFIRK/test/jet.jl b/lib/OrdinaryDiffEqFIRK/test/jet.jl new file mode 100644 index 0000000000..d792628f27 --- /dev/null +++ b/lib/OrdinaryDiffEqFIRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqFIRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqFIRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqFIRK/test/ode_firk_tests.jl b/lib/OrdinaryDiffEqFIRK/test/ode_firk_tests.jl index 2eb857827d..95f7078830 100644 --- a/lib/OrdinaryDiffEqFIRK/test/ode_firk_tests.jl +++ b/lib/OrdinaryDiffEqFIRK/test/ode_firk_tests.jl @@ -1,69 +1,110 @@ using OrdinaryDiffEqFIRK, DiffEqDevTools, Test, LinearAlgebra -import ODEProblemLibrary: prob_ode_linear, prob_ode_2Dlinear, van +import ODEProblemLibrary: prob_ode_linear, prob_ode_2Dlinear, prob_ode_vanderpol -testTol = 0.3 +testTol = 0.5 for prob in [prob_ode_linear, prob_ode_2Dlinear] - sim21 = test_convergence(1 .// 2 .^ (6:-1:3), prob, RadauIIA5()) + sim21 = test_convergence(1 .// 2 .^ (6:-1:3), prob, RadauIIA5(), dense_errors = true) @test sim21.𝒪est[:final]≈5 atol=testTol + @test sim21.𝒪est[:L2]≈4 atol=testTol end -sim21 = test_convergence(1 ./ 2 .^ (2.5:-1:0.5), prob_ode_linear, RadauIIA9()) -@test sim21.𝒪est[:final]≈8.5 atol=testTol +sim21 = test_convergence(1 ./ 2 .^ (2.5:-1:0.5), prob_ode_linear, RadauIIA9(), dense_errors = true) +@test sim21.𝒪est[:final]≈8 atol=testTol +@test sim21.𝒪est[:L2]≈6 atol=testTol -sim21 = test_convergence(1 ./ 2 .^ (2.5:-1:0.5), prob_ode_2Dlinear, RadauIIA9()) -@test sim21.𝒪est[:final]≈8.5 atol=testTol +sim21 = test_convergence(1 ./ 2 .^ (2.5:-1:0.5), prob_ode_2Dlinear, RadauIIA9(), dense_errors = true) +@test sim21.𝒪est[:final]≈8 atol=testTol +@test sim21.𝒪est[:L2]≈6 atol=testTol -prob_ode_linear_big = remake(prob_ode_linear, u0 = big.(prob_ode_linear.u0), tspan = big.(prob_ode_linear.tspan)) -prob_ode_2Dlinear_big = remake(prob_ode_2Dlinear, u0 = big.(prob_ode_2Dlinear.u0), tspan = big.(prob_ode_2Dlinear.tspan)) +using GenericSchur + +prob_ode_linear_big = remake( + prob_ode_linear, u0 = big.(prob_ode_linear.u0), tspan = big.(prob_ode_linear.tspan)) +prob_ode_2Dlinear_big = remake(prob_ode_2Dlinear, u0 = big.(prob_ode_2Dlinear.u0), + tspan = big.(prob_ode_2Dlinear.tspan)) + +#non-threaded tests +for i in [5, 9, 13, 17, 21, 25], prob in [prob_ode_linear_big, prob_ode_2Dlinear_big] -for i in [3, 5, 7, 9], prob in [prob_ode_linear_big, prob_ode_2Dlinear_big] dts = 1 ./ 2 .^ (4.25:-1:0.25) - sim21 = test_convergence(dts, prob, AdaptiveRadau(num_stages = i)) - @test sim21.𝒪est[:final]≈ (2 * i - 1) atol=testTol + local sim21 = test_convergence(dts, prob, AdaptiveRadau(min_order = i, max_order = i), dense_errors = true) + @test sim21.𝒪est[:final] ≈ i atol=testTol + @test sim21.𝒪est[:L2] ≈ ((i + 3) ÷ 2) atol=testTol +end + +#threaded tests +using OrdinaryDiffEqCore +for i in [5, 9, 13, 17, 21, 25], prob in [prob_ode_linear_big, prob_ode_2Dlinear_big] + + dts = 1 ./ 2 .^ (4.25:-1:0.25) + local sim21 = test_convergence(dts, + prob, + AdaptiveRadau(min_order = i, max_order = i, threading = OrdinaryDiffEqCore.PolyesterThreads())) + @test sim21.𝒪est[:final] ≈ i atol=testTol +end + +# Create Van der Pol stiff problem using the same ordering as ODEProblemLibrary +# New implementation: u[1] = x, u[2] = y, p[1] = μ +# Initial conditions: [x, y] = [sqrt(3), 0] (matching original [sys.x => sqrt(3), sys.y => 0]) +function vanderpol_firk(du, u, p, t) + x, y = u[1], u[2] + μ = p[1] + du[1] = y # dx/dt = y + du[2] = μ * ((1 - x^2) * y - x) # dy/dt = μ * ((1 - x^2) * y - x) +end + +function vanderpol_firk(u, p, t) + x, y = u[1], u[2] + μ = p[1] + [y, # dx/dt = y + μ * ((1 - x^2) * y - x)] # dy/dt = μ * ((1 - x^2) * y - x) end # test adaptivity for iip in (true, false) - if iip - vanstiff = ODEProblem{iip}(van, [0; sqrt(3)], (0.0, 1.0), 1e6) - else - vanstiff = ODEProblem{false}((u, p, t) -> van(u, p, t), [0; sqrt(3)], (0.0, 1.0), - 1e6) - end + vanstiff = ODEProblem{iip}(vanderpol_firk, [sqrt(3), 0.0], (0.0, 1.0), [1e6]) sol = solve(vanstiff, RadauIIA5()) if iip @test sol.stats.naccept + sol.stats.nreject > sol.stats.njacs # J reuse @test sol.stats.njacs < sol.stats.nw # W reuse end @test length(sol) < 150 - @test length(solve(remake(vanstiff, p = 1e7), RadauIIA5())) < 150 - @test length(solve(remake(vanstiff, p = 1e7), reltol = [1e-4, 1e-6], RadauIIA5())) < 170 - @test length(solve(remake(vanstiff, p = 1e7), RadauIIA5(), reltol = 1e-9, - abstol = 1e-9)) < 870 - @test length(solve(remake(vanstiff, p = 1e9), RadauIIA5())) < 170 - @test length(solve(remake(vanstiff, p = 1e10), RadauIIA5())) < 190 + @test SciMLBase.successful_retcode(sol) + sol_temp = solve(remake(vanstiff, p = [1e7]), RadauIIA5()) + @test length(sol_temp) < 150 + @test SciMLBase.successful_retcode(sol_temp) + sol_temp2 = solve(remake(vanstiff, p = [1e7]), reltol = [1e-6, 1e-4], RadauIIA5()) + @test length(sol_temp2) < 180 + @test SciMLBase.successful_retcode(sol_temp2) + sol_temp3 = solve(remake(vanstiff, p = [1e7]), RadauIIA5(), reltol = 1e-9, + abstol = 1e-9) + @test length(sol_temp3) < 970 + @test SciMLBase.successful_retcode(sol_temp3) + sol_temp4 = solve(remake(vanstiff, p = [1e9]), RadauIIA5()) + @test length(sol_temp4) < 170 + @test SciMLBase.successful_retcode(sol_temp4) + sol_temp5 = solve(remake(vanstiff, p = [1e10]), RadauIIA5()) + @test length(sol_temp5) < 190 + @test SciMLBase.successful_retcode(sol_temp5) end ##Tests for RadauIIA3 for prob in [prob_ode_linear, prob_ode_2Dlinear] dts = 1 ./ 2 .^ (8:-1:1) - sim = test_convergence(dts, prob, RadauIIA3()) + sim = test_convergence(dts, prob, RadauIIA3(), dense_errors = true) @test sim.𝒪est[:final]≈3 atol=0.25 + @test sim.𝒪est[:L2]≈3 atol=0.25 end # test adaptivity for iip in (true, false) - if iip - vanstiff = ODEProblem{iip}(van, [0; sqrt(3)], (0.0, 1.0), 1e6) - else - vanstiff = ODEProblem{false}((u, p, t) -> van(u, p, t), [0; sqrt(3)], (0.0, 1.0), - 1e6) - end + vanstiff = ODEProblem{iip}(vanderpol_firk, [sqrt(3), 0], (0.0, 1.0), [1e6]) sol = solve(vanstiff, RadauIIA3()) if iip @test sol.stats.naccept + sol.stats.nreject > sol.stats.njacs # J reuse @test sol.stats.njacs < sol.stats.nw # W reuse end @test length(sol) < 5000 # the error estimate is not very good + @test SciMLBase.successful_retcode(sol) end diff --git a/lib/OrdinaryDiffEqFIRK/test/qa.jl b/lib/OrdinaryDiffEqFIRK/test/qa.jl new file mode 100644 index 0000000000..c518334253 --- /dev/null +++ b/lib/OrdinaryDiffEqFIRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqFIRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqFIRK + ) +end diff --git a/lib/OrdinaryDiffEqFIRK/test/runtests.jl b/lib/OrdinaryDiffEqFIRK/test/runtests.jl index 39ede8c3b3..a407bc397a 100644 --- a/lib/OrdinaryDiffEqFIRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqFIRK/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "FIRK Tests" include("ode_firk_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqFeagin/Project.toml b/lib/OrdinaryDiffEqFeagin/Project.toml index 8bdd4a7222..bbd905e512 100644 --- a/lib/OrdinaryDiffEqFeagin/Project.toml +++ b/lib/OrdinaryDiffEqFeagin/Project.toml @@ -1,40 +1,51 @@ name = "OrdinaryDiffEqFeagin" uuid = "101fe9f7-ebb6-4678-b671-3a81e7194747" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.4.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" + +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" [compat] -DiffEqBase = "6" -DiffEqDevTools = "2.44.4" +Test = "<0.0.1, 1" FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" MuladdMacro = "0.2" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1" Polyester = "0.7" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1" -Test = "<0.0.1, 1" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" julia = "1.10" - -[extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqFeagin/src/OrdinaryDiffEqFeagin.jl b/lib/OrdinaryDiffEqFeagin/src/OrdinaryDiffEqFeagin.jl index a1a4236c9f..a796596133 100644 --- a/lib/OrdinaryDiffEqFeagin/src/OrdinaryDiffEqFeagin.jl +++ b/lib/OrdinaryDiffEqFeagin/src/OrdinaryDiffEqFeagin.jl @@ -16,7 +16,7 @@ using Static: False import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqFeagin/test/jet.jl b/lib/OrdinaryDiffEqFeagin/test/jet.jl new file mode 100644 index 0000000000..2e74088464 --- /dev/null +++ b/lib/OrdinaryDiffEqFeagin/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqFeagin +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqFeagin, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqFeagin/test/qa.jl b/lib/OrdinaryDiffEqFeagin/test/qa.jl new file mode 100644 index 0000000000..7cceede6e7 --- /dev/null +++ b/lib/OrdinaryDiffEqFeagin/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqFeagin +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqFeagin + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqFeagin/test/runtests.jl b/lib/OrdinaryDiffEqFeagin/test/runtests.jl index ebdbb63cb5..5c2f9b2f13 100644 --- a/lib/OrdinaryDiffEqFeagin/test/runtests.jl +++ b/lib/OrdinaryDiffEqFeagin/test/runtests.jl @@ -2,3 +2,5 @@ using SafeTestsets @time @safetestset "Feagin Tests" include("ode_feagin_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqFunctionMap/Project.toml b/lib/OrdinaryDiffEqFunctionMap/Project.toml index ae358acea2..eea9aade8f 100644 --- a/lib/OrdinaryDiffEqFunctionMap/Project.toml +++ b/lib/OrdinaryDiffEqFunctionMap/Project.toml @@ -1,38 +1,47 @@ name = "OrdinaryDiffEqFunctionMap" uuid = "d3585ca7-f5d3-4ba6-8057-292ed1abd90f" authors = ["ParamThakkar123 "] -version = "1.1.1" +version = "1.5.0" [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -SciMLBase = "2.48.1" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqFunctionMap/src/OrdinaryDiffEqFunctionMap.jl b/lib/OrdinaryDiffEqFunctionMap/src/OrdinaryDiffEqFunctionMap.jl index c13a3e1fee..7f35f5dc06 100644 --- a/lib/OrdinaryDiffEqFunctionMap/src/OrdinaryDiffEqFunctionMap.jl +++ b/lib/OrdinaryDiffEqFunctionMap/src/OrdinaryDiffEqFunctionMap.jl @@ -15,7 +15,7 @@ import Static: False import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") @@ -25,6 +25,17 @@ include("interpolants.jl") include("functionmap_perform_step.jl") include("fixed_timestep_perform_step.jl") +# Default algorithm for DiscreteProblem +function SciMLBase.__solve(prob::SciMLBase.DiscreteProblem, ::Nothing, args...; + kwargs...) + SciMLBase.__solve(prob, FunctionMap(), args...; kwargs...) +end + +function SciMLBase.__init(prob::SciMLBase.DiscreteProblem, ::Nothing, args...; + kwargs...) + SciMLBase.__init(prob, FunctionMap(), args...; kwargs...) +end + export FunctionMap end diff --git a/lib/OrdinaryDiffEqFunctionMap/src/algorithms.jl b/lib/OrdinaryDiffEqFunctionMap/src/algorithms.jl index 6463d23a8e..d583a379b0 100644 --- a/lib/OrdinaryDiffEqFunctionMap/src/algorithms.jl +++ b/lib/OrdinaryDiffEqFunctionMap/src/algorithms.jl @@ -1,2 +1,14 @@ +@doc raw""" + FunctionMap(; scale_by_time = false) + +A fixed timestep method for when the ODE is a discrete dynamical system. In the +operator setting, this is equivalent to operator splitting for additive operators. + +When `scale_by_time = true`, the method becomes `u_{n+1} = u_n + dt*f(u_n,p,t_n)`, +otherwise it's `u_{n+1} = f(u_n,p,t_n)`. + +!!! note + This method requires a fixed timestep dt and is not adaptive. +""" struct FunctionMap{scale_by_time} <: OrdinaryDiffEqAlgorithm end FunctionMap(; scale_by_time = false) = FunctionMap{scale_by_time}() diff --git a/lib/OrdinaryDiffEqFunctionMap/src/interp_func.jl b/lib/OrdinaryDiffEqFunctionMap/src/interp_func.jl index 7f2ff30ca5..9ff3cc13c2 100644 --- a/lib/OrdinaryDiffEqFunctionMap/src/interp_func.jl +++ b/lib/OrdinaryDiffEqFunctionMap/src/interp_func.jl @@ -1,9 +1,9 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where {cacheType <: FunctionMapConstantCache} "left-endpoint piecewise constant" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where {cacheType <: FunctionMapCache} "left-endpoint piecewise constant" end diff --git a/lib/OrdinaryDiffEqFunctionMap/test/discrete_problem_defaults.jl b/lib/OrdinaryDiffEqFunctionMap/test/discrete_problem_defaults.jl new file mode 100644 index 0000000000..a3c2a0a237 --- /dev/null +++ b/lib/OrdinaryDiffEqFunctionMap/test/discrete_problem_defaults.jl @@ -0,0 +1,91 @@ +import OrdinaryDiffEqFunctionMap +import OrdinaryDiffEqCore +using Test +using SciMLBase +using SciMLBase: solve, init, DiscreteProblem + +const FunctionMap = OrdinaryDiffEqFunctionMap.FunctionMap + +# Helper functions to check algorithm properties regardless of module context +is_functionmap(alg) = typeof(alg).name.name == :FunctionMap +function get_scale_by_time(alg) + # Access the type parameter directly since it's FunctionMap{scale_by_time} + T = typeof(alg) + # The parameter is stored as a type parameter + return T.parameters[1] +end + +@testset "DiscreteProblem Default Algorithm" begin + # Test scalar DiscreteProblem + f(u, p, t) = 1.01 * u + prob_scalar = DiscreteProblem(f, 0.5, (0.0, 1.0)) + + @testset "Scalar DiscreteProblem" begin + # Test solve without explicit algorithm + sol = solve(prob_scalar) + @test is_functionmap(sol.alg) + @test get_scale_by_time(sol.alg) == false + @test length(sol.u) > 1 + + # Test init without explicit algorithm + integrator = init(prob_scalar) + @test is_functionmap(integrator.alg) + @test get_scale_by_time(integrator.alg) == false + end + + # Test array DiscreteProblem + function f_array!(du, u, p, t) + du[1] = 1.01 * u[1] + du[2] = 0.99 * u[2] + end + prob_array = DiscreteProblem(f_array!, [0.5, 1.0], (0.0, 1.0)) + + @testset "Array DiscreteProblem" begin + # Test solve without explicit algorithm + sol = solve(prob_array) + @test is_functionmap(sol.alg) + @test get_scale_by_time(sol.alg) == false + @test length(sol.u) > 1 + + # Test init without explicit algorithm + integrator = init(prob_array) + @test is_functionmap(integrator.alg) + @test get_scale_by_time(integrator.alg) == false + end + + # Test that explicit algorithm specification still works + @testset "Explicit FunctionMap specification" begin + sol1 = solve(prob_scalar, FunctionMap()) + @test is_functionmap(sol1.alg) + @test get_scale_by_time(sol1.alg) == false + + sol2 = solve(prob_scalar, FunctionMap(scale_by_time=true), dt=0.1) + @test is_functionmap(sol2.alg) + @test get_scale_by_time(sol2.alg) == true + + integrator1 = init(prob_scalar, FunctionMap()) + @test is_functionmap(integrator1.alg) + @test get_scale_by_time(integrator1.alg) == false + + integrator2 = init(prob_scalar, FunctionMap(scale_by_time=true), dt=0.1) + @test is_functionmap(integrator2.alg) + @test get_scale_by_time(integrator2.alg) == true + end + + # Test that the default behaves correctly with different problem types + @testset "DiscreteProblem with integer time" begin + henon_map!(u_next, u, p, t) = begin + u_next[1] = 1 + u[2] - 1.4 * u[1]^2 + u_next[2] = 0.3 * u[1] + end + + prob_int = DiscreteProblem(henon_map!, [0.5, 0.5], (0, 10)) + + sol = solve(prob_int) + @test is_functionmap(sol.alg) + @test eltype(sol.t) <: Integer + + integrator = init(prob_int) + @test is_functionmap(integrator.alg) + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqFunctionMap/test/jet.jl b/lib/OrdinaryDiffEqFunctionMap/test/jet.jl new file mode 100644 index 0000000000..7a66377433 --- /dev/null +++ b/lib/OrdinaryDiffEqFunctionMap/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqFunctionMap +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqFunctionMap, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqFunctionMap/test/qa.jl b/lib/OrdinaryDiffEqFunctionMap/test/qa.jl new file mode 100644 index 0000000000..9a84171581 --- /dev/null +++ b/lib/OrdinaryDiffEqFunctionMap/test/qa.jl @@ -0,0 +1,9 @@ +using OrdinaryDiffEqFunctionMap +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqFunctionMap; + piracies = false # Piracy is necessary for default algorithm dispatch + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqFunctionMap/test/runtests.jl b/lib/OrdinaryDiffEqFunctionMap/test/runtests.jl index 8b13789179..629e974a06 100644 --- a/lib/OrdinaryDiffEqFunctionMap/test/runtests.jl +++ b/lib/OrdinaryDiffEqFunctionMap/test/runtests.jl @@ -1 +1,5 @@ +using SafeTestsets +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") +@time @safetestset "DiscreteProblem Defaults" include("discrete_problem_defaults.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqHighOrderRK/Project.toml b/lib/OrdinaryDiffEqHighOrderRK/Project.toml index 7a6f19a94f..06f7e70337 100644 --- a/lib/OrdinaryDiffEqHighOrderRK/Project.toml +++ b/lib/OrdinaryDiffEqHighOrderRK/Project.toml @@ -1,38 +1,49 @@ name = "OrdinaryDiffEqHighOrderRK" uuid = "d28bc4f8-55e1-4f49-af69-84c1a99f0f58" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.5.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "ODEProblemLibrary", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "ODEProblemLibrary", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqHighOrderRK/src/OrdinaryDiffEqHighOrderRK.jl b/lib/OrdinaryDiffEqHighOrderRK/src/OrdinaryDiffEqHighOrderRK.jl index aa19504945..db7e15ffe0 100644 --- a/lib/OrdinaryDiffEqHighOrderRK/src/OrdinaryDiffEqHighOrderRK.jl +++ b/lib/OrdinaryDiffEqHighOrderRK/src/OrdinaryDiffEqHighOrderRK.jl @@ -21,7 +21,7 @@ using DiffEqBase: @def, @tight_loop_macros import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqHighOrderRK/src/algorithms.jl b/lib/OrdinaryDiffEqHighOrderRK/src/algorithms.jl index 87f2740948..cf4f35f911 100644 --- a/lib/OrdinaryDiffEqHighOrderRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqHighOrderRK/src/algorithms.jl @@ -1,5 +1,5 @@ @doc explicit_rk_docstring( - "Tanaka-Yamashita 7 Runge-Kutta method. (7th order interpolant).", + "Tanaka-Yamashita 7 Runge-Kutta method.", "TanYam7", references = "Tanaka M., Muramatsu S., Yamashita S., (1992), On the Optimization of Some Nine-Stage Seventh-order Runge-Kutta Method, Information Processing Society of Japan, @@ -37,7 +37,7 @@ function TsitPap8(stage_limiter!, step_limiter! = trivial_limiter!) end @doc explicit_rk_docstring( - "Hairer's 8/5/3 adaption of the Dormand-Prince Runge-Kutta method. (7th order interpolant).", + "Hairer's 8/5/3 adaption of the Dormand-Prince Runge-Kutta method.", "DP8", references = "E. Hairer, S.P. Norsett, G. Wanner, (1993) Solving Ordinary Differential Equations I. Nonstiff Problems. 2nd Edition. Springer Series in Computational Mathematics, diff --git a/lib/OrdinaryDiffEqHighOrderRK/src/interp_func.jl b/lib/OrdinaryDiffEqHighOrderRK/src/interp_func.jl index 450c8692d9..a7211ab354 100644 --- a/lib/OrdinaryDiffEqHighOrderRK/src/interp_func.jl +++ b/lib/OrdinaryDiffEqHighOrderRK/src/interp_func.jl @@ -1,4 +1,4 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{DP8ConstantCache, DP8Cache}} diff --git a/lib/OrdinaryDiffEqHighOrderRK/test/allocation_tests.jl b/lib/OrdinaryDiffEqHighOrderRK/test/allocation_tests.jl new file mode 100644 index 0000000000..6df9a0f131 --- /dev/null +++ b/lib/OrdinaryDiffEqHighOrderRK/test/allocation_tests.jl @@ -0,0 +1,46 @@ +using OrdinaryDiffEqHighOrderRK +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqHighOrderRK solvers using AllocCheck.jl. +These tests verify that the step! operation does not allocate during stepping. +""" + +@testset "HighOrderRK Allocation Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported HighOrderRK solvers for allocation-free behavior + high_order_solvers = [TanYam7(), DP8(), PFRK87(), TsitPap8()] + + @testset "HighOrderRK Solver Allocation Analysis" begin + for solver in high_order_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test_broken length(allocs) == 0 + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqHighOrderRK/test/jet.jl b/lib/OrdinaryDiffEqHighOrderRK/test/jet.jl new file mode 100644 index 0000000000..2899c72a10 --- /dev/null +++ b/lib/OrdinaryDiffEqHighOrderRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqHighOrderRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqHighOrderRK, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqHighOrderRK/test/qa.jl b/lib/OrdinaryDiffEqHighOrderRK/test/qa.jl new file mode 100644 index 0000000000..7afa33773b --- /dev/null +++ b/lib/OrdinaryDiffEqHighOrderRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqHighOrderRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqHighOrderRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqHighOrderRK/test/runtests.jl b/lib/OrdinaryDiffEqHighOrderRK/test/runtests.jl index 14748a70f2..b9c5046422 100644 --- a/lib/OrdinaryDiffEqHighOrderRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqHighOrderRK/test/runtests.jl @@ -1,3 +1,10 @@ using SafeTestsets @time @safetestset "High Order ERK Convergence Tests" include("high_order_erk_convergence_tests.jl") + +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqIMEXMultistep/Project.toml b/lib/OrdinaryDiffEqIMEXMultistep/Project.toml index ff8bd8f36b..f53e6032c0 100644 --- a/lib/OrdinaryDiffEqIMEXMultistep/Project.toml +++ b/lib/OrdinaryDiffEqIMEXMultistep/Project.toml @@ -1,34 +1,53 @@ name = "OrdinaryDiffEqIMEXMultistep" uuid = "9f002381-b378-40b7-97a6-27a27c83f129" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.7.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqNonlinearSolve = "<0.0.1, 1" -Random = "<0.0.1, 1" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Test = "<0.0.1, 1" -julia = "1.10" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +OrdinaryDiffEqDifferentiation = "1.12.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqNonlinearSolve] +path = "../OrdinaryDiffEqNonlinearSolve" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqIMEXMultistep/src/OrdinaryDiffEqIMEXMultistep.jl b/lib/OrdinaryDiffEqIMEXMultistep/src/OrdinaryDiffEqIMEXMultistep.jl index 567e6b5eae..09ce3c180a 100644 --- a/lib/OrdinaryDiffEqIMEXMultistep/src/OrdinaryDiffEqIMEXMultistep.jl +++ b/lib/OrdinaryDiffEqIMEXMultistep/src/OrdinaryDiffEqIMEXMultistep.jl @@ -5,16 +5,17 @@ import OrdinaryDiffEqCore: alg_order, issplit, OrdinaryDiffEqNewtonAlgorithm, _u OrdinaryDiffEqMutableCache, @cache, alg_cache, initialize!, perform_step!, @unpack, full_cache, get_fsalfirstlast, - generic_solver_docstring + generic_solver_docstring, _bool_to_ADType, _process_AD_choice using FastBroadcast import OrdinaryDiffEqCore using OrdinaryDiffEqDifferentiation: dolinsolve using OrdinaryDiffEqNonlinearSolve: NLNewton, build_nlsolver, markfirststage!, nlsolve!, nlsolvefail, du_alias_or_new +import ADTypes: AutoForwardDiff, AbstractADType using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqIMEXMultistep/src/algorithms.jl b/lib/OrdinaryDiffEqIMEXMultistep/src/algorithms.jl index 69e0d7ab57..b6549128f7 100644 --- a/lib/OrdinaryDiffEqIMEXMultistep/src/algorithms.jl +++ b/lib/OrdinaryDiffEqIMEXMultistep/src/algorithms.jl @@ -1,6 +1,6 @@ # IMEX Multistep methods -@doc generic_solver_docstring("Crank-Nicholson Adams-Bashforth 2.", +@doc generic_solver_docstring("Crank-Nicolson Adams Bashforth Order 2 (fixed time step)", "CNAB2", "IMEX Multistep method.", "@article{jorgenson2014unconditional, @@ -26,19 +26,24 @@ struct CNAB2{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function CNAB2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function CNAB2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + CNAB2{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}( linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc generic_solver_docstring("Crank-Nicholson Leapfrong 2.", @@ -66,16 +71,21 @@ struct CNLF2{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function CNLF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function CNLF2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + CNLF2{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}( linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end diff --git a/lib/OrdinaryDiffEqIMEXMultistep/src/imex_multistep_perform_step.jl b/lib/OrdinaryDiffEqIMEXMultistep/src/imex_multistep_perform_step.jl index 6a38280fb9..8d6f343acd 100644 --- a/lib/OrdinaryDiffEqIMEXMultistep/src/imex_multistep_perform_step.jl +++ b/lib/OrdinaryDiffEqIMEXMultistep/src/imex_multistep_perform_step.jl @@ -3,8 +3,7 @@ function initialize!(integrator, cache::CNAB2ConstantCache) integrator.kshortsize = 2 integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) - integrator.fsalfirst = integrator.f.f1(integrator.uprev, integrator.p, integrator.t) + - integrator.f.f2(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal + integrator.fsalfirst = integrator.f.f1(integrator.uprev, integrator.p, integrator.t) + integrator.f.f2(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 @@ -103,8 +102,7 @@ end function initialize!(integrator, cache::CNLF2ConstantCache) integrator.kshortsize = 2 integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) - integrator.fsalfirst = integrator.f.f1(integrator.uprev, integrator.p, integrator.t) + - integrator.f.f2(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal + integrator.fsalfirst = integrator.f.f1(integrator.uprev, integrator.p, integrator.t) + integrator.f.f2(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 diff --git a/lib/OrdinaryDiffEqIMEXMultistep/test/jet.jl b/lib/OrdinaryDiffEqIMEXMultistep/test/jet.jl new file mode 100644 index 0000000000..f10091d9e0 --- /dev/null +++ b/lib/OrdinaryDiffEqIMEXMultistep/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqIMEXMultistep +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqIMEXMultistep, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqIMEXMultistep/test/qa.jl b/lib/OrdinaryDiffEqIMEXMultistep/test/qa.jl new file mode 100644 index 0000000000..1757af4c40 --- /dev/null +++ b/lib/OrdinaryDiffEqIMEXMultistep/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqIMEXMultistep +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqIMEXMultistep + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqIMEXMultistep/test/runtests.jl b/lib/OrdinaryDiffEqIMEXMultistep/test/runtests.jl index 8b13789179..75ab3bccf9 100644 --- a/lib/OrdinaryDiffEqIMEXMultistep/test/runtests.jl +++ b/lib/OrdinaryDiffEqIMEXMultistep/test/runtests.jl @@ -1 +1,4 @@ +using SafeTestsets +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") diff --git a/lib/OrdinaryDiffEqLinear/Project.toml b/lib/OrdinaryDiffEqLinear/Project.toml index 107dd521f1..cdf74b27dd 100644 --- a/lib/OrdinaryDiffEqLinear/Project.toml +++ b/lib/OrdinaryDiffEqLinear/Project.toml @@ -1,44 +1,59 @@ name = "OrdinaryDiffEqLinear" uuid = "521117fe-8c41-49f8-b3b6-30780b3f0fb5" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.6.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" ExponentialUtilities = "d4d017d3-3776-5f7e-afef-a10c40355c18" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" -OrdinaryDiffEqVerner = "79d7bb75-1356-48c1-b8c0-6832512096c2" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -ExponentialUtilities = "1.26.1" -LinearAlgebra = "<0.0.1, 1" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqRosenbrock = "<0.0.1, 1" -OrdinaryDiffEqTsit5 = "<0.0.1, 1" -OrdinaryDiffEqVerner = "<0.0.1, 1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -SciMLBase = "2.48.1" -SciMLOperators = "0.3.9" -Test = "<0.0.1, 1" -julia = "1.10" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" OrdinaryDiffEqRosenbrock = "43230ef6-c299-4910-a778-202eb28ce4ce" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +OrdinaryDiffEqVerner = "79d7bb75-1356-48c1-b8c0-6832512096c2" + +[compat] +DiffEqBase = "6.176" +OrdinaryDiffEqTsit5 = "1.4.0" +Test = "<0.0.1, 1" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +OrdinaryDiffEqVerner = "1.5.0" +ExponentialUtilities = "1.27" +LinearAlgebra = "1.10" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +OrdinaryDiffEqRosenbrock = "1.15.1" +Reexport = "1.2" +SciMLOperators = "1.4" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "OrdinaryDiffEqRosenbrock", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "OrdinaryDiffEqRosenbrock", "SafeTestsets", "Test", "JET", "Aqua", "OrdinaryDiffEqVerner", "OrdinaryDiffEqTsit5", "AllocCheck"] + +[sources.OrdinaryDiffEqTsit5] +path = "../OrdinaryDiffEqTsit5" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" + +[sources.OrdinaryDiffEqVerner] +path = "../OrdinaryDiffEqVerner" diff --git a/lib/OrdinaryDiffEqLinear/src/OrdinaryDiffEqLinear.jl b/lib/OrdinaryDiffEqLinear/src/OrdinaryDiffEqLinear.jl index e7954b1833..0fdb370b03 100644 --- a/lib/OrdinaryDiffEqLinear/src/OrdinaryDiffEqLinear.jl +++ b/lib/OrdinaryDiffEqLinear/src/OrdinaryDiffEqLinear.jl @@ -15,9 +15,10 @@ using SciMLOperators: AbstractSciMLOperator using ExponentialUtilities using RecursiveArrayTools import OrdinaryDiffEqCore +import DiffEqBase using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqLinear/src/integrator_interface.jl b/lib/OrdinaryDiffEqLinear/src/integrator_interface.jl index 8cdaefe902..070694d5d3 100644 --- a/lib/OrdinaryDiffEqLinear/src/integrator_interface.jl +++ b/lib/OrdinaryDiffEqLinear/src/integrator_interface.jl @@ -1,4 +1,4 @@ -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::LinearExponential, cache::OrdinaryDiffEqMutableCache) (cache.tmp,) diff --git a/lib/OrdinaryDiffEqLinear/src/linear_caches.jl b/lib/OrdinaryDiffEqLinear/src/linear_caches.jl index 47a1d1bde1..c2867776d1 100644 --- a/lib/OrdinaryDiffEqLinear/src/linear_caches.jl +++ b/lib/OrdinaryDiffEqLinear/src/linear_caches.jl @@ -571,9 +571,10 @@ function _phiv_timestep_caches(u_prototype, maxiter::Int, p::Int) n = length(u_prototype) T = eltype(u_prototype) u = zero(u_prototype) # stores the current state - W = Matrix{T}(undef, n, p + 1) # stores the w vectors - P = Matrix{T}(undef, n, p + 2) # stores output from phiv! - Ks = KrylovSubspace{T}(n, maxiter) # stores output from arnoldi! + W = similar(u_prototype, n, p + 1) # stores the w vectors + P = similar(u_prototype, n, p + 2) # stores output from phiv! + Ks = KrylovSubspace{T, T, typeof(similar(u_prototype, size(u_prototype, 1), 2))}( + n, maxiter) # stores output from arnoldi! phiv_cache = PhivCache(u_prototype, maxiter, p + 1) # cache used by phiv! (need +1 for error estimation) return u, W, P, Ks, phiv_cache end @@ -591,7 +592,7 @@ function alg_cache(alg::LinearExponential, u, rate_prototype, ::Type{uEltypeNoUn if alg.krylov == :off KsCache = nothing elseif alg.krylov == :simple - Ks = KrylovSubspace{T}(n, m) + Ks = KrylovSubspace{T, T, typeof(similar(u, size(u, 1), 2))}(n, m) expv_cache = ExpvCache{T}(m) KsCache = (Ks, expv_cache) elseif alg.krylov == :adaptive diff --git a/lib/OrdinaryDiffEqLinear/test/jet.jl b/lib/OrdinaryDiffEqLinear/test/jet.jl new file mode 100644 index 0000000000..c6c146e8f7 --- /dev/null +++ b/lib/OrdinaryDiffEqLinear/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqLinear +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqLinear, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLinear/test/qa.jl b/lib/OrdinaryDiffEqLinear/test/qa.jl new file mode 100644 index 0000000000..f5a6790cc8 --- /dev/null +++ b/lib/OrdinaryDiffEqLinear/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqLinear +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqLinear + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLinear/test/runtests.jl b/lib/OrdinaryDiffEqLinear/test/runtests.jl index fd166282ab..cb444f2ebe 100644 --- a/lib/OrdinaryDiffEqLinear/test/runtests.jl +++ b/lib/OrdinaryDiffEqLinear/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "Linear Methods Tests" include("linear_method_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowOrderRK/Project.toml b/lib/OrdinaryDiffEqLowOrderRK/Project.toml index 75b4acea91..6d0c460560 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/Project.toml +++ b/lib/OrdinaryDiffEqLowOrderRK/Project.toml @@ -1,42 +1,51 @@ name = "OrdinaryDiffEqLowOrderRK" uuid = "1344f307-1e59-4825-a18e-ace9aa3fa4c6" authors = ["ParamThakkar123 "] -version = "1.2.0" +version = "1.6.0" [deps] DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -SciMLBase = "2.48.1" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearAlgebra = "1.10" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqLowOrderRK/src/OrdinaryDiffEqLowOrderRK.jl b/lib/OrdinaryDiffEqLowOrderRK/src/OrdinaryDiffEqLowOrderRK.jl index 9aec0897c1..19d4c7ab50 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/src/OrdinaryDiffEqLowOrderRK.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/src/OrdinaryDiffEqLowOrderRK.jl @@ -14,10 +14,9 @@ import OrdinaryDiffEqCore: alg_order, isfsal, beta2_default, beta1_default, OrdinaryDiffEqMutableCache, uses_uprev, OrdinaryDiffEqConstantCache, @fold, @cache, CompiledFloats, alg_cache, CompositeAlgorithm, - copyat_or_push!, AutoAlgSwitch, _ode_interpolant, _ode_interpolant!, full_cache, accept_step_controller, DerivativeOrderNotPossibleError, - du_cache, u_cache, get_fsalfirstlast + du_cache, u_cache, get_fsalfirstlast, copyat_or_push! using SciMLBase import MuladdMacro: @muladd import FastBroadcast: @.. @@ -25,10 +24,11 @@ import LinearAlgebra: norm import RecursiveArrayTools: recursivefill!, recursive_unitless_bottom_eltype import Static: False using DiffEqBase: @def, @tight_loop_macros +import DiffEqBase: prepare_alg import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqLowOrderRK/src/alg_utils.jl b/lib/OrdinaryDiffEqLowOrderRK/src/alg_utils.jl index a7056f8338..464f23297c 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/src/alg_utils.jl @@ -41,7 +41,7 @@ alg_stability_size(alg::DP5) = 3.3066 ssp_coefficient(alg::Euler) = 1 -function DiffEqBase.prepare_alg( +function prepare_alg( alg::SplitEuler, u0::AbstractArray, p, prob) diff --git a/lib/OrdinaryDiffEqLowOrderRK/src/algorithms.jl b/lib/OrdinaryDiffEqLowOrderRK/src/algorithms.jl index 2c9472fb27..d328dc2d3c 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/src/algorithms.jl @@ -7,6 +7,11 @@ Springer-Verlag.""", "", "") struct Euler <: OrdinaryDiffEqAlgorithm end +@doc generic_solver_docstring( + "1st order fully explicit method for testing split accuracy", + "SplitEuler", + "Split Method.", + "", "", "") struct SplitEuler <: OrdinaryDiffEqExponentialAlgorithm{0, false, Val{:forward}, Val{true}, nothing} end @@ -61,8 +66,7 @@ function Midpoint(stage_limiter!, step_limiter! = trivial_limiter!) Midpoint(stage_limiter!, step_limiter!, False()) end -@doc explicit_rk_docstring("The canonical Runge-Kutta Order 4 method. -Uses a defect control for adaptive stepping using maximum error over the whole interval.", +@doc explicit_rk_docstring("The canonical Runge-Kutta Order 4 method. Uses a defect control for adaptive stepping using maximum error over the whole interval. Classic fourth-order method. Good for medium accuracy calculations.", "RK4", references = "@article{shampine2005solving, title={Solving ODEs and DDEs with residual control}, @@ -85,8 +89,7 @@ function RK4(stage_limiter!, step_limiter! = trivial_limiter!) end @doc explicit_rk_docstring( - "A third-order, four-stage FSAL method with embedded error -estimator of Bogacki and Shampine.", + "Bogacki-Shampine 3/2 method. Third-order adaptive method using embedded Euler method for adaptivity. Recommended for non-stiff problems at moderate tolerances.", "BS3", references = "@article{bogacki19893, title={A 3 (2) pair of Runge-Kutta formulas}, @@ -256,7 +259,7 @@ function Anas5(stage_limiter!, step_limiter! = trivial_limiter!; w = 1) Anas5(stage_limiter!, step_limiter!, False(), w) end -@doc explicit_rk_docstring("5th order method.", "RKO65", +@doc explicit_rk_docstring("Tsitouras' Runge-Kutta-Oliver 6 stage 5th order method.", "RKO65", references = "Tsitouras, Ch. \"Explicit Runge–Kutta methods for starting integration of Lane–Emden problem.\" Applied Mathematics and Computation 354 (2019): 353-364. doi: https://doi.org/10.1016/j.amc.2019.02.047") diff --git a/lib/OrdinaryDiffEqLowOrderRK/src/interp_func.jl b/lib/OrdinaryDiffEqLowOrderRK/src/interp_func.jl index 239179d60d..76040b4e13 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/src/interp_func.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/src/interp_func.jl @@ -1,28 +1,28 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{OwrenZen3Cache, OwrenZen3ConstantCache}} dense ? "specialized 3rd order \"free\" interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{OwrenZen4Cache, OwrenZen4ConstantCache}} dense ? "specialized 4th order \"free\" interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{OwrenZen5Cache, OwrenZen5ConstantCache}} dense ? "specialized 5th order \"free\" interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{DP5ConstantCache, DP5Cache}} dense ? "specialized 4th order \"free\" interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{BS5ConstantCache, BS5Cache}} diff --git a/lib/OrdinaryDiffEqLowOrderRK/src/low_order_rk_perform_step.jl b/lib/OrdinaryDiffEqLowOrderRK/src/low_order_rk_perform_step.jl index 9d9928f678..43b2f8bbfe 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/src/low_order_rk_perform_step.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/src/low_order_rk_perform_step.jl @@ -1553,11 +1553,11 @@ function perform_step!(integrator, cache::Stepanov5ConstantCache, repeat_step = OrdinaryDiffEqCore.increment_nf!(integrator.stats, 6) if integrator.opts.adaptive - @.. broadcast=false utilde=dt * (btilde1 * k1 + btilde2 * k2 + + utilde=dt * (btilde1 * k1 + btilde2 * k2 + btilde3 * k3 + btilde4 * k4 + btilde5 * k5 + btilde6 * k6 + btilde7 * k7) - calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, + atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) end @@ -2033,4 +2033,4 @@ function perform_step!(integrator, cache::Alshina6Cache, repeat_step = false) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 7) integrator.fsallast = k7 return nothing -end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowOrderRK/test/allocation_tests.jl b/lib/OrdinaryDiffEqLowOrderRK/test/allocation_tests.jl new file mode 100644 index 0000000000..11474c11f3 --- /dev/null +++ b/lib/OrdinaryDiffEqLowOrderRK/test/allocation_tests.jl @@ -0,0 +1,55 @@ +using OrdinaryDiffEqLowOrderRK +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqLowOrderRK solvers using AllocCheck.jl. +These tests verify that the step! operation does not allocate during stepping. +""" + +@testset "LowOrderRK Allocation Tests" begin + # Test problem for adaptive methods + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported LowOrderRK solvers for allocation-free behavior + low_order_solvers = [Euler(), Heun(), Ralston(), Midpoint(), RK4(), + BS3(), OwrenZen3(), OwrenZen4(), OwrenZen5(), BS5(), + DP5(), Anas5(), RKO65(), FRK65(), RKM(), MSRK5(), MSRK6(), + PSRK4p7q6(), PSRK3p5q4(), PSRK3p6q5(), Stepanov5(), SIR54(), + Alshina2(), Alshina3(), Alshina6(), AutoDP5(DP5())] + + @testset "LowOrderRK Solver Allocation Analysis" begin + for solver in low_order_solvers + @testset "$(typeof(solver)) allocation check" begin + # Some solvers need fixed timestep + if solver isa Euler || solver isa Midpoint || solver isa Heun + integrator = init(prob, solver, dt=0.1, save_everystep=false, adaptive=false) + else + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + end + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test length(allocs) == 0 broken=true + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowOrderRK/test/jet.jl b/lib/OrdinaryDiffEqLowOrderRK/test/jet.jl new file mode 100644 index 0000000000..1a105c85c9 --- /dev/null +++ b/lib/OrdinaryDiffEqLowOrderRK/test/jet.jl @@ -0,0 +1,47 @@ +import OrdinaryDiffEqLowOrderRK +using OrdinaryDiffEqLowOrderRK +using OrdinaryDiffEqCore +using JET +using Test + +@testset "JET Tests" begin + # Test package for typos (commented out due to false positive) + # test_package( + # OrdinaryDiffEqLowOrderRK, target_defined_modules = true, mode = :typo) + + # Test individual solver type stability + @testset "Solver Type Stability Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported LowOrderRK solvers + low_order_solvers = [Euler(), Heun(), Ralston(), Midpoint(), RK4(), + BS3(), OwrenZen3(), OwrenZen4(), OwrenZen5(), BS5(), + DP5(), Anas5(), RKO65(), FRK65(), RKM(), MSRK5(), MSRK6(), + PSRK4p7q6(), PSRK3p5q4(), PSRK3p6q5(), Stepanov5(), SIR54(), + Alshina2(), Alshina3(), Alshina6(), AutoDP5(DP5())] + + for solver in low_order_solvers + @testset "$(typeof(solver)) type stability" begin + try + # Some solvers need fixed timestep + if solver isa Euler || solver isa Midpoint || solver isa Heun + @test_opt broken=true init(prob, solver, dt=0.1, save_everystep=false, adaptive=false) + integrator = init(prob, solver, dt=0.1, save_everystep=false, adaptive=false) + else + @test_opt broken=true init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + end + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowOrderRK/test/owrenzen_tests.jl b/lib/OrdinaryDiffEqLowOrderRK/test/owrenzen_tests.jl index f9ccf66afa..19c9137693 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/test/owrenzen_tests.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/test/owrenzen_tests.jl @@ -9,10 +9,13 @@ testTol = 0.2 prob = prob_ode_linear sol = solve(prob, OwrenZen3()) @test length(sol) < 20 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, OwrenZen4()) @test length(sol) < 20 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, OwrenZen5()) @test length(sol) < 20 +@test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, OwrenZen3(), dense_errors = true) @test sim.𝒪est[:final]≈3 atol=testTol @@ -27,10 +30,13 @@ sim = test_convergence(dts, prob, OwrenZen5(), dense_errors = true) prob = prob_ode_2Dlinear sol = solve(prob, OwrenZen3()) @test length(sol) < 20 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, OwrenZen4()) @test length(sol) < 20 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, OwrenZen5()) @test length(sol) < 20 +@test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, OwrenZen3(), dense_errors = true) @test sim.𝒪est[:final]≈3 atol=testTol diff --git a/lib/OrdinaryDiffEqLowOrderRK/test/qa.jl b/lib/OrdinaryDiffEqLowOrderRK/test/qa.jl new file mode 100644 index 0000000000..bba8bb41bb --- /dev/null +++ b/lib/OrdinaryDiffEqLowOrderRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqLowOrderRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqLowOrderRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowOrderRK/test/runtests.jl b/lib/OrdinaryDiffEqLowOrderRK/test/runtests.jl index 6676589614..98cfca762b 100644 --- a/lib/OrdinaryDiffEqLowOrderRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqLowOrderRK/test/runtests.jl @@ -3,3 +3,10 @@ using SafeTestsets @time @safetestset "Low Order ERK Convergence Tests" include("low_order_erk_convergence_tests.jl") @time @safetestset "OwrenZen Tests" include("owrenzen_tests.jl") @time @safetestset "Euler SSP Tests" include("euler_ssp.jl") + +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowStorageRK/Project.toml b/lib/OrdinaryDiffEqLowStorageRK/Project.toml index 9ca09e32d2..d88c73a70c 100644 --- a/lib/OrdinaryDiffEqLowStorageRK/Project.toml +++ b/lib/OrdinaryDiffEqLowStorageRK/Project.toml @@ -1,48 +1,61 @@ name = "OrdinaryDiffEqLowStorageRK" uuid = "b0944070-b475-4768-8dec-fb6eb410534d" authors = ["ParamThakkar123 "] -version = "1.2.1" +version = "1.7.0" [deps] -Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Preferences = "21216c6a-2e73-6563-6e65-726566657250" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[compat] -Adapt = "4.0.4" -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -Polyester = "0.7.16" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -julia = "1.10" +Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +StructArrays = "0.6, 0.7" +MuladdMacro = "0.2" +PrecompileTools = "1.2" +Polyester = "0.7" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +Preferences = "1.4" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +Adapt = "4.3" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "StructArrays", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqLowStorageRK/src/OrdinaryDiffEqLowStorageRK.jl b/lib/OrdinaryDiffEqLowStorageRK/src/OrdinaryDiffEqLowStorageRK.jl index 8822c04e18..22596ff12b 100644 --- a/lib/OrdinaryDiffEqLowStorageRK/src/OrdinaryDiffEqLowStorageRK.jl +++ b/lib/OrdinaryDiffEqLowStorageRK/src/OrdinaryDiffEqLowStorageRK.jl @@ -19,7 +19,7 @@ import RecursiveArrayTools: recursive_unitless_bottom_eltype import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("arrayfuse.jl") include("algorithms.jl") diff --git a/lib/OrdinaryDiffEqLowStorageRK/src/algorithms.jl b/lib/OrdinaryDiffEqLowStorageRK/src/algorithms.jl index 226212fd42..0fab550bd5 100644 --- a/lib/OrdinaryDiffEqLowStorageRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqLowStorageRK/src/algorithms.jl @@ -1000,10 +1000,9 @@ struct HSLDDRK64{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAlgorithm thread::Thread williamson_condition::Bool function HSLDDRK64(stage_limiter! = trivial_limiter!, step_limiter! = trivial_limiter!; - williamson_condition = true) + williamson_condition = true, thread = False()) Base.depwarn("HSLDDRK64 is deprecated, use SHLDDRK64 instead.", :HSLDDRK64) - SHLDDRK64(stage_limiter!, step_limiter!, thread; - williamson_condition = williamson_condition) + SHLDDRK64(; stage_limiter!, step_limiter!, thread, williamson_condition) end end diff --git a/lib/OrdinaryDiffEqLowStorageRK/src/low_storage_rk_perform_step.jl b/lib/OrdinaryDiffEqLowStorageRK/src/low_storage_rk_perform_step.jl index 5344dc296a..2509415be9 100644 --- a/lib/OrdinaryDiffEqLowStorageRK/src/low_storage_rk_perform_step.jl +++ b/lib/OrdinaryDiffEqLowStorageRK/src/low_storage_rk_perform_step.jl @@ -966,6 +966,7 @@ end integrator.fsallast = f(u, p, t + dt) # For interpolation, then FSAL'd integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) integrator.u = u end @@ -1012,6 +1013,7 @@ end step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) end function initialize!(integrator, cache::SHLDDRK_2NConstantCache) @@ -1053,7 +1055,7 @@ end # u5 = u tmp = α51 * tmp + dt * f(u, p, t + c51 * dt) u = u + β51 * tmp - + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 4) else cache.step += 1 # u1 @@ -1073,11 +1075,13 @@ end u = u + β52 * tmp tmp = α62 * tmp + dt * f(u, p, t + c62 * dt) u = u + β62 * tmp + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) end integrator.fsallast = f(u, p, t + dt) # For interpolation, then FSAL'd integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.u = u end @@ -1089,6 +1093,7 @@ function initialize!(integrator, cache::SHLDDRK_2NCache) integrator.k[1] = integrator.fsalfirst integrator.k[2] = integrator.fsallast integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) # FSAL for interpolation + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end @muladd function perform_step!(integrator, cache::SHLDDRK_2NCache, repeat_step = false) @@ -1128,6 +1133,7 @@ end step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 5) else # u1 @.. thread=thread tmp=dt * fsalfirst @@ -1161,5 +1167,6 @@ end step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 6) end end diff --git a/lib/OrdinaryDiffEqLowStorageRK/test/jet.jl b/lib/OrdinaryDiffEqLowStorageRK/test/jet.jl new file mode 100644 index 0000000000..a3916b9fac --- /dev/null +++ b/lib/OrdinaryDiffEqLowStorageRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqLowStorageRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqLowStorageRK, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowStorageRK/test/ode_low_storage_rk_tests.jl b/lib/OrdinaryDiffEqLowStorageRK/test/ode_low_storage_rk_tests.jl index 2ddc6f4401..8257d245a0 100644 --- a/lib/OrdinaryDiffEqLowStorageRK/test/ode_low_storage_rk_tests.jl +++ b/lib/OrdinaryDiffEqLowStorageRK/test/ode_low_storage_rk_tests.jl @@ -101,13 +101,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -116,7 +116,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -146,13 +146,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -161,10 +161,16 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end +@testset "HSLDDRK64" begin + # this method is deprecated + alg = HSLDDRK64() + @test alg isa SHLDDRK64 +end + @testset "SHLDDRK64" begin alg = SHLDDRK64() alg2 = SHLDDRK64(; williamson_condition = true) @@ -191,13 +197,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -206,7 +212,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -236,13 +242,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -251,7 +257,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -281,13 +287,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -296,7 +302,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -326,13 +332,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -341,7 +347,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -371,13 +377,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -386,7 +392,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -416,13 +422,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -431,7 +437,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -461,13 +467,13 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 2 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg2, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -476,7 +482,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -499,7 +505,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -508,7 +514,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -531,7 +537,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -540,7 +546,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -593,7 +599,7 @@ test_problems_nonlinear_BigFloat = [prob_nonlinear_A, prob_nonlinear_B] save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 7 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -602,7 +608,7 @@ test_problems_nonlinear_BigFloat = [prob_nonlinear_A, prob_nonlinear_B] save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -628,7 +634,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 7 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -637,7 +643,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -663,7 +669,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 7 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -672,7 +678,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -698,7 +704,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 7 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -707,7 +713,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -733,7 +739,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 7 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -742,7 +748,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -768,7 +774,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 10 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 9 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -777,7 +783,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -803,7 +809,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 10 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 9 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -812,7 +818,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -838,7 +844,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 10 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 9 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -847,7 +853,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -873,7 +879,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 10 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 9 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -882,7 +888,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -908,7 +914,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 10 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 9 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -917,7 +923,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -943,7 +949,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 10 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 9 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -952,7 +958,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -978,7 +984,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 12 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 11 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -987,7 +993,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1013,7 +1019,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 12 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 11 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1022,7 +1028,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1048,7 +1054,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 12 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 11 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1057,7 +1063,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1083,7 +1089,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 12 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 11 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1092,7 +1098,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1118,7 +1124,7 @@ end save_end = false, save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 14 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 13 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1127,7 +1133,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1153,7 +1159,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1162,7 +1168,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1186,7 +1192,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1195,7 +1201,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1219,7 +1225,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1228,7 +1234,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1254,7 +1260,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1263,7 +1269,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1286,7 +1292,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1295,7 +1301,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1319,7 +1325,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1328,7 +1334,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1353,7 +1359,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1362,7 +1368,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1376,7 +1382,7 @@ end dts = 1 ./ 2 .^ (5:-1:2) for prob in test_problems_linear sim = test_convergence(dts, prob, alg) - @test sim.𝒪est[:final]≈OrdinaryDiffEqLowStorageRK.alg_order(alg) atol=testTol + @test sim.𝒪est[:final]≈OrdinaryDiffEqLowStorageRK.alg_order(alg) atol=0.33 end dts = 1.5 ./ 2 .^ (5:-1:2) for prob in test_problems_nonlinear @@ -1387,7 +1393,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1396,7 +1402,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1422,7 +1428,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1431,7 +1437,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1456,7 +1462,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1465,7 +1471,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1488,7 +1494,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1497,7 +1503,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1521,7 +1527,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1530,7 +1536,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1555,7 +1561,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1564,7 +1570,7 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end @@ -1587,7 +1593,7 @@ end save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 # test whether aliasing u0 is bad new_prob_ode_nonlinear_inplace = ODEProblem(prob_ode_nonlinear_inplace.f, [1.0], @@ -1596,6 +1602,39 @@ end save_start = false) sol_new = solve( new_prob_ode_nonlinear_inplace, alg, dt = 1.e-4, save_everystep = false, - save_start = false, alias_u0 = true) + save_start = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test sol_old[end] ≈ sol_new[end] end + +@testset "VectorOfArray/StructArray compatibility" begin + using RecursiveArrayTools, StaticArrays, StructArrays + + function rhs!(du_voa, u_voa, p, t) + du = parent(du_voa) + u = parent(u_voa) + du .= u + end + + # StructArray storage + u = StructArray{SVector{1, Float64}}(ntuple(_ -> [1.0, 2.0], 1)) + ode = ODEProblem(rhs!, VectorOfArray(u), (0, 0.7)) + sol_SA = solve(ode, RDPK3SpFSAL35()) + + # Vector{<:SVector} storage + u = SVector{1, Float64}.([1.0, 2.0]) + ode = ODEProblem(rhs!, VectorOfArray(u), (0, 0.7)) + sol_SV = solve(ode, RDPK3SpFSAL35()) + + @test sol_SA ≈ sol_SV + @test sol_SV.stats.naccept == sol_SA.stats.naccept + + # Plain vector + u = [1.0, 2.0] + ode = ODEProblem(rhs!, u, (0, 0.7)) + sol = solve(ode, RDPK3SpFSAL35()) + @test sol.stats.naccept == sol_SA.stats.naccept + @test sol.t ≈ sol_SA.t + for i in eachindex(sol_SA.u), j in eachindex(u) + @test sol.u[i][j] ≈ sol_SA.u[i][j][1] + end +end diff --git a/lib/OrdinaryDiffEqLowStorageRK/test/qa.jl b/lib/OrdinaryDiffEqLowStorageRK/test/qa.jl new file mode 100644 index 0000000000..146604d4f3 --- /dev/null +++ b/lib/OrdinaryDiffEqLowStorageRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqLowStorageRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqLowStorageRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqLowStorageRK/test/runtests.jl b/lib/OrdinaryDiffEqLowStorageRK/test/runtests.jl index 7225e9390c..f39a42edb5 100644 --- a/lib/OrdinaryDiffEqLowStorageRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqLowStorageRK/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "Low Storage RK Tests" include("ode_low_storage_rk_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqNonlinearSolve/Project.toml b/lib/OrdinaryDiffEqNonlinearSolve/Project.toml index 1d93f1277d..d12ca68235 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/Project.toml +++ b/lib/OrdinaryDiffEqNonlinearSolve/Project.toml @@ -1,60 +1,78 @@ name = "OrdinaryDiffEqNonlinearSolve" uuid = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" authors = ["Chris Rackauckas ", "Yingbo Ma "] -version = "1.2.1" +version = "1.14.0" [deps] -ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" -FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" -PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" -SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7" +FastClosures = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" +ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[compat] -ADTypes = "1.7.1" -ArrayInterface = "7.15.0" -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -FastClosures = "0.3.2" -ForwardDiff = "0.10.36" -LinearAlgebra = "<0.0.1, 1" -LinearSolve = "2.32.0" -MuladdMacro = "0.2.4" -NonlinearSolve = "3.14.0" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -PreallocationTools = "0.4.23" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -SafeTestsets = "0.1.0" -SciMLBase = "2.48.1" -SciMLOperators = "0.3.9" -SciMLStructures = "1.4.2" -SimpleNonlinearSolve = "1.12.0" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -julia = "1.10" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLStructures = "53ae85a6-f571-4167-b2af-e1d143709226" +SciMLOperators = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +NonlinearSolve = "4.12" +ForwardDiff = "0.10.38, 1" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearSolve = "3.26" +LineSearches = "7.4" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +OrdinaryDiffEqSDIRK = "1.6.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +SimpleNonlinearSolve = "2.7" +FastClosures = "0.3" +Aqua = "0.8.11" +ArrayInterface = "7.19" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +PreallocationTools = "0.4" +AllocCheck = "0.2" +DiffEqBase = "6.190.2" +SafeTestsets = "0.1.0" +SciMLOperators = "1.4" +SciMLStructures = "1.7" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "LineSearches", "ODEProblemLibrary", "OrdinaryDiffEqSDIRK", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl index b3c9592736..4e58484ffb 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/OrdinaryDiffEqNonlinearSolve.jl @@ -1,23 +1,27 @@ module OrdinaryDiffEqNonlinearSolve -import ADTypes: AutoFiniteDiff, AutoForwardDiff +using ADTypes: ADTypes, dense_ad, AutoForwardDiff, AutoFiniteDiff import SciMLBase -import SciMLBase: init, solve, solve! +import SciMLBase: init, solve, solve!, remake using SciMLBase: DAEFunction, DEIntegrator, NonlinearFunction, NonlinearProblem, NonlinearLeastSquaresProblem, LinearProblem, ODEProblem, DAEProblem, - update_coefficients!, get_tmp_cache, AbstractSciMLOperator, ReturnCode + update_coefficients!, get_tmp_cache, AbstractSciMLOperator, ReturnCode, + AbstractNonlinearProblem, LinearAliasSpecifier import DiffEqBase -import PreallocationTools +import PreallocationTools: dualcache, get_tmp using SimpleNonlinearSolve: SimpleTrustRegion, SimpleGaussNewton -using NonlinearSolve: FastShortcutNonlinearPolyalg, FastShortcutNLLSPolyalg, NewtonRaphson -using MuladdMacro, FastBroadcast +using NonlinearSolve: FastShortcutNonlinearPolyalg, FastShortcutNLLSPolyalg, NewtonRaphson, + step! +using MuladdMacro: @muladd +using FastBroadcast: @.. import FastClosures: @closure -using LinearAlgebra: UniformScaling, UpperTriangular +using LinearAlgebra: UniformScaling, UpperTriangular, givens, cond, dot, lmul!, axpy! import LinearAlgebra -import ArrayInterface +import ArrayInterface: ArrayInterface, ismutable, restructure +import LinearSolve: OperatorAssumptions import LinearSolve -import ForwardDiff +import ForwardDiff: ForwardDiff, pickchunksize using ForwardDiff: Dual using LinearSolve: I, rmul!, norm, mul!, ldiv! using RecursiveArrayTools: recursivecopy! @@ -63,4 +67,6 @@ include("functional.jl") include("newton.jl") include("initialize_dae.jl") +export BrownFullBasicInit, ShampineCollocationInit + end diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/functional.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/functional.jl index 377e9c12a5..871555e9fc 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/functional.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/functional.jl @@ -1,14 +1,14 @@ ## initialize! @muladd function initialize!(nlsolver::NLSolver{<:NLFunctional}, - integrator::DiffEqBase.DEIntegrator) + integrator::SciMLBase.DEIntegrator) nlsolver.cache.tstep = integrator.t + nlsolver.c * integrator.dt nothing end @muladd function initialize!(nlsolver::NLSolver{<:NLAnderson}, - integrator::DiffEqBase.DEIntegrator) + integrator::SciMLBase.DEIntegrator) @unpack cache = nlsolver cache.history = 0 @@ -60,7 +60,7 @@ end elseif previter > aa_start # actually perform Anderson acceleration nlsolver.z = anderson(nlsolver.z, cache) - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) integrator.stats.nsolve += 1 end end @@ -82,7 +82,7 @@ end elseif previter > aa_start # actually perform Anderson acceleration anderson!(nlsolver.z, cache) - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) integrator.stats.nsolve += 1 end end @@ -134,7 +134,7 @@ end end end end - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end @@ -200,7 +200,7 @@ end end end - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/initialize_dae.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/initialize_dae.jl index 67c3fb177e..e87963f362 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/initialize_dae.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/initialize_dae.jl @@ -1,5 +1,23 @@ +# Optimized tolerance checking that avoids allocations +@inline function check_dae_tolerance(integrator, err, abstol, t, ::Val{true}) + if abstol isa Number + return integrator.opts.internalnorm(err, t) / abstol <= 1 + else + @. err = err / abstol # Safe for in-place functions + return integrator.opts.internalnorm(err, t) <= 1 + end +end + +@inline function check_dae_tolerance(integrator, err, abstol, t, ::Val{false}) + if abstol isa Number + return integrator.opts.internalnorm(err, t) / abstol <= 1 + else + return integrator.opts.internalnorm(err ./ abstol, t) <= 1 # Allocates for out-of-place + end +end + function default_nlsolve( - ::Nothing, isinplace::Val{true}, u, ::NonlinearProblem, autodiff = false) + ::Nothing, isinplace::Val{true}, u, ::AbstractNonlinearProblem, autodiff = false) FastShortcutNonlinearPolyalg(; autodiff = autodiff ? AutoForwardDiff() : AutoFiniteDiff()) end @@ -8,7 +26,7 @@ function default_nlsolve( FastShortcutNLLSPolyalg(; autodiff = autodiff ? AutoForwardDiff() : AutoFiniteDiff()) end function default_nlsolve( - ::Nothing, isinplace::Val{false}, u, ::NonlinearProblem, autodiff = false) + ::Nothing, isinplace::Val{false}, u, ::AbstractNonlinearProblem, autodiff = false) FastShortcutNonlinearPolyalg(; autodiff = autodiff ? AutoForwardDiff() : AutoFiniteDiff()) end @@ -17,7 +35,7 @@ function default_nlsolve( FastShortcutNLLSPolyalg(; autodiff = autodiff ? AutoForwardDiff() : AutoFiniteDiff()) end function default_nlsolve(::Nothing, isinplace::Val{false}, u::StaticArray, - ::NonlinearProblem, autodiff = false) + ::AbstractNonlinearProblem, autodiff = false) SimpleTrustRegion(autodiff = autodiff ? AutoForwardDiff() : AutoFiniteDiff()) end function default_nlsolve(::Nothing, isinplace::Val{false}, u::StaticArray, @@ -35,7 +53,7 @@ Solve for `u` =# -function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocationInit, +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::ODEProblem, alg::DiffEqBase.ShampineCollocationInit, isinplace::Val{true}) @unpack p, t, f = integrator M = integrator.f.mass_matrix @@ -43,11 +61,12 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation tmp = first(get_tmp_cache(integrator)) u0 = integrator.u - dt = if alg.initdt === nothing + initdt = alg.initdt + dt = if initdt === nothing integrator.dt != 0 ? min(integrator.dt / 5, dtmax) : (prob.tspan[end] - prob.tspan[begin]) / 1000 # Haven't implemented norm reduction else - alg.initdt + initdt end algebraic_vars = [all(iszero, x) for x in eachcol(M)] @@ -57,27 +76,29 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation f(tmp, u0, p, t) tmp .= ArrayInterface.restructure(tmp, algebraic_eqs .* _vec(tmp)) - integrator.opts.internalnorm(tmp, t) <= integrator.opts.abstol && return + check_dae_tolerance(integrator, tmp, integrator.opts.abstol, t, isinplace) && return if isdefined(integrator.cache, :nlsolver) && !isnothing(alg.nlsolve) # backward Euler nlsolver = integrator.cache.nlsolver - oldγ, oldc, oldmethod, olddt = nlsolver.γ, nlsolver.c, nlsolver.method, + oldγ, oldc, oldmethod, + olddt = nlsolver.γ, nlsolver.c, nlsolver.method, integrator.dt nlsolver.tmp .= integrator.uprev nlsolver.γ, nlsolver.c = 1, 1 nlsolver.method = DIRK integrator.dt = dt z = nlsolve!(nlsolver, integrator, integrator.cache) - nlsolver.γ, nlsolver.c, nlsolver.method, integrator.dt = oldγ, oldc, oldmethod, + nlsolver.γ, nlsolver.c, nlsolver.method, + integrator.dt = oldγ, oldc, oldmethod, olddt failed = nlsolvefail(nlsolver) - @.. broadcast=false integrator.u=integrator.uprev + z + @.. broadcast=false integrator.u=integrator.uprev+z else # _u0 should be non-dual since NonlinearSolve does not differentiate the solver # These non-dual values are thus used to make the caches - #_du = DiffEqBase.value.(du) + #_du = SciMLBase.value.(du) _u0 = DiffEqBase.value.(u0) # If not doing auto-diff of the solver, save an allocation @@ -91,7 +112,7 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation typeof(u0) !== typeof(_u0) if isAD chunk = ForwardDiff.pickchunksize(length(tmp)) - _tmp = PreallocationTools.dualcache(tmp, chunk) + _tmp = dualcache(tmp, chunk) else _tmp = tmp end @@ -105,7 +126,7 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation end update_coefficients!(M, u, p, t) # f(u,p,t) + M * (u0 - u)/dt - tmp = isAD ? PreallocationTools.get_tmp(_tmp, T) : _tmp + tmp = isAD ? get_tmp(_tmp, T) : _tmp @. tmp = (_u0 - u) / dt mul!(_vec(out), M, _vec(tmp)) f(tmp, u, p, t) @@ -148,18 +169,19 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation return end -function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocationInit, +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::ODEProblem, alg::DiffEqBase.ShampineCollocationInit, isinplace::Val{false}) @unpack p, t, f = integrator u0 = integrator.u M = integrator.f.mass_matrix dtmax = integrator.opts.dtmax - dt = if alg.initdt === nothing + initdt = alg.initdt + dt = if initdt === nothing integrator.dt != 0 ? min(integrator.dt / 5, dtmax) : (prob.tspan[end] - prob.tspan[begin]) / 1000 # Haven't implemented norm reduction else - alg.initdt + initdt end algebraic_vars = [all(iszero, x) for x in eachcol(M)] @@ -169,22 +191,24 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation du = f(u0, p, t) resid = _vec(du)[algebraic_eqs] - integrator.opts.internalnorm(resid, t) <= integrator.opts.abstol && return + check_dae_tolerance(integrator, resid, integrator.opts.abstol, t, isinplace) && return if isdefined(integrator.cache, :nlsolver) && !isnothing(alg.nlsolve) # backward Euler nlsolver = integrator.cache.nlsolver - oldγ, oldc, oldmethod, olddt = nlsolver.γ, nlsolver.c, nlsolver.method, + oldγ, oldc, oldmethod, + olddt = nlsolver.γ, nlsolver.c, nlsolver.method, integrator.dt nlsolver.tmp .= integrator.uprev nlsolver.γ, nlsolver.c = 1, 1 nlsolver.method = DIRK integrator.dt = dt z = nlsolve!(nlsolver, integrator, integrator.cache) - nlsolver.γ, nlsolver.c, nlsolver.method, integrator.dt = oldγ, oldc, oldmethod, + nlsolver.γ, nlsolver.c, nlsolver.method, + integrator.dt = oldγ, oldc, oldmethod, olddt failed = nlsolvefail(nlsolver) - @.. broadcast=false integrator.u=integrator.uprev + z + @.. broadcast=false integrator.u=integrator.uprev+z else nlequation_oop = @closure (u, _) -> begin update_coefficients!(M, u, p, t) @@ -224,7 +248,7 @@ function _initialize_dae!(integrator, prob::ODEProblem, alg::ShampineCollocation return end -function _initialize_dae!(integrator, prob::DAEProblem, +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::DAEProblem, alg::ShampineCollocationInit, isinplace::Val{true}) @unpack p, t, f = integrator u0 = integrator.u @@ -235,11 +259,11 @@ function _initialize_dae!(integrator, prob::DAEProblem, dt = t != 0 ? min(t / 1000, dtmax / 10) : dtmax / 10 # Haven't implemented norm reduction f(resid, integrator.du, u0, p, t) - integrator.opts.internalnorm(resid, t) <= integrator.opts.abstol && return + check_dae_tolerance(integrator, resid, integrator.opts.abstol, t, isinplace) && return # _du and _u should be non-dual since NonlinearSolve does not differentiate the solver # These non-dual values are thus used to make the caches - #_du = DiffEqBase.value.(du) + #_du = SciMLBase.value.(du) _u0 = DiffEqBase.value.(u0) # If not doing auto-diff of the solver, save an allocation @@ -252,7 +276,7 @@ function _initialize_dae!(integrator, prob::DAEProblem, isAD = alg_autodiff(integrator.alg) isa AutoForwardDiff || typeof(u0) !== typeof(_u0) if isAD chunk = ForwardDiff.pickchunksize(length(tmp)) - _tmp = PreallocationTools.dualcache(tmp, chunk) + _tmp = dualcache(tmp, chunk) else _tmp = tmp end @@ -264,7 +288,7 @@ function _initialize_dae!(integrator, prob::DAEProblem, else T = eltype(u) end - tmp = isAD ? PreallocationTools.get_tmp(_tmp, T) : _tmp + tmp = isAD ? get_tmp(_tmp, T) : _tmp #M * (u-u0)/dt - f(u,p,t) @. tmp = (u - _u0) / dt f(out, tmp, u, p, t) @@ -301,7 +325,7 @@ function _initialize_dae!(integrator, prob::DAEProblem, return end -function _initialize_dae!(integrator, prob::DAEProblem, +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::DAEProblem, alg::ShampineCollocationInit, isinplace::Val{false}) @unpack p, t, f = integrator u0 = integrator.u @@ -316,7 +340,7 @@ function _initialize_dae!(integrator, prob::DAEProblem, nlequation = (u, _) -> nlequation_oop(u) resid = f(integrator.du, u0, p, t) - integrator.opts.internalnorm(resid, t) <= integrator.opts.abstol && return + check_dae_tolerance(integrator, resid, integrator.opts.abstol, t, isinplace) && return jac = if isnothing(f.jac) f.jac @@ -365,8 +389,8 @@ function algebraic_jacobian(jac_prototype::T, algebraic_eqs, jac_prototype[algebraic_eqs, algebraic_vars] end -function _initialize_dae!(integrator, prob::ODEProblem, - alg::BrownFullBasicInit, isinplace::Val{true}) +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::ODEProblem, + alg::DiffEqBase.BrownFullBasicInit, isinplace::Val{true}) @unpack p, t, f = integrator u = integrator.u M = integrator.f.mass_matrix @@ -381,7 +405,7 @@ function _initialize_dae!(integrator, prob::ODEProblem, tmp .= ArrayInterface.restructure(tmp, algebraic_eqs .* _vec(tmp)) - integrator.opts.internalnorm(tmp, t) <= alg.abstol && return + check_dae_tolerance(integrator, tmp, alg.abstol, t, isinplace) && return alg_u = @view u[algebraic_vars] # These non-dual values are thus used to make the caches @@ -403,8 +427,8 @@ function _initialize_dae!(integrator, prob::ODEProblem, end end chunk = ForwardDiff.pickchunksize(csize) - _tmp = PreallocationTools.dualcache(tmp, chunk) - _du_tmp = PreallocationTools.dualcache(similar(tmp), chunk) + _tmp = dualcache(tmp, chunk) + _du_tmp = dualcache(similar(tmp), chunk) else _tmp, _du_tmp = tmp, similar(tmp) end @@ -416,8 +440,8 @@ function _initialize_dae!(integrator, prob::ODEProblem, else T = eltype(x) end - uu = isAD ? PreallocationTools.get_tmp(_tmp, T) : _tmp - du_tmp = isAD ? PreallocationTools.get_tmp(_du_tmp, T) : _du_tmp + uu = isAD ? get_tmp(_tmp, T) : _tmp + du_tmp = isAD ? get_tmp(_du_tmp, T) : _du_tmp copyto!(uu, _u) alg_uu = @view uu[algebraic_vars] alg_uu .= x @@ -446,8 +470,8 @@ function _initialize_dae!(integrator, prob::ODEProblem, return end -function _initialize_dae!(integrator, prob::ODEProblem, - alg::BrownFullBasicInit, isinplace::Val{false}) +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::ODEProblem, + alg::DiffEqBase.BrownFullBasicInit, isinplace::Val{false}) @unpack p, t, f = integrator u0 = integrator.u @@ -460,12 +484,12 @@ function _initialize_dae!(integrator, prob::ODEProblem, du = f(u0, p, t) resid = _vec(du)[algebraic_eqs] - integrator.opts.internalnorm(resid, t) <= alg.abstol && return + check_dae_tolerance(integrator, resid, alg.abstol, t, isinplace) && return isAD = alg_autodiff(integrator.alg) isa AutoForwardDiff if isAD chunk = ForwardDiff.pickchunksize(count(algebraic_vars)) - _tmp = PreallocationTools.dualcache(similar(u0), chunk) + _tmp = dualcache(similar(u0), chunk) else _tmp = similar(u0) end @@ -478,7 +502,7 @@ function _initialize_dae!(integrator, prob::ODEProblem, end nlequation = @closure (x, _) -> begin - uu = isAD ? PreallocationTools.get_tmp(_tmp, x) : _tmp + uu = isAD ? get_tmp(_tmp, x) : _tmp copyto!(uu, integrator.u) alg_u = @view uu[algebraic_vars] alg_u .= x @@ -514,8 +538,8 @@ function _initialize_dae!(integrator, prob::ODEProblem, return end -function _initialize_dae!(integrator, prob::DAEProblem, - alg::BrownFullBasicInit, isinplace::Val{true}) +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::DAEProblem, + alg::DiffEqBase.BrownFullBasicInit, isinplace::Val{true}) @unpack p, t, f = integrator differential_vars = prob.differential_vars u = integrator.u @@ -539,7 +563,7 @@ function _initialize_dae!(integrator, prob::DAEProblem, normtmp = get_tmp_cache(integrator)[1] f(normtmp, du, u, p, t) - if integrator.opts.internalnorm(normtmp, t) <= alg.abstol + if check_dae_tolerance(integrator, normtmp, alg.abstol, t, isinplace) return elseif differential_vars === nothing error("differential_vars must be set for DAE initialization to occur. Either set consistent initial conditions, differential_vars, or use a different initialization algorithm.") @@ -548,8 +572,8 @@ function _initialize_dae!(integrator, prob::DAEProblem, isAD = alg_autodiff(integrator.alg) isa AutoForwardDiff || typeof(u) !== typeof(_u) if isAD chunk = ForwardDiff.pickchunksize(length(tmp)) - _tmp = PreallocationTools.dualcache(tmp, chunk) - _du_tmp = PreallocationTools.dualcache(du_tmp, chunk) + _tmp = dualcache(tmp, chunk) + _du_tmp = dualcache(du_tmp, chunk) else _tmp, _du_tmp = tmp, du_tmp end @@ -561,8 +585,8 @@ function _initialize_dae!(integrator, prob::DAEProblem, else T = eltype(x) end - du_tmp = isAD ? PreallocationTools.get_tmp(_du_tmp, T) : _du_tmp - uu = isAD ? PreallocationTools.get_tmp(_tmp, T) : _tmp + du_tmp = isAD ? get_tmp(_du_tmp, T) : _du_tmp + uu = isAD ? get_tmp(_tmp, T) : _tmp @. du_tmp = ifelse(differential_vars, x, _du) @. uu = ifelse(differential_vars, _u, x) @@ -570,8 +594,9 @@ function _initialize_dae!(integrator, prob::DAEProblem, f(out, du_tmp, uu, p, t) end - if alg.nlsolve !== nothing - nlsolve = alg.nlsolve + nlsolve_alg = alg.nlsolve + if nlsolve_alg !== nothing + nlsolve = nlsolve_alg else nlsolve = NewtonRaphson(autodiff = alg_autodiff(integrator.alg)) end @@ -595,12 +620,13 @@ function _initialize_dae!(integrator, prob::DAEProblem, return end -function _initialize_dae!(integrator, prob::DAEProblem, - alg::BrownFullBasicInit, isinplace::Val{false}) +function _initialize_dae!(integrator::OrdinaryDiffEqCore.ODEIntegrator, prob::DAEProblem, + alg::DiffEqBase.BrownFullBasicInit, isinplace::Val{false}) @unpack p, t, f = integrator differential_vars = prob.differential_vars - if integrator.opts.internalnorm(f(integrator.du, integrator.u, p, t), t) <= alg.abstol + if check_dae_tolerance( + integrator, f(integrator.du, integrator.u, p, t), alg.abstol, t, isinplace) return elseif differential_vars === nothing error("differential_vars must be set for DAE initialization to occur. Either set consistent initial conditions, differential_vars, or use a different initialization algorithm.") @@ -616,9 +642,9 @@ function _initialize_dae!(integrator, prob::DAEProblem, end nlequation = @closure (x, _) -> begin - du = ifelse.(differential_vars, x, du) - u = ifelse.(differential_vars, u, x) - f(du, u, p, t) + du_ = ifelse.(differential_vars, x, du) + u_ = ifelse.(differential_vars, u, x) + f.f(du_, u_, p, t) end nlfunc = NonlinearFunction(nlequation; jac_prototype = f.jac_prototype) @@ -626,6 +652,8 @@ function _initialize_dae!(integrator, prob::DAEProblem, nlsolve = default_nlsolve(alg.nlsolve, isinplace, nlprob, integrator.u) + @show nlsolve + nlsol = solve(nlprob, nlsolve) du = ifelse.(differential_vars, nlsol.u, du) diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/newton.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/newton.jl index c1c8f67db7..d12eae3f20 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/newton.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/newton.jl @@ -1,7 +1,7 @@ ## initialize! @muladd function initialize!(nlsolver::NLSolver{<:NLNewton, false}, - integrator::DiffEqBase.DEIntegrator) + integrator::SciMLBase.DEIntegrator) @unpack dt = integrator @unpack cache = nlsolver @@ -12,7 +12,7 @@ end @muladd function initialize!(nlsolver::NLSolver{<:NLNewton, true}, - integrator::DiffEqBase.DEIntegrator) + integrator::SciMLBase.DEIntegrator) @unpack u, uprev, t, dt, opts = integrator @unpack cache = nlsolver @unpack weight = cache @@ -26,14 +26,14 @@ end end function initialize!(nlsolver::NLSolver{<:NonlinearSolveAlg, false}, - integrator::DiffEqBase.DEIntegrator) + integrator::SciMLBase.DEIntegrator) @unpack uprev, t, p, dt, opts, f = integrator @unpack z, tmp, ztmp, γ, α, iter, cache, method, alg = nlsolver cache.invγdt = inv(dt * nlsolver.γ) cache.tstep = integrator.t + nlsolver.c * dt @unpack ustep, tstep, k, invγdt = cache - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) integrator.stats.nf += cache.cache.stats.nf integrator.stats.nnonliniter += cache.cache.stats.nsteps integrator.stats.njacs += cache.cache.stats.njacs @@ -49,27 +49,43 @@ function initialize!(nlsolver::NLSolver{<:NonlinearSolveAlg, false}, end function initialize!(nlsolver::NLSolver{<:NonlinearSolveAlg, true}, - integrator::DiffEqBase.DEIntegrator) + integrator::SciMLBase.DEIntegrator) @unpack uprev, t, p, dt, opts, f = integrator @unpack z, tmp, ztmp, γ, α, iter, cache, method, alg = nlsolver cache.invγdt = inv(dt * nlsolver.γ) cache.tstep = integrator.t + nlsolver.c * dt - @unpack ustep, tstep, k, invγdt = cache + @unpack ustep, atmp, tstep, k, invγdt = cache - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) integrator.stats.nf += cache.cache.stats.nf integrator.stats.nnonliniter += cache.cache.stats.nsteps integrator.stats.njacs += cache.cache.stats.njacs end - if f isa DAEFunction - nlp_params = (tmp, ztmp, ustep, γ, α, tstep, k, invγdt, p, dt, f) + + nlstep_data = f.nlstep_data + if nlstep_data !== nothing + atmp .= 0 + if method === COEFFICIENT_MULTISTEP + nlstep_data.set_γ_c(nlstep_data.nlprob, (one(t), one(t), α * invγdt, tstep)) + nlstep_data.set_inner_tmp(nlstep_data.nlprob, atmp) + nlstep_data.set_outer_tmp(nlstep_data.nlprob, tmp) + else + nlstep_data.set_γ_c(nlstep_data.nlprob, (dt, γ, one(t), tstep)) + nlstep_data.set_inner_tmp(nlstep_data.nlprob, tmp) + nlstep_data.set_outer_tmp(nlstep_data.nlprob, atmp) + end + nlstep_data.nlprob.u0 .= @view z[nlstep_data.u0perm] + SciMLBase.reinit!(cache.cache, nlstep_data.nlprob.u0, p=nlstep_data.nlprob.p) else - nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, method, p, dt, f) + if f isa DAEFunction + nlp_params = (tmp, ztmp, ustep, γ, α, tstep, k, invγdt, p, dt, f) + else + nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, method, p, dt, f) + end + SciMLBase.reinit!(cache.cache, z, p=nlp_params) end - new_prob = remake(cache.prob, p = nlp_params, u0 = z) - cache.cache = init(new_prob, alg.alg) nothing end @@ -102,14 +118,30 @@ end @unpack z, tmp, ztmp, γ, α, cache, method = nlsolver @unpack tstep, invγdt, atmp, ustep = cache + nlstep_data = integrator.f.nlstep_data nlcache = nlsolver.cache.cache step!(nlcache) - @.. broadcast=false ztmp=nlcache.u - ustep = compute_ustep!(ustep, tmp, γ, z, method) - calculate_residuals!(atmp, nlcache.fu, uprev, ustep, opts.abstol, opts.reltol, - opts.internalnorm, t) - ndz = opts.internalnorm(atmp, t) + if nlstep_data !== nothing + nlstepsol = SciMLBase.build_solution( + nlcache.prob, nlcache.alg, nlcache.u, nlcache.fu; + nlcache.retcode, nlcache.stats, nlcache.trace + ) + nlstep_data.nlprobmap(ztmp, nlstepsol) + ustep = compute_ustep!(ustep, tmp, γ, z, method) + calculate_residuals!(@view(atmp[nlstep_data.u0perm]), nlcache.fu, + @view(uprev[nlstep_data.u0perm]), + @view(ustep[nlstep_data.u0perm]), opts.abstol, + opts.reltol, opts.internalnorm, t) + ndz = opts.internalnorm(atmp, t) + else + @.. broadcast=false ztmp=nlcache.u + ustep = compute_ustep!(ustep, tmp, γ, z, method) + calculate_residuals!(atmp, nlcache.fu, uprev, ustep, opts.abstol, opts.reltol, + opts.internalnorm, t) + ndz = opts.internalnorm(atmp, t) + end + #ndz = opts.internalnorm(nlcache.fu, t) # NDF and BDF are special because the truncation error is directly # proportional to the total displacement. @@ -155,7 +187,7 @@ Equations II, Springer Series in Computational Mathematics. ISBN ztmp, ustep = _compute_rhs(tmp, γ, α, tstep, invγdt, method, p, dt, f, z) end - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end @@ -167,7 +199,7 @@ Equations II, Springer Series in Computational Mathematics. ISBN end dz = _reshape(W \ _vec(ztmp), axes(ztmp)) dz = relax(dz, nlsolver, integrator, f) - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) integrator.stats.nsolve += 1 end @@ -194,7 +226,7 @@ end f = nlsolve_f(integrator) isdae = f isa DAEFunction - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end @@ -229,9 +261,14 @@ end reltol = reltol) end + if !SciMLBase.successful_retcode(linres.retcode) && + linres.retcode != SciMLBase.ReturnCode.Default + return convert(eltype(atmp,), Inf) + end + cache.linsolve = linres.cache - if DiffEqBase.has_stats(integrator) + if SciMLBase.has_stats(integrator) integrator.stats.nsolve += 1 end @@ -293,7 +330,7 @@ function compute_ustep!(ustep, tmp, γ, z, method) ustep end -function _compute_rhs(tmp, γ, α, tstep, invγdt, method::MethodType, p, dt, f, z) +function _compute_rhs(tmp, γ, α, tstep, invγdt, method::MethodType, p, dt, f::F, z) where F mass_matrix = f.mass_matrix ustep = compute_ustep(tmp, γ, z, method) if method === COEFFICIENT_MULTISTEP @@ -301,7 +338,7 @@ function _compute_rhs(tmp, γ, α, tstep, invγdt, method::MethodType, p, dt, f, if mass_matrix === I ztmp = tmp .+ f(z, p, tstep) .- (α * invγdt) .* z else - update_coefficients!(mass_matrix, ustep, p, tstep) + update_coefficients!(mass_matrix, z, p, tstep) ztmp = tmp .+ f(z, p, tstep) .- (mass_matrix * z) .* (α * invγdt) end else @@ -405,11 +442,16 @@ end function relax(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF) where {TF} relax(dz, nlsolver, integrator, f, relax(nlsolver)) end +function relax!(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, + r::Nothing) where {TF} + dz +end function relax!(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, r::Number) where {TF} if !iszero(r) rmul!(dz, 1 - r) end + dz end function relax!(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, @@ -422,7 +464,7 @@ function relax!(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, @unpack uprev, t, p, dt, opts, isdae = integrator @unpack z, tmp, ztmp, γ, iter, α, cache, method = nlsolver - @unpack ustep, atmp, tstep, k, invγdt, tstep, k, invγdt = cache + @unpack ustep, atmp, tstep, k, invγdt = cache function resid(z) # recompute residual (rhs) if isdae @@ -470,6 +512,11 @@ function relax(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, return dz end +function relax(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, + r::Nothing) where {TF} + return dz +end + function relax(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, linesearch) where {TF} let dz = dz, @@ -479,7 +526,8 @@ function relax(dz, nlsolver::AbstractNLSolver, integrator::DEIntegrator, f::TF, linesearch = linesearch @unpack uprev, t, p, dt, opts = integrator - @unpack z, tmp, ztmp, γ, iter, cache = nlsolver + @unpack z, tmp, ztmp, γ, iter, cache, method = nlsolver + @unpack ustep, atmp, tstep, k, invγdt = cache function resid(z) # recompute residual (rhs) if f isa DAEFunction @@ -524,9 +572,8 @@ function Base.resize!(nlcache::NLNewtonCache, ::AbstractNLSolver, integrator, i: resize!(nlcache.atmp, i) resize!(nlcache.dz, i) resize!(nlcache.du1, i) - if nlcache.jac_config !== nothing - resize_jac_config!(nlcache.jac_config, i) - end + + resize_jac_config!(nlcache, integrator) resize!(nlcache.weight, i) # resize J and W (or rather create new ones of appropriate size and type) @@ -534,3 +581,4 @@ function Base.resize!(nlcache::NLNewtonCache, ::AbstractNLSolver, integrator, i: nothing end + diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/nlsolve.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/nlsolve.jl index 1633531bdc..3e389d4270 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/nlsolve.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/nlsolve.jl @@ -11,7 +11,7 @@ dt⋅f(innertmp + γ⋅z, p, t + c⋅dt) + outertmp = z where `dt` is the step size and `γ` and `c` are constants, and return the solution `z`. """ -function nlsolve!(nlsolver::NL, integrator::DiffEqBase.DEIntegrator, +function nlsolve!(nlsolver::NL, integrator::SciMLBase.DEIntegrator, cache = nothing, repeat_step = false) where {NL <: AbstractNLSolver} always_new = is_always_new(nlsolver) check_div′ = check_div(nlsolver) @@ -104,10 +104,10 @@ function nlsolve!(nlsolver::NL, integrator::DiffEqBase.DEIntegrator, η = DiffEqBase.value(θ / (1 - θ)) # don't trust θ for non-adaptive on first iter because the solver doesn't provide feedback # for us to know whether our previous nlsolve converged sufficiently well - check_η_convergance = (iter > 1 || + check_η_convergence = (iter > 1 || (isnewton(nlsolver) && isadaptive(integrator.alg))) if (iter == 1 && ndz < 1e-5) || - (check_η_convergance && η >= zero(η) && η * ndz < κ) + (check_η_convergence && η >= zero(η) && η * ndz < κ) nlsolver.status = Convergence nlsolver.nfails = 0 break @@ -127,14 +127,14 @@ end ## default implementations -initialize!(::AbstractNLSolver, integrator::DiffEqBase.DEIntegrator) = nothing +initialize!(::AbstractNLSolver, integrator::SciMLBase.DEIntegrator) = nothing function initial_η(nlsolver::NLSolver, integrator) max(nlsolver.ηold, eps(eltype(integrator.opts.reltol)))^(0.8) end function apply_step!(nlsolver::NLSolver{algType, iip}, - integrator::DiffEqBase.DEIntegrator) where {algType, iip} + integrator::SciMLBase.DEIntegrator) where {algType, iip} if iip @.. broadcast=false nlsolver.z=nlsolver.ztmp else @@ -144,8 +144,8 @@ function apply_step!(nlsolver::NLSolver{algType, iip}, nothing end -function postamble!(nlsolver::NLSolver, integrator::DiffEqBase.DEIntegrator) - if DiffEqBase.has_stats(integrator) +function postamble!(nlsolver::NLSolver, integrator::SciMLBase.DEIntegrator) + if SciMLBase.has_stats(integrator) integrator.stats.nnonliniter += nlsolver.iter if nlsolvefail(nlsolver) diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl index 4c36666b6e..7b41c54903 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/type.jl @@ -35,7 +35,7 @@ end function NLNewton(; κ = 1 // 100, max_iter = 10, fast_convergence_cutoff = 1 // 5, new_W_dt_cutoff = 1 // 5, always_new = false, check_div = true, - relax = 0 // 1) + relax = nothing) if relax isa Number && !(0 <= relax < 1) throw(ArgumentError("The relaxation parameter must be in [0, 1), got `relax = $relax`")) end @@ -57,10 +57,6 @@ end function NonlinearSolveAlg(alg = NewtonRaphson(autodiff = AutoFiniteDiff()); κ = 1 // 100, max_iter = 10, fast_convergence_cutoff = 1 // 5, new_W_dt_cutoff = 1 // 5, always_new = false, check_div = true) - if relax isa Number && !(0 <= relax < 1) - throw(ArgumentError("The relaxation parameter must be in [0, 1), got `relax = $relax`")) - end - NonlinearSolveAlg( κ, max_iter, fast_convergence_cutoff, new_W_dt_cutoff, always_new, check_div, alg) @@ -100,7 +96,7 @@ function NLSolver{iip, tType}(z, tmp, ztmp, γ, c, α, alg, κ, fast_convergence tmp, tmp2, ztmp, - γ, + float(γ), convert(tType, c), convert(tType, α), alg, diff --git a/lib/OrdinaryDiffEqNonlinearSolve/src/utils.jl b/lib/OrdinaryDiffEqNonlinearSolve/src/utils.jl index 3bed6a453a..49a0db411d 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/src/utils.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/src/utils.jl @@ -71,11 +71,12 @@ mutable struct DAEResidualJacobianWrapper{isAD, F, pType, duType, uType, alphaTy tmp::tmpType uprev::uprevType t::tType - function DAEResidualJacobianWrapper(alg, f, p, α, invγdt, tmp, uprev, t) - isautodiff = alg_autodiff(alg) isa AutoForwardDiff + function DAEResidualJacobianWrapper(alg, f::F, p, α, invγdt, tmp, uprev, t) where F + ad = ADTypes.dense_ad(alg_autodiff(alg)) + isautodiff = ad isa AutoForwardDiff if isautodiff - tmp_du = PreallocationTools.dualcache(uprev) - tmp_u = PreallocationTools.dualcache(uprev) + tmp_du = dualcache(uprev) + tmp_u = dualcache(uprev) else tmp_du = similar(uprev) tmp_u = similar(uprev) @@ -86,12 +87,19 @@ mutable struct DAEResidualJacobianWrapper{isAD, F, pType, duType, uType, alphaTy end end +function SciMLBase.setproperties(wrap::DAEResidualJacobianWrapper, patch::NamedTuple) + for key in keys(patch) + setproperty!(wrap, key, patch[key]) + end + return wrap +end + is_autodiff(m::DAEResidualJacobianWrapper{isAD}) where {isAD} = isAD function (m::DAEResidualJacobianWrapper)(out, x) if is_autodiff(m) - tmp_du = PreallocationTools.get_tmp(m.tmp_du, x) - tmp_u = PreallocationTools.get_tmp(m.tmp_u, x) + tmp_du = get_tmp(m.tmp_du, x) + tmp_u = get_tmp(m.tmp_u, x) else tmp_du = m.tmp_du tmp_u = m.tmp_u @@ -118,13 +126,13 @@ function (m::DAEResidualDerivativeWrapper)(x) m.f(tmp_du, tmp_u, m.p, m.t) end -DiffEqBase.has_jac(f::DAEResidualJacobianWrapper) = DiffEqBase.has_jac(f.f) -DiffEqBase.has_Wfact(f::DAEResidualJacobianWrapper) = DiffEqBase.has_Wfact(f.f) -DiffEqBase.has_Wfact_t(f::DAEResidualJacobianWrapper) = DiffEqBase.has_Wfact_t(f.f) +SciMLBase.has_jac(f::DAEResidualJacobianWrapper) = SciMLBase.has_jac(f.f) +SciMLBase.has_Wfact(f::DAEResidualJacobianWrapper) = SciMLBase.has_Wfact(f.f) +SciMLBase.has_Wfact_t(f::DAEResidualJacobianWrapper) = SciMLBase.has_Wfact_t(f.f) -DiffEqBase.has_jac(f::DAEResidualDerivativeWrapper) = DiffEqBase.has_jac(f.f) -DiffEqBase.has_Wfact(f::DAEResidualDerivativeWrapper) = DiffEqBase.has_Wfact(f.f) -DiffEqBase.has_Wfact_t(f::DAEResidualDerivativeWrapper) = DiffEqBase.has_Wfact_t(f.f) +SciMLBase.has_jac(f::DAEResidualDerivativeWrapper) = SciMLBase.has_jac(f.f) +SciMLBase.has_Wfact(f::DAEResidualDerivativeWrapper) = SciMLBase.has_Wfact(f.f) +SciMLBase.has_Wfact_t(f::DAEResidualDerivativeWrapper) = SciMLBase.has_Wfact_t(f.f) function build_nlsolver(alg, u, uprev, p, t, dt, f::F, rate_prototype, ::Type{uEltypeNoUnits}, @@ -145,6 +153,17 @@ function build_nlsolver(alg, u, uprev, p, t, dt, f::F, rate_prototype, uBottomEltypeNoUnits, tTypeNoUnits, γ, c, α, iip) end +function daenlf(ztmp, z, p) + tmp, ustep, γ, α, tstep, k, invγdt, _p, dt, f = p + _compute_rhs!(tmp, ztmp, ustep, γ, α, tstep, k, invγdt, _p, dt, f, z)[1] +end + +function odenlf(ztmp, z, p) + tmp, ustep, γ, α, tstep, k, invγdt, method, _p, dt, f = p + _compute_rhs!( + tmp, ztmp, ustep, γ, α, tstep, k, invγdt, method, _p, dt, f, z)[1] +end + function build_nlsolver( alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton, NonlinearSolveAlg}, u, uprev, p, t, dt, @@ -154,7 +173,7 @@ function build_nlsolver( ::Val{true}) where {F, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} #TODO - #nlalg = DiffEqBase.handle_defaults(alg, nlalg) + #nlalg = SciMLBase.handle_defaults(alg, nlalg) # define unitless type uTolType = real(uBottomEltypeNoUnits) isdae = alg isa DAEAlgorithm @@ -169,11 +188,11 @@ function build_nlsolver( tstep = zero(t) k = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) + atmp .= false dz = zero(u) if nlalg isa Union{NLNewton, NonlinearSolveAlg} nf = nlsolve_f(f, alg) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) # TODO: check if the solver is iterative weight = zero(u) @@ -191,12 +210,14 @@ function build_nlsolver( end jac_config = build_jac_config(alg, nf, uf, du1, uprev, u, ztmp, dz) end + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) linprob = LinearProblem(W, _vec(k); u0 = _vec(dz)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, dz) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init(linprob, alg.linsolve, + alias = LinearAliasSpecifier(alias_A = true, alias_b = true), Pl = Pl, Pr = Pr, assumptions = LinearSolve.OperatorAssumptions(true)) @@ -206,21 +227,17 @@ function build_nlsolver( if nlalg isa NonlinearSolveAlg α = tTypeNoUnits(α) dt = tTypeNoUnits(dt) - if isdae - nlf = (ztmp, z, p) -> begin - tmp, ustep, γ, α, tstep, k, invγdt, _p, dt, f = p - _compute_rhs!(tmp, ztmp, ustep, γ, α, tstep, k, invγdt, _p, dt, f, z)[1] - end - nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, p, dt, f) + prob = if f.nlstep_data !== nothing + prob = f.nlstep_data.nlprob else - nlf = (ztmp, z, p) -> begin - tmp, ustep, γ, α, tstep, k, invγdt, method, _p, dt, f = p - _compute_rhs!( - tmp, ztmp, ustep, γ, α, tstep, k, invγdt, method, _p, dt, f, z)[1] + nlf = isdae ? daenlf : odenlf + nlp_params = if isdae + (tmp, ustep, γ, α, tstep, k, invγdt, p, dt, f) + else + (tmp, ustep, γ, α, tstep, k, invγdt, DIRK, p, dt, f) end - nlp_params = (tmp, ustep, γ, α, tstep, k, invγdt, DIRK, p, dt, f) + NonlinearProblem(NonlinearFunction{true}(nlf), ztmp, nlp_params) end - prob = NonlinearProblem(NonlinearFunction(nlf), ztmp, nlp_params) cache = init(prob, nlalg.alg) nlcache = NonlinearSolveCache(ustep, tstep, k, atmp, invγdt, prob, cache) else @@ -253,6 +270,16 @@ function build_nlsolver( Divergence, nlcache) end +function oopdaenlf(z, p) + tmp, α, tstep, invγdt, _p, dt, uprev, f = p + _compute_rhs(tmp, α, tstep, invγdt, p, dt, uprev, f, z)[1] +end + +function oopodenlf(z, p) + tmp, γ, α, tstep, invγdt, method, _p, dt, f = p + _compute_rhs(tmp, γ, α, tstep, invγdt, method, _p, dt, f, z)[1] +end + function build_nlsolver( alg, nlalg::Union{NLFunctional, NLAnderson, NLNewton, NonlinearSolveAlg}, u, uprev, p, @@ -263,7 +290,7 @@ function build_nlsolver( ::Val{false}) where {F, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} #TODO - #nlalg = DiffEqBase.handle_defaults(alg, nlalg) + #nlalg = SciMLBase.handle_defaults(alg, nlalg) # define unitless type uTolType = real(uBottomEltypeNoUnits) isdae = alg isa DAEAlgorithm @@ -287,24 +314,17 @@ function build_nlsolver( tType = typeof(t) invγdt = inv(oneunit(t) * one(uTolType)) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) if nlalg isa NonlinearSolveAlg α = tTypeNoUnits(α) dt = tTypeNoUnits(dt) - if isdae - nlf = (z, p) -> begin - tmp, α, tstep, invγdt, _p, dt, uprev, f = p - _compute_rhs(tmp, α, tstep, invγdt, p, dt, uprev, f, z)[1] - end - nlp_params = (tmp, α, tstep, invγdt, _p, dt, uprev, f) + nlf = isdae ? oopdaenlf : oopodenlf + nlp_params = if isdae + (tmp, α, tstep, invγdt, p, dt, uprev, f) else - nlf = (z, p) -> begin - tmp, γ, α, tstep, invγdt, method, _p, dt, f = p - _compute_rhs(tmp, γ, α, tstep, invγdt, method, _p, dt, f, z)[1] - end - nlp_params = (tmp, γ, α, tstep, invγdt, DIRK, p, dt, f) + (tmp, γ, α, tstep, invγdt, DIRK, p, dt, f) end - prob = NonlinearProblem(NonlinearFunction(nlf), copy(ztmp), nlp_params) + prob = NonlinearProblem(NonlinearFunction{false}(nlf), copy(ztmp), nlp_params) cache = init(prob, nlalg.alg) nlcache = NonlinearSolveCache( nothing, tstep, nothing, nothing, invγdt, prob, cache) @@ -474,7 +494,7 @@ end ## resize -function resize_nlsolver!(integrator::DiffEqBase.DEIntegrator, i::Int) +function resize_nlsolver!(integrator::SciMLBase.DEIntegrator, i::Int) isdefined(integrator.cache, :nlsolver) || return @unpack nlsolver = integrator.cache diff --git a/lib/OrdinaryDiffEqNonlinearSolve/test/jet.jl b/lib/OrdinaryDiffEqNonlinearSolve/test/jet.jl new file mode 100644 index 0000000000..ac28aad6f9 --- /dev/null +++ b/lib/OrdinaryDiffEqNonlinearSolve/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqNonlinearSolve +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqNonlinearSolve, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqNonlinearSolve/test/newton_tests.jl b/lib/OrdinaryDiffEqNonlinearSolve/test/newton_tests.jl index bbb78122c8..312c718dde 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/test/newton_tests.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/test/newton_tests.jl @@ -1,16 +1,18 @@ +using OrdinaryDiffEqNonlinearSolve: NLNewton using OrdinaryDiffEqCore +using OrdinaryDiffEqSDIRK using DiffEqDevTools using DiffEqBase using LineSearches using Test -import ODEProblemLibrary: prob_ode_orego, prob_ode_rober, prob_ode_lorenz +using ODEProblemLibrary: prob_ode_lorenz, prob_ode_orego for prob in (prob_ode_lorenz, prob_ode_orego) sol1 = solve(prob, Trapezoid(), reltol = 1e-12, abstol = 1e-12) - @test sol1.retcode == DiffEqBase.ReturnCode.Success + @test sol1.retcode == SciMLBase.ReturnCode.Success sol2 = solve(prob, Trapezoid(nlsolve = NLNewton(relax = BackTracking())), reltol = 1e-12, abstol = 1e-12) - @test sol2.retcode == DiffEqBase.ReturnCode.Success - @test sol2.stats.nf <= sol1.stats.nf + @test sol2.retcode == SciMLBase.ReturnCode.Success + @test sol2.stats.nf <= sol1.stats.nf + 20 end diff --git a/lib/OrdinaryDiffEqNonlinearSolve/test/qa.jl b/lib/OrdinaryDiffEqNonlinearSolve/test/qa.jl new file mode 100644 index 0000000000..f380854776 --- /dev/null +++ b/lib/OrdinaryDiffEqNonlinearSolve/test/qa.jl @@ -0,0 +1,9 @@ +using OrdinaryDiffEqNonlinearSolve +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqNonlinearSolve; + piracies = false + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqNonlinearSolve/test/runtests.jl b/lib/OrdinaryDiffEqNonlinearSolve/test/runtests.jl index 37192c8dbf..4ddf17cce3 100644 --- a/lib/OrdinaryDiffEqNonlinearSolve/test/runtests.jl +++ b/lib/OrdinaryDiffEqNonlinearSolve/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets -@time @safetestset "Newton Tests" include("interface/newton_tests.jl") +@time @safetestset "Newton Tests" include("newton_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqNordsieck/Project.toml b/lib/OrdinaryDiffEqNordsieck/Project.toml index 8acc1dd828..969270877a 100644 --- a/lib/OrdinaryDiffEqNordsieck/Project.toml +++ b/lib/OrdinaryDiffEqNordsieck/Project.toml @@ -1,44 +1,58 @@ name = "OrdinaryDiffEqNordsieck" uuid = "c9986a66-5c92-4813-8696-a7ec84c806c8" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.4.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqTsit5 = "<0.0.1, 1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +OrdinaryDiffEqTsit5 = "1.4.0" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +Polyester = "0.7" +LinearAlgebra = "1.10" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqTsit5] +path = "../OrdinaryDiffEqTsit5" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqNordsieck/src/OrdinaryDiffEqNordsieck.jl b/lib/OrdinaryDiffEqNordsieck/src/OrdinaryDiffEqNordsieck.jl index fa8b873e42..5db6344b12 100644 --- a/lib/OrdinaryDiffEqNordsieck/src/OrdinaryDiffEqNordsieck.jl +++ b/lib/OrdinaryDiffEqNordsieck/src/OrdinaryDiffEqNordsieck.jl @@ -19,7 +19,7 @@ using OrdinaryDiffEqTsit5: Tsit5ConstantCache, Tsit5Cache import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("controllers.jl") diff --git a/lib/OrdinaryDiffEqNordsieck/test/jet.jl b/lib/OrdinaryDiffEqNordsieck/test/jet.jl new file mode 100644 index 0000000000..a814b9561d --- /dev/null +++ b/lib/OrdinaryDiffEqNordsieck/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqNordsieck +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqNordsieck, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqNordsieck/test/nordsieck_tests.jl b/lib/OrdinaryDiffEqNordsieck/test/nordsieck_tests.jl index 9cdf1064f1..0cbd302597 100644 --- a/lib/OrdinaryDiffEqNordsieck/test/nordsieck_tests.jl +++ b/lib/OrdinaryDiffEqNordsieck/test/nordsieck_tests.jl @@ -23,6 +23,7 @@ probArr = [prob_ode_linear, prob = probArr[i] sol = solve(prob, AN5(), reltol = 1e-6) @test length(sol.t) < 11 + @test SciMLBase.successful_retcode(sol) exact = prob.f.analytic(prob.u0, prob.p, prob.tspan[end]) @test exact≈sol[end] atol=1e-5 end @@ -35,6 +36,7 @@ end prob = probArr[i] sol = solve(prob, sol, reltol = 1e-4, abstol = 1e-7) @test length(sol.t) < 22 + @test SciMLBase.successful_retcode(sol) exact = prob.f.analytic(prob.u0, prob.p, prob.tspan[end]) @test norm(exact - sol[end], Inf) < 3e-3 end diff --git a/lib/OrdinaryDiffEqNordsieck/test/qa.jl b/lib/OrdinaryDiffEqNordsieck/test/qa.jl new file mode 100644 index 0000000000..a357974639 --- /dev/null +++ b/lib/OrdinaryDiffEqNordsieck/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqNordsieck +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqNordsieck + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqNordsieck/test/runtests.jl b/lib/OrdinaryDiffEqNordsieck/test/runtests.jl index 94733f2e58..169879e28d 100644 --- a/lib/OrdinaryDiffEqNordsieck/test/runtests.jl +++ b/lib/OrdinaryDiffEqNordsieck/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "Nordsieck Tests" include("nordsieck_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqPDIRK/Project.toml b/lib/OrdinaryDiffEqPDIRK/Project.toml index 2e1b6bb3b4..0f5d3045af 100644 --- a/lib/OrdinaryDiffEqPDIRK/Project.toml +++ b/lib/OrdinaryDiffEqPDIRK/Project.toml @@ -1,40 +1,59 @@ name = "OrdinaryDiffEqPDIRK" uuid = "5dd0a6cf-3d4b-4314-aa06-06d4e299bc89" authors = ["ParamThakkar123 "] -version = "1.1.1" +version = "1.6.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqNonlinearSolve = "<0.0.1, 1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +Polyester = "0.7" +OrdinaryDiffEqDifferentiation = "1.12.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqNonlinearSolve] +path = "../OrdinaryDiffEqNonlinearSolve" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqPDIRK/src/OrdinaryDiffEqPDIRK.jl b/lib/OrdinaryDiffEqPDIRK/src/OrdinaryDiffEqPDIRK.jl index 18a4e56205..f286f5631b 100644 --- a/lib/OrdinaryDiffEqPDIRK/src/OrdinaryDiffEqPDIRK.jl +++ b/lib/OrdinaryDiffEqPDIRK/src/OrdinaryDiffEqPDIRK.jl @@ -5,19 +5,22 @@ import OrdinaryDiffEqCore: isfsal, alg_order, _unwrap_val, OrdinaryDiffEqMutableCache, constvalue, alg_cache, uses_uprev, @unpack, unwrap_alg, @cache, DEFAULT_PRECS, @threaded, initialize!, perform_step!, isthreaded, - full_cache, get_fsalfirstlast, differentiation_rk_docstring + full_cache, get_fsalfirstlast, differentiation_rk_docstring, + _bool_to_ADType, _process_AD_choice import StaticArrays: SVector import MuladdMacro: @muladd import FastBroadcast: @.. using Polyester using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase using OrdinaryDiffEqDifferentiation: dolinsolve using OrdinaryDiffEqNonlinearSolve: NLNewton, build_nlsolver, nlsolve!, nlsolvefail, markfirststage! +import ADTypes: AutoForwardDiff, AbstractADType + include("algorithms.jl") include("alg_utils.jl") include("pdirk_caches.jl") diff --git a/lib/OrdinaryDiffEqPDIRK/src/algorithms.jl b/lib/OrdinaryDiffEqPDIRK/src/algorithms.jl index 0e93763cfd..e98895aaac 100644 --- a/lib/OrdinaryDiffEqPDIRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqPDIRK/src/algorithms.jl @@ -28,13 +28,17 @@ struct PDIRK44{CS, AD, F, F2, P, FDT, ST, CJ, TO} <: precs::P extrapolant::Symbol threading::TO + autodiff::AD end -function PDIRK44(; chunk_size = Val{0}(), autodiff = true, standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function PDIRK44(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :constant, threading = true) - PDIRK44{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + PDIRK44{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(threading)}(linsolve, nlsolve, precs, - extrapolant, threading) + extrapolant, threading, AD_choice) end diff --git a/lib/OrdinaryDiffEqPDIRK/test/jet.jl b/lib/OrdinaryDiffEqPDIRK/test/jet.jl new file mode 100644 index 0000000000..b4fb46b7ff --- /dev/null +++ b/lib/OrdinaryDiffEqPDIRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqPDIRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqPDIRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqPDIRK/test/qa.jl b/lib/OrdinaryDiffEqPDIRK/test/qa.jl new file mode 100644 index 0000000000..78304ff879 --- /dev/null +++ b/lib/OrdinaryDiffEqPDIRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqPDIRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqPDIRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqPDIRK/test/runtests.jl b/lib/OrdinaryDiffEqPDIRK/test/runtests.jl index 8b13789179..68d9fbc840 100644 --- a/lib/OrdinaryDiffEqPDIRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqPDIRK/test/runtests.jl @@ -1 +1,3 @@ +using SafeTestsets +@time @safetestset "JET Tests" include("jet.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqPRK/Project.toml b/lib/OrdinaryDiffEqPRK/Project.toml index f34b93901b..ee2acb4078 100644 --- a/lib/OrdinaryDiffEqPRK/Project.toml +++ b/lib/OrdinaryDiffEqPRK/Project.toml @@ -1,34 +1,45 @@ name = "OrdinaryDiffEqPRK" uuid = "5b33eab2-c0f1-4480-b2c3-94bc1e80bda1" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.4.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Test = "<0.0.1, 1" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +Polyester = "0.7" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqPRK/src/OrdinaryDiffEqPRK.jl b/lib/OrdinaryDiffEqPRK/src/OrdinaryDiffEqPRK.jl index 437d2769d9..8e0f3fe0d8 100644 --- a/lib/OrdinaryDiffEqPRK/src/OrdinaryDiffEqPRK.jl +++ b/lib/OrdinaryDiffEqPRK/src/OrdinaryDiffEqPRK.jl @@ -10,7 +10,7 @@ import FastBroadcast: @.. using Polyester using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqPRK/test/jet.jl b/lib/OrdinaryDiffEqPRK/test/jet.jl new file mode 100644 index 0000000000..a776622e8f --- /dev/null +++ b/lib/OrdinaryDiffEqPRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqPRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqPRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqPRK/test/qa.jl b/lib/OrdinaryDiffEqPRK/test/qa.jl new file mode 100644 index 0000000000..826d01c760 --- /dev/null +++ b/lib/OrdinaryDiffEqPRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqPRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqPRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqPRK/test/runtests.jl b/lib/OrdinaryDiffEqPRK/test/runtests.jl index 593f765d07..f971e6442f 100644 --- a/lib/OrdinaryDiffEqPRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqPRK/test/runtests.jl @@ -1 +1,4 @@ using SafeTestsets + +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqQPRK/Project.toml b/lib/OrdinaryDiffEqQPRK/Project.toml index d0fc6065d0..49f9ba3b23 100644 --- a/lib/OrdinaryDiffEqQPRK/Project.toml +++ b/lib/OrdinaryDiffEqQPRK/Project.toml @@ -1,38 +1,49 @@ name = "OrdinaryDiffEqQPRK" uuid = "04162be5-8125-4266-98ed-640baecc6514" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.4.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqQPRK/src/OrdinaryDiffEqQPRK.jl b/lib/OrdinaryDiffEqQPRK/src/OrdinaryDiffEqQPRK.jl index cb09e4bb99..9e268acbe5 100644 --- a/lib/OrdinaryDiffEqQPRK/src/OrdinaryDiffEqQPRK.jl +++ b/lib/OrdinaryDiffEqQPRK/src/OrdinaryDiffEqQPRK.jl @@ -14,7 +14,7 @@ using RecursiveArrayTools: recursive_unitless_bottom_eltype, recursivefill! import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqQPRK/test/jet.jl b/lib/OrdinaryDiffEqQPRK/test/jet.jl new file mode 100644 index 0000000000..4d53c40fc8 --- /dev/null +++ b/lib/OrdinaryDiffEqQPRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqQPRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqQPRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqQPRK/test/ode_quadruple_precision_tests.jl b/lib/OrdinaryDiffEqQPRK/test/ode_quadruple_precision_tests.jl index 36baa703b2..61ae1d7f44 100644 --- a/lib/OrdinaryDiffEqQPRK/test/ode_quadruple_precision_tests.jl +++ b/lib/OrdinaryDiffEqQPRK/test/ode_quadruple_precision_tests.jl @@ -50,6 +50,7 @@ for prob in test_problems_only_time sol = solve(prob, alg, adaptive = true, save_everystep = true) sol_exact = prob.f.analytic(prob.u0, prob.p, sol.t[end]) @test length(sol) < 7 + @test SciMLBase.successful_retcode(sol) @test minimum(abs.(sol.u[end] .- sol_exact) .< 1e-12) end @@ -60,6 +61,7 @@ for prob in test_problems_linear sol = solve(prob, alg, adaptive = true, save_everystep = true) sol_exact = prob.f.analytic(prob.u0, prob.p, sol.t[end]) @test length(sol) < 5 + @test SciMLBase.successful_retcode(sol) @test minimum(abs.(sol.u[end] .- sol_exact) .< 1e-8) end @@ -70,5 +72,6 @@ for prob in test_problems_nonlinear sol = solve(prob, alg, adaptive = true, save_everystep = true) sol_exact = prob.f.analytic(prob.u0, prob.p, sol.t[end]) @test length(sol) < 5 + @test SciMLBase.successful_retcode(sol) @test minimum(abs.(sol.u[end] .- sol_exact) .< 1e-11) end diff --git a/lib/OrdinaryDiffEqQPRK/test/qa.jl b/lib/OrdinaryDiffEqQPRK/test/qa.jl new file mode 100644 index 0000000000..d401caeb73 --- /dev/null +++ b/lib/OrdinaryDiffEqQPRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqQPRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqQPRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqQPRK/test/runtests.jl b/lib/OrdinaryDiffEqQPRK/test/runtests.jl index 080a263242..afb6e0ed86 100644 --- a/lib/OrdinaryDiffEqQPRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqQPRK/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "Quadruple Precision Tests" include("ode_quadruple_precision_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqRKN/Project.toml b/lib/OrdinaryDiffEqRKN/Project.toml index 09dc6999b8..61fdb90bb4 100644 --- a/lib/OrdinaryDiffEqRKN/Project.toml +++ b/lib/OrdinaryDiffEqRKN/Project.toml @@ -1,38 +1,49 @@ name = "OrdinaryDiffEqRKN" uuid = "af6ede74-add8-4cfd-b1df-9a4dbb109d7a" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.5.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Statistics = "1.11.1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" + +[compat] +Statistics = "<0.0.1, 1" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +Polyester = "0.7" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "Statistics"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "Statistics", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqRKN/src/OrdinaryDiffEqRKN.jl b/lib/OrdinaryDiffEqRKN/src/OrdinaryDiffEqRKN.jl index 953bc58ec6..cf23486570 100644 --- a/lib/OrdinaryDiffEqRKN/src/OrdinaryDiffEqRKN.jl +++ b/lib/OrdinaryDiffEqRKN/src/OrdinaryDiffEqRKN.jl @@ -18,7 +18,7 @@ using DiffEqBase: @def, @tight_loop_macros import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqRKN/src/algorithms.jl b/lib/OrdinaryDiffEqRKN/src/algorithms.jl index 3c8bb658af..6694d4fd13 100644 --- a/lib/OrdinaryDiffEqRKN/src/algorithms.jl +++ b/lib/OrdinaryDiffEqRKN/src/algorithms.jl @@ -10,10 +10,7 @@ Second order ODE should not depend on the first derivative.", struct IRKN3 <: OrdinaryDiffEqPartitionedAlgorithm end @doc generic_solver_docstring( - "A 4th order explicit method which can be applied directly on second order ODEs. -Can only be used with fixed time steps. -In case the ODE Problem is not dependent on the first derivative consider using -[`Nystrom4VelocityIndependent`](@ref) to increase performance.", + "4th order explicit Runge-Kutta-Nyström method. Allows acceleration to depend on velocity.", "Nystrom4", "Improved Runge-Kutta-Nyström method", "E. Hairer, S.P. Norsett, G. Wanner, (1993) Solving Ordinary Differential Equations I. diff --git a/lib/OrdinaryDiffEqRKN/src/interp_func.jl b/lib/OrdinaryDiffEqRKN/src/interp_func.jl index 1ca949d3c5..ed60ba1b2f 100644 --- a/lib/OrdinaryDiffEqRKN/src/interp_func.jl +++ b/lib/OrdinaryDiffEqRKN/src/interp_func.jl @@ -1,4 +1,4 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{DPRKN6ConstantCache, diff --git a/lib/OrdinaryDiffEqRKN/src/rkn_perform_step.jl b/lib/OrdinaryDiffEqRKN/src/rkn_perform_step.jl index 8031ca1723..ed9b47857d 100644 --- a/lib/OrdinaryDiffEqRKN/src/rkn_perform_step.jl +++ b/lib/OrdinaryDiffEqRKN/src/rkn_perform_step.jl @@ -425,7 +425,7 @@ end @unpack t, dt, k, tprev, f, p = integrator duprev, uprev = integrator.uprev.x duprev2, uprev2 = integrator.uprev2.x - @unpack bconst1, bconst2, c1, a21, b1, b2, bbar1, bbar2 = cache + @unpack bconst1, bconst2, c1, a21, b1, b2, bbar1, bbar2, k₂ = cache k₁ = integrator.fsalfirst # if there's a discontinuity or the solver is in the first step if integrator.iter < 2 && !integrator.u_modified diff --git a/lib/OrdinaryDiffEqRKN/test/jet.jl b/lib/OrdinaryDiffEqRKN/test/jet.jl new file mode 100644 index 0000000000..c484423cd7 --- /dev/null +++ b/lib/OrdinaryDiffEqRKN/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqRKN +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqRKN, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqRKN/test/nystrom_convergence_tests.jl b/lib/OrdinaryDiffEqRKN/test/nystrom_convergence_tests.jl index 107cf34235..59564bed89 100644 --- a/lib/OrdinaryDiffEqRKN/test/nystrom_convergence_tests.jl +++ b/lib/OrdinaryDiffEqRKN/test/nystrom_convergence_tests.jl @@ -80,26 +80,37 @@ sim = test_convergence(dts, prob, FineRKN5(), dense_errors = true) # Adaptive methods regression test sol = solve(prob, FineRKN4()) @test length(sol.u) < 16 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, FineRKN5()) @test length(sol.u) < 14 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN4()) @test length(sol.u) < 25 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN5()) @test length(sol.u) < 38 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN6()) @test length(sol.u) < 20 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN6FM()) @test length(sol.u) < 25 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN8()) @test length(sol.u) < 13 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN12()) @test length(sol.u) < 10 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, ERKN4(), reltol = 1e-8) @test length(sol.u) < 38 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, ERKN5(), reltol = 1e-8) @test length(sol.u) < 34 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, ERKN7(), reltol = 1e-8) @test length(sol.u) < 38 +@test SciMLBase.successful_retcode(sol) u0 = 0.0 v0 = 1.0 @@ -176,26 +187,37 @@ sim = test_convergence(dts, prob_big, ERKN7(), dense_errors = true) # Adaptive methods regression test sol = solve(prob, FineRKN4()) @test length(sol.u) < 16 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, FineRKN5()) @test length(sol.u) < 14 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN4()) @test length(sol.u) < 25 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN5()) @test length(sol.u) < 38 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN6()) @test length(sol.u) < 20 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN6FM()) @test length(sol.u) < 25 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN8()) @test length(sol.u) < 13 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, DPRKN12()) @test length(sol.u) < 10 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, ERKN4(), reltol = 1e-8) @test length(sol.u) < 38 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, ERKN5(), reltol = 1e-8) @test length(sol.u) < 34 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, ERKN7(), reltol = 1e-8) @test length(sol.u) < 38 +@test SciMLBase.successful_retcode(sol) # Testing generalized Runge-Kutte-Nyström methods on velocity dependent ODEs with the damped oscillator println("Out of Place") @@ -215,7 +237,7 @@ prob = ODEProblem( ])), ArrayPartition([0.0], [1.0]), # du0, u0 (0.0, 10.0), # tspan - DiffEqBase.NullParameters(), # p + SciMLBase.NullParameters(), # p SecondOrderODEProblem{false}()) dts = 1.0 ./ 2.0 .^ (5:-1:0) @@ -233,8 +255,10 @@ sim = test_convergence(dts, prob, FineRKN5(), dense_errors = true) sol = solve(prob, FineRKN4()) @test length(sol.u) < 28 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, FineRKN5()) @test length(sol.u) < 20 +@test SciMLBase.successful_retcode(sol) println("In Place") # Damped oscillator @@ -252,7 +276,7 @@ prob = ODEProblem( ])), ArrayPartition([0.0], [1.0]), # du0, u0 (0.0, 10.0), # tspan - DiffEqBase.NullParameters(), # p + SciMLBase.NullParameters(), # p SecondOrderODEProblem{false}()) dts = 1.0 ./ 2.0 .^ (5:-1:0) @@ -269,8 +293,10 @@ sim = test_convergence(dts, prob, FineRKN5(), dense_errors = true) # Adaptive methods regression test sol = solve(prob, FineRKN4()) @test length(sol.u) < 28 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, FineRKN5()) @test length(sol.u) < 20 +@test SciMLBase.successful_retcode(sol) # Compare in-place and out-of-place versions function damped_oscillator(du, u, p, t) @@ -433,8 +459,13 @@ end # adaptive time step sol_i = solve(ode_i, alg) sol_o = solve(ode_o, alg) - @test_broken sol_i.t ≈ sol_o.t - @test_broken sol_i.u ≈ sol_o.u + if VERSION >= v"1.11" + @test sol_i.t ≈ sol_o.t + @test sol_i.u ≈ sol_o.u + else + @test_broken sol_i.t ≈ sol_o.t + @test_broken sol_i.u ≈ sol_o.u + end end @testset "DPRKN8" begin @@ -453,8 +484,13 @@ end # adaptive time step sol_i = solve(ode_i, alg) sol_o = solve(ode_o, alg) - @test_broken sol_i.t ≈ sol_o.t - @test_broken sol_i.u ≈ sol_o.u + if VERSION >= v"1.11" + @test sol_i.t ≈ sol_o.t + @test sol_i.u ≈ sol_o.u + else + @test_broken sol_i.t ≈ sol_o.t + @test_broken sol_i.u ≈ sol_o.u + end end @testset "DPRKN12" begin diff --git a/lib/OrdinaryDiffEqRKN/test/qa.jl b/lib/OrdinaryDiffEqRKN/test/qa.jl new file mode 100644 index 0000000000..8038e73946 --- /dev/null +++ b/lib/OrdinaryDiffEqRKN/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqRKN +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqRKN + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqRKN/test/runtests.jl b/lib/OrdinaryDiffEqRKN/test/runtests.jl index 6799e1bcad..a9c45b07b2 100644 --- a/lib/OrdinaryDiffEqRKN/test/runtests.jl +++ b/lib/OrdinaryDiffEqRKN/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "Nystrom Convergence Tests" include("nystrom_convergence_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqRosenbrock/Project.toml b/lib/OrdinaryDiffEqRosenbrock/Project.toml index e837145781..837be508bf 100644 --- a/lib/OrdinaryDiffEqRosenbrock/Project.toml +++ b/lib/OrdinaryDiffEqRosenbrock/Project.toml @@ -1,62 +1,78 @@ name = "OrdinaryDiffEqRosenbrock" uuid = "43230ef6-c299-4910-a778-202eb28ce4ce" authors = ["ParamThakkar123 "] -version = "1.2.0" +version = "1.18.1" [deps] -ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" -ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" +DifferentiationInterface = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Preferences = "21216c6a-2e73-6563-6e65-726566657250" +MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" - -[compat] -ADTypes = "1.7.1" -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -FiniteDiff = "2.24.0" -ForwardDiff = "0.10.36" -LinearAlgebra = "<0.0.1, 1" -LinearSolve = "2.32.0" -MacroTools = "0.5.13" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -Polyester = "0.7.16" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" -ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +ForwardDiff = "0.10.38, 1" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +FiniteDiff = "2.27" +MuladdMacro = "0.2" +DifferentiationInterface = "0.6.54, 0.7" +LinearSolve = "3.26" +Polyester = "0.7" +PrecompileTools = "1.2" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +Preferences = "1.4" +Enzyme = "0.13" +MacroTools = "0.5" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "OrdinaryDiffEqNonlinearSolve", "SafeTestsets", "Test", "LinearAlgebra", "LinearSolve", "ForwardDiff", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "OrdinaryDiffEqNonlinearSolve", "SafeTestsets", "Test", "ODEProblemLibrary", "Enzyme", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqRosenbrock/src/OrdinaryDiffEqRosenbrock.jl b/lib/OrdinaryDiffEqRosenbrock/src/OrdinaryDiffEqRosenbrock.jl index ed5502cedd..ed279f8d43 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/OrdinaryDiffEqRosenbrock.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/OrdinaryDiffEqRosenbrock.jl @@ -8,22 +8,24 @@ import OrdinaryDiffEqCore: alg_order, alg_adaptive_order, isWmethod, isfsal, _un _vec, _reshape, perform_step!, trivial_limiter!, OrdinaryDiffEqRosenbrockAdaptiveAlgorithm, OrdinaryDiffEqRosenbrockAlgorithm, generic_solver_docstring, - namify, initialize!, perform_step!, get_fsalfirstlast, + initialize!, perform_step!, get_fsalfirstlast, constvalue, only_diagonal_mass_matrix, calculate_residuals, has_stiff_interpolation, ODEIntegrator, resize_non_user_cache!, _ode_addsteps!, full_cache, - DerivativeOrderNotPossibleError + DerivativeOrderNotPossibleError, _bool_to_ADType, + _process_AD_choice, LinearAliasSpecifier, copyat_or_push! using MuladdMacro, FastBroadcast, RecursiveArrayTools -import MacroTools +import MacroTools: namify using MacroTools: @capture using DiffEqBase: @def +import DifferentiationInterface as DI import LinearSolve import LinearSolve: UniformScaling import ForwardDiff using FiniteDiff -using LinearAlgebra: mul!, diag, diagm, I, Diagonal, norm -import ADTypes: AutoForwardDiff -import OrdinaryDiffEqCore +using LinearAlgebra: mul!, diag, diagm, I, Diagonal, norm, lu! +using ADTypes +import OrdinaryDiffEqCore, OrdinaryDiffEqDifferentiation using OrdinaryDiffEqDifferentiation: TimeDerivativeWrapper, TimeGradientWrapper, UDerivativeWrapper, UJacobianWrapper, @@ -31,15 +33,15 @@ using OrdinaryDiffEqDifferentiation: TimeDerivativeWrapper, TimeGradientWrapper, build_jac_config, issuccess_W, jacobian2W!, resize_jac_config!, resize_grad_config!, calc_W, calc_rosenbrock_differentiation!, build_J_W, - UJacobianWrapper, dolinsolve + UJacobianWrapper, dolinsolve, WOperator, resize_J_W! using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase import OrdinaryDiffEqCore: alg_autodiff import OrdinaryDiffEqCore -function rosenbrock_wanner_docstring(description::String, +function rosenbrock_wolfbrandt_docstring(description::String, name::String; references::String = "", extra_keyword_description = "", @@ -48,30 +50,29 @@ function rosenbrock_wanner_docstring(description::String, keyword_default = """ chunk_size = Val{0}(), standardtag = Val{true}(), - autodiff = Val{true}(), + autodiff = AutoForwardDiff(), concrete_jac = nothing, - diff_type = Val{:central}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, """ * extra_keyword_default keyword_default_description = """ - - `chunk_size`: The chunk size used with ForwardDiff.jl. Defaults to `Val{0}()` - and thus uses the internal ForwardDiff.jl algorithm for the choice. - `standardtag`: Specifies whether to use package-specific tags instead of the ForwardDiff default function-specific tags. For more information, see [this blog post](https://www.stochasticlifestyle.com/improved-forwarddiff-jl-stacktraces-with-package-tags/). Defaults to `Val{true}()`. - - `autodiff`: Specifies whether to use automatic differentiation via + - `autodiff`: Uses [ADTypes.jl](https://sciml.github.io/ADTypes.jl/stable/) + to specify whether to use automatic differentiation via [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) or finite - differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). - Defaults to `Val{true}()` for automatic differentiation. + differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). + Defaults to `AutoForwardDiff()` for automatic differentiation, which by default uses + `chunksize = 0`, and thus uses the internal ForwardDiff.jl algorithm for the choice. + To use `FiniteDiff.jl`, the `AutoFiniteDiff()` ADType can be used, which has a keyword argument + `fdtype` with default value `Val{:forward}()`, and alternatives `Val{:central}()` and `Val{:complex}()`. - `concrete_jac`: Specifies whether a Jacobian should be constructed. Defaults to `nothing`, which means it will be chosen true/false depending on circumstances of the solver, such as whether a Krylov subspace method is used for `linsolve`. - - `diff_type`: The type of differentiation used in FiniteDiff.jl if `autodiff=false`. - Defaults to `Val{:forward}`, with alternatives of `Val{:central}` and - `Val{:complex}`. - `linsolve`: Any [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl) compatible linear solver. For example, to use [KLU.jl](https://github.com/JuliaSparse/KLU.jl), specify `$name(linsolve = KLUFactorization()`). @@ -118,7 +119,7 @@ function rosenbrock_wanner_docstring(description::String, end generic_solver_docstring( - description, name, "Rosenbrock-Wanner Method. ", references, + description, name, "Rosenbrock-Wanner-W(olfbrandt) Method. ", references, keyword_default_description, keyword_default ) end @@ -130,22 +131,21 @@ function rosenbrock_docstring(description::String, extra_keyword_default = "", with_step_limiter = false) keyword_default = """ - - `chunk_size`: The chunk size used with ForwardDiff.jl. Defaults to `Val{0}()` - and thus uses the internal ForwardDiff.jl algorithm for the choice. - `standardtag`: Specifies whether to use package-specific tags instead of the ForwardDiff default function-specific tags. For more information, see [this blog post](https://www.stochasticlifestyle.com/improved-forwarddiff-jl-stacktraces-with-package-tags/). Defaults to `Val{true}()`. - - `autodiff`: Specifies whether to use automatic differentiation via + - `autodiff`: Uses [ADTypes.jl](https://sciml.github.io/ADTypes.jl/stable/) + to specify whether to use automatic differentiation via [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) or finite - differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). - Defaults to `Val{true}()` for automatic differentiation. + differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). + Defaults to `AutoForwardDiff()` for automatic differentiation, which by default uses + `chunksize = 0`, and thus uses the internal ForwardDiff.jl algorithm for the choice. + To use `FiniteDiff.jl`, the `AutoFiniteDiff()` ADType can be used, which has a keyword argument + `fdtype` with default value `Val{:forward}()`, and alternatives `Val{:central}()` and `Val{:complex}()`. - `concrete_jac`: Specifies whether a Jacobian should be constructed. Defaults to `nothing`, which means it will be chosen true/false depending on circumstances of the solver, such as whether a Krylov subspace method is used for `linsolve`. - - `diff_type`: The type of differentiation used in FiniteDiff.jl if `autodiff=false`. - Defaults to `Val{:forward}`, with alternatives of `Val{:central}` and - `Val{:complex}`. - `linsolve`: Any [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl) compatible linear solver. For example, to use [KLU.jl](https://github.com/JuliaSparse/KLU.jl), specify `$name(linsolve = KLUFactorization()`). @@ -202,7 +202,7 @@ function rosenbrock_docstring(description::String, end generic_solver_docstring( - description, name, "Rosenbrock Method. ", references, + description, name, "Rosenbrock-Wanner Method. ", references, keyword_default_description, keyword_default ) end @@ -267,7 +267,7 @@ end export Rosenbrock23, Rosenbrock32, RosShamp4, Veldd4, Velds4, GRK4T, GRK4A, Ros4LStab, ROS3P, Rodas3, Rodas23W, Rodas3P, Rodas4, Rodas42, Rodas4P, Rodas4P2, - Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, + Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, Rodas6P, RosenbrockW6S4OS, ROS34PW1a, ROS34PW1b, ROS34PW2, ROS34PW3, ROS34PRw, ROS3PRL, ROS3PRL2, ROK4a, ROS2, ROS2PR, ROS2S, ROS3, ROS3PR, Scholz4_7 diff --git a/lib/OrdinaryDiffEqRosenbrock/src/alg_utils.jl b/lib/OrdinaryDiffEqRosenbrock/src/alg_utils.jl index 231c1570e6..7e4e820cca 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/alg_utils.jl @@ -33,6 +33,7 @@ alg_order(alg::Rodas5) = 5 alg_order(alg::Rodas5P) = 5 alg_order(alg::Rodas5Pr) = 5 alg_order(alg::Rodas5Pe) = 5 +alg_order(alg::Rodas6P) = 6 alg_adaptive_order(alg::Rosenbrock32) = 2 alg_adaptive_order(alg::Rosenbrock23) = 3 @@ -59,10 +60,11 @@ isfsal(alg::Rodas4) = false isfsal(alg::Rodas42) = false isfsal(alg::Rodas4P) = false isfsal(alg::Rodas4P2) = false +isfsal(alg::Rodas6P) = false function has_stiff_interpolation(::Union{Rosenbrock23, Rosenbrock32, Rodas23W, Rodas3P, Rodas4, Rodas4P, Rodas4P2, Rodas5, - Rodas5P, Rodas5Pe, Rodas5Pr}) + Rodas5P, Rodas5Pe, Rodas5Pr, Rodas6P}) true end diff --git a/lib/OrdinaryDiffEqRosenbrock/src/algorithms.jl b/lib/OrdinaryDiffEqRosenbrock/src/algorithms.jl index 03cbfae9d4..04a7a9f498 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/algorithms.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/algorithms.jl @@ -85,118 +85,198 @@ University of Geneva, Switzerland. Preprint 2024 https://github.com/hbrs-cse/RosenbrockMethods/blob/main/paper/JuliaPaper.pdf + #### Rodas6P +- Steinebach G. Construction of Rosenbrock–Wanner method Rodas6P , to prepare + =# # for Rosenbrock methods with step_limiter -for Alg in [ - :Rosenbrock23, - :Rosenbrock32, - :ROS3P, - :Rodas3, - :Rodas23W, - :Rodas3P, - :Rodas4, - :Rodas42, - :Rodas4P, - :Rodas4P2, - :Rodas5, - :Rodas5P, - :Rodas5Pe, - :Rodas5Pr] +for (Alg, desc, refs, is_W) in [ + (:Rosenbrock23, "An Order 2/3 L-Stable Rosenbrock-W method which is good for very stiff equations with oscillations at low tolerances. 2nd order stiff-aware interpolation.", "- Shampine L.F. and Reichelt M., (1997) The MATLAB ODE Suite, SIAM Journal of\n Scientific Computing, 18 (1), pp. 1-22.", true), + (:Rosenbrock32, "An Order 3/2 A-Stable Rosenbrock-W method which is good for mildly stiff equations without oscillations at low tolerances. Note that this method is prone to instability in the presence of oscillations, so use with caution. 2nd order stiff-aware interpolation.", "- Shampine L.F. and Reichelt M., (1997) The MATLAB ODE Suite, SIAM Journal of\n Scientific Computing, 18 (1), pp. 1-22.", true), + (:ROS3P, "3rd order A-stable and stiffly stable Rosenbrock method. Keeps high accuracy on discretizations of nonlinear parabolic PDEs.", "- Lang, J. & Verwer, ROS3P—An Accurate Third-Order Rosenbrock Solver Designed for\n Parabolic Problems J. BIT Numerical Mathematics (2001) 41: 731. doi:10.1023/A:1021900219772", false), + (:Rodas3, "3rd order A-stable and stiffly stable Rosenbrock method.", "- Sandu, Verwer, Van Loon, Carmichael, Potra, Dabdub, Seinfeld, Benchmarking stiff ode solvers for atmospheric chemistry problems-I. \n implicit vs explicit, Atmospheric Environment, 31(19), 3151-3166, 1997.", false), + (:Rodas23W, "An Order 2/3 L-Stable Rosenbrock-W method for stiff ODEs and DAEs in mass matrix form. 2nd order stiff-aware interpolation and additional error test for interpolation.", "- Steinebach G., Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications -\n Preprint 2024. Proceedings of the JuliaCon Conferences.\n https://proceedings.juliacon.org/papers/eb04326e1de8fa819a3595b376508a40", true), + (:Rodas3P, "3rd order A-stable and stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant\nand additional error test for interpolation. Keeps accuracy on discretizations of linear parabolic PDEs.", "- Steinebach G., Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications -\n Preprint 2024. Proceedings of the JuliaCon Conferences.\n https://proceedings.juliacon.org/papers/eb04326e1de8fa819a3595b376508a40", false), + (:Rodas4, "A 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant", "- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and\n differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996)", false), + (:Rodas42, "A 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant", "- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and\n differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996)", false), + (:Rodas4P, "4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant. 4th order\non linear parabolic problems and 3rd order accurate on nonlinear parabolic problems (as opposed to\nlower if not corrected).", "- Steinebach, G., Rentrop, P., An adaptive method of lines approach for modelling flow and transport in rivers. \n Adaptive method of lines , Wouver, A. Vande, Sauces, Ph., Schiesser, W.E. (ed.),S. 181-205,Chapman & Hall/CRC, 2001,\n- Steinebach, G., Order-reduction of ROW-methods for DAEs and method of lines applications. \n Preprint-Nr. 1741, FB Mathematik, TH Darmstadt, 1995.", false), + (:Rodas4P2, "A 4th order L-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant. 4th order\non linear parabolic problems and 3rd order accurate on nonlinear parabolic problems. It is an improvement\nof Rodas4P and in case of inexact Jacobians a second order W method.", "- Steinebach G., Improvement of Rosenbrock-Wanner Method RODASP, In: Reis T., Grundel S., Schöps S. (eds) \n Progress in Differential-Algebraic Equations II. Differential-Algebraic Equations Forum. Springer, Cham., 165-184, 2020.", true), + (:Rodas5, "A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant.", "- Di Marzo G. RODAS5(4) – Méthodes de Rosenbrock d'ordre 5(4) adaptées aux problèmes\n différentiels-algébriques. MSc mathematics thesis, Faculty of Science,\n University of Geneva, Switzerland.", false), + (:Rodas5P, "A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant.\nHas improved stability in the adaptive time stepping embedding.", "- Steinebach G. Construction of Rosenbrock–Wanner method Rodas5P and numerical benchmarks\n within the Julia Differential Equations package.\n In: BIT Numerical Mathematics, 63(2), 2023. doi:10.1007/s10543-023-00967-x", true), + (:Rodas5Pe, "Variant of Rodas5P with modified embedded scheme.", "- Steinebach G. Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications -\n Preprint 2024. Proceedings of the JuliaCon Conferences.\n https://proceedings.juliacon.org/papers/eb04326e1de8fa819a3595b376508a40", true), + (:Rodas5Pr, "Variant of Rodas5P with additional residual control.", "- Steinebach G. Rosenbrock methods within OrdinaryDiffEq.jl - Overview, recent developments and applications -\n Preprint 2024. Proceedings of the JuliaCon Conferences.\n https://proceedings.juliacon.org/papers/eb04326e1de8fa819a3595b376508a40", true), + (:Rodas6P, "A 6th order A-stable stiffly stable Rosenbrock method with a stiff-aware 5th order interpolant.", "- Steinebach G. Construction of Rosenbrock–Wanner method Rodas6P.\n to prepare, 2025", true) +] @eval begin - struct $Alg{CS, AD, F, P, FDT, ST, CJ, StepLimiter, StageLimiter} <: + @doc $(is_W ? rosenbrock_wolfbrandt_docstring(desc, String(Alg), references = refs, with_step_limiter = true) : rosenbrock_docstring(desc, String(Alg), references = refs, with_step_limiter = true)) struct $Alg{CS, AD, F, P, FDT, ST, CJ, StepLimiter, StageLimiter} <: OrdinaryDiffEqRosenbrockAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F precs::P step_limiter!::StepLimiter stage_limiter!::StageLimiter + autodiff::AD end - function $Alg(; chunk_size = Val{0}(), autodiff = Val{true}(), + function $Alg(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, linsolve = nothing, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, step_limiter! = trivial_limiter!, stage_limiter! = trivial_limiter!) - $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice( + autodiff, chunk_size, diff_type) + $Alg{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!), typeof(stage_limiter!)}(linsolve, precs, step_limiter!, - stage_limiter!) + stage_limiter!, AD_choice) end end end + +@doc rosenbrock_docstring( + "An Order 2/3 L-Stable Rosenbrock-W method which is good for very stiff equations with oscillations at low tolerances. 2nd order stiff-aware interpolation. Strong stability for highly stiff systems. Good at high tolerances (>1e-2) for stiff problems. Recommended for highly stiff problems, systems with significant oscillations, low tolerance requirements.", + "Rosenbrock23", with_step_limiter = true) +Rosenbrock23 + +@doc rosenbrock_docstring( + "Efficient for medium tolerance stiff problems. A 5th order A-stable and stiffly stable embedded Rosenbrock method for differential-algebraic problems.", + "Rodas5P", with_step_limiter = true) +Rodas5P + +@doc rosenbrock_docstring( + "Efficient for medium and strict tolerance stiff problems. A 6th order A-stable and stiffly stable embedded Rosenbrock method for differential-algebraic problems.", + "Rodas6P", with_step_limiter = true) +Rodas6P + +@doc rosenbrock_docstring( + "A 3/2-order L-stable Rosenbrock-W method optimized for stiff problems. Good balance of accuracy and computational efficiency.", + "Rosenbrock32", with_step_limiter = true) +Rosenbrock32 + +@doc rosenbrock_docstring( + "A 3rd-order accurate L-stable Rosenbrock method designed for parabolic problems. Particularly effective for reaction-diffusion equations.", + "ROS3P", with_step_limiter = true) +ROS3P + +@doc rosenbrock_docstring( + "A 3rd-order accurate L-stable Rosenbrock method from Hairer and Wanner. Good general-purpose stiff ODE solver with moderate computational cost.", + "Rodas3", with_step_limiter = true) +Rodas3 + +@doc rosenbrock_docstring( + "A 4th-order accurate L-stable Rosenbrock method. Well-suited for moderately stiff problems with good efficiency.", + "Rodas4", with_step_limiter = true) +Rodas4 + +@doc rosenbrock_docstring( + "A 4th-order accurate L-stable Rosenbrock method with improved error estimation. Enhanced version of Rodas4 for better step size control.", + "Rodas42", with_step_limiter = true) +Rodas42 + +@doc rosenbrock_docstring( + "A 4th-order accurate L-stable Rosenbrock method designed for differential-algebraic equations (DAEs). Optimized for index-1 DAE problems.", + "Rodas4P", with_step_limiter = true) +Rodas4P + +@doc rosenbrock_docstring( + "An improved 4th-order accurate L-stable Rosenbrock method for DAEs with enhanced stability properties.", + "Rodas4P2", with_step_limiter = true) +Rodas4P2 + +@doc rosenbrock_docstring( + "A 5th-order accurate L-stable Rosenbrock method for differential-algebraic problems. Higher accuracy but increased computational cost.", + "Rodas5", with_step_limiter = true) +Rodas5 + struct GeneralRosenbrock{CS, AD, F, ST, CJ, TabType} <: OrdinaryDiffEqRosenbrockAdaptiveAlgorithm{CS, AD, Val{:forward}, ST, CJ} tableau::TabType factorization::F + autodiff::AD end -function GeneralRosenbrock(; chunk_size = Val{0}(), autodiff = true, +function GeneralRosenbrock(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, factorization = lu!, tableau = ROSENBROCK_DEFAULT_TABLEAU) + AD_choice, chunk_size, diff_type = _process_AD_choice( + autodiff, chunk_size, Val{:forward}()) + GeneralRosenbrock{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(factorization), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(factorization), _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(tableau)}(tableau, - factorization) + factorization, AD_choice) end -@doc rosenbrock_wanner_docstring( +@doc rosenbrock_wolfbrandt_docstring( """ A 4th order L-stable Rosenbrock-W method (fixed step only). """, "RosenbrockW6S4OS", references = """ https://doi.org/10.1016/j.cam.2009.09.017 - """) + """)) +""" struct RosenbrockW6S4OS{CS, AD, F, P, FDT, ST, CJ} <: OrdinaryDiffEqRosenbrockAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F precs::P + autodiff::AD end -function RosenbrockW6S4OS(; chunk_size = Val{0}(), autodiff = true, +function RosenbrockW6S4OS(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:central}, + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + RosenbrockW6S4OS{_unwrap_val(chunk_size), - _unwrap_val(autodiff), typeof(linsolve), typeof(precs), diff_type, + typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, - precs) + precs, AD_choice) end -for Alg in [ - :ROS2, - :ROS2PR, - :ROS2S, - :ROS3, - :ROS3PR, - :Scholz4_7, - :ROS34PW1a, - :ROS34PW1b, - :ROS34PW2, - :ROS34PW3, - :ROS34PRw, - :ROS3PRL, - :ROS3PRL2, - :ROK4a, - :RosShamp4, - :Veldd4, - :Velds4, - :GRK4T, - :GRK4A, - :Ros4LStab] +# Documentation for Rosenbrock methods without step_limiter + +for (Alg, desc, refs, is_W) in [ + (:ROS2, "A 2nd order L-stable Rosenbrock method with 2 internal stages.", "- J. G. Verwer et al. (1999): A second-order Rosenbrock method applied to photochemical dispersion problems\n https://doi.org/10.1137/S1064827597326651", false), + (:ROS2PR, "2nd order stiffly accurate Rosenbrock method with 3 internal stages with (Rinf=0).\nFor problems with medium stiffness the convergence behaviour is very poor and it is recommended to use\n[`ROS2S`](@ref) instead.", "- Rang, Joachim (2014): The Prothero and Robinson example:\n Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods.\n https://doi.org/10.24355/dbbs.084-201408121139-0", false), + (:ROS2S, "2nd order stiffly accurate Rosenbrock-Wanner W-method with 3 internal stages with B_PR consistent of order 2 with (Rinf=0).", "- Rang, Joachim (2014): The Prothero and Robinson example:\n Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods.\n https://doi.org/10.24355/dbbs.084-201408121139-0", true), + (:ROS3, "3rd order L-stable Rosenbrock method with 3 internal stages with an embedded strongly\nA-stable 2nd order method.", "- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and\n differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996)", false), + (:ROS3PR, "3nd order stiffly accurate Rosenbrock method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73.", "- Rang, Joachim (2014): The Prothero and Robinson example:\n Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods.\n https://doi.org/10.24355/dbbs.084-201408121139-0", false), + (:Scholz4_7, "3nd order stiffly accurate Rosenbrock method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73.\nConvergence with order 4 for the stiff case, but has a poor accuracy.", "- Rang, Joachim (2014): The Prothero and Robinson example:\n Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods.\n https://doi.org/10.24355/dbbs.084-201408121139-0", false), + (:ROS34PW1a, "A 4th order L-stable Rosenbrock-W method.", "- Rang, Joachim and Angermann, L (2005): New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1.\n BIT Numerical Mathematics, 45, 761--787.", true), + (:ROS34PW1b, "A 4th order L-stable Rosenbrock-W method.", "- Rang, Joachim and Angermann, L (2005): New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1.\n BIT Numerical Mathematics, 45, 761--787.", true), + (:ROS34PW2, "A 4th order stiffy accurate Rosenbrock-W method for PDAEs.", "- Rang, Joachim and Angermann, L (2005): New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1.\n BIT Numerical Mathematics, 45, 761--787.", true), + (:ROS34PW3, "A 4th order strongly A-stable (Rinf~0.63) Rosenbrock-W method.", "- Rang, Joachim and Angermann, L (2005): New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1.\n BIT Numerical Mathematics, 45, 761--787.", true), + (:ROS34PRw, "3rd order stiffly accurate Rosenbrock-Wanner W-method with 4 internal stages,\nB_PR consistent of order 2.\nThe order of convergence decreases if medium stiff problems are considered.", "- Joachim Rang, Improved traditional Rosenbrock–Wanner methods for stiff ODEs and DAEs,\n Journal of Computational and Applied Mathematics,\n https://doi.org/10.1016/j.cam.2015.03.010", true), + (:ROS3PRL, "3rd order stiffly accurate Rosenbrock method with 4 internal stages,\nB_PR consistent of order 2 with Rinf=0.\nThe order of convergence decreases if medium stiff problems are considered, but it has good results for very stiff cases.", "- Rang, Joachim (2014): The Prothero and Robinson example:\n Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods.\n https://doi.org/10.24355/dbbs.084-201408121139-0", false), + (:ROS3PRL2, "3rd order stiffly accurate Rosenbrock method with 4 internal stages,\nB_PR consistent of order 3.\nThe order of convergence does NOT decreases if medium stiff problems are considered as it does for [`ROS3PRL`](@ref).", "- Rang, Joachim (2014): The Prothero and Robinson example:\n Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods.\n https://doi.org/10.24355/dbbs.084-201408121139-0", false), + (:ROK4a, "4rd order L-stable Rosenbrock-Krylov method with 4 internal stages,\nwith a 3rd order embedded method which is strongly A-stable with Rinf~=0.55. (when using exact Jacobians)", "- Tranquilli, Paul and Sandu, Adrian (2014):\n Rosenbrock--Krylov Methods for Large Systems of Differential Equations\n https://doi.org/10.1137/130923336", true), + (:RosShamp4, "An A-stable 4th order Rosenbrock method.", "- L. F. Shampine, Implementation of Rosenbrock Methods, ACM Transactions on\n Mathematical Software (TOMS), 8: 2, 93-113. doi:10.1145/355993.355994", false), + (:Veldd4, "A 4th order D-stable Rosenbrock method.", "- van Veldhuizen, D-stability and Kaps-Rentrop-methods, M. Computing (1984) 32: 229.\n doi:10.1007/BF02243574", false), + (:Velds4, "A 4th order A-stable Rosenbrock method.", "- van Veldhuizen, D-stability and Kaps-Rentrop-methods, M. Computing (1984) 32: 229.\n doi:10.1007/BF02243574", true), + (:GRK4T, "An efficient 4th order Rosenbrock method.", "- Kaps, P. & Rentrop, Generalized Runge-Kutta methods of order four with stepsize control\n for stiff ordinary differential equations. P. Numer. Math. (1979) 33: 55. doi:10.1007/BF01396495", false), + (:GRK4A, "An A-stable 4th order Rosenbrock method. Essentially \"anti-L-stable\" but efficient.", "- Kaps, P. & Rentrop, Generalized Runge-Kutta methods of order four with stepsize control\n for stiff ordinary differential equations. P. Numer. Math. (1979) 33: 55. doi:10.1007/BF01396495", false), + (:Ros4LStab, "A 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant", "- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and\n differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996)", false) +] @eval begin - struct $Alg{CS, AD, F, P, FDT, ST, CJ} <: + @doc $(is_W ? rosenbrock_wolfbrandt_docstring(desc, String(Alg), references = refs, with_step_limiter = false) : rosenbrock_docstring(desc, String(Alg), references = refs, with_step_limiter = false)) struct $Alg{CS, AD, F, P, FDT, ST, CJ} <: OrdinaryDiffEqRosenbrockAdaptiveAlgorithm{CS, AD, FDT, ST, CJ} linsolve::F precs::P + autodiff::AD end - function $Alg(; chunk_size = Val{0}(), autodiff = Val{true}(), + function $Alg(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, linsolve = nothing, precs = DEFAULT_PRECS) - $Alg{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS) + AD_choice, chunk_size, diff_type = _process_AD_choice( + autodiff, chunk_size, diff_type) + + $Alg{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, - precs) + precs, AD_choice) end end end + diff --git a/lib/OrdinaryDiffEqRosenbrock/src/generic_rosenbrock.jl b/lib/OrdinaryDiffEqRosenbrock/src/generic_rosenbrock.jl index d04018b4a6..43231f36b9 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/generic_rosenbrock.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/generic_rosenbrock.jl @@ -227,7 +227,7 @@ function gen_algcache(cacheexpr::Expr,constcachename::Symbol,algname::Symbol,tab function alg_cache(alg::$algname,u,rate_prototype,uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits,uprev,uprev2,f,t,dt,reltol,p,calck,::Val{false}) tf = TimeDerivativeWrapper(f,u,p) uf = UDerivativeWrapper(f,t,p) - J,W = build_J_W(alg,u,uprev,p,t,dt,f,uEltypeNoUnits,Val(false)) + J,W = build_J_W(alg,u,uprev,p,t,dt,f, nothing, uEltypeNoUnits,Val(false)) $constcachename(tf,uf,$tabname(constvalue(uBottomEltypeNoUnits),constvalue(tTypeNoUnits)),J,W,nothing) end function alg_cache(alg::$algname,u,rate_prototype,uEltypeNoUnits,uBottomEltypeNoUnits,tTypeNoUnits,uprev,uprev2,f,t,dt,reltol,p,calck,::Val{true}) @@ -238,7 +238,6 @@ function gen_algcache(cacheexpr::Expr,constcachename::Symbol,algname::Symbol,tab fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - J,W = build_J_W(alg,u,uprev,p,t,dt,f,uEltypeNoUnits,Val(true)) tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) weight = similar(u, uEltypeNoUnits) @@ -247,12 +246,15 @@ function gen_algcache(cacheexpr::Expr,constcachename::Symbol,algname::Symbol,tab tf = TimeGradientWrapper(f,uprev,p) uf = UJacobianWrapper(f,t,p) linsolve_tmp = zero(rate_prototype) - linprob = LinearProblem(W,_vec(linsolve_tmp); u0=_vec(tmp)) - linsolve = init(linprob,alg.linsolve,alias_A=true,alias_b=true, - Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), - Pr = Diagonal(_vec(weight))) + grad_config = build_grad_config(alg,f,tf,du1,t) jac_config = build_jac_config(alg,f,uf,du1,uprev,u,tmp,du2) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + + linprob = LinearProblem(W,_vec(linsolve_tmp); u0=_vec(tmp)) + linsolve = init(linprob,alg.linsolve,alias = LinearAliasSpecifier(alias_A=true,alias_b=true), + Pl = LinearSolve.InvPreconditioner(Diagonal(_vec(weight))), + Pr = Diagonal(_vec(weight))) $cachename($(valsyms...)) end end @@ -911,170 +913,6 @@ function ROS2Tableau() # 2nd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_wanner_docstring( -""" -An Order 2/3 L-Stable Rosenbrock-W method which is good for very stiff equations with oscillations at low tolerances. 2nd order stiff-aware interpolation. -""", -"Rosenbrock23", -references = """ -- Shampine L.F. and Reichelt M., (1997) The MATLAB ODE Suite, SIAM Journal of -Scientific Computing, 18 (1), pp. 1-22. -""", -with_step_limiter = true) Rosenbrock23 - -@doc rosenbrock_wanner_docstring( -""" -An Order 3/2 A-Stable Rosenbrock-W method which is good for mildly stiff equations without oscillations at low tolerances. Note that this method is prone to instability in the presence of oscillations, so use with caution. 2nd order stiff-aware interpolation. -""", -"Rosenbrock32", -references = """ -- Shampine L.F. and Reichelt M., (1997) The MATLAB ODE Suite, SIAM Journal of -Scientific Computing, 18 (1), pp. 1-22. -""", -with_step_limiter = true) Rosenbrock32 - -@doc rosenbrock_docstring( -""" -3rd order A-stable and stiffly stable Rosenbrock method. Keeps high accuracy on discretizations of nonlinear parabolic PDEs. -""", -"ROS3P", -references = """ -- Lang, J. & Verwer, ROS3P—An Accurate Third-Order Rosenbrock Solver Designed for - Parabolic Problems J. BIT Numerical Mathematics (2001) 41: 731. doi:10.1023/A:1021900219772 -""", -with_step_limiter = true) ROS3P - -@doc rosenbrock_wanner_docstring( -""" -An Order 2/3 L-Stable Rosenbrock-W method for stiff ODEs and DAEs in mass matrix form. 2nd order stiff-aware interpolation and additional error test for interpolation. -""", -"Rodas23W", -references = """ -- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate for dense output and Julia implementation, - In progress. -""", -with_step_limiter = true) Rodas23W - -@doc rosenbrock_wanner_docstring( -""" -A 4th order L-stable Rosenbrock-W method. -""", -"ROS34PW1a", -references = """ -@article{rang2005new, - title={New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1}, - author={Rang, Joachim and Angermann, L}, - journal={BIT Numerical Mathematics}, - volume={45}, - pages={761--787}, - year={2005}, - publisher={Springer}} -""") ROS34PW1a - -@doc rosenbrock_wanner_docstring( -""" -A 4th order L-stable Rosenbrock-W method. -""", -"ROS34PW1b", -references = """ -@article{rang2005new, - title={New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1}, - author={Rang, Joachim and Angermann, L}, - journal={BIT Numerical Mathematics}, - volume={45}, - pages={761--787}, - year={2005}, - publisher={Springer}} -""") ROS34PW1b - -@doc rosenbrock_wanner_docstring( -""" -A 4th order stiffy accurate Rosenbrock-W method for PDAEs. -""", -"ROS34PW2", -references = """ -@article{rang2005new, - title={New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1}, - author={Rang, Joachim and Angermann, L}, - journal={BIT Numerical Mathematics}, - volume={45}, - pages={761--787}, - year={2005}, - publisher={Springer}} -""") ROS34PW2 - -@doc rosenbrock_wanner_docstring( -""" -A 4th order strongly A-stable (Rinf~0.63) Rosenbrock-W method. -""", -"ROS34PW3", -references = """ -@article{rang2005new, - title={New Rosenbrock W-methods of order 3 for partial differential algebraic equations of index 1}, - author={Rang, Joachim and Angermann, L}, - journal={BIT Numerical Mathematics}, - volume={45}, - pages={761--787}, - year={2005}, - publisher={Springer}} -""") ROS34PW3 - -@doc rosenbrock_docstring( -""" -An A-stable 4th order Rosenbrock method. -""", -"RosShamp4", -references = """ -- L. F. Shampine, Implementation of Rosenbrock Methods, ACM Transactions on - Mathematical Software (TOMS), 8: 2, 93-113. doi:10.1145/355993.355994 -""") RosShamp4 - -@doc rosenbrock_docstring( -""" -3rd order A-stable and stiffly stable Rosenbrock method. -""", -"Rodas3", -references = """ -- Steinebach G. Construction of Rosenbrock–Wanner method Rodas5P and numerical benchmarks - within the Julia Differential Equations package. - In: BIT Numerical Mathematics, 63(2), 2023 -""", -with_step_limiter=true) Rodas3 - -@doc rosenbrock_docstring( -""" -3rd order A-stable and stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant -and additional error test for interpolation. Keeps accuracy on discretizations of linear parabolic PDEs. -""", -"Rodas3P", -references = """ -- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate - for dense output and Julia implementation, - In progress. -""", -with_step_limiter=true) Rodas3P - -@doc rosenbrock_docstring( -""" -A 4th order L-stable Rosenbrock method. -""", -"Rodas4", -references = """ -- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and - differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) -""", -with_step_limiter=true) Rodas4 - -@doc rosenbrock_docstring( -""" -A 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant -""", -"Ros4LStab", -references = """ -- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and - differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) -""", -with_step_limiter=true) Ros4LStab @doc rosenbrock_docstring( @@ -1088,7 +926,7 @@ references = """ """, with_step_limiter=true) Rodas42 -@doc rosenbrock_wanner_docstring( +@doc rosenbrock_docstring( """ 4th order A-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant. 4th order on linear parabolic problems and 3rd order accurate on nonlinear parabolic problems (as opposed to @@ -1096,13 +934,14 @@ lower if not corrected). """, "Rodas4P", references = """ -- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate - for dense output and Julia implementation, - In progress. +- Steinebach, G., Rentrop, P., An adaptive method of lines approach for modelling flow and transport in rivers. + Adaptive method of lines , Wouver, A. Vande, Sauces, Ph., Schiesser, W.E. (ed.),S. 181-205,Chapman & Hall/CRC, 2001, +- Steinebach, G., Oder-reduction of ROW-methods for DAEs and method of lines applications. + Preprint-Nr. 1741, FB Mathematik, TH Darmstadt, 1995. """, with_step_limiter=true) Rodas4P -@doc rosenbrock_wanner_docstring( +@doc rosenbrock_wolfbrandt_docstring( """ A 4th order L-stable stiffly stable Rosenbrock method with a stiff-aware 3rd order interpolant. 4th order on linear parabolic problems and 3rd order accurate on nonlinear parabolic problems. It is an improvement @@ -1110,9 +949,8 @@ of Roadas4P and in case of inexact Jacobians a second order W method. """, "Rodas4P2", references = """ -- Steinebach G., Rodas23W / Rodas32P - a Rosenbrock-type method for DAEs with additional error estimate - for dense output and Julia implementation, - In progress. +- Steinebach G., Improvement of Rosenbrock-Wanner Method RODASP, In: Reis T., Grundel S., Schöps S. (eds) + Progress in Differential-Algebraic Equations II. Differential-Algebraic Equations Forum. Springer, Cham., 165-184, 2020. """, with_step_limiter=true) Rodas4P2 @@ -1128,7 +966,7 @@ references = """ """, with_step_limiter=true) Rodas5 -@doc rosenbrock_docstring( +@doc rosenbrock_wolfbrandt_docstring( """ A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. Has improved stability in the adaptive time stepping embedding. @@ -1141,10 +979,9 @@ references = """ """, with_step_limiter=true) Rodas5P -@doc rosenbrock_docstring( +@doc rosenbrock_wolfbrandt_docstring( """ -A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. -Has improved stability in the adaptive time stepping embedding. +Variant of Ropdas5P with additional residual control. """, "Rodas5Pr", references = """ @@ -1154,10 +991,9 @@ references = """ """, with_step_limiter=true) Rodas5Pr -@doc rosenbrock_docstring( +@doc rosenbrock_wolfbrandt_docstring( """ -A 5th order A-stable stiffly stable Rosenbrock method with a stiff-aware 4th order interpolant. -Has improved stability in the adaptive time stepping embedding. +Variant of Ropdas5P with modified embedded scheme. """, "Rodas5Pe", references = """ @@ -1167,6 +1003,16 @@ references = """ """, with_step_limiter=true) Rodas5Pe +@doc rosenbrock_wolfbrandt_docstring( +""" +A 6th order A-stable stiffly stable Rosenbrock method with a stiff-aware 5th order interpolant. +""", +"Rodas6P", +references = """ +- Steinebach G. Construction of Rosenbrock–Wanner method Rodas6P, to prepare +""", +with_step_limiter=true) Rodas6P + @doc rosenbrock_docstring( """ An efficient 4th order Rosenbrock method. @@ -1200,7 +1046,7 @@ references = """ """, with_step_limiter=true) Veldd4 -@doc rosenbrock_docstring( +@doc rosenbrock_wolfbrandt_docstring( """ A 4th order A-stable Rosenbrock method. """, @@ -1250,15 +1096,6 @@ macro ROS2(part) end end -@doc rosenbrock_docstring( -""" -A 2nd order L-stable Rosenbrock method with 2 internal stages. -""", -"ROS2", -references = """ -- J. G. Verwer et al. (1999): A second-order Rosenbrock method applied to photochemical dispersion problems - https://doi.org/10.1137/S1064827597326651 -""") ROS2 # 3 step ROS Methods """ @@ -1285,19 +1122,6 @@ function ROS2PRTableau() # 2nd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_docstring( -""" -2nd order stiffly accurate Rosenbrock method with 3 internal stages with (Rinf=0). -For problems with medium stiffness the convergence behaviour is very poor and it is recommended to use -[`ROS2S`](@ref) instead. -""", -"ROS2PR", -references = """ -- Rang, Joachim (2014): The Prothero and Robinson example: - Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. - https://doi.org/10.24355/dbbs.084-201408121139-0 -""") -ROS2PR @@ -1324,17 +1148,6 @@ function ROS2STableau() # 2nd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_wanner_docstring( -""" -2nd order stiffly accurate Rosenbrock-Wanner W-method with 3 internal stages with B_PR consistent of order 2 with (Rinf=0). -""", -"ROS2S", -references = """ -- Rang, Joachim (2014): The Prothero and Robinson example: - Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. - https://doi.org/10.24355/dbbs.084-201408121139-0 -""") -ROS2S """ @@ -1358,16 +1171,6 @@ function ROS3Tableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_docstring( -""" -3rd order L-stable Rosenbrock method with 3 internal stages with an embedded strongly -A-stable 2nd order method. -""", -"ROS3", -references = """ -- E. Hairer, G. Wanner, Solving ordinary differential equations II, stiff and - differential-algebraic problems. Computational mathematics (2nd revised ed.), Springer (1996) -""") ROS3 """ @@ -1392,16 +1195,6 @@ function ROS3PRTableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_docstring( -""" -3nd order stiffly accurate Rosenbrock method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73. -""", -"ROS3PR", -references = """ -- Rang, Joachim (2014): The Prothero and Robinson example: - Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. - https://doi.org/10.24355/dbbs.084-201408121139-0 -""") ROS3PR @@ -1428,17 +1221,6 @@ function Scholz4_7Tableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_docstring( -""" -3nd order stiffly accurate Rosenbrock method with 3 internal stages with B_PR consistent of order 3, which is strongly A-stable with Rinf~=-0.73. -Convergence with order 4 for the stiff case, but has a poor accuracy. -""", -"Scholz4_7", -references = """ -- Rang, Joachim (2014): The Prothero and Robinson example: - Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. - https://doi.org/10.24355/dbbs.084-201408121139-0 -""") Scholz4_7 """ @@ -1619,18 +1401,6 @@ function ROS34PRwTableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_wanner_docstring( -""" -3rd order stiffly accurate Rosenbrock-Wanner W-method with 4 internal stages, -B_PR consistent of order 2. -The order of convergence decreases if medium stiff problems are considered. -""", -"ROS34PRw", -references = """ -- Joachim Rang, Improved traditional Rosenbrock–Wanner methods for stiff ODEs and DAEs, - Journal of Computational and Applied Mathematics, - https://doi.org/10.1016/j.cam.2015.03.010 -""") ROS34PRw """ ROS3PRLTableau() @@ -1658,18 +1428,6 @@ function ROS3PRLTableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_docstring( -""" -3rd order stiffly accurate Rosenbrock method with 4 internal stages, -B_PR consistent of order 2 with Rinf=0. -The order of convergence decreases if medium stiff problems are considered, but it has good results for very stiff cases. -""", -"ROS3PRL", -references = """ -- Rang, Joachim (2014): The Prothero and Robinson example: - Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. - https://doi.org/10.24355/dbbs.084-201408121139-0 -""") ROS3PRL """ @@ -1698,18 +1456,6 @@ function ROS3PRL2Tableau() # 3rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_docstring( -""" -3rd order stiffly accurate Rosenbrock method with 4 internal stages, -B_PR consistent of order 3. -The order of convergence does NOT decreases if medium stiff problems are considered as it does for [`ROS3PRL`](@ref). -""", -"ROS3PRL2", -references = """ -- Rang, Joachim (2014): The Prothero and Robinson example: - Convergence studies for Runge-Kutta and Rosenbrock-Wanner methods. - https://doi.org/10.24355/dbbs.084-201408121139-0 -""") ROS3PRL2 """ @@ -1736,17 +1482,6 @@ function ROK4aTableau() # 4rd order RosenbrockAdaptiveTableau(a,C,b,btilde,gamma,d,c) end -@doc rosenbrock_wanner_docstring( -""" -4rd order L-stable Rosenbrock-Krylov method with 4 internal stages, -with a 3rd order embedded method which is strongly A-stable with Rinf~=0.55. (when using exact Jacobians) -""", -"ROK4a", -references = """ -- Tranquilli, Paul and Sandu, Adrian (2014): - Rosenbrock--Krylov Methods for Large Systems of Differential Equations - https://doi.org/10.1137/130923336 -""") ROK4a """ @ROS34PW(part) diff --git a/lib/OrdinaryDiffEqRosenbrock/src/integrator_interface.jl b/lib/OrdinaryDiffEqRosenbrock/src/integrator_interface.jl index f99dc3a089..9cc3a7960b 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/integrator_interface.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/integrator_interface.jl @@ -1,8 +1,8 @@ function resize_non_user_cache!(integrator::ODEIntegrator, cache::RosenbrockMutableCache, i) - cache.J = similar(cache.J, i, i) - cache.W = similar(cache.W, i, i) - resize_jac_config!(cache.jac_config, i) - resize_grad_config!(cache.grad_config, i) + resize_J_W!(cache, integrator, i) + resize_jac_config!(cache, integrator) + resize_grad_config!(cache, integrator) + nothing end diff --git a/lib/OrdinaryDiffEqRosenbrock/src/interp_func.jl b/lib/OrdinaryDiffEqRosenbrock/src/interp_func.jl index 07f4bbeee7..ba137f22fc 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/interp_func.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/interp_func.jl @@ -1,14 +1,13 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{Rosenbrock23ConstantCache, Rosenbrock32ConstantCache, - Rosenbrock23Cache, - Rosenbrock32Cache}} + RosenbrockCombinedCache}} dense ? "specialized 2nd order \"free\" stiffness-aware interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{RosenbrockCombinedConstantCache, Rodas23WConstantCache, Rodas3PConstantCache, @@ -17,11 +16,11 @@ function DiffEqBase.interp_summary(::Type{cacheType}, "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{RosenbrockCombinedConstantCache, RosenbrockCache}} - dense ? "specialized 4rd order \"free\" stiffness-aware interpolation" : + dense ? "specialized 4th (Rodas6P = 5th) order \"free\" stiffness-aware interpolation" : "1st order linear" end diff --git a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_caches.jl b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_caches.jl index 33fc5dcd2b..8c11f9ab26 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_caches.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_caches.jl @@ -12,7 +12,7 @@ end # Shampine's Low-order Rosenbrocks -mutable struct RosenbrockCache{uType, rateType, uNoUnitsType, JType, WType, TabType, +mutable struct RosenbrockCache{uType, rateType, tabType, uNoUnitsType, JType, WType, TabType, TFType, UFType, F, JCType, GCType, RTolType, A, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType @@ -21,6 +21,8 @@ mutable struct RosenbrockCache{uType, rateType, uNoUnitsType, JType, WType, TabT du::rateType du1::rateType du2::rateType + dtC::Matrix{tabType} + dtd::Vector{tabType} ks::Vector{rateType} fsalfirst::rateType fsallast::rateType @@ -39,16 +41,19 @@ mutable struct RosenbrockCache{uType, rateType, uNoUnitsType, JType, WType, TabT grad_config::GCType reltol::RTolType alg::A + algebraic_vars::AV step_limiter!::StepLimiter stage_limiter!::StageLimiter interp_order::Int end + function full_cache(c::RosenbrockCache) return [c.u, c.uprev, c.dense..., c.du, c.du1, c.du2, c.ks..., c.fsalfirst, c.fsallast, c.dT, c.tmp, c.atmp, c.weight, c.linsolve_tmp] end -struct RosenbrockCombinedConstantCache{TF, UF, Tab, JType, WType, F, AD} <: RosenbrockConstantCache +struct RosenbrockCombinedConstantCache{TF, UF, Tab, JType, WType, F, AD} <: + RosenbrockConstantCache tf::TF uf::UF tab::Tab @@ -59,7 +64,7 @@ struct RosenbrockCombinedConstantCache{TF, UF, Tab, JType, WType, F, AD} <: Rose interp_order::Int end -@cache mutable struct Rosenbrock23Cache{uType, rateType, uNoUnitsType, JType, WType, +@cache mutable struct RosenbrockCombinedCache{uType, rateType, uNoUnitsType, JType, WType, TabType, TFType, UFType, F, JCType, GCType, RTolType, A, AV, StepLimiter, StageLimiter} <: RosenbrockMutableCache u::uType @@ -92,40 +97,7 @@ end stage_limiter!::StageLimiter end -@cache mutable struct Rosenbrock32Cache{uType, rateType, uNoUnitsType, JType, WType, - TabType, TFType, UFType, F, JCType, GCType, - RTolType, A, AV, StepLimiter, StageLimiter} <: RosenbrockMutableCache - u::uType - uprev::uType - k₁::rateType - k₂::rateType - k₃::rateType - du1::rateType - du2::rateType - f₁::rateType - fsalfirst::rateType - fsallast::rateType - dT::rateType - J::JType - W::WType - tmp::rateType - atmp::uNoUnitsType - weight::uNoUnitsType - tab::TabType - tf::TFType - uf::UFType - linsolve_tmp::rateType - linsolve::F - jac_config::JCType - grad_config::GCType - reltol::RTolType - alg::A - algebraic_vars::AV - step_limiter!::StepLimiter - stage_limiter!::StageLimiter -end - -function alg_cache(alg::Rosenbrock23, u, rate_prototype, ::Type{uEltypeNoUnits}, +function alg_cache(alg::Union{Rosenbrock23, Rosenbrock32}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} @@ -139,80 +111,41 @@ function alg_cache(alg::Rosenbrock23, u, rate_prototype, ::Type{uEltypeNoUnits}, fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) weight = similar(u, uEltypeNoUnits) recursivefill!(weight, false) - tab = Rosenbrock23Tableau(constvalue(uBottomEltypeNoUnits)) + tab = RosenbrockCombinedTableau(constvalue(uBottomEltypeNoUnits)) tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) + grad_config = build_grad_config(alg, f, tf, du1, t) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), Pl = Pl, Pr = Pr, assumptions = LinearSolve.OperatorAssumptions(true)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + algebraic_vars = f.mass_matrix === I ? nothing : [all(iszero, x) for x in eachcol(f.mass_matrix)] - Rosenbrock23Cache(u, uprev, k₁, k₂, k₃, du1, du2, f₁, + RosenbrockCombinedCache(u, uprev, k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, linsolve, jac_config, grad_config, reltol, alg, algebraic_vars, alg.step_limiter!, alg.stage_limiter!) end -function alg_cache(alg::Rosenbrock32, u, rate_prototype, ::Type{uEltypeNoUnits}, - ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, - dt, reltol, p, calck, - ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - k₁ = zero(rate_prototype) - k₂ = zero(rate_prototype) - k₃ = zero(rate_prototype) - du1 = zero(rate_prototype) - du2 = zero(rate_prototype) - # f₀ = zero(u) fsalfirst - f₁ = zero(rate_prototype) - fsalfirst = zero(rate_prototype) - fsallast = zero(rate_prototype) - dT = zero(rate_prototype) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) - tmp = zero(rate_prototype) - atmp = similar(u, uEltypeNoUnits) - recursivefill!(atmp, false) - weight = similar(u, uEltypeNoUnits) - recursivefill!(weight, false) - tab = Rosenbrock32Tableau(constvalue(uBottomEltypeNoUnits)) - - tf = TimeGradientWrapper(f, uprev, p) - uf = UJacobianWrapper(f, t, p) - linsolve_tmp = zero(rate_prototype) - linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) - - Pl, Pr = wrapprecs( - alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, - nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, - Pl = Pl, Pr = Pr, - assumptions = LinearSolve.OperatorAssumptions(true)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) - algebraic_vars = f.mass_matrix === I ? nothing : - [all(iszero, x) for x in eachcol(f.mass_matrix)] - - Rosenbrock32Cache(u, uprev, k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, - tmp, atmp, weight, tab, tf, uf, linsolve_tmp, linsolve, jac_config, - grad_config, reltol, alg, algebraic_vars, alg.step_limiter!, alg.stage_limiter!) -end - struct Rosenbrock23ConstantCache{T, TF, UF, JType, WType, F, AD} <: RosenbrockConstantCache c₃₂::T @@ -226,7 +159,7 @@ struct Rosenbrock23ConstantCache{T, TF, UF, JType, WType, F, AD} <: end function Rosenbrock23ConstantCache(::Type{T}, tf, uf, J, W, linsolve, autodiff) where {T} - tab = Rosenbrock23Tableau(T) + tab = RosenbrockCombinedTableau(T) Rosenbrock23ConstantCache(tab.c₃₂, tab.d, tf, uf, J, W, linsolve, autodiff) end @@ -236,7 +169,7 @@ function alg_cache(alg::Rosenbrock23, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) Rosenbrock23ConstantCache(constvalue(uBottomEltypeNoUnits), tf, uf, J, W, linsolve, @@ -256,7 +189,7 @@ struct Rosenbrock32ConstantCache{T, TF, UF, JType, WType, F, AD} <: end function Rosenbrock32ConstantCache(::Type{T}, tf, uf, J, W, linsolve, autodiff) where {T} - tab = Rosenbrock32Tableau(T) + tab = RosenbrockCombinedTableau(T) Rosenbrock32ConstantCache(tab.c₃₂, tab.d, tf, uf, J, W, linsolve, autodiff) end @@ -266,7 +199,7 @@ function alg_cache(alg::Rosenbrock32, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) Rosenbrock32ConstantCache(constvalue(uBottomEltypeNoUnits), tf, uf, J, W, linsolve, @@ -334,7 +267,6 @@ function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) @@ -344,15 +276,20 @@ function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) + + grad_config = build_grad_config(alg, f, tf, du1, t) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), Pl = Pl, Pr = Pr, assumptions = LinearSolve.OperatorAssumptions(true)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + Rosenbrock33Cache(u, uprev, du, du1, du2, k1, k2, k3, k4, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, @@ -366,7 +303,7 @@ function alg_cache(alg::ROS3P, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) Rosenbrock33ConstantCache(tf, uf, @@ -419,7 +356,6 @@ function alg_cache(alg::Rodas3, u, rate_prototype, ::Type{uEltypeNoUnits}, fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) @@ -430,15 +366,21 @@ function alg_cache(alg::Rodas3, u, rate_prototype, ::Type{uEltypeNoUnits}, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) + + grad_config = build_grad_config(alg, f, tf, du1, t) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), Pl = Pl, Pr = Pr, assumptions = LinearSolve.OperatorAssumptions(true)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + Rosenbrock34Cache(u, uprev, du, du1, du2, k1, k2, k3, k4, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, @@ -462,7 +404,7 @@ function alg_cache(alg::Rodas3, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) Rosenbrock34ConstantCache(tf, uf, @@ -612,7 +554,6 @@ function alg_cache(alg::Rodas23W, u, rate_prototype, ::Type{uEltypeNoUnits}, fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) @@ -623,15 +564,21 @@ function alg_cache(alg::Rodas23W, u, rate_prototype, ::Type{uEltypeNoUnits}, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) linsolve_tmp = zero(rate_prototype) + + grad_config = build_grad_config(alg, f, tf, du1, t) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), Pl = Pl, Pr = Pr, assumptions = LinearSolve.OperatorAssumptions(true)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + Rodas23WCache(u, uprev, dense1, dense2, dense3, du, du1, du2, k1, k2, k3, k4, k5, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, @@ -656,7 +603,6 @@ function alg_cache(alg::Rodas3P, u, rate_prototype, ::Type{uEltypeNoUnits}, fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) recursivefill!(atmp, false) @@ -666,16 +612,22 @@ function alg_cache(alg::Rodas3P, u, rate_prototype, ::Type{uEltypeNoUnits}, tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) + + grad_config = build_grad_config(alg, f, tf, du1, t) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) + linsolve_tmp = zero(rate_prototype) linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A = true, alias_b = true), Pl = Pl, Pr = Pr, assumptions = LinearSolve.OperatorAssumptions(true)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + Rodas3PCache(u, uprev, dense1, dense2, dense3, du, du1, du2, k1, k2, k3, k4, k5, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, @@ -688,7 +640,7 @@ function alg_cache(alg::Rodas23W, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) Rodas23WConstantCache(tf, uf, @@ -703,7 +655,7 @@ function alg_cache(alg::Rodas3P, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) Rodas3PConstantCache(tf, uf, @@ -722,15 +674,17 @@ tabtype(::Rodas5) = Rodas5Tableau tabtype(::Rodas5P) = Rodas5PTableau tabtype(::Rodas5Pr) = Rodas5PTableau tabtype(::Rodas5Pe) = Rodas5PTableau +tabtype(::Rodas6P) = Rodas6PTableau -function alg_cache(alg::Union{Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr}, +function alg_cache( + alg::Union{Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, Rodas6P}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} tf = TimeDerivativeWrapper(f, u, p) uf = UDerivativeWrapper(f, t, p) - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(false)) + J, W = build_J_W(alg, u, uprev, p, t, dt, f, nothing, uEltypeNoUnits, Val(false)) linprob = nothing #LinearProblem(W,copy(u); u0=copy(u)) linsolve = nothing #init(linprob,alg.linsolve,alias_A=true,alias_b=true) tab = tabtype(alg)(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) @@ -739,28 +693,28 @@ function alg_cache(alg::Union{Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5 alg_autodiff(alg), size(tab.H, 1)) end -function alg_cache(alg::Union{Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr}, +function alg_cache( + alg::Union{Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, Rodas6P}, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - tab = tabtype(alg)(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) - # Initialize vectors dense = [zero(rate_prototype) for _ in 1:size(tab.H, 1)] - ks = [zero(rate_prototype) for _ in 1:size(tab.A, 1)] du = zero(rate_prototype) du1 = zero(rate_prototype) du2 = zero(rate_prototype) + ks = [zero(rate_prototype) for _ in 1:size(tab.A, 1)] + + # Promote t-type for AD + dtC = zero(tab.C) .* dt + dtd = zero(tab.d) .* dt # Initialize other variables fsalfirst = zero(rate_prototype) fsallast = zero(rate_prototype) dT = zero(rate_prototype) - # Build J and W matrices - J, W = build_J_W(alg, u, uprev, p, t, dt, f, uEltypeNoUnits, Val(true)) - # Temporary and helper variables tmp = zero(rate_prototype) atmp = similar(u, uEltypeNoUnits) @@ -770,31 +724,35 @@ function alg_cache(alg::Union{Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5 tf = TimeGradientWrapper(f, uprev, p) uf = UJacobianWrapper(f, t, p) - linsolve_tmp = zero(rate_prototype) - linprob = LinearProblem(W, _vec(linsolve_tmp); u0 = _vec(tmp)) + + grad_config = build_grad_config(alg, f, tf, du1, t) + jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + + J, W = build_J_W(alg, u, uprev, p, t, dt, f, jac_config, uEltypeNoUnits, Val(true)) Pl, Pr = wrapprecs( alg.precs(W, nothing, u, p, t, nothing, nothing, nothing, nothing)..., weight, tmp) - linsolve = init(linprob, alg.linsolve, alias_A = true, alias_b = true, - Pl = Pl, Pr = Pr, - assumptions = LinearSolve.OperatorAssumptions(true)) + linsolve_tmp = zero(rate_prototype) + linprob = LinearProblem(W, _vec(linsolve_tmp); u0=_vec(tmp)) - grad_config = build_grad_config(alg, f, tf, du1, t) - jac_config = build_jac_config(alg, f, uf, du1, uprev, u, tmp, du2) + linsolve = init( + linprob, alg.linsolve, alias = LinearAliasSpecifier(alias_A=true, alias_b=true), + Pl=Pl, Pr=Pr, + assumptions=LinearSolve.OperatorAssumptions(true)) + # Return the cache struct with vectors RosenbrockCache( - u, uprev, dense, du, du1, du2, ks, fsalfirst, fsallast, + u, uprev, dense, du, du1, du2, dtC, dtd, ks, fsalfirst, fsallast, dT, J, W, tmp, atmp, weight, tab, tf, uf, linsolve_tmp, linsolve, jac_config, grad_config, reltol, alg, alg.step_limiter!, alg.stage_limiter!, size(tab.H, 1)) end - function get_fsalfirstlast( - cache::Union{Rosenbrock23Cache, Rosenbrock32Cache, Rosenbrock33Cache, + cache::Union{RosenbrockCombinedCache, Rosenbrock33Cache, Rosenbrock34Cache, Rosenbrock4Cache}, u) diff --git a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_interpolants.jl b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_interpolants.jl index 003595567e..addac97faf 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_interpolants.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_interpolants.jl @@ -1,6 +1,6 @@ ### Fallbacks to capture -ROSENBROCKS_WITH_INTERPOLATIONS = Union{Rosenbrock23ConstantCache, Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache, +ROSENBROCKS_WITH_INTERPOLATIONS = Union{Rosenbrock23ConstantCache, RosenbrockCombinedCache, + Rosenbrock32ConstantCache, Rodas23WConstantCache, Rodas3PConstantCache, Rodas23WCache, Rodas3PCache, RosenbrockCombinedConstantCache, @@ -18,8 +18,6 @@ function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, throw(DerivativeOrderNotPossibleError()) end -#### - """ From MATLAB ODE Suite by Shampine """ @@ -46,37 +44,37 @@ end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, - cache::Union{Rosenbrock23Cache, Rosenbrock32Cache}, + cache::RosenbrockCombinedCache, idxs::Nothing, T::Type{Val{0}}, differential_vars) @rosenbrock2332pre0 - @inbounds @.. y₀+dt * (c1 * k[1] + c2 * k[2]) + @inbounds @.. y₀ + dt * (c1 * k[1] + c2 * k[2]) end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, - cache::Union{Rosenbrock23ConstantCache, Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + cache::Union{Rosenbrock23ConstantCache, RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs, T::Type{Val{0}}, differential_vars) @rosenbrock2332pre0 - @.. y₀[idxs]+dt * (c1 * k[1][idxs] + c2 * k[2][idxs]) + @.. y₀[idxs] + dt * (c1 * k[1][idxs] + c2 * k[2][idxs]) end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{Rosenbrock23ConstantCache, - Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs::Nothing, T::Type{Val{0}}, differential_vars) @rosenbrock2332pre0 - @inbounds @.. out=y₀ + dt * (c1 * k[1] + c2 * k[2]) + @inbounds @.. out = y₀ + dt * (c1 * k[1] + c2 * k[2]) out end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{Rosenbrock23ConstantCache, - Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs, T::Type{Val{0}}, differential_vars) @rosenbrock2332pre0 - @views @.. out=y₀[idxs] + dt * (c1 * k[1][idxs] + c2 * k[2][idxs]) + @views @.. out = y₀[idxs] + dt * (c1 * k[1][idxs] + c2 * k[2][idxs]) out end @@ -88,38 +86,38 @@ end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, - cache::Union{Rosenbrock23ConstantCache, Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + cache::Union{Rosenbrock23ConstantCache, RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs::Nothing, T::Type{Val{1}}, differential_vars) @rosenbrock2332pre1 - @.. c1diff * k[1]+c2diff * k[2] + @.. c1diff * k[1] + c2diff * k[2] end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, - cache::Union{Rosenbrock23ConstantCache, Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + cache::Union{Rosenbrock23ConstantCache, RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs, T::Type{Val{1}}, differential_vars) @rosenbrock2332pre1 - @.. c1diff * k[1][idxs]+c2diff * k[2][idxs] + @.. c1diff * k[1][idxs] + c2diff * k[2][idxs] end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{Rosenbrock23ConstantCache, - Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs::Nothing, T::Type{Val{1}}, differential_vars) @rosenbrock2332pre1 - @.. out=c1diff * k[1] + c2diff * k[2] + @.. out = c1diff * k[1] + c2diff * k[2] out end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{Rosenbrock23ConstantCache, - Rosenbrock23Cache, - Rosenbrock32ConstantCache, Rosenbrock32Cache + RosenbrockCombinedCache, + Rosenbrock32ConstantCache }, idxs, T::Type{Val{1}}, differential_vars) @rosenbrock2332pre1 - @views @.. out=c1diff * k[1][idxs] + c2diff * k[2][idxs] + @views @.. out = c1diff * k[1][idxs] + c2diff * k[2][idxs] out end @@ -128,108 +126,162 @@ From MATLAB ODE Suite by Shampine """ @muladd function _ode_interpolant( - Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, Rodas23WConstantCache, Rodas3PConstantCache, RosenbrockCache, Rodas23WCache, Rodas3PCache}, + Θ, dt, + y₀, + y₁, + k, + cache::Union{RosenbrockCombinedConstantCache, Rodas23WConstantCache, + Rodas3PConstantCache, RosenbrockCache, Rodas23WCache, Rodas3PCache}, idxs::Nothing, T::Type{Val{0}}, differential_vars) Θ1 = 1 - Θ if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @.. Θ1 * y₀+Θ * (y₁ + Θ1 * (k[1] + Θ * k[2])) + @.. Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * k[2])) + elseif cache.interp_order == 4 + @.. Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * (k[2] + Θ * (k[3] + Θ * k[4])))) else - @.. Θ1 * y₀+Θ * (y₁ + Θ1 * (k[1] + Θ * (k[2] + Θ * k[3]))) + @.. Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * (k[2] + Θ * k[3]))) end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, - cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, + cache::Union{ + RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, Rodas23WCache, Rodas3PConstantCache, Rodas3PCache}, idxs, T::Type{Val{0}}, differential_vars) Θ1 = 1 - Θ if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @views @.. Θ1 * y₀[idxs]+Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + Θ * k[2][idxs])) + @views @.. Θ1 * y₀[idxs] + Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + Θ * k[2][idxs])) + elseif cache.interp_order == 4 + @views @.. Θ1 * y₀[idxs] + Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + + Θ * (k[2][idxs] + Θ * (k[3][idxs] + Θ * k[4][idxs])))) else - @views @.. Θ1 * y₀[idxs]+Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + Θ * (k[2][idxs] + Θ * k[3][idxs]))) + @views @.. Θ1 * y₀[idxs] + + Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + Θ * (k[2][idxs] + Θ * k[3][idxs]))) end end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, - cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, + cache::Union{ + RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, Rodas23WCache, Rodas3PConstantCache, Rodas3PCache}, idxs::Nothing, T::Type{Val{0}}, differential_vars) Θ1 = 1 - Θ if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @.. out=Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * k[2])) + @.. out = Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * k[2])) + elseif cache.interp_order == 4 + @.. out = Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * (k[2] + Θ * (k[3] + Θ * k[4])))) else - @.. out=Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * (k[2] + Θ * k[3]))) + @.. out = Θ1 * y₀ + Θ * (y₁ + Θ1 * (k[1] + Θ * (k[2] + Θ * k[3]))) end out end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, - cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, + cache::Union{ + RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, Rodas23WCache, Rodas3PConstantCache, Rodas3PCache}, idxs, T::Type{Val{0}}, differential_vars) Θ1 = 1 - Θ if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @views @.. out=Θ1 * y₀[idxs] + Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + Θ * k[2][idxs])) + @views @.. out = Θ1 * y₀[idxs] + Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + Θ * k[2][idxs])) + elseif cache.interp_order == 4 + @views @.. out = Θ1 * y₀[idxs] + Θ * (y₁[idxs] + Θ1 * (k[1][idxs] + + Θ * (k[2][idxs] + Θ * (k[3][idxs] + Θ * k[4][idxs])))) else - @views @.. out=Θ1 * y₀[idxs]+Θ * (y₁[idxs] + - Θ1 * (k[1][idxs] + Θ * (k[2][idxs] + Θ * k[3][idxs]))) + @views @.. out = Θ1 * y₀[idxs] + + Θ * (y₁[idxs] + + Θ1 * (k[1][idxs] + Θ * (k[2][idxs] + Θ * k[3][idxs]))) end out end # First Derivative @muladd function _ode_interpolant( - Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCache, Rodas23WCache, Rodas3PCache, RosenbrockCombinedConstantCache, Rodas23WConstantCache, Rodas3PConstantCache}, + Θ, dt, + y₀, + y₁, + k, + cache::Union{ + RosenbrockCache, Rodas23WCache, Rodas3PCache, RosenbrockCombinedConstantCache, + Rodas23WConstantCache, Rodas3PConstantCache}, idxs::Nothing, T::Type{Val{1}}, differential_vars) if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @.. (k[1] + Θ * (-2 * k[1] + 2 * k[2] - 3 * k[2] * Θ) - y₀ + y₁)/dt + @.. (k[1] + Θ * (-2 * k[1] + 2 * k[2] - 3 * k[2] * Θ) - y₀ + y₁) / dt + elseif cache.interp_order == 4 + @.. (k[1] + Θ * (-2 * k[1] + 2 * k[2] + + Θ * (-3 * k[2] + 3 * k[3] + + Θ * (-4 * k[3] + 4 * k[4] - 5 * Θ * k[4]))) - + y₀ + y₁) / dt else - @.. (k[1] + Θ * (-2 * k[1] + 2 * k[2] + - Θ * (-3 * k[2] + 3 * k[3] - 4 * Θ * k[3])) - - y₀ + y₁)/dt + @.. (k[1] + Θ * (-2 * k[1] + 2 * k[2] + + Θ * (-3 * k[2] + 3 * k[3] - 4 * Θ * k[3])) - + y₀ + y₁) / dt end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, - cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, + cache::Union{ + RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, Rodas23WCache, Rodas3PConstantCache, Rodas3PCache}, idxs, T::Type{Val{1}}, differential_vars) if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @views @.. (k[1][idxs] + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] - 3 * k[2][idxs] * Θ) - - y₀[idxs] + y₁[idxs])/dt + @views @.. (k[1][idxs] + + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] - 3 * k[2][idxs] * Θ) - + y₀[idxs] + y₁[idxs]) / dt + elseif cache.interp_order == 4 + @views @.. (k[1][idxs] + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] + + Θ * (-3 * k[2][idxs] + 3 * k[3][idxs] + + Θ * (-4 * k[3][idxs] + 4 * k[4][idxs] - 5 * Θ * k[4][idxs]))) - + y₀[idxs] + y₁[idxs]) / dt else - @views @.. (k[1][idxs] + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] + - Θ * (-3 * k[2][idxs] + 3 * k[3][idxs] - 4 * Θ * k[3][idxs])) - y₀[idxs] + y₁[idxs])/dt + @views @.. (k[1][idxs] + + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] + + Θ * (-3 * k[2][idxs] + 3 * k[3][idxs] - 4 * Θ * k[3][idxs])) - + y₀[idxs] + y₁[idxs]) / dt end end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, - cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, + cache::Union{ + RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, Rodas23WCache, Rodas3PConstantCache, Rodas3PCache}, idxs::Nothing, T::Type{Val{1}}, differential_vars) if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @.. out=(k[1] + Θ * (-2 * k[1] + 2 * k[2] - 3 * k[2] * Θ) - y₀ + y₁) / dt + @.. out = (k[1] + Θ * (-2 * k[1] + 2 * k[2] - 3 * k[2] * Θ) - y₀ + y₁) / dt + elseif cache.interp_order == 4 + @.. out = (k[1] + Θ * (-2 * k[1] + 2 * k[2] + + Θ * (-3 * k[2] + 3 * k[3] + + Θ * (-4 * k[3] + 4 * k[4] - 5 * Θ * k[4]))) - + y₀ + y₁) / dt else - @.. out=(k[1] + Θ * (-2 * k[1] + 2 * k[2] + - Θ * (-3 * k[2] + 3 * k[3] - 4 * Θ * k[3])) - y₀ + y₁) / dt + @.. out = (k[1] + + Θ * (-2 * k[1] + 2 * k[2] + + Θ * (-3 * k[2] + 3 * k[3] - 4 * Θ * k[3])) - y₀ + y₁) / dt end out end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, - cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, + cache::Union{ + RosenbrockCombinedConstantCache, RosenbrockCache, Rodas23WConstantCache, Rodas23WCache, Rodas3PConstantCache, Rodas3PCache}, idxs, T::Type{Val{1}}, differential_vars) if !hasproperty(cache, :interp_order) || cache.interp_order == 2 - @views @.. out=(k[1][idxs] + - Θ * - (-2 * k[1][idxs] + 2 * k[2][idxs] - - 3 * k[2][idxs] * Θ) - - y₀[idxs] + y₁[idxs]) / dt + @views @.. out = (k[1][idxs] + + Θ * + (-2 * k[1][idxs] + 2 * k[2][idxs] - + 3 * k[2][idxs] * Θ) - + y₀[idxs] + y₁[idxs]) / dt + elseif cache.interp_order == 4 + @views @.. out = (k[1][idxs] + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] + + Θ * (-3 * k[2][idxs] + 3 * k[3][idxs] + + Θ * (-4 * k[3][idxs] + 4 * k[4][idxs] - 5 * Θ * k[4][idxs]))) - + y₀[idxs] + y₁[idxs]) / dt else @views @.. broadcast=false out=(k[1][idxs] + Θ * (-2 * k[1][idxs] + 2 * k[2][idxs] + Θ * - (-3 * k[2][idxs] + 3 * k[3][idxs] - 4 * Θ * k[3][idxs])) - + (-3 * k[2][idxs] + 3 * k[3][idxs] - + 4 * Θ * k[3][idxs])) - y₀[idxs] + y₁[idxs]) / dt end out @@ -238,68 +290,115 @@ end # Second Derivative @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, cache::RosenbrockCombinedConstantCache, idxs::Nothing, T::Type{Val{2}}, differential_vars) - @inbounds (-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] - 12 * Θ * k[3])) / dt^2 + if cache.interp_order == 4 + @inbounds (-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] + + Θ * (-12 * k[3] + 12 * k[4] - 20 * Θ * k[4]))) / dt^2 + else + @inbounds (-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] - 12 * Θ * k[3])) / dt^2 + end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, cache::RosenbrockCache, idxs::Nothing, T::Type{Val{2}}, differential_vars) - @inbounds @.. broadcast=false (-2 * k[1] + 2 * k[2] + + if cache.interp_order == 4 + @inbounds @.. broadcast=false (-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] + + Θ * (-12 * k[3] + 12 * k[4] - 20 * Θ * k[4]))) / dt^2 + else + @inbounds @.. broadcast=false (-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] - 12 * Θ * k[3]))/dt^2 + end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache}, idxs, T::Type{Val{2}}, differential_vars) - @.. broadcast=false (-2 * k[1][idxs] + 2 * k[2][idxs] + + if cache.interp_order == 4 + @.. broadcast=false (-2 * k[1][idxs] + 2 * k[2][idxs] + Θ * (-6 * k[2][idxs] + 6 * k[3][idxs] + + Θ * (-12 * k[3][idxs] + 12 * k[4][idxs] - 20 * Θ * k[4][idxs]))) / dt^2 + else + @.. broadcast=false (-2 * k[1][idxs] + 2 * k[2][idxs] + Θ * (-6 * k[2][idxs] + 6 * k[3][idxs] - 12 * Θ * k[3][idxs]))/dt^2 + end end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache}, idxs::Nothing, T::Type{Val{2}}, differential_vars) - @.. broadcast=false out=(-2 * k[1] + 2 * k[2] + + if cache.interp_order == 4 + @.. broadcast=false out=(-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] + + Θ * (-12 * k[3] + 12 * k[4] - 20 * Θ * k[4]))) / dt^2 + else + @.. broadcast=false out=(-2 * k[1] + 2 * k[2] + Θ * (-6 * k[2] + 6 * k[3] - 12 * Θ * k[3])) / dt^2 + end out end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache}, idxs, T::Type{Val{2}}, differential_vars) - @views @.. broadcast=false out=(-2 * k[1][idxs] + 2 * k[2][idxs] + + if cache.interp_order == 4 + @views @.. broadcast=false out=(-2 * k[1][idxs] + 2 * k[2][idxs] + Θ * (-6 * k[2][idxs] + 6 * k[3][idxs] + + Θ * (-12 * k[3][idxs] + 12 * k[4][idxs] - 20 * Θ * k[4][idxs]))) / dt^2 + else + @views @.. broadcast=false out=(-2 * k[1][idxs] + 2 * k[2][idxs] + Θ * (-6 * k[2][idxs] + 6 * k[3][idxs] - 12 * Θ * k[3][idxs])) / dt^2 + end out end # Third Derivative @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, cache::RosenbrockCombinedConstantCache, idxs::Nothing, T::Type{Val{3}}, differential_vars) - @inbounds (-6 * k[2] + 6 * k[3] - 24 * Θ * k[3]) / dt^3 + if cache.interp_order == 4 + @inbounds (-6 * k[2] + 6 * k[3] + Θ * (-24 * k[3] + 24 * k[4] - 60 * Θ * k[4])) / dt^3 + else + @inbounds (-6 * k[2] + 6 * k[3] - 24 * Θ * k[3]) / dt^3 + end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, cache::RosenbrockCache, idxs::Nothing, T::Type{Val{3}}, differential_vars) - @inbounds @.. broadcast=false (-6 * k[2] + 6 * k[3] - 24 * Θ * k[3])/dt^3 + if cache.interp_order == 4 + @inbounds @.. broadcast=false (-6 * k[2] + 6 * k[3] + Θ * (-24 * k[3] + 24 * k[4] - 60 * Θ * k[4])) / dt^3 + else + @inbounds @.. broadcast=false (-6 * k[2] + 6 * k[3] - 24 * Θ * k[3])/dt^3 + end end @muladd function _ode_interpolant(Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache}, idxs, T::Type{Val{3}}, differential_vars) - @.. broadcast=false (-6 * k[2][idxs] + 6 * k[3][idxs] - 24 * Θ * k[3][idxs])/dt^3 + if cache.interp_order == 4 + @.. broadcast=false (-6 * k[2][idxs] + 6 * k[3][idxs] + + Θ * (-24 * k[3][idxs] + 24 * k[4][idxs] - 60 * Θ * k[4][idxs])) / dt^3 + else + @.. broadcast=false (-6 * k[2][idxs] + 6 * k[3][idxs] - 24 * Θ * k[3][idxs])/dt^3 + end end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache}, idxs::Nothing, T::Type{Val{3}}, differential_vars) - @.. broadcast=false out=(-6 * k[2] + 6 * k[3] - 24 * Θ * k[3]) / dt^3 + if cache.interp_order == 4 + @.. broadcast=false out=(-6 * k[2] + 6 * k[3] + Θ * (-24 * k[3] + 24 * k[4] - 60 * Θ * k[4])) / dt^3 + else + @.. broadcast=false out=(-6 * k[2] + 6 * k[3] - 24 * Θ * k[3]) / dt^3 + end out end @muladd function _ode_interpolant!(out, Θ, dt, y₀, y₁, k, cache::Union{RosenbrockCombinedConstantCache, RosenbrockCache}, idxs, T::Type{Val{3}}, differential_vars) - @views @.. broadcast=false out=(-6 * k[2][idxs] + 6 * k[3][idxs] - + if cache.interp_order == 4 + @views @.. broadcast=false out=(-6 * k[2][idxs] + 6 * k[3][idxs] + + Θ * (-24 * k[3][idxs] + 24 * k[4][idxs] - 60 * Θ * k[4][idxs])) / dt^3 + else + @views @.. broadcast=false out=(-6 * k[2][idxs] + 6 * k[3][idxs] - 24 * Θ * k[3][idxs]) / dt^3 + end out end diff --git a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_perform_step.jl b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_perform_step.jl index 1414a93f92..7a3dcd448c 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_perform_step.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_perform_step.jl @@ -1,5 +1,4 @@ -function initialize!(integrator, cache::Union{Rosenbrock23Cache, - Rosenbrock32Cache}) +function initialize!(integrator, cache::RosenbrockCombinedCache) integrator.kshortsize = 2 @unpack k₁, k₂, fsalfirst, fsallast = cache resize!(integrator.k, integrator.kshortsize) @@ -23,7 +22,7 @@ function initialize!(integrator, integrator.k[2] = zero(integrator.fsalfirst) end -@muladd function perform_step!(integrator, cache::Rosenbrock23Cache, repeat_step = false) +@muladd function perform_step!(integrator, cache::RosenbrockCombinedCache, repeat_step = false) @unpack t, dt, uprev, u, f, p, opts = integrator @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache @unpack c₃₂, d = cache.tab @@ -66,18 +65,18 @@ end @.. veck₁ = vecu * neginvdtγ integrator.stats.nsolve += 1 - @.. u = uprev + dto2 * k₁ + @.. broadcast=false u = uprev + dto2 * k₁ stage_limiter!(u, integrator, p, t + dto2) f(f₁, u, p, t + dto2) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) if mass_matrix === I - copyto!(tmp, k₁) + tmp .= k₁ else mul!(_vec(tmp), mass_matrix, _vec(k₁)) end - @.. linsolve_tmp = f₁ - tmp + @.. broadcast=false linsolve_tmp = f₁ - tmp linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) vecu = _vec(linres.u) @@ -86,153 +85,72 @@ end @.. veck₂ = vecu * neginvdtγ + veck₁ integrator.stats.nsolve += 1 - @.. u = uprev + dt * k₂ - stage_limiter!(u, integrator, p, t + dt) - step_limiter!(u, integrator, p, t + dt) - - if integrator.opts.adaptive - f(fsallast, u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=fsallast - c₃₂ * (k₂ - f₁) - - 2(k₁ - fsalfirst) + dt * dT - else - @.. broadcast=false du2=c₃₂ * k₂ + 2k₁ - mul!(_vec(du1), mass_matrix, _vec(du2)) - @.. broadcast=false linsolve_tmp=fsallast - du1 + c₃₂ * f₁ + 2fsalfirst + - dt * dT - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - vecu = _vec(linres.u) - veck3 = _vec(k₃) - @.. veck3 = vecu * neginvdtγ - - integrator.stats.nsolve += 1 - - if mass_matrix === I - @.. broadcast=false tmp=dto6 * (k₁ - 2 * k₂ + k₃) - else - veck₁ = _vec(k₁) - veck₂ = _vec(k₂) - veck₃ = _vec(k₃) - vectmp = _vec(tmp) - @.. broadcast=false vectmp=ifelse(cache.algebraic_vars, - false, dto6 * (veck₁ - 2 * veck₂ + veck₃)) - end - calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = integrator.opts.internalnorm(atmp, t) - - if mass_matrix !== I - algvar = reshape(cache.algebraic_vars, size(u)) - invatol = inv(integrator.opts.abstol) - @.. atmp = ifelse(algvar, fsallast, false) * invatol - integrator.EEst += integrator.opts.internalnorm(atmp, t) - end - end - cache.linsolve = linres.cache -end - -@muladd function perform_step!(integrator, cache::Rosenbrock32Cache, repeat_step = false) - @unpack t, dt, uprev, u, f, p, opts = integrator - @unpack k₁, k₂, k₃, du1, du2, f₁, fsalfirst, fsallast, dT, J, W, tmp, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache - @unpack c₃₂, d = cache.tab - - # Assignments - sizeu = size(u) - mass_matrix = integrator.f.mass_matrix - - # Precalculations - dtγ = dt * d - neginvdtγ = -inv(dtγ) - dto2 = dt / 2 - dto6 = dt / 6 - - if repeat_step - f(integrator.fsalfirst, uprev, p, t) + if cache.alg isa Rosenbrock32 + @.. tmp = uprev + dt * k₂ + stage_limiter!(u, integrator, p, t + dt) + f(fsallast, tmp, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - end - - calc_rosenbrock_differentiation!(integrator, cache, dtγ, dtγ, repeat_step) - - calculate_residuals!(weight, fill!(weight, one(eltype(u))), uprev, uprev, - integrator.opts.abstol, integrator.opts.reltol, - integrator.opts.internalnorm, t) - - if repeat_step - linres = dolinsolve( - integrator, cache.linsolve; A = nothing, b = _vec(linsolve_tmp), - du = integrator.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtγ)) - else - linres = dolinsolve(integrator, cache.linsolve; A = W, b = _vec(linsolve_tmp), - du = integrator.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtγ)) - end - - vecu = _vec(linres.u) - veck₁ = _vec(k₁) - - @.. veck₁ = vecu * neginvdtγ - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + dto2 * k₁ - stage_limiter!(u, integrator, p, t + dto2) - f(f₁, u, p, t + dto2) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - tmp .= k₁ else - mul!(_vec(tmp), mass_matrix, _vec(k₁)) + @.. u = uprev + dt * k₂ + stage_limiter!(u, integrator, p, t + dt) + f(fsallast, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) end - - @.. broadcast=false linsolve_tmp=f₁ - tmp - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - vecu = _vec(linres.u) - veck₂ = _vec(k₂) - - @.. veck₂ = vecu * neginvdtγ + veck₁ - integrator.stats.nsolve += 1 - - @.. tmp = uprev + dt * k₂ - stage_limiter!(u, integrator, p, t + dt) - f(fsallast, tmp, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - + + step_limiter!(u, integrator, p, t + dt) if mass_matrix === I - @.. broadcast=false linsolve_tmp=fsallast - c₃₂ * (k₂ - f₁) - 2(k₁ - fsalfirst) + - dt * dT + @.. broadcast=false linsolve_tmp=fsallast - c₃₂ * (k₂ - f₁) - + 2(k₁ - fsalfirst) + dt * dT else @.. broadcast=false du2=c₃₂ * k₂ + 2k₁ mul!(_vec(du1), mass_matrix, _vec(du2)) - @.. broadcast=false linsolve_tmp=fsallast - du1 + c₃₂ * f₁ + 2fsalfirst + dt * dT + @.. broadcast=false linsolve_tmp=fsallast - du1 + c₃₂ * f₁ + 2fsalfirst + + dt * dT end linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) vecu = _vec(linres.u) veck3 = _vec(k₃) - @.. veck3 = vecu * neginvdtγ integrator.stats.nsolve += 1 - @.. broadcast=false u=uprev + dto6 * (k₁ + 4k₂ + k₃) - - step_limiter!(u, integrator, p, t + dt) + if cache.alg isa Rosenbrock32 + @.. broadcast=false u=uprev + dto6 * (k₁ + 4k₂ + k₃) + step_limiter!(u, integrator, p, t + dt) + end if integrator.opts.adaptive - @.. broadcast=false tmp=dto6 * (k₁ - 2 * k₂ + k₃) - calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = integrator.opts.internalnorm(atmp, t) + if cache.alg isa Rosenbrock32 + @.. broadcast=false tmp=dto6 * (k₁ - 2 * k₂ + k₃) + calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) + if mass_matrix !== I + invatol = inv(integrator.opts.abstol) + @.. atmp = ifelse(cache.algebraic_vars, fsallast, false) * invatol + integrator.EEst += integrator.opts.internalnorm(atmp, t) + end + else + if mass_matrix === I + @.. broadcast=false tmp=dto6 * (k₁ - 2 * k₂ + k₃) + else + veck₁ = _vec(k₁) + veck₂ = _vec(k₂) + veck₃ = _vec(k₃) + vectmp = _vec(tmp) + @.. broadcast=false vectmp=ifelse(cache.algebraic_vars, + false, dto6 * (veck₁ - 2 * veck₂ + veck₃)) + end + calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) - if mass_matrix !== I - invatol = inv(integrator.opts.abstol) - @.. atmp = ifelse(cache.algebraic_vars, fsallast, false) * invatol - integrator.EEst += integrator.opts.internalnorm(atmp, t) + if mass_matrix !== I + algvar = reshape(cache.algebraic_vars, size(u)) + invatol = inv(integrator.opts.abstol) + @.. atmp = ifelse(algvar, fsallast, false) * invatol + integrator.EEst += integrator.opts.internalnorm(atmp, t) + end end end cache.linsolve = linres.cache @@ -383,8 +301,7 @@ end if mass_matrix !== I invatol = inv(integrator.opts.abstol) - atmp = ifelse(integrator.differential_vars, false, integrator.fsallast) .* - invatol + atmp = ifelse(integrator.differential_vars, false, integrator.fsallast) .* invatol integrator.EEst += integrator.opts.internalnorm(atmp, t) end end @@ -395,53 +312,56 @@ end return nothing end -function initialize!(integrator, - cache::Union{Rosenbrock33ConstantCache, - Rosenbrock34ConstantCache, - Rosenbrock4ConstantCache}) - integrator.kshortsize = 2 - integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) - integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) +#### ROS2 type method - # Avoid undefined entries if k is an array of arrays - integrator.fsallast = zero(integrator.fsalfirst) - integrator.k[1] = integrator.fsalfirst - integrator.k[2] = integrator.fsallast -end +@ROS2(:init) +@ROS2(:performstep) -function initialize!(integrator, - cache::Union{Rosenbrock33Cache, - Rosenbrock34Cache, - Rosenbrock4Cache}) - integrator.kshortsize = 2 - @unpack fsalfirst, fsallast = cache - resize!(integrator.k, integrator.kshortsize) - integrator.k[1] = fsalfirst - integrator.k[2] = fsallast - integrator.f(integrator.fsalfirst, integrator.uprev, integrator.p, integrator.t) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) +################################################################################ + +#### ROS23 type method + +@ROS23(:init) +@ROS23(:performstep) + +################################################################################ + +#### ROS34PW type method + +@ROS34PW(:init) +@ROS34PW(:performstep) + +################################################################################ + +#### ROS4 type method + +@Rosenbrock4(:performstep) + +#### Arbirary order method +function initialize!(integrator, cache::RosenbrockCombinedConstantCache) + integrator.kshortsize = size(cache.tab.H, 1) + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + # Avoid undefined entries if k is an array of arrays + for i in 1:(integrator.kshortsize) + integrator.k[i] = zero(integrator.u) + end end -@muladd function perform_step!(integrator, cache::Rosenbrock33ConstantCache, - repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack tf, uf = cache - @unpack a21, a31, a32, C21, C31, C32, b1, b2, b3, btilde1, btilde2, btilde3, gamma, c2, c3, d1, d2, d3 = cache.tab +@muladd function perform_step!( + integrator, cache::RosenbrockCombinedConstantCache, repeat_step = false) + (; t, dt, uprev, u, f, p) = integrator + (; tf, uf) = cache + (; A, C, gamma, c, d, H) = cache.tab # Precalculations - dtC21 = C21 / dt - dtC31 = C31 / dt - dtC32 = C32 / dt - - dtd1 = dt * d1 - dtd2 = dt * d2 - dtd3 = dt * d3 + dtC = C ./ dt + dtd = dt .* d dtgamma = dt * gamma mass_matrix = integrator.f.mass_matrix # Time derivative + tf.u = uprev dT = calc_tderivative(integrator, cache) W = calc_W(integrator, cache, dtgamma, repeat_step) @@ -450,72 +370,123 @@ end return nothing end - linsolve_tmp = integrator.fsalfirst + dtd1 * dT - - k1 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + a21 * k1 - du = f(u, p, t + c2 * dt) + # Initialize ks + num_stages = size(A, 1) + du = f(uprev, p, t) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + linsolve_tmp = @.. du + dtd[1] * dT + k1 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) + # constant number for type stability make sure this is greater than num_stages + ks = ntuple(Returns(k1), 20) + # Loop for stages + for stage in 2:num_stages + u = uprev + for i in 1:(stage - 1) + u = @.. u + A[stage, i] * ks[i] + end - if mass_matrix === I - linsolve_tmp = du + dtd2 * dT + dtC21 * k1 - else - linsolve_tmp = du + dtd2 * dT + mass_matrix * (dtC21 * k1) - end + du = f(u, p, t + c[stage] * dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - k2 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + a31 * k1 + a32 * k2 - du = f(u, p, t + c3 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + # Compute linsolve_tmp for current stage + linsolve_tmp = zero(du) + if mass_matrix === I + for i in 1:(stage - 1) + linsolve_tmp = @.. linsolve_tmp + dtC[stage, i] * ks[i] + end + else + for i in 1:(stage - 1) + linsolve_tmp = @.. linsolve_tmp + dtC[stage, i] * ks[i] + end + linsolve_tmp = mass_matrix * linsolve_tmp + end + linsolve_tmp = @.. du + dtd[stage] * dT + linsolve_tmp - if mass_matrix === I - linsolve_tmp = du + dtd3 * dT + dtC31 * k1 + dtC32 * k2 + ks = Base.setindex(ks, _reshape(W \ -_vec(linsolve_tmp), axes(uprev)), stage) + integrator.stats.nsolve += 1 + end + if (integrator.alg isa Rodas6P) + du = ks[16] + u = uprev + for i in 1:15 + u = @.. u + A[16, i] * ks[i] + end + u = u .+ ks[16] else - linsolve_tmp = du + dtd3 * dT + mass_matrix * (dtC31 * k1 + dtC32 * k2) + du = ks[num_stages] + u = u .+ ks[num_stages] end - k3 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + b1 * k1 + b2 * k2 + b3 * k3 - integrator.fsallast = f(u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - if integrator.opts.adaptive - utilde = btilde1 * k1 + btilde2 * k2 + btilde3 * k3 - atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, + if (integrator.alg isa Rodas5Pe) + du = 0.2606326497975715 * ks[1] - 0.005158627295444251 * ks[2] + + 1.3038988631109731 * ks[3] + 1.235000722062074 * ks[4] + + -0.7931985603795049 * ks[5] - 1.005448461135913 * ks[6] - + 0.18044626132120234 * ks[7] + 0.17051519239113755 * ks[8] + end + atmp = calculate_residuals(du, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) end - integrator.k[1] = integrator.fsalfirst - integrator.k[2] = integrator.fsallast + if integrator.opts.calck + for j in eachindex(integrator.k) + integrator.k[j] = zero(integrator.k[1]) + end + for i in 1:num_stages + for j in eachindex(integrator.k) + integrator.k[j] = @.. integrator.k[j] + H[j, i] * ks[i] + end + end + if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && + (integrator.EEst < 1.0) + k2 = 0.5 * (uprev + u + + 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) + du1 = (0.25 * (integrator.k[2] + integrator.k[3]) - uprev + u) / dt + du = f(k2, p, t + dt / 2) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + if mass_matrix === I + du2 = du1 - du + else + du2 = mass_matrix * du1 - du + end + EEst = norm(du2) / norm(integrator.opts.abstol .+ integrator.opts.reltol .* k2) + integrator.EEst = max(EEst, integrator.EEst) + end + end + integrator.u = u return nothing end -@muladd function perform_step!(integrator, cache::Rosenbrock33Cache, repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, fsalfirst, fsallast, k1, k2, k3, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache - @unpack a21, a31, a32, C21, C31, C32, b1, b2, b3, btilde1, btilde2, btilde3, gamma, c2, c3, d1, d2, d3 = cache.tab +function initialize!(integrator, cache::RosenbrockCache) + integrator.kshortsize = size(cache.tab.H, 1) + resize!(integrator.k, integrator.kshortsize) + for i in 1:(integrator.kshortsize) + integrator.k[i] = cache.dense[i] + end +end + +@muladd function perform_step!(integrator, cache::RosenbrockCache, repeat_step = false) + (; t, dt, uprev, u, f, p) = integrator + (; du, du1, du2, dT, dtC, dtd, J, W, uf, tf, ks, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter!) = cache + (; A, C, gamma, c, d, H) = cache.tab # Assignments - mass_matrix = integrator.f.mass_matrix sizeu = size(u) - utilde = du + uidx = eachindex(integrator.uprev) + mass_matrix = integrator.f.mass_matrix # Precalculations - dtC21 = C21 / dt - dtC31 = C31 / dt - dtC32 = C32 / dt - - dtd1 = dt * d1 - dtd2 = dt * d2 - dtd3 = dt * d3 + @. dtC = C * inv(dt) + @. dtd = dt * d dtgamma = dt * gamma + utilde = du + + f(cache.fsalfirst, uprev, p, t) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - calc_rosenbrock_differentiation!(integrator, cache, dtd1, dtgamma, repeat_step) + calc_rosenbrock_differentiation!(integrator, cache, dtd[1], dtgamma, repeat_step) calculate_residuals!(weight, fill!(weight, one(eltype(u))), uprev, uprev, integrator.opts.abstol, integrator.opts.reltol, @@ -524,854 +495,32 @@ end if repeat_step linres = dolinsolve( integrator, cache.linsolve; A = nothing, b = _vec(linsolve_tmp), - du = integrator.fsalfirst, u = u, p = p, t = t, weight = weight, + du = cache.fsalfirst, u = u, p = p, t = t, weight = weight, solverdata = (; gamma = dtgamma)) else linres = dolinsolve(integrator, cache.linsolve; A = W, b = _vec(linsolve_tmp), - du = integrator.fsalfirst, u = u, p = p, t = t, weight = weight, + du = cache.fsalfirst, u = u, p = p, t = t, weight = weight, solverdata = (; gamma = dtgamma)) end - vecu = _vec(linres.u) - veck1 = _vec(k1) - - @.. broadcast=false veck1=-vecu + @.. $(_vec(ks[1])) = -linres.u integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + a21 * k1 - stage_limiter!(u, integrator, p, t + c2 * dt) - f(du, u, p, t + c2 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + dtd2 * dT + dtC21 * k1 - else - @.. broadcast=false du1=dtC21 * k1 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + dtd2 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - vecu = _vec(linres.u) - veck2 = _vec(k2) - - @.. broadcast=false veck2=-vecu - - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + a31 * k1 + a32 * k2 - stage_limiter!(u, integrator, p, t + c3 * dt) - f(du, u, p, t + c3 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + dtd3 * dT + dtC31 * k1 + dtC32 * k2 - else - @.. broadcast=false du1=dtC31 * k1 + dtC32 * k2 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + dtd3 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - vecu = _vec(linres.u) - veck3 = _vec(k3) - - @.. broadcast=false veck3=-vecu - - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + b1 * k1 + b2 * k2 + b3 * k3 - - step_limiter!(u, integrator, p, t + dt) - - f(fsallast, u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if integrator.opts.adaptive - @.. broadcast=false utilde=btilde1 * k1 + btilde2 * k2 + btilde3 * k3 - calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = integrator.opts.internalnorm(atmp, t) - end - cache.linsolve = linres.cache -end - -################################################################################ - -@muladd function perform_step!(integrator, cache::Rosenbrock34ConstantCache, - repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack tf, uf = cache - @unpack a21, a31, a32, a41, a42, a43, C21, C31, C32, C41, C42, C43, b1, b2, b3, b4, btilde1, btilde2, btilde3, btilde4, gamma, c2, c3, d1, d2, d3, d4 = cache.tab - - # Precalculations - dtC21 = C21 / dt - dtC31 = C31 / dt - dtC32 = C32 / dt - dtC41 = C41 / dt - dtC42 = C42 / dt - dtC43 = C43 / dt - - dtd1 = dt * d1 - dtd2 = dt * d2 - dtd3 = dt * d3 - dtd4 = dt * d4 - dtgamma = dt * gamma - - mass_matrix = integrator.f.mass_matrix - # Time derivative - tf.u = uprev - dT = calc_tderivative(integrator, cache) - - W = calc_W(integrator, cache, dtgamma, repeat_step) - if !issuccess_W(W) - integrator.EEst = 2 - return nothing - end - - linsolve_tmp = integrator.fsalfirst + dtd1 * dT - - k1 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev # +a21*k1 a21 == 0 - # du = f(u, p, t+c2*dt) c2 == 0 and a21 == 0 => du = f(uprev, p, t) == fsalfirst - - if mass_matrix === I - linsolve_tmp = integrator.fsalfirst + dtd2 * dT + dtC21 * k1 - else - linsolve_tmp = integrator.fsalfirst + dtd2 * dT + mass_matrix * (dtC21 * k1) - end - - k2 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + a31 * k1 + a32 * k2 - du = f(u, p, t + c3 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - linsolve_tmp = du + dtd3 * dT + dtC31 * k1 + dtC32 * k2 - else - linsolve_tmp = du + dtd3 * dT + mass_matrix * (dtC31 * k1 + dtC32 * k2) - end - - k3 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + a41 * k1 + a42 * k2 + a43 * k3 - du = f(u, p, t + dt) #-- c4 = 1 - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - linsolve_tmp = du + dtd4 * dT + dtC41 * k1 + dtC42 * k2 + dtC43 * k3 - else - linsolve_tmp = du + dtd4 * dT + mass_matrix * (dtC41 * k1 + dtC42 * k2 + dtC43 * k3) - end - - k4 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 - integrator.fsallast = f(u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if integrator.opts.adaptive - utilde = btilde1 * k1 + btilde2 * k2 + btilde3 * k3 + btilde4 * k4 - atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = integrator.opts.internalnorm(atmp, t) - end - - integrator.k[1] = integrator.fsalfirst - integrator.k[2] = integrator.fsallast - integrator.u = u - return nothing -end - -@muladd function perform_step!(integrator, cache::Rosenbrock34Cache, repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, fsalfirst, fsallast, k1, k2, k3, k4, dT, J, W, uf, tf, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache - @unpack a21, a31, a32, a41, a42, a43, C21, C31, C32, C41, C42, C43, b1, b2, b3, b4, btilde1, btilde2, btilde3, btilde4, gamma, c2, c3, d1, d2, d3, d4 = cache.tab - - # Assignments - uidx = eachindex(integrator.uprev) - sizeu = size(u) - mass_matrix = integrator.f.mass_matrix - utilde = du - - # Precalculations - dtC21 = C21 / dt - dtC31 = C31 / dt - dtC32 = C32 / dt - dtC41 = C41 / dt - dtC42 = C42 / dt - dtC43 = C43 / dt - - dtd1 = dt * d1 - dtd2 = dt * d2 - dtd3 = dt * d3 - dtd4 = dt * d4 - dtgamma = dt * gamma - - calc_rosenbrock_differentiation!(integrator, cache, dtd1, dtgamma, repeat_step) - - calculate_residuals!(weight, fill!(weight, one(eltype(u))), uprev, uprev, - integrator.opts.abstol, integrator.opts.reltol, - integrator.opts.internalnorm, t) - - if repeat_step - linres = dolinsolve( - integrator, cache.linsolve; A = nothing, b = _vec(linsolve_tmp), - du = integrator.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtgamma)) - else - linres = dolinsolve(integrator, cache.linsolve; A = W, b = _vec(linsolve_tmp), - du = integrator.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtgamma)) - end - - vecu = _vec(linres.u) - veck1 = _vec(k1) - - @.. broadcast=false veck1=-vecu - integrator.stats.nsolve += 1 - - #= - a21 == 0 and c2 == 0 - so du = integrator.fsalfirst! - @.. broadcast=false u = uprev + a21*k1 - - f(du, u, p, t+c2*dt) - =# - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=fsalfirst + dtd2 * dT + dtC21 * k1 - else - @.. broadcast=false du1=dtC21 * k1 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=fsalfirst + dtd2 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - veck2 = _vec(k2) - @.. broadcast=false veck2=-vecu - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + a31 * k1 + a32 * k2 - stage_limiter!(u, integrator, p, t + c3 * dt) - f(du, u, p, t + c3 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + dtd3 * dT + dtC31 * k1 + dtC32 * k2 - else - @.. broadcast=false du1=dtC31 * k1 + dtC32 * k2 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + dtd3 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - veck3 = _vec(k3) - @.. broadcast=false veck3=-vecu - integrator.stats.nsolve += 1 - @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 - stage_limiter!(u, integrator, p, t + dt) - f(du, u, p, t + dt) #-- c4 = 1 - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + dtd4 * dT + dtC41 * k1 + dtC42 * k2 + - dtC43 * k3 - else - @.. broadcast=false du1=dtC41 * k1 + dtC42 * k2 + dtC43 * k3 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + dtd4 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - veck4 = _vec(k4) - @.. broadcast=false veck4=-vecu - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + b1 * k1 + b2 * k2 + b3 * k3 + b4 * k4 - - step_limiter!(u, integrator, p, t + dt) - - f(fsallast, u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if integrator.opts.adaptive - @.. broadcast=false utilde=btilde1 * k1 + btilde2 * k2 + btilde3 * k3 + btilde4 * k4 - calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = integrator.opts.internalnorm(atmp, t) - end - cache.linsolve = linres.cache -end - -################################################################################ - -#### ROS2 type method - -@ROS2(:init) -@ROS2(:performstep) - -################################################################################ - -#### ROS23 type method - -@ROS23(:init) -@ROS23(:performstep) - -################################################################################ - -#### ROS34PW type method - -@ROS34PW(:init) -@ROS34PW(:performstep) - -################################################################################ - -#### ROS4 type method - -@Rosenbrock4(:performstep) - -################################################################################ - -#### Rodas3P type method - -function initialize!(integrator, cache::Union{Rodas23WConstantCache, Rodas3PConstantCache}) - integrator.kshortsize = 3 - integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) - # Avoid undefined entries if k is an array of arrays - integrator.k[1] = zero(integrator.u) - integrator.k[2] = zero(integrator.u) - integrator.k[3] = zero(integrator.u) -end - -@muladd function perform_step!( - integrator, cache::Union{Rodas23WConstantCache, Rodas3PConstantCache}, - repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack tf, uf = cache - @unpack a21, a41, a42, a43, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, gamma, c2, c3, d1, d2, d3 = cache.tab - - # Precalculations - dtC21 = C21 / dt - dtC31 = C31 / dt - dtC32 = C32 / dt - dtC41 = C41 / dt - dtC42 = C42 / dt - dtC43 = C43 / dt - dtC51 = C51 / dt - dtC52 = C52 / dt - dtC53 = C53 / dt - dtC54 = C54 / dt - - dtd1 = dt * d1 - dtd2 = dt * d2 - dtd3 = dt * d3 - dtgamma = dt * gamma - - mass_matrix = integrator.f.mass_matrix - - # Time derivative - tf.u = uprev - dT = calc_tderivative(integrator, cache) - - W = calc_W(integrator, cache, dtgamma, repeat_step) - if !issuccess_W(W) - integrator.EEst = 2 - return nothing - end - - du = f(uprev, p, t) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - k3 = copy(du) #-- save for stage 3 - - linsolve_tmp = du + dtd1 * dT - - k1 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + a21 * k1 - du = f(u, p, t + c2 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - linsolve_tmp = du + dtd2 * dT + dtC21 * k1 - else - linsolve_tmp = du + dtd2 * dT + mass_matrix * (dtC21 * k1) - end - - k2 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - - if mass_matrix === I - linsolve_tmp = k3 + dtd3 * dT + (dtC31 * k1 + dtC32 * k2) - else - linsolve_tmp = k3 + dtd3 * dT + mass_matrix * (dtC31 * k1 + dtC32 * k2) - end - - k3 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - u = uprev + a41 * k1 + a42 * k2 + a43 * k3 - du = f(u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - linsolve_tmp = du + (dtC41 * k1 + dtC42 * k2 + dtC43 * k3) - else - linsolve_tmp = du + mass_matrix * (dtC41 * k1 + dtC42 * k2 + dtC43 * k3) - end - - k4 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - - if mass_matrix === I - linsolve_tmp = du + (dtC52 * k2 + dtC54 * k4 + dtC51 * k1 + dtC53 * k3) - else - linsolve_tmp = du + - mass_matrix * (dtC52 * k2 + dtC54 * k4 + dtC51 * k1 + dtC53 * k3) - end - - k5 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - integrator.stats.nsolve += 1 - du = u + k4 #-- solution p=2 - u = u + k5 #-- solution p=3 - - EEst = 0.0 - if integrator.opts.calck - @unpack h21, h22, h23, h24, h25, h31, h32, h33, h34, h35, h2_21, h2_22, h2_23, h2_24, h2_25 = cache.tab - integrator.k[1] = h21 * k1 + h22 * k2 + h23 * k3 + h24 * k4 + h25 * k5 - integrator.k[2] = h31 * k1 + h32 * k2 + h33 * k3 + h34 * k4 + h35 * k5 - integrator.k[3] = h2_21 * k1 + h2_22 * k2 + h2_23 * k3 + h2_24 * k4 + h2_25 * k5 - if integrator.opts.adaptive - if isa(linsolve_tmp, AbstractFloat) - u_int, u_diff = calculate_interpoldiff( - uprev, du, u, integrator.k[1], integrator.k[2], integrator.k[3]) - else - u_int = linsolve_tmp - u_diff = linsolve_tmp .+ 0 - calculate_interpoldiff!(u_int, u_diff, uprev, du, u, integrator.k[1], - integrator.k[2], integrator.k[3]) - end - atmp = calculate_residuals(u_diff, uprev, u_int, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - EEst = max(EEst, integrator.opts.internalnorm(atmp, t)) #-- role of t unclear - end - end - - if (integrator.alg isa Rodas23W) - k1 = u .+ 0 - u = du .+ 0 - du = k1 .+ 0 - if integrator.opts.calck - integrator.k[1] = integrator.k[3] .+ 0 - integrator.k[2] = 0 * integrator.k[2] - end - end - - if integrator.opts.adaptive - atmp = calculate_residuals(u - du, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = max(EEst, integrator.opts.internalnorm(atmp, t)) - end - - integrator.u = u - return nothing -end - -function initialize!(integrator, cache::Union{Rodas23WCache, Rodas3PCache}) - integrator.kshortsize = 3 - @unpack dense1, dense2, dense3 = cache - resize!(integrator.k, integrator.kshortsize) - integrator.k[1] = dense1 - integrator.k[2] = dense2 - integrator.k[3] = dense3 -end - -@muladd function perform_step!( - integrator, cache::Union{Rodas23WCache, Rodas3PCache}, repeat_step = false) - @unpack t, dt, uprev, u, f, p = integrator - @unpack du, du1, du2, dT, J, W, uf, tf, k1, k2, k3, k4, k5, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter! = cache - @unpack a21, a41, a42, a43, C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, gamma, c2, c3, d1, d2, d3 = cache.tab - - # Assignments - sizeu = size(u) - uidx = eachindex(integrator.uprev) - mass_matrix = integrator.f.mass_matrix - - # Precalculations - dtC21 = C21 / dt - dtC31 = C31 / dt - dtC32 = C32 / dt - dtC41 = C41 / dt - dtC42 = C42 / dt - dtC43 = C43 / dt - dtC51 = C51 / dt - dtC52 = C52 / dt - dtC53 = C53 / dt - dtC54 = C54 / dt - - dtd1 = dt * d1 - dtd2 = dt * d2 - dtd3 = dt * d3 - dtgamma = dt * gamma - - f(cache.fsalfirst, uprev, p, t) # used in calc_rosenbrock_differentiation! - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - calc_rosenbrock_differentiation!(integrator, cache, dtd1, dtgamma, repeat_step) - - calculate_residuals!(weight, fill!(weight, one(eltype(u))), uprev, uprev, - integrator.opts.abstol, integrator.opts.reltol, - integrator.opts.internalnorm, t) - - if repeat_step - linres = dolinsolve( - integrator, cache.linsolve; A = nothing, b = _vec(linsolve_tmp), - du = cache.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtgamma)) - else - linres = dolinsolve(integrator, cache.linsolve; A = W, b = _vec(linsolve_tmp), - du = cache.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtgamma)) - end - - @.. broadcast=false $(_vec(k1))=-linres.u - - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + a21 * k1 - stage_limiter!(u, integrator, p, t + c2 * dt) - f(du, u, p, t + c2 * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + dtd2 * dT + dtC21 * k1 - else - @.. broadcast=false du1=dtC21 * k1 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + dtd2 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - @.. broadcast=false $(_vec(k2))=-linres.u - integrator.stats.nsolve += 1 - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=cache.fsalfirst + dtd3 * dT + - (dtC31 * k1 + dtC32 * k2) - else - @.. broadcast=false du1=dtC31 * k1 + dtC32 * k2 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=cache.fsalfirst + dtd3 * dT + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - @.. broadcast=false $(_vec(k3))=-linres.u - integrator.stats.nsolve += 1 - - @.. broadcast=false u=uprev + a41 * k1 + a42 * k2 + a43 * k3 - stage_limiter!(u, integrator, p, t + c2 * dt) - f(du, u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + - (dtC41 * k1 + dtC42 * k2 + dtC43 * k3) - else - @.. broadcast=false du1=dtC41 * k1 + dtC42 * k2 + dtC43 * k3 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - @.. broadcast=false $(_vec(k4))=-linres.u - integrator.stats.nsolve += 1 - - if mass_matrix === I - @.. broadcast=false linsolve_tmp=du + - (dtC52 * k2 + dtC54 * k4 + dtC51 * k1 + dtC53 * k3) - else - @.. broadcast=false du1=dtC52 * k2 + dtC54 * k4 + dtC51 * k1 + dtC53 * k3 - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. broadcast=false linsolve_tmp=du + du2 - end - - linres = dolinsolve(integrator, linres.cache; b = _vec(linsolve_tmp)) - @.. broadcast=false $(_vec(k5))=-linres.u - integrator.stats.nsolve += 1 - - du = u + k4 #-- p=2 solution - u .+= k5 - - step_limiter!(u, integrator, p, t + dt) - - EEst = 0.0 - if integrator.opts.calck - @unpack h21, h22, h23, h24, h25, h31, h32, h33, h34, h35, h2_21, h2_22, h2_23, h2_24, h2_25 = cache.tab - @.. broadcast=false integrator.k[1]=h21 * k1 + h22 * k2 + h23 * k3 + h24 * k4 + - h25 * k5 - @.. broadcast=false integrator.k[2]=h31 * k1 + h32 * k2 + h33 * k3 + h34 * k4 + - h35 * k5 - @.. broadcast=false integrator.k[3]=h2_21 * k1 + h2_22 * k2 + h2_23 * k3 + - h2_24 * k4 + h2_25 * k5 - if integrator.opts.adaptive - calculate_interpoldiff!( - du1, du2, uprev, du, u, integrator.k[1], integrator.k[2], integrator.k[3]) - calculate_residuals!(atmp, du2, uprev, du1, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - EEst = max(EEst, integrator.opts.internalnorm(atmp, t)) #-- role of t unclear - end - end - - if (integrator.alg isa Rodas23W) - du1[:] = u[:] - u[:] = du[:] - du[:] = du1[:] - if integrator.opts.calck - integrator.k[1][:] = integrator.k[3][:] - integrator.k[2][:] .= 0.0 - end - end - - if integrator.opts.adaptive - calculate_residuals!(atmp, u - du, uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = max(EEst, integrator.opts.internalnorm(atmp, t)) - end - cache.linsolve = linres.cache -end - -function calculate_interpoldiff(uprev, up2, up3, c_koeff, d_koeff, c2_koeff) - u_int = 0.0 - u_diff = 0.0 - a1 = up3 + c_koeff - up2 - c2_koeff - a2 = d_koeff - c_koeff + c2_koeff - a3 = -d_koeff - dis = a2^2 - 3 * a1 * a3 - u_int = up3 - u_diff = 0.0 - if dis > 0.0 #-- Min/Max occurs - tau1 = (-a2 - sqrt(dis)) / (3 * a3) - tau2 = (-a2 + sqrt(dis)) / (3 * a3) - if tau1 > tau2 - tau1, tau2 = tau2, tau1 - end - for tau in (tau1, tau2) - if (tau > 0.0) && (tau < 1.0) - y_tau = (1 - tau) * uprev + - tau * (up3 + (1 - tau) * (c_koeff + tau * d_koeff)) - dy_tau = ((a3 * tau + a2) * tau + a1) * tau - if abs(dy_tau) > abs(u_diff) - u_diff = dy_tau - u_int = y_tau - end - end - end - end - return u_int, u_diff -end - -function calculate_interpoldiff!(u_int, u_diff, uprev, up2, up3, c_koeff, d_koeff, c2_koeff) - for i in eachindex(up2) - a1 = up3[i] + c_koeff[i] - up2[i] - c2_koeff[i] - a2 = d_koeff[i] - c_koeff[i] + c2_koeff[i] - a3 = -d_koeff[i] - dis = a2^2 - 3 * a1 * a3 - u_int[i] = up3[i] - u_diff[i] = 0.0 - if dis > 0.0 #-- Min/Max occurs - tau1 = (-a2 - sqrt(dis)) / (3 * a3) - tau2 = (-a2 + sqrt(dis)) / (3 * a3) - if tau1 > tau2 - tau1, tau2 = tau2, tau1 - end - for tau in (tau1, tau2) - if (tau > 0.0) && (tau < 1.0) - y_tau = (1 - tau) * uprev[i] + - tau * (up3[i] + (1 - tau) * (c_koeff[i] + tau * d_koeff[i])) - dy_tau = ((a3 * tau + a2) * tau + a1) * tau - if abs(dy_tau) > abs(u_diff[i]) - u_diff[i] = dy_tau - u_int[i] = y_tau - end - end - end - end - end -end - -#### Rodas4 type method - -function initialize!(integrator, cache::RosenbrockCombinedConstantCache) - integrator.kshortsize = size(cache.tab.H, 1) - integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) - # Avoid undefined entries if k is an array of arrays - for i in 1:integrator.kshortsize - integrator.k[i] = zero(integrator.u) - end -end - -@muladd function perform_step!(integrator, cache::RosenbrockCombinedConstantCache, repeat_step = false) - (;t, dt, uprev, u, f, p) = integrator - (;tf, uf) = cache - (;A, C, gamma, c, d, H) = cache.tab - - # Precalculations - dtC = C ./ dt - dtd = dt .* d - dtgamma = dt * gamma - - mass_matrix = integrator.f.mass_matrix - - # Time derivative - tf.u = uprev - dT = calc_tderivative(integrator, cache) - - W = calc_W(integrator, cache, dtgamma, repeat_step) - if !issuccess_W(W) - integrator.EEst = 2 - return nothing - end - - # Initialize ks - num_stages = size(A, 1) - du = f(uprev, p, t) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - linsolve_tmp = @.. du + dtd[1] * dT - k1 = _reshape(W \ -_vec(linsolve_tmp), axes(uprev)) - # constant number for type stability make sure this is greater than num_stages - ks = ntuple(Returns(k1), 10) - # Loop for stages - for stage in 2:num_stages - u = uprev - for i in 1:(stage - 1) - u = @.. u + A[stage, i] * ks[i] - end - - du = f(u, p, t + c[stage] * dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - # Compute linsolve_tmp for current stage - linsolve_tmp = zero(du) - if mass_matrix === I - for i in 1:(stage - 1) - linsolve_tmp = @.. linsolve_tmp + dtC[stage, i] * ks[i] - end - else - for i in 1:(stage - 1) - linsolve_tmp = @.. linsolve_tmp + dtC[stage, i] * ks[i] - end - linsolve_tmp = mass_matrix * linsolve_tmp - end - linsolve_tmp = @.. du + dtd[stage] * dT + linsolve_tmp - - ks = Base.setindex(ks, _reshape(W \ -_vec(linsolve_tmp), axes(uprev)), stage) - integrator.stats.nsolve += 1 - end - #@show ks - u = u .+ ks[num_stages] - - if integrator.opts.adaptive - atmp = calculate_residuals(ks[num_stages], uprev, u, integrator.opts.abstol, - integrator.opts.reltol, integrator.opts.internalnorm, t) - integrator.EEst = integrator.opts.internalnorm(atmp, t) - end - - if integrator.opts.calck - for j in eachindex(integrator.k) - integrator.k[j] = zero(integrator.k[1]) - end - for i in 1:num_stages - for j in eachindex(integrator.k) - integrator.k[j] = @.. integrator.k[j] + H[j, i] * ks[i] - end - end - if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && - (integrator.EEst < 1.0) - k2 = 0.5 * (uprev + u + - 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) - du1 = (0.25 * (integrator.k[2] + integrator.k[3]) - uprev + u) / dt - du = f(k2, p, t + dt / 2) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - if mass_matrix === I - du2 = du1 - du - else - du2 = mass_matrix * du1 - du - end - EEst = norm(du2) / norm(integrator.opts.abstol .+ integrator.opts.reltol .* k2) - integrator.EEst = max(EEst, integrator.EEst) - end - end - - integrator.u = u - return nothing -end - -function initialize!(integrator, cache::RosenbrockCache) - integrator.kshortsize = size(cache.tab.H, 1) - resize!(integrator.k, integrator.kshortsize) - for i in 1:integrator.kshortsize - integrator.k[i] = cache.dense[i] - end -end - -@muladd function perform_step!(integrator, cache::RosenbrockCache, repeat_step = false) - (; t, dt, uprev, u, f, p) = integrator - (; du, du1, du2, dT, J, W, uf, tf, ks, linsolve_tmp, jac_config, atmp, weight, stage_limiter!, step_limiter!) = cache - (; A, C, gamma, c, d, H) = cache.tab - - # Assignments - sizeu = size(u) - uidx = eachindex(integrator.uprev) - mass_matrix = integrator.f.mass_matrix - - # Precalculations - dtC = C .* inv(dt) - dtd = dt .* d - dtgamma = dt * gamma - - f(cache.fsalfirst, uprev, p, t) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - - calc_rosenbrock_differentiation!(integrator, cache, dtd[1], dtgamma, repeat_step) - - calculate_residuals!(weight, fill!(weight, one(eltype(u))), uprev, uprev, - integrator.opts.abstol, integrator.opts.reltol, - integrator.opts.internalnorm, t) - - if repeat_step - linres = dolinsolve( - integrator, cache.linsolve; A = nothing, b = _vec(linsolve_tmp), - du = cache.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtgamma)) - else - linres = dolinsolve(integrator, cache.linsolve; A = W, b = _vec(linsolve_tmp), - du = cache.fsalfirst, u = u, p = p, t = t, weight = weight, - solverdata = (; gamma = dtgamma)) - end - - @.. $(_vec(ks[1])) = -linres.u - integrator.stats.nsolve += 1 - - for stage in 2:length(ks) - u .= uprev - for i in 1:(stage - 1) - @.. u += A[stage, i] * ks[i] - end + num_stages = length(ks) + for stage in 2:num_stages + u .= uprev + for i in 1:(stage - 1) + @.. u += A[stage, i] * ks[i] + end stage_limiter!(u, integrator, p, t + c[stage] * dt) f(du, u, p, t + c[stage] * dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) du1 .= 0 - if mass_matrix === I - for i in 1:(stage - 1) - @.. du1 += dtC[stage, i] * ks[i] - end - else - for i in 1:(stage - 1) - @.. du1 += dtC[stage, i] * ks[i] - end + for i in 1:(stage - 1) + @.. du1 += dtC[stage, i] * ks[i] + end + if mass_matrix !== I mul!(_vec(du2), mass_matrix, _vec(du1)) du1 .= du2 end @@ -1381,19 +530,32 @@ end @.. $(_vec(ks[stage])) = -linres.u integrator.stats.nsolve += 1 end - du .= ks[end] - u .+= ks[end] + if (integrator.alg isa Rodas6P) + du .= ks[16] + u .= uprev + for i in 1:15 + @.. u += A[16, i] * ks[i] + end + u .+= ks[16] + else + du .= ks[end] + u .+= ks[end] + end step_limiter!(u, integrator, p, t + dt) if integrator.opts.adaptive + @.. utilde = 0 * u + for i in 1:num_stages + @.. utilde += btilde[i] * ks[i] + end if (integrator.alg isa Rodas5Pe) @.. du = 0.2606326497975715 * ks[1] - 0.005158627295444251 * ks[2] + - 1.3038988631109731 * ks[3] + 1.235000722062074 * ks[4] + - -0.7931985603795049 * ks[5] - 1.005448461135913 * ks[6] - - 0.18044626132120234 * ks[7] + 0.17051519239113755 * ks[8] + 1.3038988631109731 * ks[3] + 1.235000722062074 * ks[4] + + -0.7931985603795049 * ks[5] - 1.005448461135913 * ks[6] - + 0.18044626132120234 * ks[7] + 0.17051519239113755 * ks[8] end - calculate_residuals!(atmp, ks[end], uprev, u, integrator.opts.abstol, + calculate_residuals!(atmp, du, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) end @@ -1408,24 +570,26 @@ end end end if (integrator.alg isa Rodas5Pr) && integrator.opts.adaptive && - (integrator.EEst < 1.0) - ks[2] = 0.5 * (uprev + u + - 0.5 * (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) - du1 = (0.25 * (integrator.k[2] + integrator.k[3]) - uprev + u) / dt - f(du, ks[2], p, t + dt / 2) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) - if mass_matrix === I - @.. du2 = du1 - du - else - mul!(_vec(du2), mass_matrix, _vec(du1)) - @.. du2 -= du - end - EEst = norm(du2) / norm(integrator.opts.abstol .+ integrator.opts.reltol .* ks[2]) - integrator.EEst = max(EEst, integrator.EEst) - end + (integrator.EEst < 1.0) + ks[2] = 0.5 * (uprev + u + + 0.5 * + (integrator.k[1] + 0.5 * (integrator.k[2] + 0.5 * integrator.k[3]))) + du1 = (0.25 * (integrator.k[2] + integrator.k[3]) - uprev + u) / dt + f(du, ks[2], p, t + dt / 2) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + if mass_matrix === I + @.. du2 = du1 - du + else + mul!(_vec(du2), mass_matrix, _vec(du1)) + @.. du2 -= du + end + EEst = norm(du2) / + norm(integrator.opts.abstol .+ integrator.opts.reltol .* ks[2]) + integrator.EEst = max(EEst, integrator.EEst) + end end cache.linsolve = linres.cache end @RosenbrockW6S4OS(:init) -@RosenbrockW6S4OS(:performstep) +@RosenbrockW6S4OS(:performstep) \ No newline at end of file diff --git a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_tableaus.jl b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_tableaus.jl index d7968cc572..5817ae368e 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_tableaus.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/rosenbrock_tableaus.jl @@ -1,219 +1,93 @@ -struct Rosenbrock23Tableau{T} +struct RosenbrockCombinedTableau{T} c₃₂::T d::T end -function Rosenbrock23Tableau(T) +function RosenbrockCombinedTableau(T) c₃₂ = convert(T, 6 + sqrt(2)) d = convert(T, 1 / (2 + sqrt(2))) - Rosenbrock23Tableau(c₃₂, d) + RosenbrockCombinedTableau(c₃₂, d) end -struct Rosenbrock32Tableau{T} - c₃₂::T - d::T -end - -function Rosenbrock32Tableau(T) - c₃₂ = convert(T, 6 + sqrt(2)) - d = convert(T, 1 / (2 + sqrt(2))) - Rosenbrock32Tableau(c₃₂, d) -end - -struct ROS3PTableau{T, T2} - a21::T - a31::T - a32::T - C21::T - C31::T - C32::T - b1::T - b2::T - b3::T - btilde1::T - btilde2::T - btilde3::T - gamma::T2 - c2::T2 - c3::T2 - d1::T - d2::T - d3::T -end function ROS3PTableau(T, T2) - gamma = convert(T, 1 / 2 + sqrt(3) / 6) - igamma = inv(gamma) - a21 = convert(T, igamma) - a31 = convert(T, igamma) - a32 = convert(T, 0) - C21 = convert(T, -igamma^2) - tmp = -igamma * (convert(T, 2) - convert(T, 1 / 2) * igamma) - C31 = -igamma * (convert(T, 1) - tmp) - C32 = tmp - tmp = igamma * (convert(T, 2 / 3) - convert(T, 1 / 6) * igamma) - b1 = igamma * (convert(T, 1) + tmp) - b2 = tmp - b3 = convert(T, 1 / 3) * igamma - # btilde1 = convert(T,2.113248654051871) - # btilde2 = convert(T,1.000000000000000) - # btilde3 = convert(T,0.4226497308103742) - btilde1 = b1 - convert(T, 2.113248654051871) - btilde2 = b2 - convert(T, 1.000000000000000) - btilde3 = b3 - convert(T, 0.4226497308103742) - c2 = convert(T, 1) - c3 = convert(T, 1) - d1 = convert(T, 0.7886751345948129) - d2 = convert(T, -0.2113248654051871) - d3 = convert(T, -1.077350269189626) - ROS3PTableau( - a21, a31, a32, C21, C31, C32, b1, b2, b3, btilde1, btilde2, btilde3, gamma, - c2, c3, d1, d2, d3) -end - -struct Rodas3Tableau{T, T2} - a21::T - a31::T - a32::T - a41::T - a42::T - a43::T - C21::T - C31::T - C32::T - C41::T - C42::T - C43::T - b1::T - b2::T - b3::T - b4::T - btilde1::T - btilde2::T - btilde3::T - btilde4::T - gamma::T2 - c2::T2 - c3::T2 - d1::T - d2::T - d3::T - d4::T + sqrt3 = convert(T, -sqrt(3)) + gamma = convert(T, 0.5 + sqrt3 / 6) + igamma = 3 - sqrt3 + A = T[ + 0 0 0 + igamma 0 0 + igamma 0 0 + ] + C = T[ + 0 0 0 + -igamma^2 0 0 + 2*sqrt3 -sqrt3 0 + ] + b = T[2, inv(sqrt3), igamma / 3] + btilde = b .- T[2.113248654051871, 1, 0.4226497308103742] + c = T2[0, 1, 1] + d = T[0.7886751345948129, -0.2113248654051871, -1.077350269189626] + H = zeros(T, 2, 3) + RodasTableau(A, C, b, btilde, gamma, c, d, H) end function Rodas3Tableau(T, T2) gamma = convert(T, 1 // 2) - a21 = convert(T, 0) - a31 = convert(T, 2) - a32 = convert(T, 0) - a41 = convert(T, 2) - a42 = convert(T, 0) - a43 = convert(T, 1) - C21 = convert(T, 4) - C31 = convert(T, 1) - C32 = convert(T, -1) - C41 = convert(T, 1) - C42 = convert(T, -1) - C43 = convert(T, -8 // 3) - b1 = convert(T, 2) - b2 = convert(T, 0) - b3 = convert(T, 1) - b4 = convert(T, 1) - btilde1 = convert(T, 0.0) - btilde2 = convert(T, 0.0) - btilde3 = convert(T, 0.0) - btilde4 = convert(T, 1.0) - c2 = convert(T, 0.0) - c3 = convert(T, 1.0) - c4 = convert(T, 1.0) - d1 = convert(T, 1 // 2) - d2 = convert(T, 3 // 2) - d3 = convert(T, 0) - d4 = convert(T, 0) - Rodas3Tableau(a21, a31, a32, a41, a42, a43, C21, C31, C32, C41, C42, C43, b1, b2, b3, - b4, btilde1, btilde2, btilde3, btilde4, gamma, c2, c3, d1, d2, d3, d4) -end - -struct Rodas3PTableau{T, T2} - a21::T - a41::T - a42::T - a43::T - C21::T - C31::T - C32::T - C41::T - C42::T - C43::T - C51::T - C52::T - C53::T - C54::T - gamma::T - c2::T2 - c3::T2 - d1::T - d2::T - d3::T - h21::T - h22::T - h23::T - h24::T - h25::T - h31::T - h32::T - h33::T - h34::T - h35::T - h2_21::T - h2_22::T - h2_23::T - h2_24::T - h2_25::T + A = T[ + 0 0 0 0 + 0 0 0 0 + 2 0 0 0 + 2 0 1 0 + ] + C = T[ + 0 0 0 + 4 0 0 + 1 -1 0 + 1 -1 -8 // 3 + ] + b = T[2, 0, 1, 1] + btilde = T[0, 0, 0, 1] + c = T[0, 0, 1, 1] + d = T[1 // 2, 3 // 2, 0, 0] + H = zeros(T, 2, 4) + RodasTableau(A, C, b, btilde, gamma, c, d, H) end function Rodas3PTableau(T, T2) gamma = convert(T, 1 // 3) - a21 = convert(T, 4.0 / 3.0) - a41 = convert(T, 2.90625) - a42 = convert(T, 3.375) - a43 = convert(T, 0.40625) - C21 = -convert(T, 4.0) - C31 = convert(T, 8.25) - C32 = convert(T, 6.75) - C41 = convert(T, 1.21875) - C42 = -convert(T, 5.0625) - C43 = -convert(T, 1.96875) - C51 = convert(T, 4.03125) - C52 = -convert(T, 15.1875) - C53 = -convert(T, 4.03125) - C54 = convert(T, 6.0) - c2 = convert(T2, 4.0 / 9.0) - c3 = convert(T2, 0.0) - d1 = convert(T, 1.0 / 3.0) - d2 = -convert(T, 1.0 / 9.0) - d3 = convert(T, 1.0) - h21 = convert(T, 1.78125) - h22 = convert(T, 6.75) - h23 = convert(T, 0.15625) - h24 = -convert(T, 6.0) - h25 = -convert(T, 1.0) - h31 = convert(T, 4.21875) - h32 = -convert(T, 15.1875) - h33 = -convert(T, 3.09375) - h34 = convert(T, 9.0) - h35 = convert(T, 0.0) - h2_21 = convert(T, 4.21875) - h2_22 = -convert(T, 2.025) - h2_23 = -convert(T, 1.63125) - h2_24 = -convert(T, 1.7) - h2_25 = -convert(T, 0.1) - Rodas3PTableau(a21, a41, a42, a43, - C21, C31, C32, C41, C42, C43, C51, C52, C53, C54, - gamma, c2, c3, d1, d2, d3, - h21, h22, h23, h24, h25, h31, h32, h33, h34, h35, h2_21, h2_22, h2_23, h2_24, h2_25) + A = T[ + 0 0 0 0 0 + 4 // 3 0 0 0 0 + 0 0 0 0 0 + 2.90625 3.375 0.40625 0 0 + 2.90625 3.375 0.40625 0 0 + ] + C = T[ + 0 0 0 0 + -4 0 0 0 + 8.25 6.75 0 0 + 1.21875 -5.0625 -1.96875 0 + 4.03125 -15.1875 -4.03125 6 + ] + b = T[2.90625, 3.375, 0.40625, 0, 1] + btilde = T[0, 0, 0, 1, -1] + c = T2[0, 4 // 9, 4 // 9, 1, 1] + d = T[1 // 3, -1 // 9, 1, 0, 0] + H = T[ + 1.78125 6.75 0.15625 6 1 + 4.21875 15.1875 3.09375 9 0 + ] + h2_2 = T[4.21875, 2.025, 1.63125, 1.7, 0.1] + RodasTableau(A, C, b, btilde, gamma, c, d, H)#, h2_2) end +function Rodas23WTableau(T, T2) + tab = Rodas3PTableau(T, T2) + b = T[2.90625, 3.375, 0.40625, 1, 0] + btilde = T[0, 0, 0, 1, -1] + RodasTableau(tab.A, tab.C, b, btilde, tab.gamma, tab.c, tab.d, tab.H)#, h2_2) +end @ROS2(:tableau) @ROS23(:tableau) @@ -225,194 +99,201 @@ end struct RodasTableau{T, T2} A::Matrix{T} C::Matrix{T} - gamma::T + gamma::T2 c::Vector{T2} d::Vector{T} H::Matrix{T} end -function Rodas4Tableau(T, T2) - gamma = convert(T, 1 // 4) - #BET2P=0.0317D0 - #BET3P=0.0635D0 - #BET4P=0.3438D0 - A = T[ - 0 0 0 0 0 0 - 1.544 0 0 0 0 0 - 0.9466785280815826 0.2557011698983284 0 0 0 0 - 3.314825187068521 2.896124015972201 0.9986419139977817 0 0 0 - 1.221224509226641 6.019134481288629 12.53708332932087 -0.6878860361058950 0 0 - 1.221224509226641 6.019134481288629 12.53708332932087 -0.6878860361058950 1 0 - ] - C = T[ - 0 0 0 0 0 - -5.6688 0 0 0 0 - -2.430093356833875 -0.2063599157091915 0 0 0 - -0.1073529058151375 -9.594562251023355 -20.47028614809616 0 0 - 7.496443313967647 -10.24680431464352 -33.99990352819905 11.70890893206160 0 - 8.083246795921522 -7.981132988064893 -31.52159432874371 16.31930543123136 -6.058818238834054 - ] - c = T2[0, 0.386, 0.21, 0.63, 1, 1] - d = T[0.25, -0.1043, 0.1035, -0.0362, 0, 0] - H = T[10.12623508344586 -7.487995877610167 -34.80091861555747 -7.992771707568823 1.025137723295662 0 +const RODAS4A = [0 0 0 0 0 0 + 1.544 0 0 0 0 0 + 0.9466785280815826 0.2557011698983284 0 0 0 0 + 3.314825187068521 2.896124015972201 0.9986419139977817 0 0 0 + 1.221224509226641 6.019134481288629 12.53708332932087 -0.6878860361058950 0 0 + 1.221224509226641 6.019134481288629 12.53708332932087 -0.6878860361058950 1 0] +const RODAS4C = [0 0 0 0 0 + -5.6688 0 0 0 0 + -2.430093356833875 -0.2063599157091915 0 0 0 + -0.1073529058151375 -9.594562251023355 -20.47028614809616 0 0 + 7.496443313967647 -10.24680431464352 -33.99990352819905 11.70890893206160 0 + 8.083246795921522 -7.981132988064893 -31.52159432874371 16.31930543123136 -6.058818238834054] +const RODAS4c = [0, 0.386, 0.21, 0.63, 1, 1] +const RODAS4d = [0.25, -0.1043, 0.1035, -0.0362, 0, 0] +const RODAS4H = [10.12623508344586 -7.487995877610167 -34.80091861555747 -7.992771707568823 1.025137723295662 0 -0.6762803392801253 6.087714651680015 16.43084320892478 24.76722511418386 -6.594389125716872 0] - RodasTableau(A, C, gamma, c, d, H) +function Rodas4Tableau(T, T2) + gamma = .25 + RodasTableau{T, T2}(RODAS4A, RODAS4C, gamma, RODAS4c, RODAS4d, RODAS4H) end -function Rodas42Tableau(T, T2) - gamma = convert(T, 1 // 4) - A = T[0.0 0 0 0 0 0 + +const RODAS42A = [0 0 0 0 0 0 1.4028884 0 0 0 0 0 0.6581212688557198 -1.320936088384301 0 0 0 0 7.131197445744498 16.02964143958207 -5.561572550509766 0 0 0 22.73885722420363 67.38147284535289 -31.21877493038560 0.7285641833203814 0 0 22.73885722420363 67.38147284535289 -31.21877493038560 0.7285641833203814 1 0] - C = T[0 0 0 0 0 +const RODAS42C = [0 0 0 0 0 -5.1043536 0 0 0 0 -2.899967805418783 4.040399359702244 0 0 0 -32.64449927841361 -99.35311008728094 49.99119122405989 0 0 -76.46023087151691 -278.5942120829058 153.9294840910643 10.97101866258358 0 -76.29701586804983 -294.2795630511232 162.0029695867566 23.65166903095270 -7.652977706771382] - c = T2[0, 0.3507221, 0.2557041, 0.681779, 1, 1] - d = T[0.25, -0.0690221, -0.0009672, -0.087979, 0, 0] - H = T[-38.71940424117216 -135.8025833007622 64.51068857505875 -4.192663174613162 -2.531932050335060 0 +const RODAS42c = [0, 0.3507221, 0.2557041, 0.681779, 1, 1] +const RODAS42d = [0.25, -0.0690221, -0.0009672, -0.087979, 0, 0] +const RODAS42H = [-38.71940424117216 -135.8025833007622 64.51068857505875 -4.192663174613162 -2.531932050335060 0 -14.99268484949843 -76.30242396627033 58.65928432851416 16.61359034616402 -0.6758691794084156 0] - RodasTableau(A, C, gamma, c, d, H) +function Rodas42Tableau(T, T2) + gamma = .25 + RodasTableau{T, T2}(RODAS42A, RODAS42C, gamma, RODAS42c, RODAS42d, RODAS42H) end -function Rodas4PTableau(T, T2) - gamma = convert(T, 1 // 4) - #BET2P=0.D0 - #BET3P=c3*c3*(c3/6.d0-GAMMA/2.d0)/(GAMMA*GAMMA) - #BET4P=0.3438D0 - A = T[0 0 0 0 0 0 +const RODAS4PA = [0 0 0 0 0 0 3 0 0 0 0 0 1.831036793486759 0.4955183967433795 0 0 0 0 2.304376582692669 -0.05249275245743001 -1.176798761832782 0 0 0 -7.170454962423024 -4.741636671481785 -16.31002631330971 -1.062004044111401 0 0 -7.170454962423024 -4.741636671481785 -16.31002631330971 -1.062004044111401 1 0] - C = T[0 0 0 0 0 +const RODAS4PC = [0 0 0 0 0 -12 0 0 0 0 -8.791795173947035 -2.207865586973518 0 0 0 10.81793056857153 6.780270611428266 19.53485944642410 0 0 34.19095006749676 15.49671153725963 54.74760875964130 14.16005392148534 0 34.62605830930532 15.30084976114473 56.99955578662667 18.40807009793095 -5.714285714285717] - c = T2[0, 0.75, 0.21, 0.63, 1, 1] - d = T[0.25, -0.5, -0.023504, -0.0362, 0, 0] - H = T[25.09876703708589 11.62013104361867 28.49148307714626 -5.664021568594133 0 0 +const RODAS4Pc = [0, 0.75, 0.21, 0.63, 1, 1] +const RODAS4Pd = [0.25, -0.5, -0.023504, -0.0362, 0, 0] +const RODAS4PH = [25.09876703708589 11.62013104361867 28.49148307714626 -5.664021568594133 0 0 1.638054557396973 -0.7373619806678748 8.477918219238990 15.99253148779520 -1.882352941176471 0] - RodasTableau(A, C, gamma, c, d, H) +function Rodas4PTableau(T, T2) + gamma = .25 + RodasTableau{T, T2}(RODAS4PA, RODAS4PC, gamma, RODAS4Pc, RODAS4Pd, RODAS4PH) end -function Rodas4P2Tableau(T, T2) - gamma = convert(T, 1 // 4) - A = T[0 0 0 0 0 0 +const RODAS4P2A = [0 0 0 0 0 0 3 0 0 0 0 0 0.906377755268814 -0.189707390391685 0 0 0 0 3.758617027739064 1.161741776019525 -0.849258085312803 0 0 0 7.089566927282776 4.573591406461604 -8.423496976860259 -0.959280113459775 0 0 7.089566927282776 4.573591406461604 -8.423496976860259 -0.959280113459775 1 0] - C = T[0 0 0 0 0 +const RODAS4P2C = [0 0 0 0 0 -12 0 0 0 0 -6.354581592719008 0.338972550544623 0 0 0 -8.575016317114033 -7.606483992117508 12.224997650124820 0 0 -5.888975457523102 -8.157396617841821 24.805546872612922 12.790401512796979 0 -4.408651676063871 -6.692003137674639 24.625568527593117 16.627521966636085 -5.714285714285718] - c = T2[0, 0.75, 0.321448134013046, 0.519745732277726, 1, 1] - d = T[0.25, -0.5, -0.189532918363016, 0.085612108792769, 0, 0] - H = [-5.323528268423303 -10.042123754867493 17.175254928256965 -5.079931171878093 -0.016185991706112 0 +const RODAS4P2c = [0, 0.75, 0.321448134013046, 0.519745732277726, 1, 1] +const RODAS4P2d = [0.25, -0.5, -0.189532918363016, 0.085612108792769, 0, 0] +const RODAS4P2H = [-5.323528268423303 -10.042123754867493 17.175254928256965 -5.079931171878093 -0.016185991706112 0 6.984505741529879 6.914061169603662 -0.849178943070653 18.104410789349338 -3.516963011559032 0] - RodasTableau(A, C, gamma, c, d, H) +function Rodas4P2Tableau(T, T2) + gamma = .25 + RodasTableau{T, T2}(RODAS4P2A, RODAS4P2C, gamma, RODAS4P2c, RODAS4P2d, RODAS4P2H) end -function Rodas5Tableau(T, T2) - gamma = convert(T2, 0.19) - A = T[ - 0 0 0 0 0 0 0 0 - 2.0 0 0 0 0 0 0 0 - 3.040894194418781 1.041747909077569 0 0 0 0 0 0 - 2.576417536461461 1.622083060776640 -0.9089668560264532 0 0 0 0 0 - 2.760842080225597 1.446624659844071 -0.3036980084553738 0.2877498600325443 0 0 0 0 - -14.09640773051259 6.925207756232704 -41.47510893210728 2.343771018586405 24.13215229196062 0 0 0 - -14.09640773051259 6.925207756232704 -41.47510893210728 2.343771018586405 24.13215229196062 1 0 0 - -14.09640773051259 6.925207756232704 -41.47510893210728 2.343771018586405 24.13215229196062 1 1 0 - ] - C = T[ - 0 0 0 0 0 0 0 - -10.31323885133993 0 0 0 0 0 0 - -21.04823117650003 -7.234992135176716 0 0 0 0 0 - 32.22751541853323 -4.943732386540191 19.44922031041879 0 0 0 0 - -20.69865579590063 -8.816374604402768 1.260436877740897 -0.7495647613787146 0 0 0 - -46.22004352711257 -17.49534862857472 -289.6389582892057 93.60855400400906 318.3822534212147 0 0 - 34.20013733472935 -14.15535402717690 57.82335640988400 25.83362985412365 1.408950972071624 -6.551835421242162 0 - 42.57076742291101 -13.80770672017997 93.98938432427124 18.77919633714503 -31.58359187223370 -6.685968952921985 -5.810979938412932 - ] - c = T2[0, 0.38, 0.3878509998321533, 0.4839718937873840, 0.4570477008819580, 1, 1, 1] - d = T[gamma, -0.1823079225333714636, -0.319231832186874912, 0.3449828624725343, -0.377417564392089818, 0, 0, 0] +const RODAS5A = [0 0 0 0 0 0 0 0 + 2.0 0 0 0 0 0 0 0 + 3.040894194418781 1.041747909077569 0 0 0 0 0 0 + 2.576417536461461 1.622083060776640 -0.9089668560264532 0 0 0 0 0 + 2.760842080225597 1.446624659844071 -0.3036980084553738 0.2877498600325443 0 0 0 0 + -14.09640773051259 6.925207756232704 -41.47510893210728 2.343771018586405 24.13215229196062 0 0 0 + -14.09640773051259 6.925207756232704 -41.47510893210728 2.343771018586405 24.13215229196062 1 0 0 + -14.09640773051259 6.925207756232704 -41.47510893210728 2.343771018586405 24.13215229196062 1 1 0] +const RODAS5C = [0 0 0 0 0 0 0 + -10.31323885133993 0 0 0 0 0 0 + -21.04823117650003 -7.234992135176716 0 0 0 0 0 + 32.22751541853323 -4.943732386540191 19.44922031041879 0 0 0 0 + -20.69865579590063 -8.816374604402768 1.260436877740897 -0.7495647613787146 0 0 0 + -46.22004352711257 -17.49534862857472 -289.6389582892057 93.60855400400906 318.3822534212147 0 0 + 34.20013733472935 -14.15535402717690 57.82335640988400 25.83362985412365 1.408950972071624 -6.551835421242162 0 + 42.57076742291101 -13.80770672017997 93.98938432427124 18.77919633714503 -31.58359187223370 -6.685968952921985 -5.810979938412932] +const RODAS5c = [0, 0.38, 0.3878509998321533, 0.4839718937873840, 0.4570477008819580, 1, 1, 1] +const RODAS5d = [0.19, -0.1823079225333714636, -0.319231832186874912, + 0.3449828624725343, -0.377417564392089818, 0, 0, 0] - H = T[ - 27.354592673333357 -6.925207756232857 26.40037733258859 0.5635230501052979 -4.699151156849391 -1.6008677469422725 -1.5306074446748028 -1.3929872940716344 - 44.19024239501722 1.3677947663381929e-13 202.93261852171622 -35.5669339789154 -181.91095152160645 3.4116351403665033 2.5793540257308067 2.2435122582734066 - -44.0988150021747 -5.755396159656812e-13 -181.26175034586677 56.99302194811676 183.21182741427398 -7.480257918273637 -5.792426076169686 -5.32503859794143 - ] - # println("---Rodas5---") +const RODAS5H = [27.354592673333357 -6.925207756232857 26.40037733258859 0.5635230501052979 -4.699151156849391 -1.6008677469422725 -1.5306074446748028 -1.3929872940716344 + 44.19024239501722 1.3677947663381929e-13 202.93261852171622 -35.5669339789154 -181.91095152160645 3.4116351403665033 2.5793540257308067 2.2435122582734066 + -44.0988150021747 -5.755396159656812e-13 -181.26175034586677 56.99302194811676 183.21182741427398 -7.480257918273637 -5.792426076169686 -5.32503859794143] - #= - a71 = -14.09640773051259 - a72 = 6.925207756232704 - a73 = -41.47510893210728 - a74 = 2.343771018586405 - a75 = 24.13215229196062 - a76 = convert(T,1) - a81 = -14.09640773051259 - a82 = 6.925207756232704 - a83 = -41.47510893210728 - a84 = 2.343771018586405 - a85 = 24.13215229196062 - a86 = convert(T,1) - a87 = convert(T,1) - b1 = -14.09640773051259 - b2 = 6.925207756232704 - b3 = -41.47510893210728 - b4 = 2.343771018586405 - b5 = 24.13215229196062 - b6 = convert(T,1) - b7 = convert(T,1) - b8 = convert(T,1) - =# - RodasTableau(A, C, gamma, c, d, H) +function Rodas5Tableau(T, T2) + gamma = 0.19 + RodasTableau{T, T2}(RODAS5A, RODAS5C, gamma, RODAS5c, RODAS5d, RODAS5H) end +const RODAS5PA = [0 0 0 0 0 0 0 0 + 3.0 0 0 0 0 0 0 0 + 2.849394379747939 0.45842242204463923 0 0 0 0 0 0 + -6.954028509809101 2.489845061869568 -10.358996098473584 0 0 0 0 0 + 2.8029986275628964 0.5072464736228206 -0.3988312541770524 -0.04721187230404641 0 0 0 0 + -7.502846399306121 2.561846144803919 -11.627539656261098 -0.18268767659942256 0.030198172008377946 0 0 0 + -7.502846399306121 2.561846144803919 -11.627539656261098 -0.18268767659942256 0.030198172008377946 1 0 0 + -7.502846399306121 2.561846144803919 -11.627539656261098 -0.18268767659942256 0.030198172008377946 1 1 0] +const RODAS5PC = [0 0 0 0 0 0 0 + -14.155112264123755 0 0 0 0 0 0 + -17.97296035885952 -2.859693295451294 0 0 0 0 0 + 147.12150275711716 -1.41221402718213 71.68940251302358 0 0 0 0 + 165.43517024871676 -0.4592823456491126 42.90938336958603 -5.961986721573306 0 0 0 + 24.854864614690072 -3.0009227002832186 47.4931110020768 5.5814197821558125 -0.6610691825249471 0 0 + 30.91273214028599 -3.1208243349937974 77.79954646070892 34.28646028294783 -19.097331116725623 -28.087943162872662 0 + 37.80277123390563 -3.2571969029072276 112.26918849496327 66.9347231244047 -40.06618937091002 -54.66780262877968 -9.48861652309627] +const RODAS5Pc = [0, 0.6358126895828704, 0.4095798393397535, + 0.9769306725060716, 0.4288403609558664, 1, 1, 1] +const RODAS5Pd = [0.21193756319429014, -0.42387512638858027, -0.3384627126235924, + 1.8046452872882734, 2.325825639765069, 0, 0, 0] +const RODAS5PH = [25.948786856663858 -2.5579724845846235 10.433815404888879 -2.3679251022685204 0.524948541321073 1.1241088310450404 0.4272876194431874 -0.17202221070155493 + -9.91568850695171 -0.9689944594115154 3.0438037242978453 -24.495224566215796 20.176138334709044 15.98066361424651 -6.789040303419874 -6.710236069923372 + 11.419903575922262 2.8879645146136994 72.92137995996029 80.12511834622643 -52.072871366152654 -59.78993625266729 -0.15582684282751913 4.883087185713722] function Rodas5PTableau(T, T2) - gamma = convert(T2, 0.21193756319429014) - A = T[ - 0 0 0 0 0 0 0 0 - 3.0 0 0 0 0 0 0 0 - 2.849394379747939 0.45842242204463923 0 0 0 0 0 0 - -6.954028509809101 2.489845061869568 -10.358996098473584 0 0 0 0 0 - 2.8029986275628964 0.5072464736228206 -0.3988312541770524 -0.04721187230404641 0 0 0 0 - -7.502846399306121 2.561846144803919 -11.627539656261098 -0.18268767659942256 0.030198172008377946 0 0 0 - -7.502846399306121 2.561846144803919 -11.627539656261098 -0.18268767659942256 0.030198172008377946 1 0 0 - -7.502846399306121 2.561846144803919 -11.627539656261098 -0.18268767659942256 0.030198172008377946 1 1 0 - ] - C = T[ - 0 0 0 0 0 0 0 - -14.155112264123755 0 0 0 0 0 0 - -17.97296035885952 -2.859693295451294 0 0 0 0 0 - 147.12150275711716 -1.41221402718213 71.68940251302358 0 0 0 0 - 165.43517024871676 -0.4592823456491126 42.90938336958603 -5.961986721573306 0 0 0 - 24.854864614690072 -3.0009227002832186 47.4931110020768 5.5814197821558125 -0.6610691825249471 0 0 - 30.91273214028599 -3.1208243349937974 77.79954646070892 34.28646028294783 -19.097331116725623 -28.087943162872662 0 - 37.80277123390563 -3.2571969029072276 112.26918849496327 66.9347231244047 -40.06618937091002 -54.66780262877968 -9.48861652309627 - ] - c = T2[0, 0.6358126895828704, 0.4095798393397535, 0.9769306725060716, 0.4288403609558664, 1, 1, 1] - d = T[0.21193756319429014, -0.42387512638858027, -0.3384627126235924, 1.8046452872882734, 2.325825639765069, 0, 0, 0] - H = T[ - 25.948786856663858 -2.5579724845846235 10.433815404888879 -2.3679251022685204 0.524948541321073 1.1241088310450404 0.4272876194431874 -0.17202221070155493 - -9.91568850695171 -0.9689944594115154 3.0438037242978453 -24.495224566215796 20.176138334709044 15.98066361424651 -6.789040303419874 -6.710236069923372 - 11.419903575922262 2.8879645146136994 72.92137995996029 80.12511834622643 -52.072871366152654 -59.78993625266729 -0.15582684282751913 4.883087185713722 - ] - RodasTableau(A, C, gamma, c, d, H) + gamma = 0.21193756319429014 + RodasTableau{T, T2}(RODAS5PA, RODAS5PC, gamma, RODAS5Pc, RODAS5Pd, RODAS5PH) +end + +const RODAS6PA = [0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.7111784962693573 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 3.338661438538325 1.7785154948506772 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 2.936071270275081 0.9182685464146361 0.3700626437020361 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 4.659498341685848 1.750740798902701 0.5870646872926452 0.8880273208834594 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 4.0197306615530755 2.839611966871549 -0.5985886977898102 0.08804800108767567 1.5622259206803966 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.988416726724047 -0.379547946940864 0.9004347186464728 1.4277449221484224 -0.7433508015345144 -0.042432590368607255 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 1.8376133238441654 1.9114959548124457 -0.6715227349230231 0.2358079620635186 3.6095202089874117 0.8151701113738031 0.9206065341545108 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -0.766306772356088 3.209956697664864 -3.3123779344961592 -3.0203200762095332 4.800864725315542 1.1604579105760842 0.4424812765132964 0.3706918590956091 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 6.232416226700401 2.6089061288608786 -0.6004565639275875 -3.3845987889094653 0.42397260663019737 0.35421155529651493 0.30716464971632756 1.5008969261275715 0.5102657561692372 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.023392109748070492 1.4081998520657641 -0.7199787823918794 0.7361286083371824 2.4632772861278043 0.46923886035475726 0.1205787235019629 -0.8578747086506138 -0.2588726092696778 -0.4397748045492015 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 2.953951852943472 -0.5094757863221286 0.3109577019600045 -3.5298051247141733 -3.545755924579993 -0.33681829638738314 -0.5663219967973026 1.1332773651373889 0.15030559921640937 0.25755454716019555 0.29836356640198125 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 3.613614004197333 0.6635854700997046 0.021719370087612728 -1.4950066071478674 0.7257768429136315 -0.05542296424699332 0.6617050893162496 1.5916006835996634 0.004468857383033254 0.3492741589610665 -0.20270398239783438 0.6407744206145284 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 0.6650675322630164 3.8649437891996143 -3.5568168140908862 0.30445082364848014 6.687033712252074 1.7577448564663951 0.7252352806302017 0.8340620415656512 0.288756122559755 -0.014344518613253377 -0.9202387269679146 0.1235675186947092 0.5210532009614854 0.0 0.0 0.0 0.0 0.0 0.0 + 0.6650675322630163 3.864943789199614 -3.5568168140908876 0.30445082364847914 6.687033712252074 1.7577448564663951 0.7252352806302018 0.834062041565651 0.2887561225597551 -0.014344518613253487 -0.9202387269679145 0.12356751869470915 0.5210532009614851 1.0 0.0 0.0 0.0 0.0 0.0 + 0.6650675322630177 3.864943789199614 -3.5568168140908876 0.30445082364847964 6.687033712252074 1.7577448564663947 0.7252352806302018 0.8340620415656512 0.2887561225597553 -0.014344518613253388 -0.9202387269679146 0.12356751869470915 0.5210532009614847 0.9999999999999998 1.0 0.0 0.0 0.0 0.0 + 19.50552823691581 19.347153108620457 8.914549824296701 19.841538938728135 -30.357562810836335 -5.8051482228142195 -20.70248562796752 -21.376641384544037 -8.3987892732033 -7.736419267379574 2.0685219772918724 -8.760228330317224 5.418493374208782 1.6147496952752922 -2.4936078709750045 -2.2780749437287913 0.0 0.0 0.0 + 56.666079713903386 5.165818087889462 22.35860178936739 10.763846891315566 -12.19955923582867 -0.6557677952689249 6.699011373303813 8.198746354754231 1.677616608414471 3.1277285768268968 1.4179582645760416 -2.2744851263878836 -1.7540829181840385 -2.0011264405011304 -2.473136836317977 -1.8837562152980634 0.10307912091592847 0.0 0.0 + 0.4516803503254423 -1.1534041395134922 -4.845280220499032 -23.586737710513358 1.6878417137075876 0.7868554635343545 3.0270371561482805 6.0990245036017745 2.600755391135945 1.3246029905944345 2.0716827798306645 1.0885240892776982 -2.406764303616696 -1.0934035335348031 -0.08817028752603433 0.1628623060793163 -0.0494871328758008 -0.053891050773493175 0.0] +const RODAS6PC = [0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -6.581455754882143 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -17.99898897860265 -8.573983492685619 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -9.381383431453385 -3.147640353879416 -1.3459246069197102 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -2.6265331637613007 -4.114341661049238 2.3552716210903446 0.7916860595752533 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 13.234071865054425 -6.5531726714288245 10.73126008968739 7.881893740344428 -12.771533510641573 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 2.830906994202388 0.2604988641272497 1.2537810312593667 -3.3671244579321455 -10.786563365589606 -1.9308385166591397 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -11.060311196714387 -1.3456656966931244 -0.7657970115506183 6.107723730659436 2.2037867523584938 -0.07238767937020778 -0.8050462039096485 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -18.12844382677043 -8.753725825758918 2.21059342699439 11.608007179779365 -0.05812583279366939 -0.5568300956262869 0.22469855334210373 -3.2370311176417705 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + -27.976343920035056 -8.591555353546772 0.7281452536154736 17.638493457476986 -5.306189757628467 -3.0476569146401444 -5.904770682441327 -11.929084037829442 -5.050568446376497 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 16.354749252471326 1.4669223994142209 5.928484441955681 10.74513480723443 10.673355125609953 3.688805562318594 9.180717730517506 10.247712646451996 1.465303310058304 2.6508985881732774 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 6.914935441832399 5.38984958631352 5.862037438875566 5.348681436005972 -7.013382408252529 -1.0246660674824237 -2.9837100715597376 -5.836566084094612 -1.6109549842142277 -1.1760399923017764 1.9280128334739643 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 4.198711896534994 0.6181084056782703 0.8167077246607498 -11.236495255410707 -4.824409089261172 0.7728367826492113 1.3033341851336357 3.1220057171705977 1.917167519177393 0.740911936448596 2.3884839541537675 -1.0646261824518854 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + 8.439457273665866 -12.395217711948733 8.717809686910918 -22.620864451522902 -20.113605406532766 -4.689776805197894 1.6982447341017708 4.543406791431926 1.613366829028557 1.9707273458768597 5.732578765805261 1.7624664316708778 -5.245856774591262 0.0 0.0 0.0 0.0 0.0 0.0 + 1.71450490512272 -13.840042084553074 6.437347401872298 -39.22048912909508 -25.603335547270504 -8.064795628637777 -0.0416146802576695 1.2346482358729156 2.7009872115209252 0.896525973043981 11.303609670096813 1.7547024586563815 -10.02276713006834 -6.93945857648056 0.0 0.0 0.0 0.0 0.0 + 19.61213176916848 -14.311603723508286 12.96694128305561 -28.107332490598257 -27.192311861144052 -4.26577843330566 4.2210733410202135 10.487402162301366 0.8300940888935481 2.8025411207314455 8.878715452726594 1.4612348690788786 -9.853595041510669 -7.6808377648250294 -6.870056791600298 0.0 0.0 0.0 0.0 + -371.4374434114548 -183.45541467767708 -245.2624549214238 -955.0201586246473 19.423673137681643 -0.9607917923114558 84.24290713671253 150.79467360315542 63.95986343894305 44.75849836276605 140.71019894715903 48.45923399488863 -146.47504553991118 -81.54609927566207 -25.07839993898753 3.829875020371404 0.0 0.0 0.0 + -164.17333724090065 -123.20834760012879 41.95443520088893 -239.77049586199965 -114.21790985713952 -12.341946126859007 15.750890701780254 39.790586318490696 -15.10728752295998 -12.824535901748304 16.73312629333741 -11.045750202895642 -14.639022723428816 -4.819493713790297 0.12987727446051117 0.04274137296376776 1.204312390836273 0.0 0.0 + 461.9368267656361 52.53840694165619 144.8183760448168 455.9093893534564 35.81740627464267 40.776479432911195 17.76376684531324 -7.606209560029927 -15.381956921574087 3.9317973949968428 -41.37771137941743 -44.920577584346 53.37495929469229 10.211466474320808 -15.84128439059478 -19.507483543094224 1.884309895179932 5.745356704710484 0.0] +const RODAS6Pc = [0.0, 0.4449064090300329, 0.5391930604628539, 0.3920739557917205, 0.5393851240464334, 0.7496615946466092, 0.09171052879621677, 0.716762001806476, 0.9201684737037024, 0.7017495611178288, 0.5587152179138446, 0.10896187906446, 0.5073827520419607, 0.9999999999999999, 0.9999999999999999, 1.0000000000000002, 0.19999999999999996, 0.4999999999999998, 0.8] +const RODAS6Pd = [0.26, -0.18490640903003291, -0.5445316852875675, -0.03230297796648507, -0.05985832397786847, 0.08292573124960323, 0.4158601113780379, -0.4887636036121086, -0.5305551731438798, 0.12166683722729399, -0.14899579330238244, 0.20995126195089908, -0.06287825975966793, -1.1102230246251565e-16, 1.1102230246251565e-16, 2.220446049250313e-16, 8.520155173756681, -7.34858003171262, 1.5593201340906078] +const RODAS6PH = [17.587737160518465 -4.506717064391614 3.246011776864481 -5.070180845870549 -6.923968603369673 -1.6592466655000042 0.8383525386642399 1.2720777724693832 2.2171542815286456 1.2791183755209752 3.3596716472022443 -0.5508890465808383 -2.0565074886981494 -2.6056952102687827 -2.100871100634552 -1.8776167550373888 -0.022326222735958842 0.25936621048769365 -0.12973178185863266 + -27.32817833553187 2.3528275077734033 7.155223685651038 10.820120934865187 -25.034320788396975 -8.268316122429903 -11.20195859714455 -5.95292555000712 -4.350123484395559 -3.4923279797567224 -7.522667509591013 6.313357154108988 3.434436480929646 4.500204746140061 3.6478467450775045 2.888705712728512 -0.031277730738519756 -1.0511708104283997 0.7378677397843861 + 48.135250596372614 1.6152029264444003 8.745836243957392 11.94240783069938 21.81240388443989 13.3043522805227 15.272804908450944 7.036607939296541 -2.212585956007379 3.686601637356048 8.623872556251557 -9.029595886738495 -6.643976834766214 -6.745850399987328 -7.810160738277424 -3.8140189856964035 0.04030442810903404 1.0072680387990685 -1.0126127084529764 + -12.232391324631207 1.7643387246585114 -0.8009754670601623 -2.893944757628759 -7.972815842366974 1.309554861689306 -4.604493120665954 1.8134270309595735 -3.751773417632513 -0.5811994801517248 -2.741530578462468 0.300651942632877 2.0061263661214994 1.8521005591286555 -0.2324954254701126 0.6873479719072509 0.12936879836252782 -0.17980608456604885 0.32290862251165836] +function Rodas6PTableau(T, T2) + gamma = 0.26 + RodasTableau{T, T2}(RODAS6PA, RODAS6PC, gamma, RODAS6Pc, RODAS6Pd, RODAS6PH) end @RosenbrockW6S4OS(:tableau) diff --git a/lib/OrdinaryDiffEqRosenbrock/src/stiff_addsteps.jl b/lib/OrdinaryDiffEqRosenbrock/src/stiff_addsteps.jl index d3967b40ee..f598a1753a 100644 --- a/lib/OrdinaryDiffEqRosenbrock/src/stiff_addsteps.jl +++ b/lib/OrdinaryDiffEqRosenbrock/src/stiff_addsteps.jl @@ -9,18 +9,21 @@ function _ode_addsteps!(k, t, uprev, u, dt, f, p, neginvdtγ = -inv(dtγ) dto2 = dt / 2 tf.u = uprev - if cache.autodiff isa AutoForwardDiff - dT = ForwardDiff.derivative(tf, t) - else - dT = FiniteDiff.finite_difference_derivative(tf, t, dir = sign(dt)) + + autodiff_alg = cache.autodiff + + if autodiff_alg isa AutoFiniteDiff + autodiff_alg = SciMLBase.@set autodiff_alg.dir = sign(dt) end + dT = DI.derivative(tf, autodiff_alg,t) + mass_matrix = f.mass_matrix if uprev isa Number - J = ForwardDiff.derivative(uf, uprev) + J = DI.derivative(uf, autodiff_alg, uprev) W = neginvdtγ .+ J else - J = ForwardDiff.jacobian(uf, uprev) + J = DI.jacobian(uf, autodiff_alg, uprev) if mass_matrix isa UniformScaling W = neginvdtγ * mass_matrix + J else @@ -58,30 +61,33 @@ function _ode_addsteps!(k, t, uprev, u, dt, f, p, cache::RosenbrockCombinedConst # Time derivative tf.u = uprev - if cache.autodiff isa AutoForwardDiff - dT = ForwardDiff.derivative(tf, t) - else - dT = FiniteDiff.finite_difference_derivative(tf, t, dir = sign(dt)) + + autodiff_alg = cache.autodiff + + if autodiff_alg isa AutoFiniteDiff + autodiff_alg = SciMLBase.@set autodiff_alg.dir = sign(dt) end + dT = DI.derivative(tf, autodiff_alg, t) + # Jacobian uf.t = t if uprev isa AbstractArray - J = ForwardDiff.jacobian(uf, uprev) + J = DI.jacobian(uf, autodiff_alg, uprev) W = mass_matrix / dtgamma - J else - J = ForwardDiff.derivative(uf, uprev) + J = DI.derivative(uf, autodiff_alg, uprev) W = 1 / dtgamma - J end - num_stages = size(A,1) + num_stages = size(A, 1) du = f(u, p, t) linsolve_tmp = @.. du + dtd[1] * dT k1 = _reshape(W \ _vec(linsolve_tmp), axes(uprev)) # constant number for type stability make sure this is greater than num_stages - ks = ntuple(Returns(k1), 10) - # Last stage doesn't affect ks - for stage in 2:(num_stages - 1) + ks = ntuple(Returns(k1), 20) + # Last stage affect's ks for Rodas5,5P,6P + for stage in 2:num_stages u = uprev for i in 1:(stage - 1) u = @.. u + A[stage, i] * ks[i] @@ -107,8 +113,8 @@ function _ode_addsteps!(k, t, uprev, u, dt, f, p, cache::RosenbrockCombinedConst for j in 1:size(H, 1) kj = zero(ks[1]) - # Last stage doesn't affect ks - for i in 1:(num_stages - 1) + # Last stage affect's ks for Rodas5,5P,6P + for i in 1:num_stages kj = @.. kj + H[j, i] * ks[i] end copyat_or_push!(k, j, kj) @@ -145,8 +151,8 @@ function _ode_addsteps!(k, t, uprev, u, dt, f, p, cache::RosenbrockCache, linres = dolinsolve( cache, linsolve; A = W, b = _vec(linsolve_tmp), reltol = cache.reltol) @.. $(_vec(ks[1])) = -linres.u - # Last stage doesn't affect ks - for stage in 2:(length(ks) - 1) + # Last stage affect's ks for Rodas5,5P,6P + for stage in 2:length(ks) tmp .= uprev for i in 1:(stage - 1) @.. tmp += A[stage, i] * _vec(ks[i]) @@ -172,11 +178,10 @@ function _ode_addsteps!(k, t, uprev, u, dt, f, p, cache::RosenbrockCache, @.. $(_vec(ks[stage])) = -linres.u end - for j in 1:size(H, 1) copyat_or_push!(k, j, zero(du)) - # Last stage doesn't affect ks - for i in 1:(length(ks) - 1) + # Last stage affect's ks for Rodas5,5P,6P + for i in 1:length(ks) @.. k[j] += H[j, i] * _vec(ks[i]) end end diff --git a/lib/OrdinaryDiffEqRosenbrock/test/allocation_tests.jl b/lib/OrdinaryDiffEqRosenbrock/test/allocation_tests.jl new file mode 100644 index 0000000000..911b472062 --- /dev/null +++ b/lib/OrdinaryDiffEqRosenbrock/test/allocation_tests.jl @@ -0,0 +1,52 @@ +using OrdinaryDiffEqRosenbrock +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqRosenbrock solvers using AllocCheck.jl. +These tests verify that the step! operation should not allocate during stepping. +Currently, Rosenbrock solvers are allocating and marked with @test_broken. +""" + +@testset "Rosenbrock Allocation Tests" begin + # Test problem - use a simple linear problem for stiff solvers + linear_prob = ODEProblem((u, p, t) -> -u, 1.0, (0.0, 1.0)) + + # Vector problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + vector_prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported Rosenbrock solvers for allocation-free behavior + rosenbrock_solvers = [Rosenbrock23(), Rosenbrock32(), RosShamp4(), Veldd4(), Velds4(), GRK4T(), GRK4A(), + Rodas3(), Rodas23W(), Rodas3P(), Rodas4(), Rodas42(), Rodas4P(), Rodas4P2(), Rodas5(), + Rodas5P(), Rodas5Pe(), Rodas5Pr(), Rodas6P()] + + @testset "Rosenbrock Solver Allocation Analysis" begin + for solver in rosenbrock_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(linear_prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck for accurate allocation detection + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test_broken length(allocs) == 0 + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqRosenbrock/test/dae_rosenbrock_ad_tests.jl b/lib/OrdinaryDiffEqRosenbrock/test/dae_rosenbrock_ad_tests.jl index ee3d55948b..049d541b54 100644 --- a/lib/OrdinaryDiffEqRosenbrock/test/dae_rosenbrock_ad_tests.jl +++ b/lib/OrdinaryDiffEqRosenbrock/test/dae_rosenbrock_ad_tests.jl @@ -1,6 +1,8 @@ using OrdinaryDiffEqRosenbrock, LinearAlgebra, ForwardDiff, Test using OrdinaryDiffEqNonlinearSolve: BrownFullBasicInit, ShampineCollocationInit +using ADTypes: AutoForwardDiff, AutoFiniteDiff +afd_cs3 = AutoForwardDiff(chunksize=3) function rober(du, u, p, t) y₁, y₂, y₃ = u k₁, k₂, k₃ = p @@ -16,25 +18,24 @@ function rober(u, p, t) k₁ * y₁ - k₃ * y₂ * y₃ - k₂ * y₂^2, y₁ + y₂ + y₃ - 1] end -M = [1.0 0 0 - 0 1.0 0 - 0 0 0] -roberf = ODEFunction(rober, mass_matrix = M) -roberf_oop = ODEFunction{false}(rober, mass_matrix = M) +M = Diagonal([1.0, 1.0, 0.0]) +roberf = ODEFunction{true, SciMLBase.AutoSpecialize}(rober, mass_matrix = M) +roberf_oop = ODEFunction{false, SciMLBase.AutoSpecialize}(rober, mass_matrix = M) prob_mm = ODEProblem(roberf, [1.0, 0.0, 0.2], (0.0, 1e5), (0.04, 3e7, 1e4)) prob_mm_oop = ODEProblem(roberf_oop, [1.0, 0.0, 0.2], (0.0, 1e5), (0.04, 3e7, 1e4)) -sol = solve(prob_mm, Rodas5P(), reltol = 1e-8, abstol = 1e-8) -sol = solve(prob_mm_oop, Rodas5P(), reltol = 1e-8, abstol = 1e-8) +# Both should be inferable so long as AutoSpecialize is used... +@test_broken sol = @inferred solve(prob_mm, Rodas5P(), reltol = 1e-8, abstol = 1e-8) +sol = @inferred solve(prob_mm_oop, Rodas5P(), reltol = 1e-8, abstol = 1e-8) # These tests flex differentiation of the solver and through the initialization # To only test the solver part and isolate potential issues, set the initialization to consistent -@testset "Inplace: $(isinplace(_prob)), DAEProblem: $(_prob isa DAEProblem), BrownBasic: $(initalg isa BrownFullBasicInit), Autodiff: $autodiff" for _prob in [ +@testset "Inplace: $(isinplace(_prob)), BrownBasic: $(initalg isa BrownFullBasicInit), Autodiff: $autodiff" for _prob in [ prob_mm, prob_mm_oop], - initalg in [BrownFullBasicInit(), ShampineCollocationInit()], autodiff in [true, false] + initalg in [BrownFullBasicInit(), ShampineCollocationInit()], autodiff in [AutoForwardDiff(chunksize=3), AutoFiniteDiff()] alg = Rodas5P(; autodiff) function f(p) - sol = solve(remake(_prob, p = p), alg, abstol = 1e-14, + sol = @inferred solve(remake(_prob, p = p), alg, abstol = 1e-14, reltol = 1e-14, initializealg = initalg) sum(sol) end diff --git a/lib/OrdinaryDiffEqRosenbrock/test/jet.jl b/lib/OrdinaryDiffEqRosenbrock/test/jet.jl new file mode 100644 index 0000000000..8477ef79d0 --- /dev/null +++ b/lib/OrdinaryDiffEqRosenbrock/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqRosenbrock +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqRosenbrock, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqRosenbrock/test/ode_rosenbrock_tests.jl b/lib/OrdinaryDiffEqRosenbrock/test/ode_rosenbrock_tests.jl index d384937120..cd984491dd 100644 --- a/lib/OrdinaryDiffEqRosenbrock/test/ode_rosenbrock_tests.jl +++ b/lib/OrdinaryDiffEqRosenbrock/test/ode_rosenbrock_tests.jl @@ -1,9 +1,13 @@ -using OrdinaryDiffEqRosenbrock, DiffEqDevTools, Test, LinearAlgebra, LinearSolve +using OrdinaryDiffEqRosenbrock, DiffEqDevTools, Test, LinearAlgebra, LinearSolve, ADTypes import ODEProblemLibrary: prob_ode_linear, prob_ode_2Dlinear, prob_ode_bigfloatlinear, prob_ode_bigfloat2Dlinear import LinearSolve +if isempty(VERSION.prerelease) + using Enzyme +end + @testset "Rosenbrock Tests" begin ## Breakout these since no other test of their adaptivity @@ -19,6 +23,7 @@ import LinearSolve sol = solve(prob, Rosenbrock23()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -27,6 +32,18 @@ import LinearSolve sol = solve(prob, Rosenbrock23()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, prob, Rosenbrock23(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const))) + @test sim.𝒪est[:final]≈2 atol=testTol + + sol = solve(prob, Rosenbrock23(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const))) + @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + end prob = prob_ode_bigfloat2Dlinear @@ -35,6 +52,7 @@ import LinearSolve sol = solve(prob, Rosenbrock23(linsolve = QRFactorization())) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### Rosenbrock32() @@ -45,6 +63,7 @@ import LinearSolve sol = solve(prob, Rosenbrock32()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -53,7 +72,31 @@ import LinearSolve sol = solve(prob, Rosenbrock32()) @test length(sol) < 20 - + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, + prob, + Rosenbrock32(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const))) + @test sim.𝒪est[:final]≈3 atol=testTol + + sol = solve(prob, + Rosenbrock32(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const))) + @test length(sol) < 20 + + sim = test_convergence(dts, + prob, + Rosenbrock32(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), linsolve = LinearSolve.KrylovJL())) + @test sim.𝒪est[:final]≈3 atol=testTol + + sol = solve(prob, + Rosenbrock32(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), linsolve = LinearSolve.KrylovJL())) + @test length(sol) < 20 + end ### ROS3P() prob = prob_ode_linear @@ -63,6 +106,7 @@ import LinearSolve sol = solve(prob, ROS3P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -71,6 +115,24 @@ import LinearSolve sol = solve(prob, ROS3P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, + prob, + ROS3P( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test sim.𝒪est[:final]≈3 atol=testTol + + sol = solve(prob, + ROS3P( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test length(sol) < 20 + end ### Rodas3() @@ -81,6 +143,7 @@ import LinearSolve sol = solve(prob, Rodas3()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -89,6 +152,24 @@ import LinearSolve sol = solve(prob, Rodas3()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, + prob, + Rodas3( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test sim.𝒪est[:final]≈3 atol=testTol + + sol = solve(prob, + Rodas3( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test length(sol) < 20 + end ### ROS2 prob = prob_ode_linear @@ -98,6 +179,7 @@ import LinearSolve sol = solve(prob, ROS2()) @test length(sol) < 61 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -106,6 +188,7 @@ import LinearSolve sol = solve(prob, ROS2PR()) @test length(sol) < 60 + @test SciMLBase.successful_retcode(sol) ### ROS2PR prob = prob_ode_linear @@ -115,6 +198,7 @@ import LinearSolve sol = solve(prob, ROS2PR()) @test length(sol) < 30 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -123,6 +207,7 @@ import LinearSolve sol = solve(prob, ROS2PR()) @test length(sol) < 30 + @test SciMLBase.successful_retcode(sol) ### ROS2S prob = prob_ode_linear @@ -132,6 +217,7 @@ import LinearSolve sol = solve(prob, ROS2S()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -140,6 +226,7 @@ import LinearSolve sol = solve(prob, ROS2S()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS3 prob = prob_ode_linear @@ -149,6 +236,7 @@ import LinearSolve sol = solve(prob, ROS3()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -157,6 +245,7 @@ import LinearSolve sol = solve(prob, ROS3()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS3PR prob = prob_ode_linear @@ -165,7 +254,8 @@ import LinearSolve @test sim.𝒪est[:final]≈3 atol=testTol sol = solve(prob, ROS3PR()) - @test length(sol) < 20 #length(sol) = 4 => Too Small?? + @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) #length(sol) = 4 => Too Small?? prob = prob_ode_2Dlinear @@ -173,7 +263,8 @@ import LinearSolve @test sim.𝒪est[:final]≈3 atol=testTol sol = solve(prob, ROS3PR()) - @test length(sol) < 20 #length(sol) = 4 => Too Small?? + @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) #length(sol) = 4 => Too Small?? ### Scholz4_7 prob = prob_ode_linear @@ -183,6 +274,7 @@ import LinearSolve sol = solve(prob, Scholz4_7()) @test length(sol) < 30 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -191,6 +283,7 @@ import LinearSolve sol = solve(prob, Scholz4_7()) @test length(sol) < 30 + @test SciMLBase.successful_retcode(sol) println("4th order Rosenbrocks") @@ -203,6 +296,7 @@ import LinearSolve sol = solve(prob, RosShamp4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -211,6 +305,7 @@ import LinearSolve sol = solve(prob, RosShamp4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### Veldd4 @@ -221,6 +316,7 @@ import LinearSolve sol = solve(prob, Veldd4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -229,6 +325,7 @@ import LinearSolve sol = solve(prob, Veldd4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### Velds4 @@ -239,6 +336,7 @@ import LinearSolve sol = solve(prob, Velds4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -247,6 +345,7 @@ import LinearSolve sol = solve(prob, Velds4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### GRK4T @@ -257,6 +356,7 @@ import LinearSolve sol = solve(prob, GRK4T()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -265,6 +365,7 @@ import LinearSolve sol = solve(prob, GRK4T()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### GRK4A dts = (1 / 2) .^ (7:-1:4) @@ -276,6 +377,7 @@ import LinearSolve sol = solve(prob, GRK4A()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -284,6 +386,7 @@ import LinearSolve sol = solve(prob, GRK4A()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### Ros4LStab @@ -294,6 +397,7 @@ import LinearSolve sol = solve(prob, Ros4LStab()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -302,6 +406,7 @@ import LinearSolve sol = solve(prob, Ros4LStab()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### Rosenbrock-W Algorithms @@ -315,6 +420,7 @@ import LinearSolve sol = solve(prob, ROS34PW1a()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -323,6 +429,7 @@ import LinearSolve sol = solve(prob, ROS34PW1a()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS34PW1b prob = prob_ode_linear @@ -332,6 +439,7 @@ import LinearSolve sol = solve(prob, ROS34PW1b()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -340,6 +448,7 @@ import LinearSolve sol = solve(prob, ROS34PW1b()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS34PW2 prob = prob_ode_linear @@ -349,6 +458,7 @@ import LinearSolve sol = solve(prob, ROS34PW2()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -357,6 +467,7 @@ import LinearSolve sol = solve(prob, ROS34PW2()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS34PW3 prob = prob_ode_linear @@ -366,6 +477,7 @@ import LinearSolve sol = solve(prob, ROS34PW3()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -374,6 +486,7 @@ import LinearSolve sol = solve(prob, ROS34PW3()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS34PRw prob = prob_ode_linear @@ -383,6 +496,7 @@ import LinearSolve sol = solve(prob, ROS34PRw()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -391,6 +505,7 @@ import LinearSolve sol = solve(prob, ROS34PRw()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS3PRL prob = prob_ode_linear @@ -400,6 +515,7 @@ import LinearSolve sol = solve(prob, ROS3PRL()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -408,6 +524,7 @@ import LinearSolve sol = solve(prob, ROS3PRL()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROS3PRL2 prob = prob_ode_linear @@ -417,6 +534,7 @@ import LinearSolve sol = solve(prob, ROS3PRL2()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -425,6 +543,7 @@ import LinearSolve sol = solve(prob, ROS3PRL2()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### ROK4a prob = prob_ode_linear @@ -434,6 +553,7 @@ import LinearSolve sol = solve(prob, ROK4a()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -442,6 +562,7 @@ import LinearSolve sol = solve(prob, ROK4a()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### RosenbrockW6S4OS sim = test_convergence(dts, prob, RosenbrockW6S4OS())#test inplace @@ -465,6 +586,7 @@ import LinearSolve sol = solve(prob, Rodas23W()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -474,6 +596,24 @@ import LinearSolve sol = solve(prob, Rodas23W()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, + prob, + Rodas23W( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test sim.𝒪est[:final] ≈ 2 atol = testTol + + sol = solve(prob, + Rodas23W( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test length(sol) < 20 + end println("Rodas3P") @@ -485,6 +625,7 @@ import LinearSolve sol = solve(prob, Rodas3P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -494,6 +635,24 @@ import LinearSolve sol = solve(prob, Rodas3P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, + prob, + Rodas3P( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test sim.𝒪est[:final]≈3 atol=testTol + + sol = solve(prob, + Rodas3P( + autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL())) + @test length(sol) < 20 + end ### Rodas4 Algorithms @@ -509,13 +668,23 @@ import LinearSolve sol = solve(prob, Rodas4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) - sim = test_convergence(dts, prob, Rodas4(autodiff = false), dense_errors = true) + sim = test_convergence( + dts, prob, Rodas4(autodiff = AutoFiniteDiff()), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @test sim.𝒪est[:L2]≈4 atol=testTol - sol = solve(prob, Rodas4(autodiff = false)) + sol = solve(prob, Rodas4(autodiff = AutoFiniteDiff())) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + if isempty(VERSION.prerelease) + sol = solve(prob, + Rodas4(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const))) + @test length(sol) < 20 + end sim = test_convergence(dts, prob, Rodas42(), dense_errors = true) @test sim.𝒪est[:final]≈5.1 atol=testTol @@ -523,6 +692,7 @@ import LinearSolve sol = solve(prob, Rodas42()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, Rodas4P(), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @@ -530,6 +700,7 @@ import LinearSolve sol = solve(prob, Rodas4P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, Rodas4P2(), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @@ -537,6 +708,7 @@ import LinearSolve sol = solve(prob, Rodas4P2()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -546,33 +718,38 @@ import LinearSolve sol = solve(prob, Rodas4()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) println("Rodas4 with finite diff") - sim = test_convergence(dts, prob, Rodas4(autodiff = false), dense_errors = true) + sim = test_convergence( + dts, prob, Rodas4(autodiff = AutoFiniteDiff()), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @test sim.𝒪est[:L2]≈4 atol=testTol - sol = solve(prob, Rodas4(autodiff = false)) + sol = solve(prob, Rodas4(autodiff = AutoFiniteDiff())) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) - sim = test_convergence(dts, prob, Rodas4(autodiff = false, - diff_type = Val{:forward}), + sim = test_convergence( + dts, prob, Rodas4(autodiff = AutoFiniteDiff(fdtype = Val(:forward))), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @test sim.𝒪est[:L2]≈4 atol=testTol - sol = solve(prob, Rodas4(autodiff = false, diff_type = Val{:forward})) + sol = solve(prob, Rodas4(autodiff = AutoFiniteDiff(fdtype = Val(:forward)))) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) - sim = test_convergence(dts, prob, Rodas4(autodiff = false, - diff_type = Val{:complex}), + sim = test_convergence( + dts, prob, Rodas4(autodiff = AutoFiniteDiff(fdtype = Val(:complex))), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @test sim.𝒪est[:L2]≈4 atol=testTol - sol = solve(prob, Rodas4(autodiff = false, diff_type = Val{:complex})) + sol = solve(prob, Rodas4(autodiff = AutoFiniteDiff(fdtype = Val(:forward)))) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, Rodas42(), dense_errors = true) @test sim.𝒪est[:final]≈5 atol=testTol @@ -580,6 +757,7 @@ import LinearSolve sol = solve(prob, Rodas42()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, Rodas4P(), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @@ -587,6 +765,7 @@ import LinearSolve sol = solve(prob, Rodas4P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) sim = test_convergence(dts, prob, Rodas4P2(), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @@ -594,15 +773,18 @@ import LinearSolve sol = solve(prob, Rodas4P2()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) println("Rodas4P2 with finite diff") - sim = test_convergence(dts, prob, Rodas4P2(autodiff = false), dense_errors = true) + sim = test_convergence( + dts, prob, Rodas4P2(autodiff = AutoFiniteDiff()), dense_errors = true) @test sim.𝒪est[:final]≈4 atol=testTol @test sim.𝒪est[:L2]≈4 atol=testTol - sol = solve(prob, Rodas4P2(autodiff = false)) + sol = solve(prob, Rodas4P2(autodiff = AutoFiniteDiff())) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) ### Rodas5 println("Rodas5") @@ -616,6 +798,7 @@ import LinearSolve sol = solve(prob, Rodas5()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -625,6 +808,7 @@ import LinearSolve sol = solve(prob, Rodas5()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) println("Rodas5P") @@ -636,6 +820,7 @@ import LinearSolve sol = solve(prob, Rodas5P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -645,6 +830,7 @@ import LinearSolve sol = solve(prob, Rodas5P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) println("Rodas5Pe") @@ -656,6 +842,7 @@ import LinearSolve sol = solve(prob, Rodas5Pe()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear @@ -665,29 +852,85 @@ import LinearSolve sol = solve(prob, Rodas5Pe()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) - println("Rodas5Pr") + println("Rodas6P") prob = prob_ode_linear - sim = test_convergence(dts, prob, Rodas5Pr(), dense_errors = true) + sim = test_convergence(dts, prob, Rodas6P(), dense_errors = true) #@test sim.𝒪est[:final]≈5 atol=testTol #-- observed order > 6 - @test sim.𝒪est[:L2]≈5 atol=testTol + @test sim.𝒪est[:L2]≈6 atol=testTol - sol = solve(prob, Rodas5Pr()) + sol = solve(prob, Rodas6P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) prob = prob_ode_2Dlinear - sim = test_convergence(dts, prob, Rodas5Pr(), dense_errors = true) + sim = test_convergence(dts, prob, Rodas6P(), dense_errors = true) #@test sim.𝒪est[:final]≈5 atol=testTol #-- observed order > 6 - @test sim.𝒪est[:L2]≈5 atol=testTol + @test sim.𝒪est[:L2]≈6 atol=testTol - sol = solve(prob, Rodas5Pr()) + sol = solve(prob, Rodas6P()) @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + + + println("Rodas5P Enzyme Forward") - prob = ODEProblem((u, p, t) -> 0.9u, 0.1, (0.0, 1.0)) - @test_nowarn solve(prob, Rosenbrock23(autodiff = false)) + prob = prob_ode_linear + + if isempty(VERSION.prerelease) + sim = test_convergence(dts, prob, + Rodas5P(autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const)), + dense_errors = true) + #@test sim.𝒪est[:final]≈5 atol=testTol #-- observed order > 6 + @test sim.𝒪est[:L2]≈5 atol=testTol + + sol = solve(prob, + Rodas5P(autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const))) + @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + prob = prob_ode_2Dlinear + + sim = test_convergence(dts, prob, + Rodas5P(autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const)), + dense_errors = true) + #@test sim.𝒪est[:final]≈5 atol=testTol #-- observed order > 6 + @test sim.𝒪est[:L2]≈5 atol=testTol + + sim = test_convergence(dts, prob, + Rodas5P(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL()), + dense_errors = true) + #@test sim.𝒪est[:final]≈5 atol=testTol #-- observed order > 6 + @test sim.𝒪est[:L2]≈5 atol=testTol + + sim = test_convergence(dts, prob, + Rodas5P(autodiff = AutoEnzyme( + mode = set_runtime_activity(Enzyme.Forward), function_annotation = Enzyme.Const), + linsolve = LinearSolve.KrylovJL_GMRES()), + dense_errors = true) + #@test sim.𝒪est[:final]≈5 atol=testTol #-- observed order > 6 + @test sim.𝒪est[:L2]≈5 atol=testTol + + sol = solve(prob, + Rodas5P(autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), + function_annotation = Enzyme.Const))) + @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) + + + prob = ODEProblem((u, p, t) -> 0.9u, 0.1, (0.0, 1.0)) + @test_nowarn solve(prob, Rosenbrock23(autodiff = AutoFiniteDiff())) + @test_nowarn solve(prob, + Rosenbrock23(autodiff = AutoEnzyme(mode = set_runtime_activity(Enzyme.Forward), + function_annotation = Enzyme.Const))) + end end @testset "Convergence with time-dependent matrix-free Jacobian" begin @@ -703,3 +946,95 @@ end sim = test_convergence(dts, prob, Rodas3(linsolve = LinearSolve.KrylovJL())) @test sim.𝒪est[:final]≈3 atol=testTol end + +@testset "ADTypes" begin + for T in [ + Rosenbrock23, + Rosenbrock32, + RosShamp4, + Veldd4, + Velds4, + GRK4T, + GRK4A, + Ros4LStab, + ROS3P, + Rodas3, + Rodas23W, + Rodas3P, + Rodas4, + Rodas42, + Rodas4P, + Rodas4P2, + Rodas5, + Rodas5P, + Rodas5Pe, + Rodas5Pr, + Rodas6P, + RosenbrockW6S4OS, + ROS34PW1a, + ROS34PW1b, + ROS34PW2, + ROS34PW3, + ROS34PRw, + ROS3PRL, + ROS3PRL2, + ROK4a, + ROS2, + ROS2PR, + ROS2S, + ROS3, + ROS3PR, + Scholz4_7 + ] + RosenbrockAlgorithm = if T <: + OrdinaryDiffEqRosenbrock.OrdinaryDiffEqRosenbrockAlgorithm + OrdinaryDiffEqRosenbrock.OrdinaryDiffEqRosenbrockAlgorithm + else + OrdinaryDiffEqRosenbrock.OrdinaryDiffEqRosenbrockAdaptiveAlgorithm + end + + ad = AutoForwardDiff(; chunksize = 3) + alg = @test_logs @inferred(T(; autodiff = ad)) + @test alg isa RosenbrockAlgorithm{3, typeof(ad), Val{:forward}()} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.alg_autodiff(alg) === ad + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.get_chunksize(alg) === Val{3}() + + alg = @test_logs (:warn, r"The `chunk_size` keyword is deprecated") match_mode=:any @inferred(T(; + autodiff = ad, chunk_size = Val{4}())) + @test alg isa RosenbrockAlgorithm{4, <:AutoForwardDiff{4}, Val{:forward}()} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.alg_autodiff(alg) isa + AutoForwardDiff{4} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.get_chunksize(alg) === Val{4}() + + ad = AutoFiniteDiff(; fdtype = Val{:central}()) + alg = @test_logs @inferred(T(; autodiff = ad)) + @test alg isa + RosenbrockAlgorithm{0, <:AutoFiniteDiff{Val{:central}}, Val{:central}()} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.alg_autodiff(alg) isa AutoFiniteDiff{Val{:central}} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.get_chunksize(alg) === Val{0}() + + alg = @test_logs (:warn, r"The `diff_type` keyword is deprecated") match_mode=:any @inferred(T(; + autodiff = ad, diff_type = Val{:complex}())) + @test alg isa + RosenbrockAlgorithm{0, <:AutoFiniteDiff{Val{:complex}}, Val{:complex}()} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.alg_autodiff(alg) isa + AutoFiniteDiff{Val{:complex}} + @test OrdinaryDiffEqRosenbrock.OrdinaryDiffEqCore.get_chunksize(alg) === Val{0}() + + # issue #2613 + f(u, _, _) = -u + prob = ODEProblem(f, [1.0, 0.0], (0.0, 1.0)) + alg = T(; autodiff = AutoForwardDiff(; chunksize = 1)) + sol = if alg isa OrdinaryDiffEqRosenbrock.OrdinaryDiffEqRosenbrockAdaptiveAlgorithm + @inferred(solve(prob, alg)) + else + @inferred(solve(prob, alg; dt = 0.1)) + end + alg = T(; autodiff = AutoFiniteDiff(; fdtype = Val(:central))) + sol = if alg isa OrdinaryDiffEqRosenbrock.OrdinaryDiffEqRosenbrockAdaptiveAlgorithm + @inferred(solve(prob, alg)) + else + @inferred(solve(prob, alg; dt = 0.1)) + end + end +end diff --git a/lib/OrdinaryDiffEqRosenbrock/test/qa.jl b/lib/OrdinaryDiffEqRosenbrock/test/qa.jl new file mode 100644 index 0000000000..956cb89095 --- /dev/null +++ b/lib/OrdinaryDiffEqRosenbrock/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqRosenbrock +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqRosenbrock + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqRosenbrock/test/runtests.jl b/lib/OrdinaryDiffEqRosenbrock/test/runtests.jl index 90fc57e617..f5011a7768 100644 --- a/lib/OrdinaryDiffEqRosenbrock/test/runtests.jl +++ b/lib/OrdinaryDiffEqRosenbrock/test/runtests.jl @@ -1,4 +1,11 @@ using SafeTestsets -@time @safetestset "Rosenbrock Convergence Tests" include("ode_rosenbrock_tests.jl") @time @safetestset "DAE Rosenbrock AD Tests" include("dae_rosenbrock_ad_tests.jl") +@time @safetestset "Rosenbrock Convergence Tests" include("ode_rosenbrock_tests.jl") + +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSDIRK/Project.toml b/lib/OrdinaryDiffEqSDIRK/Project.toml index 6204b7309e..5cce2749fa 100644 --- a/lib/OrdinaryDiffEqSDIRK/Project.toml +++ b/lib/OrdinaryDiffEqSDIRK/Project.toml @@ -1,46 +1,63 @@ name = "OrdinaryDiffEqSDIRK" uuid = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.7.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" -OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MacroTools = "0.5.13" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqNonlinearSolve = "<0.0.1, 1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -SciMLBase = "2.48.1" -Test = "<0.0.1, 1" -TruncatedStacktraces = "1.4.0" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +TruncatedStacktraces = "1.4" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +MacroTools = "0.5" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqNonlinearSolve] +path = "../OrdinaryDiffEqNonlinearSolve" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqSDIRK/src/OrdinaryDiffEqSDIRK.jl b/lib/OrdinaryDiffEqSDIRK/src/OrdinaryDiffEqSDIRK.jl index f9fc3bbd9e..a72d1e0584 100644 --- a/lib/OrdinaryDiffEqSDIRK/src/OrdinaryDiffEqSDIRK.jl +++ b/lib/OrdinaryDiffEqSDIRK/src/OrdinaryDiffEqSDIRK.jl @@ -13,8 +13,10 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, constvalue, _unwrap_val, _ode_interpolant, trivial_limiter!, _ode_interpolant!, isesdirk, issplit, - ssp_coefficient, get_fsalfirstlast, generic_solver_docstring -using TruncatedStacktraces, MuladdMacro, MacroTools, FastBroadcast, RecursiveArrayTools + ssp_coefficient, get_fsalfirstlast, generic_solver_docstring, + _bool_to_ADType, _process_AD_choice, current_extrapolant! +using TruncatedStacktraces: @truncate_stacktrace +using MuladdMacro, MacroTools, FastBroadcast, RecursiveArrayTools using SciMLBase: SplitFunction using LinearAlgebra: mul!, I import OrdinaryDiffEqCore @@ -23,9 +25,10 @@ using OrdinaryDiffEqDifferentiation: UJacobianWrapper, dolinsolve using OrdinaryDiffEqNonlinearSolve: du_alias_or_new, markfirststage!, build_nlsolver, nlsolve!, nlsolvefail, isnewton, get_W, set_new_W!, NLNewton, COEFFICIENT_MULTISTEP +import ADTypes: AutoForwardDiff using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqSDIRK/src/algorithms.jl b/lib/OrdinaryDiffEqSDIRK/src/algorithms.jl index 226f92e57f..e1f74a4d57 100644 --- a/lib/OrdinaryDiffEqSDIRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqSDIRK/src/algorithms.jl @@ -5,22 +5,24 @@ function SDIRK_docstring(description::String, extra_keyword_default::String = "") keyword_default = """ chunk_size = Val{0}(), - autodiff = true, + autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), """ * extra_keyword_default keyword_default_description = """ - - `chunk_size`: The chunk size used with ForwardDiff.jl. Defaults to `Val{0}()` - and thus uses the internal ForwardDiff.jl algorithm for the choice. - - `autodiff`: Specifies whether to use automatic differentiation via + - `autodiff`: Uses [ADTypes.jl](https://sciml.github.io/ADTypes.jl/stable/) + to specify whether to use automatic differentiation via [ForwardDiff.jl](https://github.com/JuliaDiff/ForwardDiff.jl) or finite - differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). - Defaults to `Val{true}()` for automatic differentiation. + differencing via [FiniteDiff.jl](https://github.com/JuliaDiff/FiniteDiff.jl). + Defaults to `AutoForwardDiff()` for automatic differentiation, which by default uses + `chunksize = 0`, and thus uses the internal ForwardDiff.jl algorithm for the choice. + To use `FiniteDiff.jl`, the `AutoFiniteDiff()` ADType can be used, which has a keyword argument + `fdtype` with default value `Val{:forward}()`, and alternatives `Val{:central}()` and `Val{:complex}()`. - `standardtag`: Specifies whether to use package-specific tags instead of the ForwardDiff default function-specific tags. For more information, see [this blog post](https://www.stochasticlifestyle.com/improved-forwarddiff-jl-stacktraces-with-package-tags/). @@ -28,9 +30,6 @@ function SDIRK_docstring(description::String, - `concrete_jac`: Specifies whether a Jacobian should be constructed. Defaults to `nothing`, which means it will be chosen true/false depending on circumstances of the solver, such as whether a Krylov subspace method is used for `linsolve`. - - `diff_type`: The type of differentiation used in FiniteDiff.jl if `autodiff=false`. - Defaults to `Val{:forward}`, with alternatives of `Val{:central}` and - `Val{:complex}`. - `linsolve`: Any [LinearSolve.jl](https://github.com/SciML/LinearSolve.jl) compatible linear solver. For example, to use [KLU.jl](https://github.com/JuliaSparse/KLU.jl), specify `$name(linsolve = KLUFactorization()`). @@ -78,9 +77,7 @@ function SDIRK_docstring(description::String, ) end -@doc SDIRK_docstring("A 1st order implicit solver. A-B-L-stable. - Adaptive timestepping through a divided differences estimate via memory. - Strong-stability preserving (SSP).", +@doc SDIRK_docstring("A 1st order implicit solver. A-B-L-stable. Adaptive timestepping through a divided differences estimate. Strong-stability preserving (SSP). Good for highly stiff equations.", "ImplicitEuler"; references = "@book{wanner1996solving, title={Solving ordinary differential equations II}, @@ -106,22 +103,24 @@ struct ImplicitEuler{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function ImplicitEuler(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ImplicitEuler(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :constant, controller = :PI, step_limiter! = trivial_limiter!) - ImplicitEuler{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ImplicitEuler{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, - nlsolve, precs, extrapolant, controller, step_limiter!) + nlsolve, precs, extrapolant, controller, step_limiter!, AD_choice) end -@doc SDIRK_docstring("A second order A-stable symplectic and symmetric implicit solver. - Good for highly stiff equations which need symplectic integration.", +@doc SDIRK_docstring("A second order A-stable symplectic and symmetric implicit solver. Excellent for Hamiltonian systems and highly stiff equations.", "ImplicitMidpoint"; references = "@book{wanner1996solving, title={Solving ordinary differential equations II}, @@ -144,28 +143,27 @@ struct ImplicitMidpoint{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: precs::P extrapolant::Symbol step_limiter!::StepLimiter + autodiff::AD end -function ImplicitMidpoint(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ImplicitMidpoint(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, step_limiter! = trivial_limiter!) - ImplicitMidpoint{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ImplicitMidpoint{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, - step_limiter!) + step_limiter!, AD_choice) end @doc SDIRK_docstring( - """Second order A-stable symmetric ESDIRK method. -"Almost symplectic" without numerical dampening. -Also known as Crank-Nicolson when applied to PDEs. Adaptive timestepping via divided -differences approximation to the second derivative terms in the local truncation error -estimate (the SPICE approximation strategy).""", + "A second order A-stable symmetric ESDIRK method. 'Almost symplectic' without numerical dampening.", "Trapezoid"; references = "Andre Vladimirescu. 1994. The Spice Book. John Wiley & Sons, Inc., New York, NY, USA.", extra_keyword_description = """ @@ -186,27 +184,29 @@ struct Trapezoid{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function Trapezoid(; chunk_size = Val{0}(), autodiff = Val{true}(), +function Trapezoid(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - Trapezoid{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Trapezoid{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, controller, - step_limiter!) + step_limiter!, + AD_choice) end -@doc SDIRK_docstring("A second order A-B-L-S-stable one-step ESDIRK method. - Includes stiffness-robust error estimates for accurate adaptive timestepping, - smoothed derivatives for highly stiff and oscillatory problems.", +@doc SDIRK_docstring("A second order A-B-L-S-stable one-step ESDIRK method. Includes stiffness-robust error estimates for accurate adaptive timestepping, smoothed derivatives for highly stiff and oscillatory problems. Good for high tolerances (>1e-2) on stiff problems.", "TRBDF2"; references = "@article{hosea1996analysis, title={Analysis and implementation of TR-BDF2}, @@ -238,20 +238,24 @@ struct TRBDF2{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function TRBDF2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function TRBDF2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - TRBDF2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + TRBDF2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end -TruncatedStacktraces.@truncate_stacktrace TRBDF2 +@truncate_stacktrace TRBDF2 @doc SDIRK_docstring("SDIRK2: SDIRK Method An A-B-L stable 2nd order SDIRK method", "SDIRK2"; @@ -285,19 +289,24 @@ struct SDIRK2{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function SDIRK2(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function SDIRK2(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - SDIRK2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SDIRK2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}( linsolve, nlsolve, precs, smooth_est, extrapolant, controller, - step_limiter!) + step_limiter!, + AD_choice) end @doc SDIRK_docstring("Description TBD", @@ -326,28 +335,32 @@ struct SDIRK22{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end function SDIRK22(; - chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - Trapezoid{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Trapezoid{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, extrapolant, controller, - step_limiter!) + step_limiter!, + AD_choice) end @doc SDIRK_docstring( """SSPSDIRK is an SSP-optimized SDIRK method, so it's an implicit SDIRK method for handling stiffness but if the `dt` is below the SSP `coefficient * dt`, -then the SSP property of the SSP integrators (the other page) is satisified. +then the SSP property of the SSP integrators (the other page) is satisfied. As such this is a method which is expected to be good on advection-dominated cases where an explicit SSP integrator would be used, but where reaction equations are sufficient stiff to justify implicit integration.""", "SSPSDIRK2"; @@ -378,18 +391,21 @@ struct SSPSDIRK2{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + autodiff::AD end -function SSPSDIRK2(; chunk_size = Val{0}(), autodiff = Val{true}(), +function SSPSDIRK2(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :constant, controller = :PI) - SSPSDIRK2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SSPSDIRK2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring("An A-L stable stiffly-accurate 3rd order ESDIRK method.", @@ -424,17 +440,20 @@ struct Kvaerno3{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function Kvaerno3(; chunk_size = Val{0}(), autodiff = Val{true}(), +function Kvaerno3(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - Kvaerno3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Kvaerno3{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end @doc SDIRK_docstring( @@ -466,17 +485,20 @@ struct KenCarp3{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function KenCarp3(; chunk_size = Val{0}(), autodiff = Val{true}(), +function KenCarp3(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - KenCarp3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + KenCarp3{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end @doc SDIRK_docstring("Third order method.", @@ -502,18 +524,22 @@ struct CFNLIRK3{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function CFNLIRK3(; chunk_size = Val{0}(), autodiff = Val{true}(), +function CFNLIRK3(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) - CFNLIRK3{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + CFNLIRK3{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc SDIRK_docstring("An A-L stable 4th order SDIRK method.", @@ -548,14 +574,18 @@ struct Cash4{CS, AD, F, F2, P, FDT, ST, CJ} <: extrapolant::Symbol embedding::Int controller::Symbol + autodiff::AD end -function Cash4(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function Cash4(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, embedding = 3) + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + Cash4{ - _unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + _unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}( linsolve, nlsolve, @@ -563,7 +593,8 @@ function Cash4(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Va smooth_est, extrapolant, embedding, - controller) + controller, + AD_choice) end @doc SDIRK_docstring("Method of order 4.", @@ -589,18 +620,22 @@ struct SFSDIRK4{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function SFSDIRK4(; chunk_size = Val{0}(), autodiff = Val{true}(), +function SFSDIRK4(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) - SFSDIRK4{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SFSDIRK4{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc SDIRK_docstring("Method of order 5.", @@ -626,19 +661,23 @@ struct SFSDIRK5{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function SFSDIRK5(; chunk_size = Val{0}(), autodiff = Val{true}(), +function SFSDIRK5(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) - SFSDIRK5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SFSDIRK5{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc SDIRK_docstring("Method of order 6.", @@ -664,19 +703,23 @@ struct SFSDIRK6{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function SFSDIRK6(; chunk_size = Val{0}(), autodiff = Val{true}(), +function SFSDIRK6(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) - SFSDIRK6{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SFSDIRK6{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc SDIRK_docstring("Method of order 7.", @@ -702,19 +745,23 @@ struct SFSDIRK7{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function SFSDIRK7(; chunk_size = Val{0}(), autodiff = Val{true}(), +function SFSDIRK7(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) - SFSDIRK7{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SFSDIRK7{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc SDIRK_docstring("Method of order 8.", @@ -740,19 +787,23 @@ struct SFSDIRK8{CS, AD, F, F2, P, FDT, ST, CJ} <: nlsolve::F2 precs::P extrapolant::Symbol + autodiff::AD end -function SFSDIRK8(; chunk_size = Val{0}(), autodiff = Val{true}(), +function SFSDIRK8(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear) - SFSDIRK8{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + SFSDIRK8{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, - extrapolant) + extrapolant, + AD_choice) end @doc SDIRK_docstring("An A-L stable 4th order SDIRK method.", @@ -778,17 +829,20 @@ struct Hairer4{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + autodiff::AD end function Hairer4(; - chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI) - Hairer4{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Hairer4{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring("An A-L stable 4th order SDIRK method.", @@ -814,17 +868,20 @@ struct Hairer42{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + autodiff::AD end -function Hairer42(; chunk_size = Val{0}(), autodiff = Val{true}(), +function Hairer42(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI) - Hairer42{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Hairer42{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring("An A-L stable stiffly-accurate 4th order ESDIRK method.", @@ -859,17 +916,20 @@ struct Kvaerno4{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function Kvaerno4(; chunk_size = Val{0}(), autodiff = Val{true}(), +function Kvaerno4(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - Kvaerno4{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Kvaerno4{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end @doc SDIRK_docstring("An A-L stable stiffly-accurate 5th order ESDIRK method.", @@ -904,21 +964,24 @@ struct Kvaerno5{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function Kvaerno5(; chunk_size = Val{0}(), autodiff = Val{true}(), +function Kvaerno5(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - Kvaerno5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + Kvaerno5{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end @doc SDIRK_docstring( - "An A-L stable stiffly-accurate 4th order ESDIRK method with splitting.", + "An A-L stable stiffly-accurate 4th order ESDIRK method with splitting. Includes splitting capabilities. Recommended for medium tolerance stiff problems (>1e-8).", "KenCarp4"; references = "@book{kennedy2001additive, title={Additive Runge-Kutta schemes for convection-diffusion-reaction equations}, @@ -946,20 +1009,23 @@ struct KenCarp4{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function KenCarp4(; chunk_size = Val{0}(), autodiff = Val{true}(), +function KenCarp4(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - KenCarp4{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + KenCarp4{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end -TruncatedStacktraces.@truncate_stacktrace KenCarp4 +@truncate_stacktrace KenCarp4 @doc SDIRK_docstring( "An A-L stable stiffly-accurate 4th order seven-stage ESDIRK method with splitting.", @@ -990,17 +1056,20 @@ struct KenCarp47{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + autodiff::AD end -function KenCarp47(; chunk_size = Val{0}(), autodiff = Val{true}(), +function KenCarp47(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI) - KenCarp47{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + KenCarp47{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring( @@ -1032,17 +1101,20 @@ struct KenCarp5{CS, AD, F, F2, P, FDT, ST, CJ, StepLimiter} <: extrapolant::Symbol controller::Symbol step_limiter!::StepLimiter + autodiff::AD end -function KenCarp5(; chunk_size = Val{0}(), autodiff = Val{true}(), +function KenCarp5(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI, step_limiter! = trivial_limiter!) - KenCarp5{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + KenCarp5{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(step_limiter!)}(linsolve, nlsolve, precs, - smooth_est, extrapolant, controller, step_limiter!) + smooth_est, extrapolant, controller, step_limiter!, AD_choice) end @doc SDIRK_docstring( @@ -1074,17 +1146,20 @@ struct KenCarp58{CS, AD, F, F2, P, FDT, ST, CJ} <: smooth_est::Bool extrapolant::Symbol controller::Symbol + autodiff::AD end -function KenCarp58(; chunk_size = Val{0}(), autodiff = Val{true}(), +function KenCarp58(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), smooth_est = true, extrapolant = :linear, controller = :PI) - KenCarp58{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + KenCarp58{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, smooth_est, extrapolant, - controller) + controller, AD_choice) end # `smooth_est` is not necessary, as the embedded method is also L-stable @@ -1116,16 +1191,19 @@ struct ESDIRK54I8L2SA{CS, AD, F, F2, P, FDT, ST, CJ} <: precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end -function ESDIRK54I8L2SA(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ESDIRK54I8L2SA(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI) - ESDIRK54I8L2SA{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ESDIRK54I8L2SA{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring( @@ -1156,16 +1234,19 @@ struct ESDIRK436L2SA2{CS, AD, F, F2, P, FDT, ST, CJ} <: precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end -function ESDIRK436L2SA2(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ESDIRK436L2SA2(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI) - ESDIRK436L2SA2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ESDIRK436L2SA2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring( @@ -1196,16 +1277,19 @@ struct ESDIRK437L2SA{CS, AD, F, F2, P, FDT, ST, CJ} <: precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end -function ESDIRK437L2SA(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ESDIRK437L2SA(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI) - ESDIRK437L2SA{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ESDIRK437L2SA{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring( @@ -1236,16 +1320,19 @@ struct ESDIRK547L2SA2{CS, AD, F, F2, P, FDT, ST, CJ} <: precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end -function ESDIRK547L2SA2(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ESDIRK547L2SA2(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI) - ESDIRK547L2SA2{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ESDIRK547L2SA2{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, AD_choice) end @doc SDIRK_docstring( @@ -1278,14 +1365,17 @@ struct ESDIRK659L2SA{CS, AD, F, F2, P, FDT, ST, CJ} <: precs::P extrapolant::Symbol controller::Symbol + autodiff::AD end -function ESDIRK659L2SA(; chunk_size = Val{0}(), autodiff = Val{true}(), +function ESDIRK659L2SA(; chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), concrete_jac = nothing, - diff_type = Val{:forward}, + diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), extrapolant = :linear, controller = :PI) - ESDIRK659L2SA{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + ESDIRK659L2SA{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac)}(linsolve, nlsolve, precs, extrapolant, - controller) + controller, AD_choice) end diff --git a/lib/OrdinaryDiffEqSDIRK/src/kencarp_kvaerno_caches.jl b/lib/OrdinaryDiffEqSDIRK/src/kencarp_kvaerno_caches.jl index a122c5fee0..4a09a83fed 100644 --- a/lib/OrdinaryDiffEqSDIRK/src/kencarp_kvaerno_caches.jl +++ b/lib/OrdinaryDiffEqSDIRK/src/kencarp_kvaerno_caches.jl @@ -275,7 +275,7 @@ end step_limiter!::StepLimiter end -TruncatedStacktraces.@truncate_stacktrace KenCarp4Cache 1 +@truncate_stacktrace KenCarp4Cache 1 function alg_cache(alg::KenCarp4, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, @@ -507,7 +507,7 @@ end nlsolver::N tab::Tab end -TruncatedStacktraces.@truncate_stacktrace KenCarp47Cache 1 +@truncate_stacktrace KenCarp47Cache 1 function alg_cache(alg::KenCarp47, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, @@ -594,7 +594,7 @@ end tab::Tab end -TruncatedStacktraces.@truncate_stacktrace KenCarp58Cache 1 +@truncate_stacktrace KenCarp58Cache 1 function alg_cache(alg::KenCarp58, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, diff --git a/lib/OrdinaryDiffEqSDIRK/test/jet.jl b/lib/OrdinaryDiffEqSDIRK/test/jet.jl new file mode 100644 index 0000000000..673efe2f7e --- /dev/null +++ b/lib/OrdinaryDiffEqSDIRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqSDIRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqSDIRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqSDIRK/test/qa.jl b/lib/OrdinaryDiffEqSDIRK/test/qa.jl new file mode 100644 index 0000000000..a1f9176802 --- /dev/null +++ b/lib/OrdinaryDiffEqSDIRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqSDIRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqSDIRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSDIRK/test/runtests.jl b/lib/OrdinaryDiffEqSDIRK/test/runtests.jl index 8b13789179..f971e6442f 100644 --- a/lib/OrdinaryDiffEqSDIRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqSDIRK/test/runtests.jl @@ -1 +1,4 @@ +using SafeTestsets +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSDIRK/test/sdirk_convergence_tests.jl b/lib/OrdinaryDiffEqSDIRK/test/sdirk_convergence_tests.jl index 4e9cd86216..884e8bc7f3 100644 --- a/lib/OrdinaryDiffEqSDIRK/test/sdirk_convergence_tests.jl +++ b/lib/OrdinaryDiffEqSDIRK/test/sdirk_convergence_tests.jl @@ -1,5 +1,5 @@ # This definitely needs cleaning -using OrdinaryDiffEqSDIRK, ODEProblemLibrary, DiffEqDevTools +using OrdinaryDiffEqSDIRK, ODEProblemLibrary, DiffEqDevTools, ADTypes using Test, Random Random.seed!(100) @@ -56,7 +56,7 @@ testTol = 0.2 sim14 = test_convergence(dts, prob, TRBDF2()) @test sim14.𝒪est[:final]≈2 atol=testTol - sim152 = test_convergence(dts, prob, TRBDF2(autodiff = false)) + sim152 = test_convergence(dts, prob, TRBDF2(autodiff = AutoFiniteDiff())) @test sim152.𝒪est[:final]≈2 atol=testTol + 0.1 sim15 = test_convergence(dts, prob, SDIRK2()) diff --git a/lib/OrdinaryDiffEqSIMDRK/LICENSE.md b/lib/OrdinaryDiffEqSIMDRK/LICENSE.md new file mode 100644 index 0000000000..1cda4ddaa6 --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Yingbo Ma and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/OrdinaryDiffEqSIMDRK/Project.toml b/lib/OrdinaryDiffEqSIMDRK/Project.toml new file mode 100644 index 0000000000..f3b772286a --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/Project.toml @@ -0,0 +1,39 @@ +name = "OrdinaryDiffEqSIMDRK" +uuid = "dc97f408-7a72-40e4-9b0d-228a53b292f8" +authors = ["Yingbo Ma ", "Chris Elrod "] +version = "1.1.0" + +[deps] +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +VectorizationBase = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +SLEEFPirates = "476501e8-09a2-5ece-8869-fb82de89a1fa" +MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" + +[extras] +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" + +[compat] +Test = "1" +DiffEqDevTools = "2.44" +MuladdMacro = "0.2" +OrdinaryDiffEqCore = "1.29.0" +Static = "0.7, 0.8, 1" +SLEEFPirates = "0.6" +VectorizationBase = "0.21" +StaticArrays = "1.9" +julia = "1.10" +UnPack = "1" +SafeTestsets = "0.1" +Reexport = "1" + +[targets] +test = ["DiffEqDevTools", "SafeTestsets", "StaticArrays", "Test"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqSIMDRK/src/OrdinaryDiffEqSIMDRK.jl b/lib/OrdinaryDiffEqSIMDRK/src/OrdinaryDiffEqSIMDRK.jl new file mode 100644 index 0000000000..61aa991d78 --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/src/OrdinaryDiffEqSIMDRK.jl @@ -0,0 +1,17 @@ +module OrdinaryDiffEqSIMDRK + +using MuladdMacro, UnPack, Static +using OrdinaryDiffEqCore: OrdinaryDiffEqAdaptiveAlgorithm, OrdinaryDiffEqConstantCache, + trivial_limiter!, calculate_residuals, constvalue +import OrdinaryDiffEqCore: initialize!, perform_step!, alg_cache + +using Reexport: @reexport +@reexport using OrdinaryDiffEqCore + +include("algorithms.jl") +include("caches.jl") +include("perform_step.jl") + +export MER5v2, MER6v2, RK6v4 + +end diff --git a/lib/OrdinaryDiffEqSIMDRK/src/algorithms.jl b/lib/OrdinaryDiffEqSIMDRK/src/algorithms.jl new file mode 100644 index 0000000000..b70b186aef --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/src/algorithms.jl @@ -0,0 +1,66 @@ +struct MER5v2{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function MER5v2(; stage_limiter! = trivial_limiter!, step_limiter! = trivial_limiter!, + thread = False()) + MER5v2{typeof(stage_limiter!), typeof(step_limiter!), typeof(thread)}(stage_limiter!, + step_limiter!, + thread) +end + +# for backwards compatibility +function MER5v2(stage_limiter!, step_limiter! = trivial_limiter!) + MER5v2{typeof(stage_limiter!), typeof(step_limiter!), False}(stage_limiter!, + step_limiter!, False()) +end + +struct MER6v2{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function MER6v2(; stage_limiter! = trivial_limiter!, step_limiter! = trivial_limiter!, + thread = False()) + MER6v2{typeof(stage_limiter!), typeof(step_limiter!), typeof(thread)}(stage_limiter!, + step_limiter!, + thread) +end + +# for backwards compatibility +function MER6v2(stage_limiter!, step_limiter! = trivial_limiter!) + MER6v2{typeof(stage_limiter!), typeof(step_limiter!), False}(stage_limiter!, + step_limiter!, False()) +end + +struct RK6v4{StageLimiter, StepLimiter, Thread} <: OrdinaryDiffEqAdaptiveAlgorithm + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function RK6v4(; stage_limiter! = trivial_limiter!, step_limiter! = trivial_limiter!, + thread = False()) + RK6v4{typeof(stage_limiter!), typeof(step_limiter!), typeof(thread)}(stage_limiter!, + step_limiter!, + thread) +end + +# for backwards compatibility +function RK6v4(stage_limiter!, step_limiter! = trivial_limiter!) + RK6v4{typeof(stage_limiter!), typeof(step_limiter!), False}(stage_limiter!, + step_limiter!, False()) +end + +function Base.show(io::IO, alg::Union{MER5v2, MER6v2, RK6v4}) + print(io, "$(nameof(typeof(alg)))(stage_limiter! = ", alg.stage_limiter!, + ", step_limiter! = ", alg.step_limiter!, + ", thread = ", alg.thread, ")") +end + +OrdinaryDiffEqCore.alg_order(alg::MER5v2) = 5 +OrdinaryDiffEqCore.alg_order(alg::MER6v2) = 6 +OrdinaryDiffEqCore.alg_order(alg::RK6v4) = 6 diff --git a/lib/OrdinaryDiffEqSIMDRK/src/caches.jl b/lib/OrdinaryDiffEqSIMDRK/src/caches.jl new file mode 100644 index 0000000000..82eb59633d --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/src/caches.jl @@ -0,0 +1,1079 @@ +struct MER5v2ConstantCache{T, T2} <: OrdinaryDiffEqConstantCache + # c + c_2::T2 + c_3::T2 + c_4::T2 + c_5::T2 + c_6::T2 + c_7::T2 + c_8::T2 + c_9::T2 + c_10::T2 + c_11::T2 + c_12::T2 + c_13::T2 + c_14::T2 + # A + a2_1::T + a3_1::T + a4_1::T + a5_1::T + a6_1::T + a7_1::T + a8_1::T + a9_1::T + a10_1::T + a11_1::T + a12_1::T + a13_1::T + a14_1::T + a4_2::T + a5_2::T + a6_2::T + a7_2::T + a8_2::T + a9_2::T + a10_2::T + a11_2::T + a12_2::T + a13_2::T + a14_2::T + a4_3::T + a5_3::T + a6_3::T + a7_3::T + a8_3::T + a9_3::T + a10_3::T + a11_3::T + a12_3::T + a13_3::T + a14_3::T + a6_4::T + a7_4::T + a8_4::T + a9_4::T + a10_4::T + a11_4::T + a12_4::T + a13_4::T + a14_4::T + a6_5::T + a7_5::T + a8_5::T + a9_5::T + a10_5::T + a11_5::T + a12_5::T + a13_5::T + a14_5::T + a8_6::T + a9_6::T + a10_6::T + a11_6::T + a12_6::T + a13_6::T + a14_6::T + a8_7::T + a9_7::T + a10_7::T + a11_7::T + a12_7::T + a13_7::T + a14_7::T + a10_8::T + a11_8::T + a12_8::T + a13_8::T + a14_8::T + a10_9::T + a11_9::T + a12_9::T + a13_9::T + a14_9::T + a12_10::T + a13_10::T + a14_10::T + a12_11::T + a13_11::T + a14_11::T + a14_12::T + a14_13::T + # b + btilde_1::T + btilde_2::T + btilde_3::T + btilde_4::T + btilde_5::T + btilde_6::T + btilde_7::T + btilde_8::T + btilde_9::T + btilde_10::T + btilde_11::T + btilde_12::T + btilde_13::T + btilde_14::T +end + +function MER5v2ConstantCache(::Type{T}, ::Type{T2}) where {T, T2} + c_2 = convert(T2, 0.022035024212176273) + c_3 = convert(T2, 0.02183493589050961) + c_4 = convert(T2, 0.15206330970144885) + c_5 = convert(T2, 0.08602170049475083) + c_6 = convert(T2, 0.23762227289419663) + c_7 = convert(T2, 0.3116060240081402) + c_8 = convert(T2, 0.37608190234821093) + c_9 = convert(T2, 0.5407723187279103) + c_10 = convert(T2, 0.6720526511643818) + c_11 = convert(T2, 0.6301883494613333) + c_12 = convert(T2, 0.5559779749224847) + c_13 = convert(T2, 0.8560602864167693) + c_14 = convert(T2, 0.9999999999999998) + a2_1 = convert(T, 0.022035024212176273) + a3_1 = convert(T, 0.02183493589050961) + a4_1 = convert(T, -0.34872816866757517) + a5_1 = convert(T, -0.08278958817912686) + a6_1 = convert(T, 0.14751387924336015) + a7_1 = convert(T, 0.10415324644013943) + a8_1 = convert(T, 0.16525173038472643) + a9_1 = convert(T, 0.27362109639339016) + a10_1 = convert(T, 0.04895847627716312) + a11_1 = convert(T, 0.03761353274951909) + a12_1 = convert(T, -0.040236484584306995) + a13_1 = convert(T, -0.13444291776867823) + a14_1 = convert(T, 0.0020417383068140394) + a4_2 = convert(T, 0.24020895942224316) + a5_2 = convert(T, 0.11957422836029977) + a6_2 = convert(T, -0.061993457194008124) + a7_2 = convert(T, -0.02631417421394259) + a8_2 = convert(T, -0.015500424184182592) + a9_2 = convert(T, -0.010096715159337981) + a10_2 = convert(T, 0.05549882369147236) + a11_2 = convert(T, -0.028031232720422364) + a12_2 = convert(T, 0.00220391728915983) + a13_2 = convert(T, 0.048670268860820806) + a14_2 = convert(T, -0.028528128108588024) + a4_3 = convert(T, 0.26058251894678086) + a5_3 = convert(T, 0.04923706031357792) + a6_3 = convert(T, -0.08586430248304122) + a7_3 = convert(T, -0.04087529433177786) + a8_3 = convert(T, -0.04970341851251567) + a9_3 = convert(T, 0.011606282619919847) + a10_3 = convert(T, 0.03371154290450168) + a11_3 = convert(T, -0.04192378872076009) + a12_3 = convert(T, 0.05301541772368528) + a13_3 = convert(T, 0.09544838944443924) + a14_3 = convert(T, -0.07796073180093377) + a6_4 = convert(T, 0.16704850704055443) + a7_4 = convert(T, 0.39037577397188017) + a8_4 = convert(T, -0.18632008115387888) + a9_4 = convert(T, -0.15681076020067763) + a10_4 = convert(T, 0.02190160196168485) + a11_4 = convert(T, -0.01181103246843162) + a12_4 = convert(T, 0.01611257442681573) + a13_4 = convert(T, -0.008005093363599084) + a14_4 = convert(T, 0.14862796222876595) + a6_5 = convert(T, 0.07091764628733137) + a7_5 = convert(T, -0.11573352785815892) + a8_5 = convert(T, 0.04420661272062375) + a9_5 = convert(T, -0.21126162831372586) + a10_5 = convert(T, 0.004233539425382651) + a11_5 = convert(T, 0.18547421190538863) + a12_5 = convert(T, 0.07487649225425254) + a13_5 = convert(T, 0.17695715010153226) + a14_5 = convert(T, 0.3580044925051681) + a8_6 = convert(T, 0.4554275503641829) + a9_6 = convert(T, 0.12844483994757958) + a10_6 = convert(T, 0.03830831741556788) + a11_6 = convert(T, 0.27021146786585304) + a12_6 = convert(T, 0.20543358183433777) + a13_6 = convert(T, 0.22450760788172397) + a14_6 = convert(T, -0.16854477771456608) + a8_7 = convert(T, -0.03728006727074501) + a9_7 = convert(T, 0.5052692034407622) + a10_7 = convert(T, -0.007800022793209964) + a11_7 = convert(T, -0.019097539937169) + a12_7 = convert(T, 0.09193600638823755) + a13_7 = convert(T, -0.08478741516544007) + a14_7 = convert(T, -0.18998185326189743) + a10_8 = convert(T, 0.27097241452217663) + a11_8 = convert(T, 0.0057429749421095) + a12_8 = convert(T, 0.20401465889577416) + a13_8 = convert(T, 0.17269907813077384) + a14_8 = convert(T, 0.29568833942502715) + a10_9 = convert(T, 0.20626795775964266) + a11_9 = convert(T, 0.2320097558452461) + a12_9 = convert(T, -0.16970313663025158) + a13_9 = convert(T, -0.12436417901182058) + a14_9 = convert(T, 0.40500880406992096) + a12_10 = convert(T, 0.1816011564866453) + a13_10 = convert(T, 0.3877495277324938) + a14_10 = convert(T, -0.2922672128367844) + a12_11 = convert(T, -0.06327620916186488) + a13_11 = convert(T, 0.10162786957452331) + a14_11 = convert(T, -0.15880367266753806) + a14_12 = convert(T, 0.3016929890600716) + a14_13 = convert(T, 0.40502205079453996) + btilde_1 = convert(T, 0.005225178651642811) + btilde_2 = convert(T, -0.0009511505334318555) + btilde_3 = convert(T, 0.015837213098359046) + btilde_4 = convert(T, 0.02567038436729195) + btilde_5 = convert(T, -0.006942528114386226) + btilde_6 = convert(T, -0.09368279988183577) + btilde_7 = convert(T, -0.09858638196688309) + btilde_8 = convert(T, 0.08955215288742663) + btilde_9 = convert(T, 0.3730875719960025) + btilde_10 = convert(T, -0.4333412209789405) + btilde_11 = convert(T, -0.24864311531038702) + btilde_12 = convert(T, 0.15118141529529247) + btilde_13 = convert(T, 0.3043705741223895) + btilde_14 = convert(T, -0.0827772936325406) + MER5v2ConstantCache(c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, + c_14, a2_1, a3_1, + a4_1, a5_1, a6_1, a7_1, a8_1, a9_1, a10_1, a11_1, a12_1, a13_1, + a14_1, a4_2, a5_2, a6_2, a7_2, a8_2, a9_2, a10_2, a11_2, a12_2, + a13_2, a14_2, a4_3, a5_3, a6_3, a7_3, a8_3, a9_3, a10_3, a11_3, + a12_3, a13_3, a14_3, a6_4, a7_4, a8_4, a9_4, a10_4, a11_4, a12_4, + a13_4, a14_4, a6_5, a7_5, a8_5, a9_5, a10_5, a11_5, a12_5, a13_5, + a14_5, a8_6, a9_6, a10_6, a11_6, a12_6, a13_6, a14_6, a8_7, a9_7, + a10_7, a11_7, a12_7, a13_7, a14_7, a10_8, a11_8, a12_8, a13_8, + a14_8, a10_9, a11_9, a12_9, a13_9, a14_9, a12_10, a13_10, a14_10, + a12_11, a13_11, a14_11, a14_12, a14_13, btilde_1, btilde_2, + btilde_3, + btilde_4, btilde_5, btilde_6, btilde_7, btilde_8, btilde_9, + btilde_10, + btilde_11, btilde_12, btilde_13, btilde_14) +end + +function alg_cache(alg::MER5v2, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + MER5v2ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) +end + +struct MER6v2ConstantCache{T, T2} <: OrdinaryDiffEqConstantCache + # c + c_2::T2 + c_3::T2 + c_4::T2 + c_5::T2 + c_6::T2 + c_7::T2 + c_8::T2 + c_9::T2 + c_10::T2 + c_11::T2 + c_12::T2 + c_13::T2 + c_14::T2 + c_15::T2 + # A + a2_1::T + a3_1::T + a4_1::T + a5_1::T + a6_1::T + a7_1::T + a8_1::T + a9_1::T + a10_1::T + a11_1::T + a12_1::T + a13_1::T + a14_1::T + a15_1::T + a4_2::T + a5_2::T + a6_2::T + a7_2::T + a8_2::T + a9_2::T + a10_2::T + a11_2::T + a12_2::T + a13_2::T + a14_2::T + a15_2::T + a4_3::T + a5_3::T + a6_3::T + a7_3::T + a8_3::T + a9_3::T + a10_3::T + a11_3::T + a12_3::T + a13_3::T + a14_3::T + a15_3::T + a6_4::T + a7_4::T + a8_4::T + a9_4::T + a10_4::T + a11_4::T + a12_4::T + a13_4::T + a14_4::T + a15_4::T + a6_5::T + a7_5::T + a8_5::T + a9_5::T + a10_5::T + a11_5::T + a12_5::T + a13_5::T + a14_5::T + a15_5::T + a8_6::T + a9_6::T + a10_6::T + a11_6::T + a12_6::T + a13_6::T + a14_6::T + a15_6::T + a8_7::T + a9_7::T + a10_7::T + a11_7::T + a12_7::T + a13_7::T + a14_7::T + a15_7::T + a10_8::T + a11_8::T + a12_8::T + a13_8::T + a14_8::T + a15_8::T + a10_9::T + a11_9::T + a12_9::T + a13_9::T + a14_9::T + a15_9::T + a12_10::T + a13_10::T + a14_10::T + a15_10::T + a12_11::T + a13_11::T + a14_11::T + a15_11::T + a14_12::T + a15_12::T + a14_13::T + a15_13::T + a15_14::T + # b + btilde_1::T + btilde_2::T + btilde_3::T + btilde_4::T + btilde_5::T + btilde_6::T + btilde_7::T + btilde_8::T + btilde_9::T + btilde_10::T + btilde_11::T + btilde_12::T + btilde_13::T + btilde_14::T +end + +function MER6v2ConstantCache(::Type{T}, ::Type{T2}) where {T, T2} + c_2 = convert(T2, 0.5618371230110049) + c_3 = convert(T2, 0.41873880739833325) + c_4 = convert(T2, 1.0706464563553708) + c_5 = convert(T2, 0.5156334990774533) + c_6 = convert(T2, 0.3434060471574239) + c_7 = convert(T2, 0.2768352448156825) + c_8 = convert(T2, 2.7067181171119983) + c_9 = convert(T2, 1.9005644353590094) + c_10 = convert(T2, 3.985568688595518) + c_11 = convert(T2, 2.228318841957389) + c_12 = convert(T2, 3.5912319588196766) + c_13 = convert(T2, 1.632340214366898) + c_14 = convert(T2, 1.555997589666406) + c_15 = convert(T2, 1.0000000000000004) + a2_1 = convert(T, 0.5618371230110049) + a3_1 = convert(T, 0.41873880739833325) + a4_1 = convert(T, -0.023156154972968034) + a5_1 = convert(T, 0.20790105055264566) + a6_1 = convert(T, 0.11847742998481563) + a7_1 = convert(T, 0.041856122155026425) + a8_1 = convert(T, 0.19063895184431479) + a9_1 = convert(T, 0.199538501692946) + a10_1 = convert(T, 0.594937206698603) + a11_1 = convert(T, 0.015803974965114164) + a12_1 = convert(T, 0.5996532528160414) + a13_1 = convert(T, 0.1400231459198727) + a14_1 = convert(T, 0.6831945911700997) + a15_1 = convert(T, 0.052884284243789305) + a4_2 = convert(T, 0.8245888349401788) + a5_2 = convert(T, -0.23887508255626488) + a6_2 = convert(T, -0.08260352591397041) + a7_2 = convert(T, -0.07910947322795268) + a8_2 = convert(T, 0.4176361353512002) + a9_2 = convert(T, 0.4626780563869126) + a10_2 = convert(T, 0.40154805724697873) + a11_2 = convert(T, 0.33678307374269706) + a12_2 = convert(T, 0.11246876587589483) + a13_2 = convert(T, 0.5106830223792441) + a14_2 = convert(T, 0.587754066671698) + a15_2 = convert(T, 0.38087692603094825) + a4_3 = convert(T, 0.26921377638816013) + a5_3 = convert(T, 0.5466075310810725) + a6_3 = convert(T, -0.006702748083814442) + a7_3 = convert(T, -0.1341221650098721) + a8_3 = convert(T, 0.33354075293955776) + a9_3 = convert(T, 0.28987602723952177) + a10_3 = convert(T, 0.1773473916860493) + a11_3 = convert(T, 0.3919253951355974) + a12_3 = convert(T, 0.20294860579794305) + a13_3 = convert(T, 0.08487102270703568) + a14_3 = convert(T, -0.09320741292588441) + a15_3 = convert(T, -0.1855046068718844) + a6_4 = convert(T, 0.11533941662667324) + a7_4 = convert(T, 0.01774545793953934) + a8_4 = convert(T, 0.5772924785073215) + a9_4 = convert(T, -0.11013996604678691) + a10_4 = convert(T, 0.5195399130448001) + a11_4 = convert(T, 0.24661267751728533) + a12_4 = convert(T, 0.6359293174901519) + a13_4 = convert(T, 0.3703219046298364) + a14_4 = convert(T, 0.16588889277229463) + a15_4 = convert(T, 0.028795326728474752) + a6_5 = convert(T, 0.1988954745437199) + a7_5 = convert(T, 0.43046530295894153) + a8_5 = convert(T, 0.8065807452826913) + a9_5 = convert(T, 0.33944968554180893) + a10_5 = convert(T, 0.2012897768838808) + a11_5 = convert(T, 0.6807074338552666) + a12_5 = convert(T, -0.03985096319920651) + a13_5 = convert(T, 0.37378501866388725) + a14_5 = convert(T, 0.35689989244692694) + a15_5 = convert(T, 0.27809006959208027) + a8_6 = convert(T, 0.3517150920546806) + a9_6 = convert(T, 0.18211326519070686) + a10_6 = convert(T, 0.9136194110499816) + a11_6 = convert(T, 0.4985067668584649) + a12_6 = convert(T, 0.39473312965805696) + a13_6 = convert(T, -0.08289530800419284) + a14_6 = convert(T, -0.1844814087611568) + a15_6 = convert(T, -0.20832438263807776) + a8_7 = convert(T, 0.02931396113223214) + a9_7 = convert(T, 0.5370488653539002) + a10_7 = convert(T, 0.6490325604909627) + a11_7 = convert(T, 0.07718632625920896) + a12_7 = convert(T, 0.5624252955056123) + a13_7 = convert(T, 0.3577558066315745) + a14_7 = convert(T, 0.17545047788536908) + a15_7 = convert(T, 0.5793254860448434) + a10_8 = convert(T, 0.06326946277384538) + a11_8 = convert(T, 0.018093498008754094) + a12_8 = convert(T, -0.03674656788020389) + a13_8 = convert(T, -0.1915202087332636) + a14_8 = convert(T, -0.15870729901954) + a15_8 = convert(T, 0.11347299937998527) + a10_9 = convert(T, 0.4649849087204166) + a11_9 = convert(T, -0.03730030438499948) + a12_9 = convert(T, 0.2741384642923106) + a13_9 = convert(T, -0.18405474921390433) + a14_9 = convert(T, -0.10272101825544767) + a15_9 = convert(T, 0.33555152457207227) + a12_10 = convert(T, 0.3027242249667686) + a13_10 = convert(T, 0.044370168025061454) + a14_10 = convert(T, 0.046250639585125576) + a15_10 = convert(T, -0.0033046253600586615) + a12_11 = convert(T, 0.5828084334963066) + a13_11 = convert(T, 0.20900039136174695) + a14_11 = convert(T, 0.064930263814702) + a15_11 = convert(T, -0.4230368376554586) + a14_12 = convert(T, 0.0007800382557257173) + a15_12 = convert(T, 0.0006804408448763735) + a14_13 = convert(T, 0.013965866026493252) + a15_13 = convert(T, 0.4004444438278627) + a15_14 = convert(T, -0.3499510487394529) + + btilde_1 = convert(T, -0.00039990967957576756) + btilde_2 = convert(T, 0.0019257459051852388) + btilde_3 = convert(T, -0.0024198113556601064) + btilde_4 = convert(T, -1.5645331830071996e-5) + btilde_5 = convert(T, -0.00015795164210913315) + btilde_6 = convert(T, -0.0005925919225022169) + btilde_7 = convert(T, 0.0020058853925406517) + btilde_8 = convert(T, -0.0017567943358209603) + btilde_9 = convert(T, -0.002975844021821772) + btilde_10 = convert(T, 8.620310650502222e-5) + btilde_11 = convert(T, 0.004890293749583774) + btilde_12 = convert(T, -1.5902737477948865e-5) + btilde_13 = convert(T, -0.002650053713821432) + btilde_14 = convert(T, 0.002076376586804707) + MER6v2ConstantCache(c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, + c_14, c_15, a2_1, a3_1, + a4_1, a5_1, a6_1, a7_1, a8_1, a9_1, a10_1, a11_1, a12_1, a13_1, + a14_1, a15_1, a4_2, a5_2, a6_2, a7_2, a8_2, a9_2, a10_2, a11_2, a12_2, + a13_2, a14_2, a15_2, a4_3, a5_3, a6_3, a7_3, a8_3, a9_3, a10_3, a11_3, + a12_3, a13_3, a14_3, a15_3, a6_4, a7_4, a8_4, a9_4, a10_4, a11_4, a12_4, + a13_4, a14_4, a15_4, a6_5, a7_5, a8_5, a9_5, a10_5, a11_5, a12_5, a13_5, + a14_5, a15_5, a8_6, a9_6, a10_6, a11_6, a12_6, a13_6, a14_6, a15_6, a8_7, a9_7, + a10_7, a11_7, a12_7, a13_7, a14_7, a15_7, a10_8, a11_8, a12_8, a13_8, + a14_8, a15_8, a10_9, a11_9, a12_9, a13_9, a14_9, a15_9, a12_10, a13_10, a14_10, a15_10, + a12_11, a13_11, a14_11, a15_11, a14_12, a15_12, a14_13, a15_13, a15_14, btilde_1, btilde_2, + btilde_3, + btilde_4, btilde_5, btilde_6, btilde_7, btilde_8, btilde_9, + btilde_10, + btilde_11, btilde_12, btilde_13, btilde_14) +end + +function alg_cache(alg::MER6v2, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + MER6v2ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) +end + +struct RK6v4ConstantCache{T, T2} <: OrdinaryDiffEqConstantCache + # c + c_2::T2 + c_3::T2 + c_4::T2 + c_5::T2 + c_6::T2 + c_7::T2 + c_8::T2 + c_9::T2 + c_10::T2 + c_11::T2 + c_12::T2 + c_13::T2 + c_14::T2 + c_15::T2 + c_16::T2 + c_17::T2 + c_18::T2 + c_19::T2 + c_20::T2 + c_21::T2 + c_22::T2 + # A + a2_1::T + a3_1::T + a4_1::T + a5_1::T + a6_1::T + a7_1::T + a8_1::T + a9_1::T + a10_1::T + a11_1::T + a12_1::T + a13_1::T + a14_1::T + a15_1::T + a16_1::T + a17_1::T + a18_1::T + a19_1::T + a20_1::T + a21_1::T + a22_1::T + a6_2::T + a7_2::T + a8_2::T + a9_2::T + a10_2::T + a11_2::T + a12_2::T + a13_2::T + a14_2::T + a15_2::T + a16_2::T + a17_2::T + a18_2::T + a19_2::T + a20_2::T + a21_2::T + a22_2::T + a6_3::T + a7_3::T + a8_3::T + a9_3::T + a10_3::T + a11_3::T + a12_3::T + a13_3::T + a14_3::T + a15_3::T + a16_3::T + a17_3::T + a18_3::T + a19_3::T + a20_3::T + a21_3::T + a22_3::T + a6_4::T + a7_4::T + a8_4::T + a9_4::T + a10_4::T + a11_4::T + a12_4::T + a13_4::T + a14_4::T + a15_4::T + a16_4::T + a17_4::T + a18_4::T + a19_4::T + a20_4::T + a21_4::T + a22_4::T + a6_5::T + a7_5::T + a8_5::T + a9_5::T + a10_5::T + a11_5::T + a12_5::T + a13_5::T + a14_5::T + a15_5::T + a16_5::T + a17_5::T + a18_5::T + a19_5::T + a20_5::T + a21_5::T + a22_5::T + a10_6::T + a11_6::T + a12_6::T + a13_6::T + a14_6::T + a15_6::T + a16_6::T + a17_6::T + a18_6::T + a19_6::T + a20_6::T + a21_6::T + a22_6::T + a10_7::T + a11_7::T + a12_7::T + a13_7::T + a14_7::T + a15_7::T + a16_7::T + a17_7::T + a18_7::T + a19_7::T + a20_7::T + a21_7::T + a22_7::T + a10_8::T + a11_8::T + a12_8::T + a13_8::T + a14_8::T + a15_8::T + a16_8::T + a17_8::T + a18_8::T + a19_8::T + a20_8::T + a21_8::T + a22_8::T + a10_9::T + a11_9::T + a12_9::T + a13_9::T + a14_9::T + a15_9::T + a16_9::T + a17_9::T + a18_9::T + a19_9::T + a20_9::T + a21_9::T + a22_9::T + a14_10::T + a15_10::T + a16_10::T + a17_10::T + a18_10::T + a19_10::T + a20_10::T + a21_10::T + a22_10::T + a14_11::T + a15_11::T + a16_11::T + a17_11::T + a18_11::T + a19_11::T + a20_11::T + a21_11::T + a22_11::T + a14_12::T + a15_12::T + a16_12::T + a17_12::T + a18_12::T + a19_12::T + a20_12::T + a21_12::T + a22_12::T + a14_13::T + a15_13::T + a16_13::T + a17_13::T + a18_13::T + a19_13::T + a20_13::T + a21_13::T + a22_13::T + a18_14::T + a19_14::T + a20_14::T + a21_14::T + a22_14::T + a18_15::T + a19_15::T + a20_15::T + a21_15::T + a22_15::T + a18_16::T + a19_16::T + a20_16::T + a21_16::T + a22_16::T + a18_17::T + a19_17::T + a20_17::T + a21_17::T + a22_17::T + a22_18::T + a22_19::T + a22_20::T + a22_21::T + # b + btilde_1::T + btilde_2::T + btilde_3::T + btilde_4::T + btilde_5::T + btilde_6::T + btilde_7::T + btilde_8::T + btilde_9::T + btilde_10::T + btilde_11::T + btilde_12::T + btilde_13::T + btilde_14::T + btilde_15::T + btilde_16::T + btilde_17::T + btilde_18::T + btilde_19::T + btilde_20::T + btilde_21::T +end + +function RK6v4ConstantCache(::Type{T}, ::Type{T2}) where {T, T2} + c_2 = convert(T2, -0.01316628173802263) + c_3 = convert(T2, 0.029375102606949633) + c_4 = convert(T2, 0.20294613239190776) + c_5 = convert(T2, 0.07132670027594948) + c_6 = convert(T2, 0.4592612576138006) + c_7 = convert(T2, 0.21122259962971446) + c_8 = convert(T2, 0.5505890113599897) + c_9 = convert(T2, 0.1655041019929412) + c_10 = convert(T2, 1.4583270569555153) + c_11 = convert(T2, 0.6162690648422273) + c_12 = convert(T2, 0.4871785725712332) + c_13 = convert(T2, 0.42487104910924) + c_14 = convert(T2, 1.6235001967365756) + c_15 = convert(T2, 1.7075488829740677) + c_16 = convert(T2, 0.8115482501003524) + c_17 = convert(T2, 0.8802147564524915) + c_18 = convert(T2, 2.456018926067793) + c_19 = convert(T2, 0.9575105507600276) + c_20 = convert(T2, 1.1241323299052959) + c_21 = convert(T2, 1.136108500097182) + c_22 = convert(T2, 1.0) + # A + a2_1 = convert(T, -0.01316628173802263) + a3_1 = convert(T, 0.029375102606949633) + a4_1 = convert(T, 0.20294613239190776) + a5_1 = convert(T, 0.07132670027594948) + a6_1 = convert(T, -0.48248210888167825) + a7_1 = convert(T, -0.6178491616218171) + a8_1 = convert(T, 0.3903050468644291) + a9_1 = convert(T, 0.4309303164718483) + a10_1 = convert(T, 0.9964361618263716) + a11_1 = convert(T, 0.21558998522059158) + a12_1 = convert(T, 0.14554468787163888) + a13_1 = convert(T, -0.6194661556072109) + a14_1 = convert(T, 0.12102345590080346) + a15_1 = convert(T, 0.3182994278448453) + a16_1 = convert(T, -0.3116409924709224) + a17_1 = convert(T, -0.2782405906657079) + a18_1 = convert(T, 0.15091307854280697) + a19_1 = convert(T, 0.3511471759164698) + a20_1 = convert(T, 0.12906591740279327) + a21_1 = convert(T, 0.028195954623407203) + a22_1 = convert(T, 0.35880119686145934) + a6_2 = convert(T, 1.3173164252067264) + a7_2 = convert(T, 0.36998105656756847) + a8_2 = convert(T, -0.1982571843531502) + a9_2 = convert(T, 0.15977321129906968) + a10_2 = convert(T, -0.08847173151667785) + a11_2 = convert(T, -0.10180726341074504) + a12_2 = convert(T, -0.16139790285847) + a13_2 = convert(T, 0.28056524573291536) + a14_2 = convert(T, 0.386533177517359) + a15_2 = convert(T, -0.03621994831886412) + a16_2 = convert(T, 0.40297425262475267) + a17_2 = convert(T, 0.6913068000557012) + a18_2 = convert(T, -0.3075867960901152) + a19_2 = convert(T, -0.5263413555965759) + a20_2 = convert(T, -0.39450065256939176) + a21_2 = convert(T, 0.058370106348868266) + a22_2 = convert(T, -0.36163317344022544) + a6_3 = convert(T, -0.8808808486289799) + a7_3 = convert(T, 1.0394737314843856) + a8_3 = convert(T, 0.169225561138242) + a9_3 = convert(T, -0.588399160303282) + a10_3 = convert(T, 0.5860796883704159) + a11_3 = convert(T, 0.13423616419178538) + a12_3 = convert(T, -0.15666530602235226) + a13_3 = convert(T, 0.25979978197032216) + a14_3 = convert(T, 0.09920405687919137) + a15_3 = convert(T, 0.2288805964211987) + a16_3 = convert(T, 0.09427964836150164) + a17_3 = convert(T, -0.25967632917317834) + a18_3 = convert(T, -0.18635335357878177) + a19_3 = convert(T, 0.5901113843569346) + a20_3 = convert(T, -0.012992871319684395) + a21_3 = convert(T, 0.1277331357365282) + a22_3 = convert(T, 0.11496477242177675) + a6_4 = convert(T, 0.9114655710735013) + a7_4 = convert(T, 0.02718522560889373) + a8_4 = convert(T, 0.21109740982623856) + a9_4 = convert(T, -0.025236641851771515) + a10_4 = convert(T, 0.09786800411174983) + a11_4 = convert(T, 0.05634642212576423) + a12_4 = convert(T, 0.4321860097966464) + a13_4 = convert(T, 0.353307291645736) + a14_4 = convert(T, 0.4092360715667188) + a15_4 = convert(T, -0.53051551539798) + a16_4 = convert(T, -0.24317586879879313) + a17_4 = convert(T, -0.047172330853912564) + a18_4 = convert(T, 0.2312283148170136) + a19_4 = convert(T, -0.19506496492932326) + a20_4 = convert(T, 0.31629505934955626) + a21_4 = convert(T, 0.06340241224871887) + a22_4 = convert(T, 0.08803049617374362) + a6_5 = convert(T, -0.4061577811557691) + a7_5 = convert(T, -0.6075682524093162) + a8_5 = convert(T, -0.021781822115769744) + a9_5 = convert(T, 0.18843637637707664) + a10_5 = convert(T, 0.10754314728893592) + a11_5 = convert(T, -0.28566824087990283) + a12_5 = convert(T, 0.692995780519478) + a13_5 = convert(T, 0.48459406449720893) + a14_5 = convert(T, -0.2839509093718165) + a15_5 = convert(T, 0.015843467261199694) + a16_5 = convert(T, -0.18093440194833657) + a17_5 = convert(T, -0.20634846094257264) + a18_5 = convert(T, 0.18136201594766663) + a19_5 = convert(T, -0.15505178558655375) + a20_5 = convert(T, 0.30279857140599686) + a21_5 = convert(T, -0.0060456500361145485) + a22_5 = convert(T, 0.1259594099739614) + a10_6 = convert(T, 0.3941673592043343) + a11_6 = convert(T, 0.4212391824458691) + a12_6 = convert(T, 0.8023745636124926) + a13_6 = convert(T, 0.06581900664401752) + a14_6 = convert(T, 0.6509066048811791) + a15_6 = convert(T, -0.041869376331805916) + a16_6 = convert(T, -0.30016106978059814) + a17_6 = convert(T, 0.014030560697384597) + a18_6 = convert(T, 0.34117681601937333) + a19_6 = convert(T, 0.3073163494220399) + a20_6 = convert(T, 0.8340796776340856) + a21_6 = convert(T, -0.48836104204568076) + a22_6 = convert(T, -0.03171644091081485) + a10_7 = convert(T, -1.9912951697640753) + a11_7 = convert(T, -0.24446436762472326) + a12_7 = convert(T, -0.6772613592840983) + a13_7 = convert(T, 0.3765267862314974) + a14_7 = convert(T, -0.6117714294118322) + a15_7 = convert(T, 0.04533573433276542) + a16_7 = convert(T, -0.018017153736651508) + a17_7 = convert(T, 0.3637115577256711) + a18_7 = convert(T, 0.5702084847991877) + a19_7 = convert(T, -0.05441888269725954) + a20_7 = convert(T, 0.06630897150193037) + a21_7 = convert(T, 0.3991648922391831) + a22_7 = convert(T, 0.07059507227082788) + a10_8 = convert(T, 1.8326778362224956) + a11_8 = convert(T, -0.031002351081905) + a12_8 = convert(T, -0.38615044870982207) + a13_8 = convert(T, -0.004116910667866284) + a14_8 = convert(T, 0.5561620401723206) + a15_8 = convert(T, 0.36188142999907413) + a16_8 = convert(T, -0.006496402175230515) + a17_8 = convert(T, 0.17926034013406833) + a18_8 = convert(T, 0.34669658138690573) + a19_8 = convert(T, 0.3094660794165345) + a20_8 = convert(T, -0.53348535774683) + a21_8 = convert(T, -0.5676006968582396) + a22_8 = convert(T, -0.004935172507136579) + a10_9 = convert(T, -0.47667823878803467) + a11_9 = convert(T, 0.4517995338554932) + a12_9 = convert(T, -0.20444745235428022) + a13_9 = convert(T, -0.7721580613373804) + a14_9 = convert(T, -0.2819030214576406) + a15_9 = convert(T, -0.15861951854092393) + a16_9 = convert(T, 0.4797838201769398) + a17_9 = convert(T, 0.37870755963738484) + a18_9 = convert(T, 0.162558464214073) + a19_9 = convert(T, 0.3300636796214586) + a20_9 = convert(T, 0.1702979182723194) + a21_9 = convert(T, 0.2034855324471201) + a22_9 = convert(T, -0.1652260965232391) + a14_10 = convert(T, 0.23595639484952924) + a15_10 = convert(T, 0.291726113837297) + a16_10 = convert(T, -0.006719630137495187) + a17_10 = convert(T, -0.053875076477706105) + a18_10 = convert(T, 0.43249784235025707) + a19_10 = convert(T, -0.04858962363800914) + a20_10 = convert(T, 0.13416205032645587) + a21_10 = convert(T, 0.26142931836518857) + a22_10 = convert(T, 0.002132849357660289) + a14_11 = convert(T, 0.0014457136570408323) + a15_11 = convert(T, -0.01679647560935326) + a16_11 = convert(T, 0.5036609030653351) + a17_11 = convert(T, 1.4346620752654138) + a18_11 = convert(T, 0.20451763513301913) + a19_11 = convert(T, -0.08182588583315756) + a20_11 = convert(T, 0.08998951873146484) + a21_11 = convert(T, -0.47200130416079655) + a22_11 = convert(T, 0.036306553485648756) + a14_12 = convert(T, -0.26493456352656725) + a15_12 = convert(T, 1.0700432503144561) + a16_12 = convert(T, -0.06404137670666947) + a17_12 = convert(T, -0.5873531971577279) + a18_12 = convert(T, -0.6890163026474726) + a19_12 = convert(T, -0.46445520677213326) + a20_12 = convert(T, -0.0638621914161322) + a21_12 = convert(T, 0.4914034685994716) + a22_12 = convert(T, 0.0031812580175455425) + a14_13 = convert(T, 0.6055926050802896) + a15_13 = convert(T, 0.15955969716215873) + a16_13 = convert(T, 0.46203652162652004) + a17_13 = convert(T, -0.7487981517923267) + a18_13 = convert(T, 0.2915114478672018) + a19_13 = convert(T, -0.07418972103836757) + a20_13 = convert(T, -0.05825635773552798) + a21_13 = convert(T, 0.13704131928293817) + a22_13 = convert(T, 0.4137584550963761) + a18_14 = convert(T, 0.419438162208698) + a19_14 = convert(T, -0.04485372878884935) + a20_14 = convert(T, 0.29383911653998274) + a21_14 = convert(T, 0.02740020732297193) + a22_14 = convert(T, -0.005106768728504381) + a18_15 = convert(T, 0.15735076823559277) + a19_15 = convert(T, 0.03142420915571857) + a20_15 = convert(T, -0.3091491204531662) + a21_15 = convert(T, -0.2665110980047972) + a22_15 = convert(T, 0.002391676237423355) + a18_16 = convert(T, -0.09154472531982463) + a19_16 = convert(T, 0.8776489600337575) + a20_16 = convert(T, -0.5432185135187191) + a21_16 = convert(T, 0.4326687115221769) + a22_16 = convert(T, 0.36816148546403227) + a18_17 = convert(T, 0.24106049218219158) + a19_17 = convert(T, -0.19487613228265654) + a20_17 = convert(T, 0.7027605935001623) + a21_17 = convert(T, 0.7063332324662378) + a22_17 = convert(T, -0.13123670380559585) + a22_18 = convert(T, 1.6444165775663413e-5) + a22_19 = convert(T, 0.10188020833759202) + a22_20 = convert(T, 0.023726065028842433) + a22_21 = convert(T, -0.010051586977149177) + + btilde_1 = convert(T, 0.35535072975719045) + btilde_2 = convert(T, -0.3176769551225345) + btilde_3 = convert(T, 0.021837326402837906) + btilde_4 = convert(T, -0.06255497967193582) + btilde_5 = convert(T, -0.008559305402759926) + btilde_6 = convert(T, 0.03665994254447143) + btilde_7 = convert(T, 0.13132639503404242) + btilde_8 = convert(T, 0.0051713134222386) + btilde_9 = convert(T, -0.12850676418667897) + btilde_10 = convert(T, -0.020952215450352724) + btilde_11 = convert(T, -0.15391506378338293) + btilde_12 = convert(T, 0.017647635286940615) + btilde_13 = convert(T, 0.015684038950609824) + btilde_14 = convert(T, 0.07331283525408785) + btilde_15 = convert(T, -0.047076612879172156) + btilde_16 = convert(T, 0.16814577795936286) + btilde_17 = convert(T, -0.049975370905672334) + btilde_18 = convert(T, 0.00035738463955726607) + btilde_19 = convert(T, -0.00554083323320384) + btilde_20 = convert(T, -0.05956848835084534) + btilde_21 = convert(T, 0.028833209735199462) + + RK6v4ConstantCache( + c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, c_14, c_15, + c_16, c_17, c_18, c_19, c_20, + c_21, c_22, a2_1, a3_1, a4_1, a5_1, + a6_1, a7_1, a8_1, a9_1, a10_1, a11_1, a12_1, + a13_1, a14_1, a15_1, a16_1, a17_1, a18_1, a19_1, a20_1, + a21_1, a22_1, a6_2, a7_2, a8_2, a9_2, a10_2, a11_2, a12_2, + a13_2, a14_2, a15_2, a16_2, a17_2, a18_2, a19_2, + a20_2, a21_2, a22_2, a6_3, a7_3, a8_3, a9_3, a10_3, a11_3, + a12_3, a13_3, a14_3, a15_3, a16_3, a17_3, a18_3, + a19_3, a20_3, a21_3, a22_3, a6_4, a7_4, a8_4, a9_4, a10_4, + a11_4, a12_4, a13_4, a14_4, a15_4, a16_4, a17_4, + a18_4, a19_4, a20_4, a21_4, + a22_4, a6_5, a7_5, a8_5, a9_5, a10_5, a11_5, a12_5, a13_5, + a14_5, a15_5, a16_5, a17_5, a18_5, a19_5, a20_5, + a21_5, a22_5, a10_6, a11_6, a12_6, a13_6, a14_6, a15_6, + a16_6, a17_6, a18_6, a19_6, a20_6, a21_6, a22_6, a10_7, + a11_7, a12_7, a13_7, a14_7, a15_7, a16_7, a17_7, a18_7, + a19_7, a20_7, a21_7, a22_7, a10_8, a11_8, a12_8, + a13_8, a14_8, a15_8, a16_8, a17_8, a18_8, a19_8, a20_8, + a21_8, a22_8, a10_9, a11_9, a12_9, a13_9, a14_9, a15_9, + a16_9, a17_9, a18_9, a19_9, a20_9, a21_9, a22_9, a14_10, + a15_10, a16_10, a17_10, a18_10, a19_10, a20_10, a21_10, + a22_10, a14_11, a15_11, a16_11, a17_11, a18_11, a19_11, + a20_11, a21_11, a22_11, a14_12, a15_12, a16_12, a17_12, + a18_12, a19_12, a20_12, a21_12, a22_12, a14_13, a15_13, + a16_13, a17_13, a18_13, a19_13, a20_13, a21_13, a22_13, + a18_14, a19_14, a20_14, a21_14, a22_14, a18_15, a19_15, + a20_15, a21_15, a22_15, a18_16, a19_16, a20_16, a21_16, + a22_16, a18_17, a19_17, a20_17, a21_17, a22_17, a22_18, + a22_19, a22_20, a22_21, btilde_1, btilde_2, btilde_3, + btilde_4, btilde_5, btilde_6, btilde_7, btilde_8, btilde_9, + btilde_10, btilde_11, btilde_12, btilde_13, + btilde_14, btilde_15, btilde_16, btilde_17, btilde_18, btilde_19, btilde_20, btilde_21) +end + +function alg_cache(alg::RK6v4, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + RK6v4ConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) +end diff --git a/lib/OrdinaryDiffEqSIMDRK/src/perform_step.jl b/lib/OrdinaryDiffEqSIMDRK/src/perform_step.jl new file mode 100644 index 0000000000..9b0e38d1c3 --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/src/perform_step.jl @@ -0,0 +1,531 @@ +function initialize!(integrator, + cache::Union{MER5v2ConstantCache, MER6v2ConstantCache, RK6v4ConstantCache}) + integrator.kshortsize = 2 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) + integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t) # Pre-start fsal + integrator.stats.nf += 1 + + # Avoid undefined entries if k is an array of arrays + integrator.fsallast = zero(integrator.fsalfirst) + integrator.k[1] = integrator.fsalfirst + integrator.k[integrator.kshortsize] = integrator.fsallast +end + +using VectorizationBase, SLEEFPirates + +#= +function foo(x, n = x ÷ 2 - 1) + s = """ + c_$(x)_$(x+1) = Vec(c_$(x), c_$(x+1)) + a$(x)_$(x+1)_1 = Vec(a$(x)_1, a$(x+1)_1) + """ + + for i in 1:n + s *= """ + a$(x)_$(2i)_$(x+1)_$(2i+1) = Vec(a$(x)_$(2i), a$(x+1)_$(2i+1)) + a$(x)_$(2i+1)_$(x+1)_$(2i) = Vec(a$(x)_$(2i+1), a$(x+1)_$(2i)) + """ + end + s *= "k_$(x-1)_$(x-2) = VectorizationBase.shufflevector.(k_$(x-2)_$(x-1), Val{(1,0)}())" + + s *= "\nk_$(x)_$(x+1) = f(uprev + + dt * (a$(x)_$(x+1)_1 * k_1" + for i in 1:n + s *= " + a$(x)_$(2i)_$(x+1)_$(2i+1) * k_$(2i)_$(2i+1)" + s *= " + a$(x)_$(2i+1)_$(x+1)_$(2i) * k_$(2i+1)_$(2i)" + end + s *= "), p, t + c_$(x)_$(x+1) * dt)" + return s +end +=# + +# pirate +@inline function (f::ODEFunction)( + v::AbstractArray{<:VectorizationBase.AbstractSIMD}, args...) + @inline f.f(v, args...) +end + +@muladd function perform_step!( + integrator, cache::MER5v2ConstantCache, + repeat_step = false) + @unpack t, dt, uprev, u, f, p = integrator + @unpack ( + c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, c_14, a2_1, a3_1, + a4_1, a5_1, a6_1, a7_1, a8_1, a9_1, a10_1, a11_1, a12_1, a13_1, + a14_1, a4_2, a5_2, a6_2, a7_2, a8_2, a9_2, a10_2, a11_2, a12_2, + a13_2, a14_2, a4_3, a5_3, a6_3, a7_3, a8_3, a9_3, a10_3, a11_3, + a12_3, a13_3, a14_3, a6_4, a7_4, a8_4, a9_4, a10_4, a11_4, a12_4, + a13_4, a14_4, a6_5, a7_5, a8_5, a9_5, a10_5, a11_5, a12_5, a13_5, + a14_5, a8_6, a9_6, a10_6, a11_6, a12_6, a13_6, a14_6, a8_7, a9_7, + a10_7, a11_7, a12_7, a13_7, a14_7, a10_8, a11_8, a12_8, a13_8, + a14_8, a10_9, a11_9, a12_9, a13_9, a14_9, a12_10, a13_10, a14_10, + a12_11, a13_11, a14_11, a14_12, a14_13, btilde_1, btilde_2, btilde_3, + btilde_4, btilde_5, btilde_6, btilde_7, btilde_8, btilde_9, btilde_10, + btilde_11, btilde_12, btilde_13, btilde_14) = cache + + k_1 = integrator.fsalfirst + + a_2_3_1 = Vec(a2_1, a3_1) + c_2_3 = Vec(c_2, c_3) + + k_2_3 = @inline f(uprev + dt * a_2_3_1 * k_1, p, t + c_2_3 * dt) + #k_2 = f(uprev + dt * a2_1 * k_1, p, t + c_2 * dt) + #k_3 = f(uprev + dt * a3_1 * k_1, p, t + c_3 * dt) + + k_3_2 = VectorizationBase.shufflevector.(k_2_3, Val{(1, 0)}()) + #Base.Cartesian.@nexprs 3 i -> a_4_5_i = Vec(a4_i, a5_i) + a_4_5_1 = Vec(a4_1, a5_1) + a_4_2_5_3 = Vec(a4_2, a5_3) + a_4_3_5_2 = Vec(a4_3, a5_2) + c_4_5 = Vec(c_4, c_5) + k_4_5 = @inline f( + uprev + dt * (a_4_5_1 * k_1 + a_4_2_5_3 * k_2_3 + a_4_3_5_2 * k_3_2), p, + t + c_4_5 * dt) + #k_4 = f(uprev + dt * (a4_1 * k_1 + a4_2 * k_2 + a4_3 * k_3), p, t + c_4 * dt) + #k_5 = f(uprev + dt * (a5_1 * k_1 + a5_2 * k_2 + a5_3 * k_3), p, t + c_5 * dt) + + k_5_4 = VectorizationBase.shufflevector.(k_4_5, Val{(1, 0)}()) + a6_7_1 = Vec(a6_1, a7_1) + a6_2_7_3 = Vec(a6_2, a7_3) + a6_3_7_2 = Vec(a6_3, a7_2) + a6_4_7_5 = Vec(a6_4, a7_5) + a6_5_7_4 = Vec(a6_5, a7_4) + c_6_7 = Vec(c_6, c_7) + + #k_2 = map(x -> x(1), k_2_3) + #k_3 = map(x -> x(2), k_2_3) + #k_4 = map(x -> x(1), k_4_5) + #k_5 = map(x -> x(2), k_4_5) + + k_6_7 = @inline f( + uprev + + dt * + (a6_7_1 * k_1 + a6_2_7_3 * k_2_3 + a6_3_7_2 * k_3_2 + a6_4_7_5 * k_4_5 + + a6_5_7_4 * k_5_4), + p, + t + c_6_7 * dt) + k_7_6 = VectorizationBase.shufflevector.(k_6_7, Val{(1, 0)}()) + + c_8_9 = Vec(c_8, c_9) + a8_9_1 = Vec(a8_1, a9_1) + a8_2_9_3 = Vec(a8_2, a9_3) + a8_3_9_2 = Vec(a8_3, a9_2) + a8_4_9_5 = Vec(a8_4, a9_5) + a8_5_9_4 = Vec(a8_5, a9_4) + a8_6_9_7 = Vec(a8_6, a9_7) + a8_7_9_6 = Vec(a8_7, a9_6) + k_7_6 = VectorizationBase.shufflevector.(k_6_7, Val{(1, 0)}()) + k_8_9 = @inline f( + uprev + + dt * + (a8_9_1 * k_1 + a8_2_9_3 * k_2_3 + a8_3_9_2 * k_3_2 + a8_4_9_5 * k_4_5 + + a8_5_9_4 * k_5_4 + a8_6_9_7 * k_6_7 + a8_7_9_6 * k_7_6), + p, + t + c_8_9 * dt) + + c_10_11 = Vec(c_10, c_11) + a10_11_1 = Vec(a10_1, a11_1) + a10_2_11_3 = Vec(a10_2, a11_3) + a10_3_11_2 = Vec(a10_3, a11_2) + a10_4_11_5 = Vec(a10_4, a11_5) + a10_5_11_4 = Vec(a10_5, a11_4) + a10_6_11_7 = Vec(a10_6, a11_7) + a10_7_11_6 = Vec(a10_7, a11_6) + a10_8_11_9 = Vec(a10_8, a11_9) + a10_9_11_8 = Vec(a10_9, a11_8) + k_9_8 = VectorizationBase.shufflevector.(k_8_9, Val{(1, 0)}()) + k_10_11 = @inline f( + uprev + + dt * (a10_11_1 * k_1 + a10_2_11_3 * k_2_3 + a10_3_11_2 * k_3_2 + + a10_4_11_5 * k_4_5 + a10_5_11_4 * k_5_4 + a10_6_11_7 * k_6_7 + + a10_7_11_6 * k_7_6 + a10_8_11_9 * k_8_9 + a10_9_11_8 * k_9_8), + p, + t + c_10_11 * dt) + c_12_13 = Vec(c_12, c_13) + a12_13_1 = Vec(a12_1, a13_1) + a12_2_13_3 = Vec(a12_2, a13_3) + a12_3_13_2 = Vec(a12_3, a13_2) + a12_4_13_5 = Vec(a12_4, a13_5) + a12_5_13_4 = Vec(a12_5, a13_4) + a12_6_13_7 = Vec(a12_6, a13_7) + a12_7_13_6 = Vec(a12_7, a13_6) + a12_8_13_9 = Vec(a12_8, a13_9) + a12_9_13_8 = Vec(a12_9, a13_8) + a12_10_13_11 = Vec(a12_10, a13_11) + a12_11_13_10 = Vec(a12_11, a13_10) + k_11_10 = VectorizationBase.shufflevector.(k_10_11, Val{(1, 0)}()) + k_12_13 = @inline f( + uprev + + dt * (a12_13_1 * k_1 + a12_2_13_3 * k_2_3 + a12_3_13_2 * k_3_2 + + a12_4_13_5 * k_4_5 + a12_5_13_4 * k_5_4 + a12_6_13_7 * k_6_7 + + a12_7_13_6 * k_7_6 + a12_8_13_9 * k_8_9 + a12_9_13_8 * k_9_8 + + a12_10_13_11 * k_10_11 + a12_11_13_10 * k_11_10), + p, + t + c_12_13 * dt) + + u = uprev + + dt * (a14_1 * k_1 + + VectorizationBase.vsum.(Vec(a14_2, a14_3) * k_2_3 + Vec(a14_4, a14_5) * k_4_5 + + Vec(a14_6, a14_7) * k_6_7 + Vec(a14_8, a14_9) * k_8_9 + + Vec(a14_10, a14_11) * k_10_11 + + Vec(a14_12, a14_13) * k_12_13)) + + k_14 = integrator.fsallast = @inline f(u, p, t + dt) + + integrator.stats.nf += 12 + if integrator.opts.adaptive + utilde = dt * (VectorizationBase.vsum.(Vec(btilde_2, btilde_3) * k_2_3 + + Vec(btilde_4, btilde_5) * k_4_5 + + Vec(btilde_6, btilde_7) * k_6_7 + + Vec(btilde_8, btilde_9) * k_8_9 + + Vec(btilde_10, btilde_11) * k_10_11 + + Vec(btilde_12, btilde_13) * k_12_13 + + Vec(btilde_1, btilde_14) * Vec.(k_1, k_14))) + atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) + end + integrator.u = u +end + +@muladd function perform_step!( + integrator, cache::MER6v2ConstantCache, + repeat_step = false) + @unpack t, dt, uprev, u, f, p = integrator + @unpack (c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, + c_11, c_12, c_13, c_14, c_15, a2_1, a3_1, + a4_1, a5_1, a6_1, a7_1, a8_1, a9_1, a10_1, a11_1, a12_1, a13_1, + a14_1, a15_1, a4_2, a5_2, a6_2, a7_2, a8_2, a9_2, a10_2, a11_2, a12_2, + a13_2, a14_2, a15_2, a4_3, a5_3, a6_3, a7_3, a8_3, a9_3, a10_3, a11_3, + a12_3, a13_3, a14_3, a15_3, a6_4, a7_4, a8_4, a9_4, a10_4, a11_4, a12_4, + a13_4, a14_4, a15_4, a6_5, a7_5, a8_5, a9_5, a10_5, a11_5, a12_5, a13_5, + a14_5, a15_5, a8_6, a9_6, a10_6, a11_6, a12_6, a13_6, a14_6, a15_6, a8_7, a9_7, + a10_7, a11_7, a12_7, a13_7, a14_7, a15_7, a10_8, a11_8, a12_8, a13_8, + a14_8, a15_8, a10_9, a11_9, a12_9, a13_9, a14_9, a15_9, a12_10, a13_10, a14_10, a15_10, + a12_11, a13_11, a14_11, a15_11, a14_12, a15_12, a14_13, + a15_13, a15_14, btilde_1, btilde_2, btilde_3, + btilde_4, btilde_5, btilde_6, btilde_7, btilde_8, btilde_9, btilde_10, + btilde_11, btilde_12, btilde_13, btilde_14) = cache + + k_1 = integrator.fsalfirst + + a_2_3_1 = Vec(a2_1, a3_1) + c_2_3 = Vec(c_2, c_3) + + k_2_3 = @inline f(uprev + dt * a_2_3_1 * k_1, p, t + c_2_3 * dt) + + k_3_2 = VectorizationBase.shufflevector.(k_2_3, Val{(1, 0)}()) + a_4_5_1 = Vec(a4_1, a5_1) + a_4_2_5_3 = Vec(a4_2, a5_3) + a_4_3_5_2 = Vec(a4_3, a5_2) + c_4_5 = Vec(c_4, c_5) + k_4_5 = @inline f( + uprev + dt * (a_4_5_1 * k_1 + a_4_2_5_3 * k_2_3 + a_4_3_5_2 * k_3_2), p, + t + c_4_5 * dt) + + k_5_4 = VectorizationBase.shufflevector.(k_4_5, Val{(1, 0)}()) + a6_7_1 = Vec(a6_1, a7_1) + a6_2_7_3 = Vec(a6_2, a7_3) + a6_3_7_2 = Vec(a6_3, a7_2) + a6_4_7_5 = Vec(a6_4, a7_5) + a6_5_7_4 = Vec(a6_5, a7_4) + c_6_7 = Vec(c_6, c_7) + k_6_7 = @inline f( + uprev + + dt * + (a6_7_1 * k_1 + a6_2_7_3 * k_2_3 + a6_3_7_2 * k_3_2 + a6_4_7_5 * k_4_5 + + a6_5_7_4 * k_5_4), + p, + t + c_6_7 * dt) + k_7_6 = VectorizationBase.shufflevector.(k_6_7, Val{(1, 0)}()) + + c_8_9 = Vec(c_8, c_9) + a8_9_1 = Vec(a8_1, a9_1) + a8_2_9_3 = Vec(a8_2, a9_3) + a8_3_9_2 = Vec(a8_3, a9_2) + a8_4_9_5 = Vec(a8_4, a9_5) + a8_5_9_4 = Vec(a8_5, a9_4) + a8_6_9_7 = Vec(a8_6, a9_7) + a8_7_9_6 = Vec(a8_7, a9_6) + k_7_6 = VectorizationBase.shufflevector.(k_6_7, Val{(1, 0)}()) + k_8_9 = @inline f( + uprev + + dt * + (a8_9_1 * k_1 + a8_2_9_3 * k_2_3 + a8_3_9_2 * k_3_2 + a8_4_9_5 * k_4_5 + + a8_5_9_4 * k_5_4 + a8_6_9_7 * k_6_7 + a8_7_9_6 * k_7_6), + p, + t + c_8_9 * dt) + + c_10_11 = Vec(c_10, c_11) + a10_11_1 = Vec(a10_1, a11_1) + a10_2_11_3 = Vec(a10_2, a11_3) + a10_3_11_2 = Vec(a10_3, a11_2) + a10_4_11_5 = Vec(a10_4, a11_5) + a10_5_11_4 = Vec(a10_5, a11_4) + a10_6_11_7 = Vec(a10_6, a11_7) + a10_7_11_6 = Vec(a10_7, a11_6) + a10_8_11_9 = Vec(a10_8, a11_9) + a10_9_11_8 = Vec(a10_9, a11_8) + k_9_8 = VectorizationBase.shufflevector.(k_8_9, Val{(1, 0)}()) + k_10_11 = @inline f( + uprev + + dt * (a10_11_1 * k_1 + a10_2_11_3 * k_2_3 + a10_3_11_2 * k_3_2 + + a10_4_11_5 * k_4_5 + a10_5_11_4 * k_5_4 + a10_6_11_7 * k_6_7 + + a10_7_11_6 * k_7_6 + a10_8_11_9 * k_8_9 + a10_9_11_8 * k_9_8), + p, + t + c_10_11 * dt) + c_12_13 = Vec(c_12, c_13) + a12_13_1 = Vec(a12_1, a13_1) + a12_2_13_3 = Vec(a12_2, a13_3) + a12_3_13_2 = Vec(a12_3, a13_2) + a12_4_13_5 = Vec(a12_4, a13_5) + a12_5_13_4 = Vec(a12_5, a13_4) + a12_6_13_7 = Vec(a12_6, a13_7) + a12_7_13_6 = Vec(a12_7, a13_6) + a12_8_13_9 = Vec(a12_8, a13_9) + a12_9_13_8 = Vec(a12_9, a13_8) + a12_10_13_11 = Vec(a12_10, a13_11) + a12_11_13_10 = Vec(a12_11, a13_10) + k_11_10 = VectorizationBase.shufflevector.(k_10_11, Val{(1, 0)}()) + k_12_13 = @inline f( + uprev + + dt * (a12_13_1 * k_1 + a12_2_13_3 * k_2_3 + a12_3_13_2 * k_3_2 + + a12_4_13_5 * k_4_5 + a12_5_13_4 * k_5_4 + a12_6_13_7 * k_6_7 + + a12_7_13_6 * k_7_6 + a12_8_13_9 * k_8_9 + a12_9_13_8 * k_9_8 + + a12_10_13_11 * k_10_11 + a12_11_13_10 * k_11_10), + p, + t + c_12_13 * dt) + + a14_2_14_3 = Vec(a14_2, a14_3) + a14_4_14_5 = Vec(a14_4, a14_5) + a14_6_14_7 = Vec(a14_6, a14_7) + a14_8_14_9 = Vec(a14_8, a14_9) + a14_10_14_11 = Vec(a14_10, a14_11) + a14_12_14_13 = Vec(a14_12, a14_13) + + k_14 = @inline f( + uprev + + dt * (a14_1 * k_1 + + VectorizationBase.vsum.(a14_2_14_3 * k_2_3 + a14_4_14_5 * k_4_5 + + a14_6_14_7 * k_6_7 + a14_8_14_9 * k_8_9 + + a14_10_14_11 * k_10_11 + a14_12_14_13 * k_12_13)), + p, + t + c_14 * dt) + + u = uprev + + dt * + (VectorizationBase.vsum.(Vec(a15_2, a15_3) * k_2_3 + Vec(a15_4, a15_5) * k_4_5 + + Vec(a15_6, a15_7) * k_6_7 + Vec(a15_8, a15_9) * k_8_9 + + Vec(a15_10, a15_11) * k_10_11 + + Vec(a15_12, a15_13) * k_12_13 + + Vec(a15_1, a15_14) * Vec.(k_1, k_14))) + + integrator.fsallast = @inline f(u, p, t + dt) + + integrator.stats.nf += 14 + if integrator.opts.adaptive + utilde = dt * (VectorizationBase.vsum.(Vec(btilde_2, btilde_3) * k_2_3 + + Vec(btilde_4, btilde_5) * k_4_5 + + Vec(btilde_6, btilde_7) * k_6_7 + + Vec(btilde_8, btilde_9) * k_8_9 + + Vec(btilde_10, btilde_11) * k_10_11 + + Vec(btilde_12, btilde_13) * k_12_13 + + Vec(btilde_1, btilde_14) * Vec.(k_1, k_14))) + atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) + end + integrator.u = u +end + +@muladd function perform_step!( + integrator, cache::RK6v4ConstantCache, + repeat_step = false) + @unpack t, dt, uprev, u, f, p = integrator + @unpack (c_2, c_3, c_4, c_5, c_6, c_7, c_8, c_9, c_10, c_11, c_12, c_13, c_14, c_15, + c_16, c_17, c_18, c_19, c_20, + c_21, c_22, a2_1, a3_1, a4_1, a5_1, + a6_1, a7_1, a8_1, a9_1, a10_1, a11_1, a12_1, + a13_1, a14_1, a15_1, a16_1, a17_1, a18_1, a19_1, a20_1, + a21_1, a22_1, a6_2, a7_2, a8_2, a9_2, a10_2, a11_2, a12_2, + a13_2, a14_2, a15_2, a16_2, a17_2, a18_2, a19_2, + a20_2, a21_2, a22_2, a6_3, a7_3, a8_3, a9_3, a10_3, a11_3, + a12_3, a13_3, a14_3, a15_3, a16_3, a17_3, a18_3, + a19_3, a20_3, a21_3, a22_3, a6_4, a7_4, a8_4, a9_4, a10_4, + a11_4, a12_4, a13_4, a14_4, a15_4, a16_4, a17_4, + a18_4, a19_4, a20_4, a21_4, + a22_4, a6_5, a7_5, a8_5, a9_5, a10_5, a11_5, a12_5, a13_5, + a14_5, a15_5, a16_5, a17_5, a18_5, a19_5, a20_5, + a21_5, a22_5, a10_6, a11_6, a12_6, a13_6, a14_6, a15_6, + a16_6, a17_6, a18_6, a19_6, a20_6, a21_6, a22_6, a10_7, + a11_7, a12_7, a13_7, a14_7, a15_7, a16_7, a17_7, a18_7, + a19_7, a20_7, a21_7, a22_7, a10_8, a11_8, a12_8, + a13_8, a14_8, a15_8, a16_8, a17_8, a18_8, a19_8, a20_8, + a21_8, a22_8, a10_9, a11_9, a12_9, a13_9, a14_9, a15_9, + a16_9, a17_9, a18_9, a19_9, a20_9, a21_9, a22_9, a14_10, + a15_10, a16_10, a17_10, a18_10, a19_10, a20_10, a21_10, + a22_10, a14_11, a15_11, a16_11, a17_11, a18_11, a19_11, + a20_11, a21_11, a22_11, a14_12, a15_12, a16_12, a17_12, + a18_12, a19_12, a20_12, a21_12, a22_12, a14_13, a15_13, + a16_13, a17_13, a18_13, a19_13, a20_13, a21_13, a22_13, + a18_14, a19_14, a20_14, a21_14, a22_14, a18_15, a19_15, + a20_15, a21_15, a22_15, a18_16, a19_16, a20_16, a21_16, + a22_16, a18_17, a19_17, a20_17, a21_17, a22_17, a22_18, + a22_19, a22_20, a22_21, btilde_1, btilde_2, btilde_3, + btilde_4, btilde_5, btilde_6, btilde_7, btilde_8, btilde_9, + btilde_10, btilde_11, btilde_12, btilde_13, + btilde_14, btilde_15, btilde_16, btilde_17, btilde_18, btilde_19, btilde_20, btilde_21) = cache + + k_1 = integrator.fsalfirst + + c_2_3_4_5 = Vec(c_2, c_3, c_4, c_5) + a_2_3_4_5_1 = Vec(a2_1, a3_1, a4_1, a5_1) + + k_2_3_4_5 = @inline f(uprev + dt * (a_2_3_4_5_1 * k_1), p, t + + c_2_3_4_5 * dt) + + c_6_7_8_9 = Vec(c_6, c_7, c_8, c_9) + a_6_7_8_9_1 = Vec(a6_1, a7_1, a8_1, a9_1) + a_6_2_7_3_8_4_9_5 = Vec(a6_2, a7_3, a8_4, a9_5) + a_6_3_7_4_8_5_9_2 = Vec(a6_3, a7_4, a8_5, a9_2) + a_6_4_7_5_8_2_9_3 = Vec(a6_4, a7_5, a8_2, a9_3) + a_6_5_7_2_8_3_9_4 = Vec(a6_5, a7_2, a8_3, a9_4) + + k_3_4_5_2 = VectorizationBase.shufflevector.(k_2_3_4_5, Val{(1, 2, 3, 0)}()) + k_4_5_2_3 = VectorizationBase.shufflevector.(k_2_3_4_5, Val{(2, 3, 0, 1)}()) + k_5_2_3_4 = VectorizationBase.shufflevector.(k_2_3_4_5, Val{(3, 0, 1, 2)}()) + k_6_7_8_9 = @inline f( + uprev + + dt * + (a_6_7_8_9_1 * k_1 + a_6_2_7_3_8_4_9_5 * k_2_3_4_5 + a_6_3_7_4_8_5_9_2 * k_3_4_5_2 + + a_6_4_7_5_8_2_9_3 * k_4_5_2_3 + a_6_5_7_2_8_3_9_4 * k_5_2_3_4), + p, + t + + c_6_7_8_9 * dt) + + c_10_11_12_13 = Vec(c_10, c_11, c_12, c_13) + a_10_11_12_13_1 = Vec(a10_1, a11_1, a12_1, a13_1) + a_10_2_11_3_12_4_13_5 = Vec(a10_2, a11_3, a12_4, a13_5) + a_10_3_11_4_12_5_13_2 = Vec(a10_3, a11_4, a12_5, a13_2) + a_10_4_11_5_12_2_13_3 = Vec(a10_4, a11_5, a12_2, a13_3) + a_10_5_11_2_12_3_13_4 = Vec(a10_5, a11_2, a12_3, a13_4) + a_10_6_11_7_12_8_13_9 = Vec(a10_6, a11_7, a12_8, a13_9) + a_10_7_11_8_12_9_13_6 = Vec(a10_7, a11_8, a12_9, a13_6) + a_10_8_11_9_12_6_13_7 = Vec(a10_8, a11_9, a12_6, a13_7) + a_10_9_11_6_12_7_13_8 = Vec(a10_9, a11_6, a12_7, a13_8) + + k_7_8_9_6 = VectorizationBase.shufflevector.(k_6_7_8_9, Val{(1, 2, 3, 0)}()) + k_8_9_6_7 = VectorizationBase.shufflevector.(k_6_7_8_9, Val{(2, 3, 0, 1)}()) + k_9_6_7_8 = VectorizationBase.shufflevector.(k_6_7_8_9, Val{(3, 0, 1, 2)}()) + k_10_11_12_13 = f( + uprev + + dt * (a_10_11_12_13_1 * k_1 + a_10_2_11_3_12_4_13_5 * k_2_3_4_5 + + a_10_3_11_4_12_5_13_2 * k_3_4_5_2 + a_10_4_11_5_12_2_13_3 * k_4_5_2_3 + + a_10_5_11_2_12_3_13_4 * k_5_2_3_4 + a_10_6_11_7_12_8_13_9 * k_6_7_8_9 + + a_10_7_11_8_12_9_13_6 * k_7_8_9_6 + a_10_8_11_9_12_6_13_7 * k_8_9_6_7 + + a_10_9_11_6_12_7_13_8 * k_9_6_7_8), + p, + t + + c_10_11_12_13 * dt) + + c_14_15_16_17 = Vec(c_14, c_15, c_16, c_17) + a_14_15_16_17_1 = Vec(a14_1, a15_1, a16_1, a17_1) + a_14_2_15_3_16_4_17_5 = Vec(a14_2, a15_3, a16_4, a17_5) + a_14_3_15_4_16_5_17_2 = Vec(a14_3, a15_4, a16_5, a17_2) + a_14_4_15_5_16_2_17_3 = Vec(a14_4, a15_5, a16_2, a17_3) + a_14_5_15_2_16_3_17_4 = Vec(a14_5, a15_2, a16_3, a17_4) + a_14_6_15_7_16_8_17_9 = Vec(a14_6, a15_7, a16_8, a17_9) + a_14_7_15_8_16_9_17_6 = Vec(a14_7, a15_8, a16_9, a17_6) + a_14_8_15_9_16_6_17_7 = Vec(a14_8, a15_9, a16_6, a17_7) + a_14_9_15_6_16_7_17_8 = Vec(a14_9, a15_6, a16_7, a17_8) + a_14_10_15_11_16_12_17_13 = Vec(a14_10, a15_11, a16_12, a17_13) + a_14_11_15_12_16_13_17_10 = Vec(a14_11, a15_12, a16_13, a17_10) + a_14_12_15_13_16_10_17_11 = Vec(a14_12, a15_13, a16_10, a17_11) + a_14_13_15_10_16_11_17_12 = Vec(a14_13, a15_10, a16_11, a17_12) + + k_11_12_13_10 = VectorizationBase.shufflevector.(k_10_11_12_13, Val{(1, 2, 3, 0)}()) + k_12_13_10_11 = VectorizationBase.shufflevector.(k_10_11_12_13, Val{(2, 3, 0, 1)}()) + k_13_10_11_12 = VectorizationBase.shufflevector.(k_10_11_12_13, Val{(3, 0, 1, 2)}()) + k_14_15_16_17 = f( + uprev + + dt * (a_14_15_16_17_1 * k_1 + a_14_2_15_3_16_4_17_5 * k_2_3_4_5 + + a_14_3_15_4_16_5_17_2 * k_3_4_5_2 + a_14_4_15_5_16_2_17_3 * k_4_5_2_3 + + a_14_5_15_2_16_3_17_4 * k_5_2_3_4 + a_14_6_15_7_16_8_17_9 * k_6_7_8_9 + + a_14_7_15_8_16_9_17_6 * k_7_8_9_6 + a_14_8_15_9_16_6_17_7 * k_8_9_6_7 + + a_14_9_15_6_16_7_17_8 * k_9_6_7_8 + a_14_10_15_11_16_12_17_13 * k_10_11_12_13 + + a_14_11_15_12_16_13_17_10 * k_11_12_13_10 + + a_14_12_15_13_16_10_17_11 * k_12_13_10_11 + + a_14_13_15_10_16_11_17_12 * k_13_10_11_12), + p, + t + + c_14_15_16_17 * dt) + + c_18_19_20_21 = Vec(c_18, c_19, c_20, c_21) + a_18_19_20_21_1 = Vec(a18_1, a19_1, a20_1, a21_1) + a_18_2_19_3_20_4_21_5 = Vec(a18_2, a19_3, a20_4, a21_5) + a_18_3_19_4_20_5_21_2 = Vec(a18_3, a19_4, a20_5, a21_2) + a_18_4_19_5_20_2_21_3 = Vec(a18_4, a19_5, a20_2, a21_3) + a_18_5_19_2_20_3_21_4 = Vec(a18_5, a19_2, a20_3, a21_4) + a_18_6_19_7_20_8_21_9 = Vec(a18_6, a19_7, a20_8, a21_9) + a_18_7_19_8_20_9_21_6 = Vec(a18_7, a19_8, a20_9, a21_6) + a_18_8_19_9_20_6_21_7 = Vec(a18_8, a19_9, a20_6, a21_7) + a_18_9_19_6_20_7_21_8 = Vec(a18_9, a19_6, a20_7, a21_8) + a_18_10_19_11_20_12_21_13 = Vec(a18_10, a19_11, a20_12, a21_13) + a_18_11_19_12_20_13_21_10 = Vec(a18_11, a19_12, a20_13, a21_10) + a_18_12_19_13_20_10_21_11 = Vec(a18_12, a19_13, a20_10, a21_11) + a_18_13_19_10_20_11_21_12 = Vec(a18_13, a19_10, a20_11, a21_12) + a_18_14_19_15_20_16_21_17 = Vec(a18_14, a19_15, a20_16, a21_17) + a_18_15_19_16_20_17_21_14 = Vec(a18_15, a19_16, a20_17, a21_14) + a_18_16_19_17_20_14_21_15 = Vec(a18_16, a19_17, a20_14, a21_15) + a_18_17_19_14_20_15_21_16 = Vec(a18_17, a19_14, a20_15, a21_16) + + k_15_16_17_14 = VectorizationBase.shufflevector.(k_14_15_16_17, Val{(1, 2, 3, 0)}()) + k_16_17_14_15 = VectorizationBase.shufflevector.(k_14_15_16_17, Val{(2, 3, 0, 1)}()) + k_17_14_15_16 = VectorizationBase.shufflevector.(k_14_15_16_17, Val{(3, 0, 1, 2)}()) + k_18_19_20_21 = f( + uprev + + dt * (a_18_19_20_21_1 * k_1 + a_18_2_19_3_20_4_21_5 * k_2_3_4_5 + + a_18_3_19_4_20_5_21_2 * k_3_4_5_2 + a_18_4_19_5_20_2_21_3 * k_4_5_2_3 + + a_18_5_19_2_20_3_21_4 * k_5_2_3_4 + a_18_6_19_7_20_8_21_9 * k_6_7_8_9 + + a_18_7_19_8_20_9_21_6 * k_7_8_9_6 + a_18_8_19_9_20_6_21_7 * k_8_9_6_7 + + a_18_9_19_6_20_7_21_8 * k_9_6_7_8 + a_18_10_19_11_20_12_21_13 * k_10_11_12_13 + + a_18_11_19_12_20_13_21_10 * k_11_12_13_10 + + a_18_12_19_13_20_10_21_11 * k_12_13_10_11 + + a_18_13_19_10_20_11_21_12 * k_13_10_11_12 + + a_18_14_19_15_20_16_21_17 * k_14_15_16_17 + + a_18_15_19_16_20_17_21_14 * k_15_16_17_14 + + a_18_16_19_17_20_14_21_15 * k_16_17_14_15 + + a_18_17_19_14_20_15_21_16 * k_17_14_15_16), + p, + t + + c_18_19_20_21 * dt) + + u = uprev + + dt * (a22_1 * k_1 + + VectorizationBase.vsum.(Vec(a22_2, a22_3, a22_4, a22_5) * k_2_3_4_5 + + Vec(a22_6, a22_7, a22_8, a22_9) * k_6_7_8_9 + + Vec(a22_10, a22_11, a22_12, a22_13) * k_10_11_12_13 + + Vec(a22_14, a22_15, a22_16, a22_17) * k_14_15_16_17 + + Vec(a22_18, a22_19, a22_20, a22_21) * k_18_19_20_21)) + + integrator.fsallast = f(u, p, t + dt) + + integrator.stats.nf += 21 + if integrator.opts.adaptive + utilde = dt * (btilde_1 * k_1 + + VectorizationBase.vsum.(Vec(btilde_2, btilde_3, btilde_4, btilde_5) * + k_2_3_4_5 + + Vec(btilde_6, btilde_7, btilde_8, btilde_9) * + k_6_7_8_9 + + Vec(btilde_10, btilde_11, btilde_12, btilde_13) * + k_10_11_12_13 + + Vec(btilde_14, btilde_15, btilde_16, btilde_17) * + k_14_15_16_17 + + Vec(btilde_18, btilde_19, btilde_20, btilde_21) * + k_18_19_20_21)) + atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) + end + integrator.u = u +end diff --git a/lib/OrdinaryDiffEqSIMDRK/test/adaptivity_tests.jl b/lib/OrdinaryDiffEqSIMDRK/test/adaptivity_tests.jl new file mode 100644 index 0000000000..a81e948463 --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/test/adaptivity_tests.jl @@ -0,0 +1,16 @@ +using OrdinaryDiffEqSIMDRK, StaticArrays, Test + +function lorenz(u, p, t) + SA[10.0(u[2] - u[1]), u[1] * (28.0 - u[3]) - u[2], u[1] * u[2] - (8 / 3) * u[3]] +end +u0 = SA[1.0; 0.0; 0.0] +tspan = (0.0, 100.0) +prob = ODEProblem(lorenz, u0, tspan) +sol = solve(prob, MER5v2()) +@test length(sol.t) < 1100 + +sol = solve(prob, MER6v2()) +@test length(sol.t) < 1100 + +sol = solve(prob, RK6v4()) +@test length(sol.t) < 1700 diff --git a/lib/OrdinaryDiffEqSIMDRK/test/convergence_tests.jl b/lib/OrdinaryDiffEqSIMDRK/test/convergence_tests.jl new file mode 100644 index 0000000000..f06b39b4a8 --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/test/convergence_tests.jl @@ -0,0 +1,44 @@ +using OrdinaryDiffEqSIMDRK, DiffEqDevTools, Test + +function nonauto1(u, p, t) + x, _ = u + [t * x, 0] +end + +function nonauto2(u, p, t) + _, y = u + [y, t * y] +end + +function analytic(u0, p, t) + x0, y0 = u0 + et = exp(t^2 / 2) + [et * (x0 + t * y0), et * y0] +end + +u0 = [1.1, 2.2] +tspan = (0.0, 1.0) +prob1 = ODEProblem( + ODEFunction{true}((du, u, p, t) -> du .= nonauto1(u, p, t) .+ + nonauto2(u, p, t), + analytic = analytic), + u0, tspan) +prob2 = ODEProblem( + ODEFunction{false}((u, p, t) -> nonauto1(u, p, t) .+ nonauto2(u, p, t), + analytic = analytic), + u0, tspan) + +for prob in [prob2] + #=prob1,=# + dts1 = 1 .// 2 .^ (7:-1:4) + dts2 = 1 .// 2 .^ (4:-1:1) + + sim = test_convergence(dts1, prob, MER5v2()) + @test 5 <= sim.𝒪est[:l∞] <= 6 + + sim = test_convergence(dts1, prob, MER6v2()) + @test 6 <= sim.𝒪est[:l∞] <= 7 + + sim = test_convergence(dts2, prob, RK6v4()) + @test sim.𝒪est[:l∞]≈6 atol=1e-2 +end diff --git a/lib/OrdinaryDiffEqSIMDRK/test/runtests.jl b/lib/OrdinaryDiffEqSIMDRK/test/runtests.jl new file mode 100644 index 0000000000..d3e94704fe --- /dev/null +++ b/lib/OrdinaryDiffEqSIMDRK/test/runtests.jl @@ -0,0 +1,8 @@ +using SafeTestsets + +@time @safetestset "Convergence Tests" begin + include("convergence_tests.jl") +end +@time @safetestset "Adaptivity Tests" begin + include("adaptivity_tests.jl") +end diff --git a/lib/OrdinaryDiffEqSSPRK/Project.toml b/lib/OrdinaryDiffEqSSPRK/Project.toml index faccc02874..a216726008 100644 --- a/lib/OrdinaryDiffEqSSPRK/Project.toml +++ b/lib/OrdinaryDiffEqSSPRK/Project.toml @@ -1,48 +1,61 @@ name = "OrdinaryDiffEqSSPRK" uuid = "669c94d9-1f4b-4b64-b377-1aa079aa2388" authors = ["ParamThakkar123 "] -version = "1.2.0" +version = "1.7.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Preferences = "21216c6a-2e73-6563-6e65-726566657250" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqLowStorageRK = "<0.0.1, 1" -Polyester = "0.7.16" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" OrdinaryDiffEqLowStorageRK = "b0944070-b475-4768-8dec-fb6eb410534d" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +StructArrays = "0.6, 0.7" +MuladdMacro = "0.2" +PrecompileTools = "1.2" +Polyester = "0.7" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +Preferences = "1.4" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +OrdinaryDiffEqLowStorageRK = "1.5.0" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "OrdinaryDiffEqLowStorageRK"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "StructArrays", "Test", "ODEProblemLibrary", "OrdinaryDiffEqLowStorageRK", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqSSPRK/src/OrdinaryDiffEqSSPRK.jl b/lib/OrdinaryDiffEqSSPRK/src/OrdinaryDiffEqSSPRK.jl index 527bae3c4f..911c3099ae 100644 --- a/lib/OrdinaryDiffEqSSPRK/src/OrdinaryDiffEqSSPRK.jl +++ b/lib/OrdinaryDiffEqSSPRK/src/OrdinaryDiffEqSSPRK.jl @@ -12,14 +12,14 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, constvalue, _unwrap_val, explicit_rk_docstring, trivial_limiter!, _ode_interpolant, _ode_interpolant!, - _ode_addsteps!, get_fsalfirstlast + _ode_addsteps!, get_fsalfirstlast, copyat_or_push! using FastBroadcast, Polyester, MuladdMacro, RecursiveArrayTools using DiffEqBase: @def using Static: False import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase import StaticArrays: SArray, MVector, SVector, @SVector, StaticArray, MMatrix, SA diff --git a/lib/OrdinaryDiffEqSSPRK/src/functions.jl b/lib/OrdinaryDiffEqSSPRK/src/functions.jl index 6ebf7d3715..de7421fb3e 100644 --- a/lib/OrdinaryDiffEqSSPRK/src/functions.jl +++ b/lib/OrdinaryDiffEqSSPRK/src/functions.jl @@ -1,4 +1,4 @@ -@inline function DiffEqBase.get_tmp_cache(integrator, +@inline function SciMLBase.get_tmp_cache(integrator, alg::Union{SSPRK22, SSPRK33, SSPRK53_2N1, SSPRK53_2N2, SSPRK43, SSPRK432, SSPRK932}, diff --git a/lib/OrdinaryDiffEqSSPRK/src/interp_func.jl b/lib/OrdinaryDiffEqSSPRK/src/interp_func.jl index 098457edf9..0c6f1759f2 100644 --- a/lib/OrdinaryDiffEqSSPRK/src/interp_func.jl +++ b/lib/OrdinaryDiffEqSSPRK/src/interp_func.jl @@ -1,4 +1,4 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{SSPRK22, SSPRK22ConstantCache, diff --git a/lib/OrdinaryDiffEqSSPRK/src/ssprk_perform_step.jl b/lib/OrdinaryDiffEqSSPRK/src/ssprk_perform_step.jl index 21109ec47a..bfe3c63637 100644 --- a/lib/OrdinaryDiffEqSSPRK/src/ssprk_perform_step.jl +++ b/lib/OrdinaryDiffEqSSPRK/src/ssprk_perform_step.jl @@ -82,6 +82,7 @@ end stage_limiter!(u, integrator, p, t + dt) step_limiter!(u, integrator, p, t + dt) f(k, u, p, t + dt) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 4) end function initialize!(integrator, cache::KYKSSPRK42ConstantCache) @@ -113,6 +114,7 @@ end integrator.fsallast = f(u, p, t + dt) # For interpolation, then FSAL'd integrator.k[1] = integrator.fsalfirst + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 4) integrator.u = u end diff --git a/lib/OrdinaryDiffEqSSPRK/test/allocation_tests.jl b/lib/OrdinaryDiffEqSSPRK/test/allocation_tests.jl new file mode 100644 index 0000000000..5ca72c3bff --- /dev/null +++ b/lib/OrdinaryDiffEqSSPRK/test/allocation_tests.jl @@ -0,0 +1,48 @@ +using OrdinaryDiffEqSSPRK +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqSSPRK solvers using AllocCheck.jl. +These tests verify that the step! operation does not allocate during stepping. +""" + +@testset "SSPRK Allocation Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported SSPRK solvers for allocation-free behavior + ssprk_solvers = [SSPRK53_2N2(), SSPRK22(), SSPRK53(), SSPRK63(), SSPRK83(), SSPRK43(), SSPRK432(), SSPRKMSVS32(), + SSPRK54(), SSPRK53_2N1(), SSPRK104(), SSPRK932(), SSPRKMSVS43(), SSPRK73(), SSPRK53_H(), + SSPRK33(), KYKSSPRK42(), KYK2014DGSSPRK_3S2()] + + @testset "SSPRK Solver Allocation Analysis" begin + for solver in ssprk_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test_broken length(allocs) == 0 + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSSPRK/test/jet.jl b/lib/OrdinaryDiffEqSSPRK/test/jet.jl new file mode 100644 index 0000000000..99102b7790 --- /dev/null +++ b/lib/OrdinaryDiffEqSSPRK/test/jet.jl @@ -0,0 +1,38 @@ +import OrdinaryDiffEqSSPRK +using OrdinaryDiffEqSSPRK +using OrdinaryDiffEqCore +using JET +using Test + +@testset "JET Tests" begin + # Test package for typos - now passing + test_package( + OrdinaryDiffEqSSPRK, target_defined_modules = true, mode = :typo) + + # Test individual solver type stability + @testset "Solver Type Stability Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test main SSPRK solvers (mark as broken) + ssprk_solvers = [SSPRK22(), SSPRK33(), SSPRK43(), SSPRK432(), SSPRKMSVS32(), SSPRKMSVS43(), + SSPRK932(), SSPRK54(), SSPRK73(), SSPRK83(), SSPRK63()] + + for solver in ssprk_solvers + @testset "$(typeof(solver)) type stability" begin + try + @test_opt broken=true init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + end +end diff --git a/lib/OrdinaryDiffEqSSPRK/test/ode_ssprk_tests.jl b/lib/OrdinaryDiffEqSSPRK/test/ode_ssprk_tests.jl index ec0c73f11b..8a29a3a764 100644 --- a/lib/OrdinaryDiffEqSSPRK/test/ode_ssprk_tests.jl +++ b/lib/OrdinaryDiffEqSSPRK/test/ode_ssprk_tests.jl @@ -80,7 +80,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 println("KYKSSPRK42") @@ -134,7 +134,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 println("SSPRK53") @@ -160,7 +160,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 println("SSPRK53_2N1") @@ -186,7 +186,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 # for SSPRK53_2N2 to be in asymptotic range @@ -214,7 +214,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 3 dts = 1 .// 2 .^ (9:-1:5) @@ -241,7 +241,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 4 #reverting back to original dts @@ -334,7 +334,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 println("SSPRK432") @@ -368,7 +368,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 alg = SSPRKMSVS32() @@ -423,7 +423,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 println("SSPRK54") @@ -470,7 +470,7 @@ integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = fal save_everystep = false) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 6 integ = init(prob_ode_large, alg, dt = 1.e-2, save_start = false, save_end = false, - save_everystep = false, alias_u0 = true) + save_everystep = false, alias = ODEAliasSpecifier(alias_u0 = true)) @test Base.summarysize(integ) ÷ Base.summarysize(u0_large) <= 5 println("KYK2014DGSSPRK_3S2") @@ -491,3 +491,26 @@ end sol = solve(test_problem_ssp_long, alg, dt = OrdinaryDiffEqSSPRK.ssp_coefficient(alg), dense = false) @test all(sol.u .>= 0) + +@testset "VectorOfArray/StructArray compatibility" begin + using RecursiveArrayTools, StaticArrays, StructArrays + + function rhs!(du_voa, u_voa, p, t) + du = parent(du_voa) + u = parent(u_voa) + du .= u + end + + # StructArray storage + u = StructArray{SVector{1, Float64}}(ntuple(_ -> [1.0, 2.0], 1)) + ode = ODEProblem(rhs!, VectorOfArray(u), (0, 0.7)) + sol_SA = solve(ode, SSPRK43()) + + # Vector{<:SVector} storage + u = SVector{1, Float64}.([1.0, 2.0]) + ode = ODEProblem(rhs!, VectorOfArray(u), (0, 0.7)) + sol_SV = solve(ode, SSPRK43()) + + @test sol_SA ≈ sol_SV + @test sol_SV.stats.naccept == sol_SA.stats.naccept +end diff --git a/lib/OrdinaryDiffEqSSPRK/test/qa.jl b/lib/OrdinaryDiffEqSSPRK/test/qa.jl new file mode 100644 index 0000000000..ae57485288 --- /dev/null +++ b/lib/OrdinaryDiffEqSSPRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqSSPRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqSSPRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSSPRK/test/runtests.jl b/lib/OrdinaryDiffEqSSPRK/test/runtests.jl index 228a1f248f..63814c4ac9 100644 --- a/lib/OrdinaryDiffEqSSPRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqSSPRK/test/runtests.jl @@ -1,3 +1,10 @@ using SafeTestsets @time @safetestset "SSPRK Tests" include("ode_ssprk_tests.jl") + +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqStabilizedIRK/Project.toml b/lib/OrdinaryDiffEqStabilizedIRK/Project.toml index da92cbbb91..739352e46a 100644 --- a/lib/OrdinaryDiffEqStabilizedIRK/Project.toml +++ b/lib/OrdinaryDiffEqStabilizedIRK/Project.toml @@ -1,42 +1,66 @@ name = "OrdinaryDiffEqStabilizedIRK" uuid = "e3e12d00-db14-5390-b879-ac3dd2ef6296" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.6.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" OrdinaryDiffEqDifferentiation = "4302a76b-040a-498a-8c04-15b101fed76b" -OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +OrdinaryDiffEqStabilizedRK = "358294b1-0aab-51c3-aafe-ad5ab194a2ad" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqDifferentiation = "<0.0.1, 1" -OrdinaryDiffEqNonlinearSolve = "<0.0.1, 1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearAlgebra = "1.10" +OrdinaryDiffEqDifferentiation = "1.12.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +OrdinaryDiffEqStabilizedRK = "1.4.0" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +ADTypes = "1.16" +RecursiveArrayTools = "3.36" +OrdinaryDiffEqNonlinearSolve = "1.13.0" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "LinearAlgebra"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "LinearAlgebra", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqDifferentiation] +path = "../OrdinaryDiffEqDifferentiation" + +[sources.OrdinaryDiffEqNonlinearSolve] +path = "../OrdinaryDiffEqNonlinearSolve" + +[sources.OrdinaryDiffEqStabilizedRK] +path = "../OrdinaryDiffEqStabilizedRK" + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqStabilizedIRK/src/OrdinaryDiffEqStabilizedIRK.jl b/lib/OrdinaryDiffEqStabilizedIRK/src/OrdinaryDiffEqStabilizedIRK.jl index f16310de7e..2410c2a55b 100644 --- a/lib/OrdinaryDiffEqStabilizedIRK/src/OrdinaryDiffEqStabilizedIRK.jl +++ b/lib/OrdinaryDiffEqStabilizedIRK/src/OrdinaryDiffEqStabilizedIRK.jl @@ -11,17 +11,21 @@ import OrdinaryDiffEqCore: alg_order, alg_maximum_order, OrdinaryDiffEqAdaptiveImplicitAlgorithm, alg_cache, _unwrap_val, DEFAULT_PRECS, @cache, _reshape, _vec, full_cache, get_fsalfirstlast, - generic_solver_docstring + generic_solver_docstring, _bool_to_ADType, _process_AD_choice using OrdinaryDiffEqDifferentiation: dolinsolve, update_W! using OrdinaryDiffEqNonlinearSolve: NLNewton, nlsolve!, isnewton, build_nlsolver, markfirststage!, du_alias_or_new, get_W + +using OrdinaryDiffEqStabilizedRK: ESERK4, ESERK5, RKC, SERK2 + using FastBroadcast, MuladdMacro, RecursiveArrayTools import StaticArrays: SArray, MVector, SVector, @SVector, StaticArray, MMatrix, SA import OrdinaryDiffEqCore +import ADTypes: AutoForwardDiff, AbstractADType using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqStabilizedIRK/src/algorithms.jl b/lib/OrdinaryDiffEqStabilizedIRK/src/algorithms.jl index 85cf0825fa..719cc9e566 100644 --- a/lib/OrdinaryDiffEqStabilizedIRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqStabilizedIRK/src/algorithms.jl @@ -1,6 +1,6 @@ @doc generic_solver_docstring("Implicit Runge-Kutta-Chebyshev method.", "IRKC", - "Stabalized Implicit Runge Kutta method.", + "Stabilized Implicit Runge Kutta method.", "REF TBD", "- `eigen_est`: function of the form `(integrator) -> integrator.eigen_est = upper_bound`, @@ -17,15 +17,19 @@ struct IRKC{CS, AD, F, F2, P, FDT, ST, CJ, K, T, E} <: extrapolant::Symbol controller::Symbol eigen_est::E + autodiff::AD end -function IRKC(; chunk_size = Val{0}(), autodiff = Val{true}(), standardtag = Val{true}(), - concrete_jac = nothing, diff_type = Val{:forward}, +function IRKC(; + chunk_size = Val{0}(), autodiff = AutoForwardDiff(), standardtag = Val{true}(), + concrete_jac = nothing, diff_type = Val{:forward}(), linsolve = nothing, precs = DEFAULT_PRECS, nlsolve = NLNewton(), κ = nothing, tol = nothing, extrapolant = :linear, controller = :Standard, eigen_est = nothing) - IRKC{_unwrap_val(chunk_size), _unwrap_val(autodiff), typeof(linsolve), typeof(nlsolve), + AD_choice, chunk_size, diff_type = _process_AD_choice(autodiff, chunk_size, diff_type) + + IRKC{_unwrap_val(chunk_size), typeof(AD_choice), typeof(linsolve), typeof(nlsolve), typeof(precs), diff_type, _unwrap_val(standardtag), _unwrap_val(concrete_jac), typeof(κ), typeof(tol), typeof(eigen_est)}(linsolve, nlsolve, precs, κ, tol, - extrapolant, controller, eigen_est) + extrapolant, controller, eigen_est, AD_choice) end diff --git a/lib/OrdinaryDiffEqStabilizedIRK/src/irkc_perform_step.jl b/lib/OrdinaryDiffEqStabilizedIRK/src/irkc_perform_step.jl index da07d95c41..4c0c7ae390 100644 --- a/lib/OrdinaryDiffEqStabilizedIRK/src/irkc_perform_step.jl +++ b/lib/OrdinaryDiffEqStabilizedIRK/src/irkc_perform_step.jl @@ -84,9 +84,7 @@ function perform_step!(integrator, cache::IRKCConstantCache, repeat_step = false f2ⱼ₋₁ = f2(gprev, p, t + Cⱼ₋₁ * dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 - nlsolver.tmp = (1 - μ - ν) * uprev + μ * gprev + ν * gprev2 + dt * μs * f2ⱼ₋₁ + - dt * νs * du₂ + (νs - (1 - μ - ν) * μs₁) * dt * du₁ - - ν * μs₁ * dt * f1ⱼ₋₂ + nlsolver.tmp = (1 - μ - ν) * uprev + μ * gprev + ν * gprev2 + dt * μs * f2ⱼ₋₁ + dt * νs * du₂ + (νs - (1 - μ - ν) * μs₁) * dt * du₁ - ν * μs₁ * dt * f1ⱼ₋₂ nlsolver.z = dt * f1ⱼ₋₁ nlsolver.c = Cⱼ z = nlsolve!(nlsolver, integrator, cache, false) @@ -216,10 +214,7 @@ function perform_step!(integrator, cache::IRKCCache, repeat_step = false) f2(f2ⱼ₋₁, gprev, p, t + Cⱼ₋₁ * dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.stats.nf2 += 1 - @.. broadcast=false nlsolver.tmp=(1 - μ - ν) * uprev + μ * gprev + ν * gprev2 + - dt * μs * f2ⱼ₋₁ + dt * νs * du₂ + - (νs - (1 - μ - ν) * μs₁) * dt * du₁ - - ν * μs₁ * dt * f1ⱼ₋₂ + @.. broadcast=false nlsolver.tmp=(1 - μ - ν) * uprev + μ * gprev + ν * gprev2 + dt * μs * f2ⱼ₋₁ + dt * νs * du₂ + (νs - (1 - μ - ν) * μs₁) * dt * du₁ - ν * μs₁ * dt * f1ⱼ₋₂ @.. broadcast=false nlsolver.z=dt * f1ⱼ₋₁ nlsolver.c = Cⱼ @@ -252,8 +247,7 @@ function perform_step!(integrator, cache::IRKCCache, repeat_step = false) # error estimate if isnewton(nlsolver) && integrator.opts.adaptive update_W!(integrator, cache, dt, false) - @.. broadcast=false gprev=dt * 0.5 * (du₂ - f2ⱼ₋₁) + - dt * (0.5 - μs₁) * (du₁ - f1ⱼ₋₁) + @.. broadcast=false gprev=dt * 0.5 * (du₂ - f2ⱼ₋₁) + dt * (0.5 - μs₁) * (du₁ - f1ⱼ₋₁) linsolve = nlsolver.cache.linsolve linres = dolinsolve(integrator, linsolve; b = _vec(gprev), linu = _vec(tmp)) diff --git a/lib/OrdinaryDiffEqStabilizedIRK/test/jet.jl b/lib/OrdinaryDiffEqStabilizedIRK/test/jet.jl new file mode 100644 index 0000000000..885c6e8e91 --- /dev/null +++ b/lib/OrdinaryDiffEqStabilizedIRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqStabilizedIRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqStabilizedIRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqStabilizedIRK/test/qa.jl b/lib/OrdinaryDiffEqStabilizedIRK/test/qa.jl new file mode 100644 index 0000000000..8912b488b0 --- /dev/null +++ b/lib/OrdinaryDiffEqStabilizedIRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqStabilizedIRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqStabilizedIRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqStabilizedIRK/test/runtests.jl b/lib/OrdinaryDiffEqStabilizedIRK/test/runtests.jl index de44281497..fcb0139b33 100644 --- a/lib/OrdinaryDiffEqStabilizedIRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqStabilizedIRK/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "IRKC Tests" include("irkc_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqStabilizedRK/Project.toml b/lib/OrdinaryDiffEqStabilizedRK/Project.toml index 950345829a..37c265a3cb 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/Project.toml +++ b/lib/OrdinaryDiffEqStabilizedRK/Project.toml @@ -1,40 +1,51 @@ name = "OrdinaryDiffEqStabilizedRK" uuid = "358294b1-0aab-51c3-aafe-ad5ab194a2ad" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.5.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -ODEProblemLibrary = "0.1.8" -OrdinaryDiffEqCore = "1.1" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -StaticArrays = "1.9.7" -Test = "<0.0.1, 1" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +LinearAlgebra = "1.10" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +StaticArrays = "1.9" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +ODEProblemLibrary = "0.1.8" +AllocCheck = "0.2" +DiffEqBase = "6.176" +SafeTestsets = "0.1.0" +Reexport = "1.2" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "LinearAlgebra", "ODEProblemLibrary"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "LinearAlgebra", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqStabilizedRK/src/OrdinaryDiffEqStabilizedRK.jl b/lib/OrdinaryDiffEqStabilizedRK/src/OrdinaryDiffEqStabilizedRK.jl index d9ad47342e..8ee60216d9 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/src/OrdinaryDiffEqStabilizedRK.jl +++ b/lib/OrdinaryDiffEqStabilizedRK/src/OrdinaryDiffEqStabilizedRK.jl @@ -14,9 +14,10 @@ import OrdinaryDiffEqCore: alg_order, alg_adaptive_order, calculate_residuals!, using FastBroadcast, MuladdMacro, RecursiveArrayTools import StaticArrays: SArray, MVector, SVector, @SVector, StaticArray, MMatrix, SA import OrdinaryDiffEqCore +using DiffEqBase: DiffEqBase, value using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqStabilizedRK/src/alg_utils.jl b/lib/OrdinaryDiffEqStabilizedRK/src/alg_utils.jl index 4f4b2e68d8..b785e8e005 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqStabilizedRK/src/alg_utils.jl @@ -19,17 +19,17 @@ has_dtnew_modification(alg::Union{ROCK2, ROCK4, SERK2, ESERK4, ESERK5}) = true function dtnew_modification(integrator, alg::ROCK2, dtnew) min(dtnew, - typeof(dtnew)((((min(integrator.alg.max_stages, 200)^2.0) * 0.811 - + typeof(dtnew)((((min(integrator.alg.max_stages, 200)^2) * 0.811 - 1.5) / integrator.eigen_est))) end function dtnew_modification(integrator, alg::ROCK4, dtnew) min(dtnew, - typeof(dtnew)((((min(integrator.alg.max_stages, 152)^2.0) * 0.353 - 3) / + typeof(dtnew)((((min(integrator.alg.max_stages, 152)^2) * 0.353 - 3) / integrator.eigen_est))) end function dtnew_modification(integrator, alg::SERK2, dtnew) min(dtnew, - typeof(dtnew)((0.8 * 250 * 250 / (integrator.eigen_est + 1.0)))) + typeof(dtnew)((0.8 * 250 * 250 / (integrator.eigen_est + 1)))) end function dtnew_modification(integrator, alg::ESERK4, dtnew) min(dtnew, typeof(dtnew)((0.98 * 4000 * 4000 / integrator.eigen_est))) diff --git a/lib/OrdinaryDiffEqStabilizedRK/src/algorithms.jl b/lib/OrdinaryDiffEqStabilizedRK/src/algorithms.jl index 7102b4ab26..d74a71dc19 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqStabilizedRK/src/algorithms.jl @@ -1,6 +1,6 @@ @doc generic_solver_docstring( - """Second order method. Exhibits high stability for real eigenvalues + """High stability for real eigenvalues. Second order method. Exhibits high stability for real eigenvalues and is smoothened to allow for moderate sized complex eigenvalues.""", "ROCK2", "Stabilized Explicit Method.", @@ -29,7 +29,7 @@ function ROCK2(; min_stages = 0, max_stages = 200, eigen_est = nothing) end @doc generic_solver_docstring( - """Fourth order method. Exhibits high stability for real eigenvalues + """High stability for real eigenvalues. Fourth order method. Exhibits high stability for real eigenvalues and is smoothened to allow for moderate sized complex eigenvalues.""", "ROCK4", "Stabilized Explicit Method.", diff --git a/lib/OrdinaryDiffEqStabilizedRK/src/rkc_perform_step.jl b/lib/OrdinaryDiffEqStabilizedRK/src/rkc_perform_step.jl index 9bcdb59674..da8e8197bc 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/src/rkc_perform_step.jl +++ b/lib/OrdinaryDiffEqStabilizedRK/src/rkc_perform_step.jl @@ -18,7 +18,7 @@ end alg = unwrap_alg(integrator, true) alg.eigen_est === nothing ? maxeig!(integrator, cache) : alg.eigen_est(integrator) # The the number of degree for Chebyshev polynomial - mdeg = Int(floor(sqrt((1.5 + abs(dt) * integrator.eigen_est) / 0.811) + 1)) + mdeg = floor(Int, sqrt((1.5 + abs(dt) * integrator.eigen_est) / 0.811)) + 1 mdeg = min(max(mdeg, cache.min_stage), cache.max_stage) cache.mdeg = max(mdeg, 3) - 2 choosedeg!(cache) @@ -35,10 +35,13 @@ end μ, κ = recf[cache.start + (i - 2) * 2 + 1], recf[cache.start + (i - 2) * 2 + 2] ν = -1 - κ u = f(uᵢ₋₁, p, tᵢ₋₁) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tᵢ₋₁ = dt * μ - ν * tᵢ₋₂ - κ * tᵢ₋₃ u = (dt * μ) * u - ν * uᵢ₋₁ - κ * uᵢ₋₂ - i < cache.mdeg && (uᵢ₋₂ = uᵢ₋₁; - uᵢ₋₁ = u) + if i < cache.mdeg + uᵢ₋₂ = uᵢ₋₁ + uᵢ₋₁ = u + end tᵢ₋₃ = tᵢ₋₂ tᵢ₋₂ = tᵢ₋₁ end # end if @@ -93,7 +96,7 @@ end alg = unwrap_alg(integrator, true) alg.eigen_est === nothing ? maxeig!(integrator, cache) : alg.eigen_est(integrator) # The the number of degree for Chebyshev polynomial - mdeg = Int(floor(sqrt((1.5 + abs(dt) * integrator.eigen_est) / 0.811) + 1)) + mdeg = floor(Int, sqrt((1.5 + abs(dt) * integrator.eigen_est) / 0.811)) + 1 mdeg = min(max(mdeg, ccache.min_stage), ccache.max_stage) ccache.mdeg = max(mdeg, 3) - 2 choosedeg!(cache) @@ -110,6 +113,7 @@ end μ, κ = recf[ccache.start + (i - 2) * 2 + 1], recf[ccache.start + (i - 2) * 2 + 2] ν = -1 - κ f(k, uᵢ₋₁, p, tᵢ₋₁) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tᵢ₋₁ = dt * μ - ν * tᵢ₋₂ - κ * tᵢ₋₃ @.. broadcast=false u=(dt * μ) * k - ν * uᵢ₋₁ - κ * uᵢ₋₂ if i < ccache.mdeg @@ -152,7 +156,6 @@ end f(integrator.fsallast, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) integrator.k[2] = integrator.fsallast - integrator.u = u end function initialize!(integrator, cache::ROCK4ConstantCache) @@ -175,7 +178,7 @@ end alg = unwrap_alg(integrator, true) alg.eigen_est === nothing ? maxeig!(integrator, cache) : alg.eigen_est(integrator) # The the number of degree for Chebyshev polynomial - mdeg = Int(floor(sqrt((3 + abs(dt) * integrator.eigen_est) / 0.353) + 1)) + mdeg = floor(Int, sqrt((3 + abs(dt) * integrator.eigen_est) / 0.353)) + 1 mdeg = min(max(mdeg, cache.min_stage), cache.max_stage) cache.mdeg = max(mdeg, 5) - 4 choosedeg!(cache) @@ -186,16 +189,21 @@ end tᵢ₋₃ = t uᵢ₋₂ = copy(uprev) uᵢ₋₁ = uprev + (dt * recf[cache.start]) * fsalfirst - cache.mdeg < 2 && (u = uᵢ₋₁) + if cache.mdeg < 2 + u = uᵢ₋₁ + end # for the second to the cache.mdeg th stages for i in 2:(cache.mdeg) μ, κ = recf[cache.start + (i - 2) * 2 + 1], recf[cache.start + (i - 2) * 2 + 2] ν = -1 - κ u = f(uᵢ₋₁, p, tᵢ₋₁) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tᵢ₋₁ = dt * μ - ν * tᵢ₋₂ - κ * tᵢ₋₃ u = (dt * μ) * u - ν * uᵢ₋₁ - κ * uᵢ₋₂ - i < cache.mdeg && (uᵢ₋₂ = uᵢ₋₁; - uᵢ₋₁ = u) + if i < cache.mdeg + uᵢ₋₂ = uᵢ₋₁ + uᵢ₋₁ = u + end tᵢ₋₃ = tᵢ₋₂ tᵢ₋₂ = tᵢ₋₁ end @@ -225,7 +233,9 @@ end uᵢ₋₂ = u + a₃₁ * uᵢ₋₁ uᵢ₋₃ = u + a₄₁ * uᵢ₋₁ u += B₁ * uᵢ₋₁ - integrator.opts.adaptive && (tmp = B̂₁ * uᵢ₋₁) + if integrator.opts.adaptive + tmp = B̂₁ * uᵢ₋₁ + end uᵢ₋₁ = u + (a₂₁ - B₁) * uᵢ₋₁ # Stage-2 @@ -237,7 +247,9 @@ end uᵢ₋₂ += a₃₂ * uᵢ₋₁ uᵢ₋₃ += a₄₂ * uᵢ₋₁ u += B₂ * uᵢ₋₁ - integrator.opts.adaptive && (tmp += B̂₂ * uᵢ₋₁) + if integrator.opts.adaptive + tmp += B̂₂ * uᵢ₋₁ + end # Stage-3 c₃ = a₃₁ + a₃₂ @@ -247,7 +259,9 @@ end OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) uᵢ₋₃ += a₄₃ * uᵢ₋₂ u += B₃ * uᵢ₋₂ - integrator.opts.adaptive && (tmp += B̂₃ * uᵢ₋₂) + if integrator.opts.adaptive + tmp += B̂₃ * uᵢ₋₂ + end #Stage-4 c₄ = a₄₁ + a₄₂ + a₄₃ @@ -256,7 +270,9 @@ end uᵢ₋₃ = f(uᵢ₋₃, p, tᵢ₋₂) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) u += B₄ * uᵢ₋₃ - integrator.opts.adaptive && (tmp += B̂₄ * uᵢ₋₃) + if integrator.opts.adaptive + tmp += B̂₄ * uᵢ₋₃ + end uᵢ₋₁ = f(u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @@ -297,7 +313,7 @@ end alg = unwrap_alg(integrator, true) alg.eigen_est === nothing ? maxeig!(integrator, cache) : alg.eigen_est(integrator) # The the number of degree for Chebyshev polynomial - mdeg = Int(floor(sqrt((3 + abs(dt) * integrator.eigen_est) / 0.353) + 1)) + mdeg = floor(Int, sqrt((3 + abs(dt) * integrator.eigen_est) / 0.353)) + 1 mdeg = min(max(mdeg, ccache.min_stage), ccache.max_stage) ccache.mdeg = max(mdeg, 5) - 4 choosedeg!(cache) @@ -308,12 +324,15 @@ end tᵢ₋₃ = t @.. broadcast=false uᵢ₋₂=uprev @.. broadcast=false uᵢ₋₁=uprev + (dt * recf[ccache.start]) * fsalfirst - ccache.mdeg < 2 && (@.. broadcast=false u=uᵢ₋₁) + if ccache.mdeg < 2 + @.. broadcast=false u=uᵢ₋₁ + end # for the second to the ccache.mdeg th stages for i in 2:(ccache.mdeg) μ, κ = recf[ccache.start + (i - 2) * 2 + 1], recf[ccache.start + (i - 2) * 2 + 2] ν = -1 - κ f(k, uᵢ₋₁, p, tᵢ₋₁) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) tᵢ₋₁ = (dt * μ) - ν * tᵢ₋₂ - κ * tᵢ₋₃ @.. broadcast=false u=(dt * μ) * k - ν * uᵢ₋₁ - κ * uᵢ₋₂ if i < ccache.mdeg @@ -344,25 +363,28 @@ end # 4-stage finishing procedure. # Stage-1 - f(k, u, p, tᵢ₋₁) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @.. broadcast=false uᵢ₋₂=u + a₃₁ * k @.. broadcast=false uᵢ₋₃=u + a₄₁ * k @.. broadcast=false uᵢ₋₁=u + a₂₁ * k @.. broadcast=false u+=B₁ * k - integrator.opts.adaptive && (@.. broadcast=false tmp=B̂₁ * k) + if integrator.opts.adaptive + @.. broadcast=false tmp=B̂₁ * k + end # Stage-2 c₂ = a₂₁ - _c₂ = DiffEqBase.value(sign(c₂)) * integrator.opts.internalnorm(c₂, t) + _c₂ = value(sign(c₂)) * integrator.opts.internalnorm(c₂, t) tᵢ₋₂ = tᵢ₋₁ + _c₂ f(k, uᵢ₋₁, p, tᵢ₋₂) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @.. broadcast=false uᵢ₋₂+=a₃₂ * k @.. broadcast=false uᵢ₋₃+=a₄₂ * k @.. broadcast=false u+=B₂ * k - integrator.opts.adaptive && (@.. broadcast=false tmp+=B̂₂ * k) + if integrator.opts.adaptive + @.. broadcast=false tmp+=B̂₂ * k + end # Stage-3 c₃ = a₃₁ + a₃₂ @@ -372,7 +394,9 @@ end OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @.. broadcast=false uᵢ₋₃+=a₄₃ * k @.. broadcast=false u+=B₃ * k - integrator.opts.adaptive && (@.. broadcast=false tmp+=B̂₃ * k) + if integrator.opts.adaptive + @.. broadcast=false tmp+=B̂₃ * k + end #Stage-4 c₄ = a₄₁ + a₄₂ + a₄₃ @@ -381,14 +405,16 @@ end f(k, uᵢ₋₃, p, tᵢ₋₂) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) @.. broadcast=false u+=B₄ * k - integrator.opts.adaptive && (tmp += B̂₄ * k) + if integrator.opts.adaptive + @.. broadcast=false tmp += B̂₄ * k + end f(k, u, p, t + dt) OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) #Error estimate (embedded method of order 3) if integrator.opts.adaptive - tmp += B̂₅ * k + @.. broadcast=false tmp += B̂₅ * k calculate_residuals!(atmp, tmp, uprev, u, integrator.opts.abstol, integrator.opts.reltol, integrator.opts.internalnorm, t) integrator.EEst = integrator.opts.internalnorm(atmp, t) diff --git a/lib/OrdinaryDiffEqStabilizedRK/test/jet.jl b/lib/OrdinaryDiffEqStabilizedRK/test/jet.jl new file mode 100644 index 0000000000..d51bd793ab --- /dev/null +++ b/lib/OrdinaryDiffEqStabilizedRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqStabilizedRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqStabilizedRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqStabilizedRK/test/qa.jl b/lib/OrdinaryDiffEqStabilizedRK/test/qa.jl new file mode 100644 index 0000000000..83b8538e6f --- /dev/null +++ b/lib/OrdinaryDiffEqStabilizedRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqStabilizedRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqStabilizedRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqStabilizedRK/test/rkc_tests.jl b/lib/OrdinaryDiffEqStabilizedRK/test/rkc_tests.jl index 3849513e88..0174cd540f 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/test/rkc_tests.jl +++ b/lib/OrdinaryDiffEqStabilizedRK/test/rkc_tests.jl @@ -72,3 +72,61 @@ end @test sim.𝒪est[:l∞]≈5 atol=testTol end end + +@testset "Number of function evaluations" begin + x = Ref(0) + u0 = [1.0, 1.0] + tspan = (0.0, 1.0) + probop = ODEProblem(u0, tspan) do u, p, t + x[] += 1 + return -500 * u + end + probip = ODEProblem(u0, tspan) do du, u, p, t + x[] += 1 + @. du = -500 * u + return nothing + end + + @testset "$prob" for prob in [probop, probip] + eigen_est = (integrator) -> integrator.eigen_est = 500 + algs = [ROCK2(), ROCK2(eigen_est = eigen_est), + ROCK4(), ROCK4(eigen_est = eigen_est), + RKC(), RKC(eigen_est = eigen_est), + SERK2(), SERK2(eigen_est = eigen_est), + ESERK4(), ESERK4(eigen_est = eigen_est), + ESERK5(), ESERK5(eigen_est = eigen_est)] + @testset "$alg" for alg in algs + x[] = 0 + sol = solve(prob, alg) + @test x[] == sol.stats.nf + end + end +end + +@testset "Allocations" begin + u0 = [1.0, 1.0] + tspan = (0.0, 1.0) + prob = ODEProblem(u0, tspan) do du, u, p, t + @. du = -500 * u + return nothing + end + + eigen_est = (integrator) -> integrator.eigen_est = 500 + algs = [ROCK2(), ROCK2(eigen_est = eigen_est), + ROCK4(), ROCK4(eigen_est = eigen_est), + RKC(), RKC(eigen_est = eigen_est), + SERK2(), SERK2(eigen_est = eigen_est), + ESERK4(), ESERK4(eigen_est = eigen_est), + ESERK5(), ESERK5(eigen_est = eigen_est)] + @testset "$alg" for alg in algs + # compile once + integrator = init(prob, alg; save_everystep = false) + solve!(integrator) + # check allocations + integrator = init(prob, alg; save_everystep = false) + allocs = @allocations solve!(integrator) + # Julia 1.11 has an extra allocation in these algorithms + expected_allocs = VERSION >= v"1.11" ? 4 : 3 + @test allocs <= expected_allocs + end +end diff --git a/lib/OrdinaryDiffEqStabilizedRK/test/runtests.jl b/lib/OrdinaryDiffEqStabilizedRK/test/runtests.jl index fe60ea9a4d..1b15629103 100644 --- a/lib/OrdinaryDiffEqStabilizedRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqStabilizedRK/test/runtests.jl @@ -1,3 +1,5 @@ using SafeTestsets @time @safetestset "RKC Tests" include("rkc_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSymplecticRK/Project.toml b/lib/OrdinaryDiffEqSymplecticRK/Project.toml index 9c32d09c76..b5ce7d2aea 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/Project.toml +++ b/lib/OrdinaryDiffEqSymplecticRK/Project.toml @@ -1,44 +1,55 @@ name = "OrdinaryDiffEqSymplecticRK" uuid = "fa646aed-7ef9-47eb-84c4-9443fc8cbfa8" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.7.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" -RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" -Reexport = "189a3867-3050-52da-a836-e630ba90ab69" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -OrdinaryDiffEqRKN = "<0.0.1, 1" -OrdinaryDiffEqTsit5 = "<0.0.1, 1" -Polyester = "0.7.16" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Statistics = "1.11.1" -Test = "<0.0.1, 1" -julia = "1.10" [extras] +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrdinaryDiffEqRKN = "af6ede74-add8-4cfd-b1df-9a4dbb109d7a" -OrdinaryDiffEqTsit5 = "b1df2697-797e-41e3-8120-5422d3b24e4a" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Statistics = "<0.0.1, 1" +OrdinaryDiffEqTsit5 = "1.4.0" +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +Polyester = "0.7" +LinearAlgebra = "1.10" +OrdinaryDiffEqRKN = "1.4.0" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Aqua = "0.8.11" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "Statistics", "LinearAlgebra", "OrdinaryDiffEqTsit5", "OrdinaryDiffEqRKN"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "Statistics", "LinearAlgebra", "OrdinaryDiffEqTsit5", "OrdinaryDiffEqRKN", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqSymplecticRK/src/OrdinaryDiffEqSymplecticRK.jl b/lib/OrdinaryDiffEqSymplecticRK/src/OrdinaryDiffEqSymplecticRK.jl index c100a75215..2e05b19997 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/src/OrdinaryDiffEqSymplecticRK.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/src/OrdinaryDiffEqSymplecticRK.jl @@ -12,12 +12,12 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, constvalue, _unwrap_val, explicit_rk_docstring, trivial_limiter!, _ode_interpolant!, _ode_addsteps!, get_fsalfirstlast, - generic_solver_docstring + generic_solver_docstring, default_linear_interpolation using FastBroadcast, Polyester, MuladdMacro, RecursiveArrayTools import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") @@ -25,8 +25,8 @@ include("symplectic_caches.jl") include("symplectic_tableaus.jl") include("symplectic_perform_step.jl") -export SymplecticEuler, VelocityVerlet, VerletLeapfrog, PseudoVerletLeapfrog, - McAte2, Ruth3, McAte3, CandyRoz4, McAte4, McAte42, McAte5, +export SymplecticEuler, VelocityVerlet, VerletLeapfrog, LeapfrogDriftKickDrift, + PseudoVerletLeapfrog, McAte2, Ruth3, McAte3, CandyRoz4, McAte4, McAte42, McAte5, CalvoSanz4, Yoshida6, KahanLi6, McAte8, KahanLi8, SofSpa10 end diff --git a/lib/OrdinaryDiffEqSymplecticRK/src/alg_utils.jl b/lib/OrdinaryDiffEqSymplecticRK/src/alg_utils.jl index e6d418bb8a..e39a4d34f0 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/src/alg_utils.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/src/alg_utils.jl @@ -1,6 +1,7 @@ alg_order(alg::SymplecticEuler) = 1 alg_order(alg::VelocityVerlet) = 2 alg_order(alg::VerletLeapfrog) = 2 +alg_order(alg::LeapfrogDriftKickDrift) = 2 alg_order(alg::PseudoVerletLeapfrog) = 2 alg_order(alg::McAte2) = 2 alg_order(alg::Ruth3) = 3 diff --git a/lib/OrdinaryDiffEqSymplecticRK/src/algorithms.jl b/lib/OrdinaryDiffEqSymplecticRK/src/algorithms.jl index cdbc53d2e1..178ffc2635 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/src/algorithms.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/src/algorithms.jl @@ -24,12 +24,38 @@ publisher={APS} verlet1967, "", "") struct VelocityVerlet <: OrdinaryDiffEqPartitionedAlgorithm end -@doc generic_solver_docstring("2nd order explicit symplectic integrator.", +monaghan2005 = """ +@article{monaghan2005, + title = {Smoothed particle hydrodynamics}, + author = {Monaghan, Joseph J.}, + year = {2005}, + journal = {Reports on Progress in Physics}, + volume = {68}, + number = {8}, + pages = {1703--1759}, + doi = {10.1088/0034-4885/68/8/R01}, +} +""" + +@doc generic_solver_docstring( + "2nd order explicit symplectic integrator. Kick-drift-kick form. Requires only one evaluation of `f1` per step.", "VerletLeapfrog", "Symplectic Runge-Kutta Methods", - verlet1967, "", "") + monaghan2005, "", "") struct VerletLeapfrog <: OrdinaryDiffEqPartitionedAlgorithm end +default_linear_interpolation(alg::VerletLeapfrog, prob) = true + +@doc generic_solver_docstring( + "2nd order explicit symplectic integrator. Drift-kick-drift form of `VerletLeapfrog` +designed to work when `f1` depends on `v`. Requires two evaluation of `f1` per step.", + "LeapfrogDriftKickDrift", + "Symplectic Runge-Kutta Methods", + monaghan2005, "", "") +struct LeapfrogDriftKickDrift <: OrdinaryDiffEqPartitionedAlgorithm end + +default_linear_interpolation(alg::LeapfrogDriftKickDrift, prob) = true + @doc generic_solver_docstring("2nd order explicit symplectic integrator.", "PseudoVerletLeapfrog", "Symplectic Runge-Kutta Methods", @@ -87,7 +113,7 @@ struct McAte3 <: OrdinaryDiffEqPartitionedAlgorithm end umber={1}, ages={230--256}, ear={1991}, - ublisher={Elsevier}}""", "", "") + publisher={Elsevier}}""", "", "") struct CandyRoz4 <: OrdinaryDiffEqPartitionedAlgorithm end @doc generic_solver_docstring( diff --git a/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl b/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl index dca14b6d28..e9b0ca838c 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_caches.jl @@ -57,13 +57,50 @@ function alg_cache(alg::VelocityVerlet, u, rate_prototype, ::Type{uEltypeNoUnits VelocityVerletConstantCache(uEltypeNoUnits(1 // 2)) end -@cache struct Symplectic2Cache{uType, rateType, tableauType} <: HamiltonMutableCache +@cache struct LeapfrogDriftKickDriftCache{uType, rateType, uEltypeNoUnits} <: + OrdinaryDiffEqMutableCache u::uType uprev::uType tmp::uType k::rateType fsalfirst::rateType - tab::tableauType + half::uEltypeNoUnits +end + +struct LeapfrogDriftKickDriftConstantCache{uEltypeNoUnits} <: HamiltonConstantCache + half::uEltypeNoUnits +end + +function alg_cache(alg::LeapfrogDriftKickDrift, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + tmp = zero(rate_prototype) + k = zero(rate_prototype) + fsalfirst = zero(rate_prototype) + half = uEltypeNoUnits(1 // 2) + LeapfrogDriftKickDriftCache(u, uprev, k, tmp, fsalfirst, half) +end + +function alg_cache(alg::LeapfrogDriftKickDrift, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + LeapfrogDriftKickDriftConstantCache(uEltypeNoUnits(1 // 2)) +end + +@cache struct VerletLeapfrogCache{uType, rateType, uEltypeNoUnits} <: + OrdinaryDiffEqMutableCache + u::uType + uprev::uType + tmp::uType + k::rateType + fsalfirst::rateType + half::uEltypeNoUnits +end + +struct VerletLeapfrogConstantCache{uEltypeNoUnits} <: HamiltonConstantCache + half::uEltypeNoUnits end function alg_cache(alg::VerletLeapfrog, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -73,16 +110,24 @@ function alg_cache(alg::VerletLeapfrog, u, rate_prototype, ::Type{uEltypeNoUnits tmp = zero(u) k = zero(rate_prototype) fsalfirst = zero(rate_prototype) - tab = VerletLeapfrogConstantCache(constvalue(uBottomEltypeNoUnits), - constvalue(tTypeNoUnits)) - Symplectic2Cache(u, uprev, k, tmp, fsalfirst, tab) + half = uEltypeNoUnits(1 // 2) + VerletLeapfrogCache(u, uprev, k, tmp, fsalfirst, half) end function alg_cache(alg::VerletLeapfrog, u, rate_prototype, ::Type{uEltypeNoUnits}, ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, dt, reltol, p, calck, ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} - VerletLeapfrogConstantCache(constvalue(uBottomEltypeNoUnits), constvalue(tTypeNoUnits)) + VerletLeapfrogConstantCache(uEltypeNoUnits(1 // 2)) +end + +@cache struct Symplectic2Cache{uType, rateType, tableauType} <: HamiltonMutableCache + u::uType + uprev::uType + tmp::uType + k::rateType + fsalfirst::rateType + tab::tableauType end function alg_cache(alg::PseudoVerletLeapfrog, u, rate_prototype, ::Type{uEltypeNoUnits}, @@ -422,6 +467,7 @@ function alg_cache(alg::SofSpa10, u, rate_prototype, ::Type{uEltypeNoUnits}, end function get_fsalfirstlast( - cache::Union{HamiltonMutableCache, VelocityVerletCache, SymplecticEulerCache}, u) + cache::Union{HamiltonMutableCache, VelocityVerletCache, VerletLeapfrogCache, + SymplecticEulerCache, LeapfrogDriftKickDriftCache}, u) (cache.fsalfirst, cache.k) end diff --git a/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_perform_step.jl b/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_perform_step.jl index 2e581be283..d70d3ce517 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_perform_step.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_perform_step.jl @@ -77,16 +77,22 @@ end # f.f2(p, q, pa, t) = p which is the Newton/Lagrange equations # If called with different functions (which are possible in the Hamiltonian case) # an exception is thrown to avoid silently calculate wrong results. -verify_f2(f, p, q, pa, t, ::Any, ::C) where {C <: HamiltonConstantCache} = f(p, q, pa, t) -function verify_f2(f, res, p, q, pa, t, ::Any, ::C) where {C <: HamiltonMutableCache} +function verify_f2(f::F, p, q, pa, t, ::Any, + ::C) where {F, C <: Union{HamiltonConstantCache, VerletLeapfrogConstantCache, + LeapfrogDriftKickDriftConstantCache}} + f(p, q, pa, t) +end +function verify_f2(f::F, res, p, q, pa, t, ::Any, + ::C) where {F, C <: Union{HamiltonMutableCache, VerletLeapfrogCache, + LeapfrogDriftKickDriftCache}} f(res, p, q, pa, t) end -function verify_f2(f, p, q, pa, t, integrator, ::C) where {C <: VelocityVerletConstantCache} +function verify_f2(f::F, p, q, pa, t, integrator, ::C) where {F, C <: VelocityVerletConstantCache} res = f(p, q, pa, t) res == p ? p : throwex(integrator) end -function verify_f2(f, res, p, q, pa, t, integrator, ::C) where {C <: VelocityVerletCache} +function verify_f2(f::F, res, p, q, pa, t, integrator, ::C) where {F, C <: VelocityVerletCache} f(res, p, q, pa, t) res == p ? res : throwex(integrator) end @@ -124,8 +130,8 @@ function store_symp_state!(integrator, ::OrdinaryDiffEqMutableCache, kdu, ku) end function initialize!(integrator, - cache::C) where {C <: - Union{HamiltonMutableCache, VelocityVerletCache}} + cache::C) where {C <: Union{HamiltonMutableCache, VelocityVerletCache, + VerletLeapfrogCache, LeapfrogDriftKickDriftCache}} integrator.kshortsize = 2 resize!(integrator.k, integrator.kshortsize) integrator.k[1] = integrator.fsalfirst @@ -140,9 +146,8 @@ function initialize!(integrator, end function initialize!(integrator, - cache::C) where { - C <: - Union{HamiltonConstantCache, VelocityVerletConstantCache}} + cache::C) where {C <: Union{HamiltonConstantCache, VelocityVerletConstantCache, + VerletLeapfrogConstantCache, LeapfrogDriftKickDriftConstantCache}} integrator.kshortsize = 2 integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) @@ -171,7 +176,7 @@ end # v(t+Δt) = v(t) + 1/2*(a(t)+a(t+Δt))*Δt du = duprev + dt * (half * ku + half * kdu) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) store_symp_state!(integrator, cache, du, u, kdu, du) end @@ -186,13 +191,118 @@ end half = cache.half @.. broadcast=false u=uprev + dt * duprev + dtsq * (half * ku) f.f1(kdu, duprev, u, p, t + dt) - OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) # v(t+Δt) = v(t) + 1/2*(a(t)+a(t+Δt))*Δt @.. broadcast=false du=duprev + dt * (half * ku + half * kdu) store_symp_state!(integrator, cache, kdu, du) end +@muladd function perform_step!(integrator, cache::VerletLeapfrogConstantCache, + repeat_step = false) + @unpack t, dt, f, p = integrator + duprev, uprev, kduprev, _ = load_symp_state(integrator) + + # kick-drift-kick scheme of the Leapfrog method: + # update velocity + half = cache.half + du = duprev + dt * half * kduprev + + # update position + ku = f.f2(du, uprev, p, t + half * dt) + u = uprev + dt * ku + + # update velocity + kdu = f.f1(du, u, p, t + dt) + du = du + dt * half * kdu + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + integrator.stats.nf2 += 1 + store_symp_state!(integrator, cache, du, u, kdu, ku) +end + +@muladd function perform_step!(integrator, cache::VerletLeapfrogCache, repeat_step = false) + @unpack t, dt, f, p = integrator + duprev, uprev, kduprev, _ = load_symp_state(integrator) + du, u, kdu, ku = alloc_symp_state(integrator) + + # kick-drift-kick scheme of the Leapfrog method: + # update velocity + half = cache.half + @.. broadcast=false du=duprev + dt * half * kduprev + + # update position + f.f2(ku, du, uprev, p, t + half * dt) + @.. broadcast=false u=uprev + dt * ku + + # update velocity + f.f1(kdu, du, u, p, t + dt) + @.. broadcast=false du=du + dt * half * kdu + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 1) + integrator.stats.nf2 += 1 + store_symp_state!(integrator, cache, kdu, ku) +end + +@muladd function perform_step!(integrator, cache::LeapfrogDriftKickDriftConstantCache, + repeat_step = false) + @unpack t, dt, f, p = integrator + duprev, uprev, _, _ = load_symp_state(integrator) + + # drift-kick-drift scheme of the Leapfrog method, allowing for f1 to depend on v: + # update position half step + half = cache.half + ku = f.f2(duprev, uprev, p, t) + u = uprev + dt * half * ku + + # update velocity half step + kdu = f.f1(duprev, uprev, p, t) + du = duprev + dt * half * kdu + + # update velocity (add to previous full step velocity) + # note that this extra step is only necessary if f1 depends on v/du (or t) + kdu = f.f1(du, u, p, t + half * dt) + du = duprev + dt * kdu + + # update position (add to half step position) + ku = f.f2(du, u, p, t + dt) + u = u + dt * half * ku + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) + integrator.stats.nf2 += 2 + store_symp_state!(integrator, cache, du, u, kdu, ku) +end + +@muladd function perform_step!(integrator, cache::LeapfrogDriftKickDriftCache, + repeat_step = false) + @unpack t, dt, f, p = integrator + duprev, uprev, _, _ = load_symp_state(integrator) + du, u, kdu, ku = alloc_symp_state(integrator) + + # drift-kick-drift scheme of the Leapfrog method, allowing for f1 to depend on v: + # update position half step + half = cache.half + f.f2(ku, duprev, uprev, p, t) + @.. broadcast=false u=uprev + dt * half * ku + + # update velocity half step + f.f1(kdu, duprev, uprev, p, t) + @.. broadcast=false du=duprev + dt * half * kdu + + # update velocity (add to previous full step velocity) + # note that this extra step is only necessary if f1 depends on v/du (or t) + f.f1(kdu, du, u, p, t + half * dt) + @.. broadcast=false du=duprev + dt * kdu + + # update position (add to half step position) + f.f2(ku, du, u, p, t + dt) + @.. broadcast=false u=u + dt * half * ku + + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 2) + integrator.stats.nf2 += 2 + store_symp_state!(integrator, cache, kdu, ku) +end + @muladd function perform_step!(integrator, cache::Symplectic2ConstantCache, repeat_step = false) @unpack t, dt, f, p = integrator diff --git a/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_tableaus.jl b/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_tableaus.jl index fd5acd6e61..61e791c57f 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_tableaus.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/src/symplectic_tableaus.jl @@ -21,14 +21,6 @@ function McAte2ConstantCache(T, T2) Symplectic2ConstantCache{T, T2}(a1, a2, b1, b2) end -function VerletLeapfrogConstantCache(T, T2) - a1 = convert(T, 1 // 2) - a2 = convert(T, 1 // 2) - b1 = convert(T, 0) - b2 = convert(T, 1) - Symplectic2ConstantCache{T, T2}(a1, a2, b1, b2) -end - struct Symplectic3ConstantCache{T, T2} <: HamiltonConstantCache a1::T a2::T diff --git a/lib/OrdinaryDiffEqSymplecticRK/test/jet.jl b/lib/OrdinaryDiffEqSymplecticRK/test/jet.jl new file mode 100644 index 0000000000..467f98eef6 --- /dev/null +++ b/lib/OrdinaryDiffEqSymplecticRK/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqSymplecticRK +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqSymplecticRK, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqSymplecticRK/test/qa.jl b/lib/OrdinaryDiffEqSymplecticRK/test/qa.jl new file mode 100644 index 0000000000..6b7817e03c --- /dev/null +++ b/lib/OrdinaryDiffEqSymplecticRK/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqSymplecticRK +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqSymplecticRK + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSymplecticRK/test/runtests.jl b/lib/OrdinaryDiffEqSymplecticRK/test/runtests.jl index b051eeb6f7..c16863e320 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/test/runtests.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/test/runtests.jl @@ -2,3 +2,5 @@ using SafeTestsets @time @safetestset "Synplectic Convergence Tests" include("symplectic_convergence.jl") @time @safetestset "Synplectic Tests" include("symplectic_tests.jl") +@time @safetestset "JET Tests" include("jet.jl") +@time @safetestset "Aqua" include("qa.jl") \ No newline at end of file diff --git a/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_convergence.jl b/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_convergence.jl index 0939c97897..c303ee0799 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_convergence.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_convergence.jl @@ -62,6 +62,9 @@ position_error = :final => [mean(sim[i].u[2].x[1] - sim[i].u_analytic[2].x[1]) sim = test_convergence(dts, prob, VerletLeapfrog(), dense_errors = true) @test sim.𝒪est[:l2]≈2 rtol=1e-1 @test sim.𝒪est[:L2]≈2 rtol=1e-1 +sim = test_convergence(dts, prob, LeapfrogDriftKickDrift(), dense_errors = true) +@test sim.𝒪est[:l2]≈2 rtol=1e-1 +@test sim.𝒪est[:L2]≈2 rtol=1e-1 sim = test_convergence(dts, prob, PseudoVerletLeapfrog(), dense_errors = true) @test sim.𝒪est[:l2]≈2 rtol=1e-1 @test sim.𝒪est[:L2]≈2 rtol=1e-1 @@ -151,6 +154,9 @@ position_error = :final => [mean(sim[i].u[2].x[1] - sim[i].u_analytic[2].x[1]) sim = test_convergence(dts, prob, VerletLeapfrog(), dense_errors = true) @test sim.𝒪est[:l2]≈2 rtol=1e-1 @test sim.𝒪est[:L2]≈2 rtol=1e-1 +sim = test_convergence(dts, prob, LeapfrogDriftKickDrift(), dense_errors = true) +@test sim.𝒪est[:l2]≈2 rtol=1e-1 +@test sim.𝒪est[:L2]≈2 rtol=1e-1 sim = test_convergence(dts, prob, PseudoVerletLeapfrog(), dense_errors = true) @test sim.𝒪est[:l2]≈2 rtol=1e-1 @test sim.𝒪est[:L2]≈2 rtol=1e-1 @@ -202,3 +208,28 @@ dts = 1.0 ./ 2.0 .^ (2:-1:-2) sim = test_convergence(dts, prob, SofSpa10(), dense_errors = true) @test sim.𝒪est[:l2]≈10 rtol=1e-1 @test sim.𝒪est[:L2]≈4 rtol=1e-1 + +################# f1 dependent on v + +println("f1 dependent on v") + +u0 = fill(0.0, 2) +v0 = ones(2) +function f1_v(dv, v, u, p, t) + dv .= v +end +function f2_v(du, v, u, p, t) + du .= v +end +function f_v_analytic(y0, p, x) + v0, u0 = y0.x + ArrayPartition(v0 * exp(x), v0 * exp(x) - v0 + u0) +end +ff_v = DynamicalODEFunction(f1_v, f2_v; analytic = f_v_analytic) +prob = DynamicalODEProblem(ff_v, v0, u0, (0.0, 5.0)) + +dts = 1 .// 2 .^ (6:-1:3) +# LeapfrogDriftKickDrift +sim = test_convergence(dts, prob, LeapfrogDriftKickDrift(), dense_errors = true) +@test sim.𝒪est[:l2]≈2 rtol=1e-1 +@test sim.𝒪est[:L2]≈2 rtol=1e-1 diff --git a/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_tests.jl b/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_tests.jl index e1771678b2..32b2a8f52a 100644 --- a/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_tests.jl +++ b/lib/OrdinaryDiffEqSymplecticRK/test/symplectic_tests.jl @@ -7,6 +7,7 @@ using OrdinaryDiffEqRKN const ALGOS = ((SymplecticEuler, true, 1), (VelocityVerlet, false, 2), (VerletLeapfrog, true, 2), + (LeapfrogDriftKickDrift, true, 2), (PseudoVerletLeapfrog, true, 2), (McAte2, true, 2), (Ruth3, true, 3), diff --git a/lib/OrdinaryDiffEqTaylorSeries/LICENSE.md b/lib/OrdinaryDiffEqTaylorSeries/LICENSE.md new file mode 100644 index 0000000000..4a7df96ac5 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/LICENSE.md @@ -0,0 +1,24 @@ +The OrdinaryDiffEq.jl package is licensed under the MIT "Expat" License: + +> Copyright (c) 2016-2020: ChrisRackauckas, Yingbo Ma, Julia Computing Inc, and +> other contributors: +> +> https://github.com/SciML/OrdinaryDiffEq.jl/graphs/contributors +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. diff --git a/lib/OrdinaryDiffEqTaylorSeries/Project.toml b/lib/OrdinaryDiffEqTaylorSeries/Project.toml new file mode 100644 index 0000000000..e6a075f5af --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/Project.toml @@ -0,0 +1,60 @@ +name = "OrdinaryDiffEqTaylorSeries" +uuid = "9c7f1690-dd92-42a3-8318-297ee24d8d39" +authors = ["ParamThakkar123 "] +version = "1.4.0" + +[deps] +FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +TaylorDiff = "b36ab563-344f-407b-a36a-4f200bebf99c" +MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +Preferences = "21216c6a-2e73-6563-6e65-726566657250" +RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" + +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +ODEProblemLibrary = "fdc4e326-1af4-4b90-96e7-779fcce2daa5" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +TaylorDiff = "0.3.1" +MuladdMacro = "0.2" +PrecompileTools = "1.2" +Symbolics = "6.48.0" +LinearAlgebra = "1.10" +TruncatedStacktraces = "1.4" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +Preferences = "1.4" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" + +[targets] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "ODEProblemLibrary", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqTaylorSeries/src/OrdinaryDiffEqTaylorSeries.jl b/lib/OrdinaryDiffEqTaylorSeries/src/OrdinaryDiffEqTaylorSeries.jl new file mode 100644 index 0000000000..a06dabaaf6 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/src/OrdinaryDiffEqTaylorSeries.jl @@ -0,0 +1,60 @@ +module OrdinaryDiffEqTaylorSeries + +import OrdinaryDiffEqCore: alg_order, alg_stability_size, explicit_rk_docstring, + OrdinaryDiffEqAdaptiveAlgorithm, OrdinaryDiffEqMutableCache, + alg_cache, + OrdinaryDiffEqConstantCache, @fold, trivial_limiter!, + constvalue, @unpack, perform_step!, calculate_residuals, @cache, + calculate_residuals!, _ode_interpolant, _ode_interpolant!, + CompiledFloats, @OnDemandTableauExtract, initialize!, + perform_step!, OrdinaryDiffEqAlgorithm, + CompositeAlgorithm, _ode_addsteps!, copyat_or_push!, + AutoAlgSwitch, get_fsalfirstlast, + full_cache, DerivativeOrderNotPossibleError +import Static: False +import MuladdMacro: @muladd +import FastBroadcast: @.. +import RecursiveArrayTools: recursivefill!, recursive_unitless_bottom_eltype +import LinearAlgebra: norm +using TruncatedStacktraces: @truncate_stacktrace +using TaylorDiff, Symbolics +using TaylorDiff: make_seed, get_coefficient, append_coefficient, flatten +import SciMLBase: @def +import OrdinaryDiffEqCore + +using Reexport +@reexport using SciMLBase + +include("algorithms.jl") +include("alg_utils.jl") +include("TaylorSeries_caches.jl") +include("TaylorSeries_perform_step.jl") + +import PrecompileTools +import Preferences + +PrecompileTools.@compile_workload begin + lorenz = OrdinaryDiffEqCore.lorenz + lorenz_oop = OrdinaryDiffEqCore.lorenz_oop + solver_list = [ExplicitTaylor2()] + prob_list = [] + + if Preferences.@load_preference("PrecompileNoSpecialize", false) + push!(prob_list, + ODEProblem{true, SciMLBase.NoSpecialize}(lorenz, [1.0; 0.0; 0.0], (0.0, 1.0))) + push!(prob_list, + ODEProblem{true, SciMLBase.NoSpecialize}(lorenz, [1.0; 0.0; 0.0], (0.0, 1.0), + Float64[])) + end + + for prob in prob_list, solver in solver_list + solve(prob, solver)(5.0) + end + + prob_list = nothing + solver_list = nothing +end + +export ExplicitTaylor2, ExplicitTaylor, DAETS + +end diff --git a/lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_caches.jl b/lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_caches.jl new file mode 100644 index 0000000000..b07e9e912d --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_caches.jl @@ -0,0 +1,88 @@ +@cache struct ExplicitTaylor2Cache{ + uType, rateType, uNoUnitsType, StageLimiter, StepLimiter, + Thread} <: OrdinaryDiffEqMutableCache + u::uType + uprev::uType + k1::rateType + k2::rateType + k3::rateType + utilde::uType + tmp::uType + atmp::uNoUnitsType + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function alg_cache(alg::ExplicitTaylor2, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + k1 = zero(rate_prototype) + k2 = zero(rate_prototype) + k3 = zero(rate_prototype) + utilde = zero(u) + atmp = similar(u, uEltypeNoUnits) + recursivefill!(atmp, false) + tmp = zero(u) + ExplicitTaylor2Cache(u, uprev, k1, k2, k3, utilde, tmp, atmp, + alg.stage_limiter!, alg.step_limiter!, alg.thread) +end +struct ExplicitTaylor2ConstantCache <: OrdinaryDiffEqConstantCache end +function alg_cache(alg::ExplicitTaylor2, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + ExplicitTaylor2ConstantCache() +end +# FSAL currently not used, providing dummy implementation to satisfy the interface +get_fsalfirstlast(cache::ExplicitTaylor2Cache, u) = (cache.k1, cache.k1) + +@cache struct ExplicitTaylorCache{ + P, jetType, uType, taylorType, uNoUnitsType, StageLimiter, StepLimiter, + Thread} <: OrdinaryDiffEqMutableCache + order::Val{P} + jet::jetType + u::uType + uprev::uType + utaylor::taylorType + utilde::uType + tmp::uType + atmp::uNoUnitsType + stage_limiter!::StageLimiter + step_limiter!::StepLimiter + thread::Thread +end + +function alg_cache(alg::ExplicitTaylor{P}, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{true}) where {P, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + _, jet_iip = build_jet(f, p, Val(P), length(u)) + utaylor = TaylorDiff.make_seed(u, zero(u), Val(P)) + utilde = zero(u) + atmp = similar(u, uEltypeNoUnits) + recursivefill!(atmp, false) + tmp = zero(u) + ExplicitTaylorCache(Val(P), jet_iip, u, uprev, utaylor, utilde, tmp, atmp, + alg.stage_limiter!, alg.step_limiter!, alg.thread) +end + +struct ExplicitTaylorConstantCache{P, jetType} <: OrdinaryDiffEqConstantCache + order::Val{P} + jet::jetType +end +function alg_cache(::ExplicitTaylor{P}, u, rate_prototype, ::Type{uEltypeNoUnits}, + ::Type{uBottomEltypeNoUnits}, ::Type{tTypeNoUnits}, uprev, uprev2, f, t, + dt, reltol, p, calck, + ::Val{false}) where {P, uEltypeNoUnits, uBottomEltypeNoUnits, tTypeNoUnits} + if u isa AbstractArray + jet, _ = build_jet(f, p, Val(P), length(u)) + else + jet = build_jet(f, p, Val(P)) + end + ExplicitTaylorConstantCache(Val(P), jet) +end + +# FSAL currently not used, providing dummy implementation to satisfy the interface +get_fsalfirstlast(cache::ExplicitTaylorCache, u) = (cache.u, cache.u) diff --git a/lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_perform_step.jl b/lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_perform_step.jl new file mode 100644 index 0000000000..3b48979993 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/src/TaylorSeries_perform_step.jl @@ -0,0 +1,100 @@ +using TaylorDiff: TaylorDiff, extract_derivative, extract_derivative! + +@inline make_taylor(all::Vararg{X, P}) where {P, X <: AbstractArray} = TaylorArray( + Base.first(all), Base.tail(all)) +@inline make_taylor(all::Vararg{X, P}) where {P, X} = TaylorScalar(all) + +function initialize!(integrator, cache::ExplicitTaylor2ConstantCache) + integrator.kshortsize = 3 + integrator.k = typeof(integrator.k)(undef, integrator.kshortsize) +end + +@muladd function perform_step!( + integrator, cache::ExplicitTaylor2ConstantCache, repeat_step = false) + @unpack t, dt, uprev, u, f, p = integrator + k1 = f(uprev, p, t) + u1 = make_taylor(uprev, k1) + t1 = TaylorScalar{1}(t, one(t)) + k2 = f(u1, p, t1).partials[1] + u = @.. uprev + dt * k1 + dt^2 / 2 * k2 + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) + integrator.k[1] = k1 + integrator.k[2] = k2 + integrator.u = u +end + +function initialize!(integrator, cache::ExplicitTaylor2Cache) + integrator.kshortsize = 3 + resize!(integrator.k, integrator.kshortsize) + # Setup k pointers + integrator.k[1] = cache.k1 + integrator.k[2] = cache.k2 + integrator.k[3] = cache.k3 + return nothing +end + +@muladd function perform_step!(integrator, cache::ExplicitTaylor2Cache, repeat_step = false) + @unpack t, dt, uprev, u, f, p = integrator + @unpack k1, k2, k3, utilde, tmp = cache + + # The following code is written to be fully non-allocating + f(k1, uprev, p, t) + u1 = make_taylor(uprev, k1) + t1 = TaylorScalar{1}(t, one(t)) + out1 = make_taylor(k1, k2) + f(out1, u1, p, t1) + @.. u = uprev + dt * k1 + dt^2 / 2 * k2 + OrdinaryDiffEqCore.increment_nf!(integrator.stats, 3) + return nothing +end + +function initialize!(integrator, cache::ExplicitTaylorConstantCache{P}) where {P} + integrator.kshortsize = P + integrator.k = typeof(integrator.k)(undef, P) +end + +@muladd function perform_step!( + integrator, cache::ExplicitTaylorConstantCache{P}, repeat_step = false) where {P} + @unpack t, dt, uprev, u, f, p = integrator + @unpack jet = cache + utaylor = jet(uprev, t) + u = map(x -> evaluate_polynomial(x, dt), utaylor) + if integrator.opts.adaptive + utilde = TaylorDiff.get_coefficient(utaylor, P) * dt^(P + 1) + atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) + end + OrdinaryDiffEqCore.increment_nf!(integrator.stats, P + 1) + integrator.u = u +end + +function initialize!(integrator, cache::ExplicitTaylorCache{P}) where {P} + integrator.kshortsize = P + resize!(integrator.k, P) + # Setup k pointers + for i in 1:P + integrator.k[i] = get_coefficient(cache.utaylor, i) + end + return nothing +end + +@muladd function perform_step!( + integrator, cache::ExplicitTaylorCache{P}, repeat_step = false) where {P} + @unpack t, dt, uprev, u, f, p = integrator + @unpack jet, utaylor, utilde, tmp, atmp, thread = cache + + jet(utaylor, uprev, t) + for i in eachindex(utaylor) + u[i] = @inline evaluate_polynomial(utaylor[i], dt) + end + if integrator.opts.adaptive + @.. broadcast=false thread=thread utilde=TaylorDiff.get_coefficient(utaylor, P) * + dt^(P + 1) + calculate_residuals!(atmp, utilde, uprev, u, integrator.opts.abstol, + integrator.opts.reltol, integrator.opts.internalnorm, t) + integrator.EEst = integrator.opts.internalnorm(atmp, t) + end + OrdinaryDiffEqCore.increment_nf!(integrator.stats, P + 1) + return nothing +end diff --git a/lib/OrdinaryDiffEqTaylorSeries/src/alg_utils.jl b/lib/OrdinaryDiffEqTaylorSeries/src/alg_utils.jl new file mode 100644 index 0000000000..06907a8888 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/src/alg_utils.jl @@ -0,0 +1,55 @@ +alg_order(::ExplicitTaylor2) = 2 +alg_stability_size(alg::ExplicitTaylor2) = 1 + +alg_order(::ExplicitTaylor{P}) where {P} = P +alg_stability_size(alg::ExplicitTaylor) = 1 + +JET_CACHE = IdDict() + +function build_jet(f::ODEFunction{iip}, p, order, length = nothing) where {iip} + build_jet(f, Val{iip}(), p, order, length) +end + +function build_jet(f, ::Val{iip}, p, order::Val{P}, length = nothing) where {P, iip} + if haskey(JET_CACHE, f) + list = JET_CACHE[f] + index = findfirst(x -> x[1] == order && x[2] == p, list) + index !== nothing && return list[index][3] + end + @variables t0::Real + u0 = isnothing(length) ? Symbolics.variable(:u0) : Symbolics.variables(:u0, 1:length) + if iip + @assert length isa Integer + f0 = similar(u0) + f(f0, u0, p, t0) + else + f0 = f(u0, p, t0) + end + u = TaylorDiff.make_seed(u0, f0, Val(1)) + for index in 2:P + t = TaylorScalar{index - 1}(t0, one(t0)) + if iip + fu = similar(u) + f(fu, u, p, t) + else + fu = f(u, p, t) + end + d = get_coefficient(fu, index - 1) / index + u = append_coefficient(u, d) + end + jet = build_function(u, u0, t0; expression = Val(false), cse = true) + if !haskey(JET_CACHE, f) + JET_CACHE[f] = [] + end + push!(JET_CACHE[f], (order, p, jet)) + return jet +end + +# evaluate using Qin Jiushao's algorithm +@generated function evaluate_polynomial(t::TaylorScalar{T, P}, z) where {T, P} + ex = :(v[$(P + 1)]) + for i in P:-1:1 + ex = :(v[$i] + z * $ex) + end + return :($(Expr(:meta, :inline)); v = flatten(t); $ex) +end diff --git a/lib/OrdinaryDiffEqTaylorSeries/src/algorithms.jl b/lib/OrdinaryDiffEqTaylorSeries/src/algorithms.jl new file mode 100644 index 0000000000..cba67e76a2 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/src/algorithms.jl @@ -0,0 +1,25 @@ +@doc explicit_rk_docstring( + "A second-order explicit Taylor series method.", + "ExplicitTaylor2") +Base.@kwdef struct ExplicitTaylor2{StageLimiter, StepLimiter, Thread} <: + OrdinaryDiffEqAlgorithm + stage_limiter!::StageLimiter = trivial_limiter! + step_limiter!::StepLimiter = trivial_limiter! + thread::Thread = False() +end +@truncate_stacktrace ExplicitTaylor2 3 +# for backwards compatibility +function ExplicitTaylor2(stage_limiter!, step_limiter! = trivial_limiter!) + ExplicitTaylor2(stage_limiter!, step_limiter!, False()) +end + +@doc explicit_rk_docstring( + "An arbitrary-order explicit Taylor series method.", + "ExplicitTaylor2") +Base.@kwdef struct ExplicitTaylor{P, StageLimiter, StepLimiter, Thread} <: + OrdinaryDiffEqAdaptiveAlgorithm + order::Val{P} = Val{1}() + stage_limiter!::StageLimiter = trivial_limiter! + step_limiter!::StepLimiter = trivial_limiter! + thread::Thread = False() +end diff --git a/lib/OrdinaryDiffEqTaylorSeries/test/jet.jl b/lib/OrdinaryDiffEqTaylorSeries/test/jet.jl new file mode 100644 index 0000000000..d3add42cb9 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqTaylorSeries +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqTaylorSeries, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqTaylorSeries/test/qa.jl b/lib/OrdinaryDiffEqTaylorSeries/test/qa.jl new file mode 100644 index 0000000000..d6a03a29b5 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/test/qa.jl @@ -0,0 +1,13 @@ +using OrdinaryDiffEqTaylorSeries +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqTaylorSeries; + unbound_args = false, + undefined_exports = false, + stale_deps = false, + deps_compat = false, + ambiguities = false + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqTaylorSeries/test/runtests.jl b/lib/OrdinaryDiffEqTaylorSeries/test/runtests.jl new file mode 100644 index 0000000000..30824f51f2 --- /dev/null +++ b/lib/OrdinaryDiffEqTaylorSeries/test/runtests.jl @@ -0,0 +1,34 @@ +using OrdinaryDiffEqTaylorSeries, ODEProblemLibrary, DiffEqDevTools, JET +using Test + +@testset "Taylor2 Convergence Tests" begin + # Test convergence + dts = 2. .^ (-8:-4) + testTol = 0.2 + sim = test_convergence(dts, prob_ode_linear, ExplicitTaylor2()) + @test sim.𝒪est[:final]≈2 atol=testTol + sim = test_convergence(dts, prob_ode_2Dlinear, ExplicitTaylor2()) + @test sim.𝒪est[:final]≈2 atol=testTol +end + +@testset "TaylorN Convergence Tests" begin + # Test convergence + dts = 2. .^ (-8:-4) + testTol = 0.2 + for N in 3:4 + alg = ExplicitTaylor(order=Val(N)) + sim = test_convergence(dts, prob_ode_linear, alg) + @test sim.𝒪est[:final]≈N atol=testTol + sim = test_convergence(dts, prob_ode_2Dlinear, alg) + @test sim.𝒪est[:final]≈N atol=testTol + end +end + +@testset "TaylorN Adaptive Tests" begin + sol = solve(prob_ode_linear, ExplicitTaylor(order=Val(2))) + @test length(sol) < 20 + @test SciMLBase.successful_retcode(sol) +end + +include("jet.jl") +include("qa.jl") diff --git a/lib/OrdinaryDiffEqTsit5/Project.toml b/lib/OrdinaryDiffEqTsit5/Project.toml index 91b6491873..372f4d49e0 100644 --- a/lib/OrdinaryDiffEqTsit5/Project.toml +++ b/lib/OrdinaryDiffEqTsit5/Project.toml @@ -1,44 +1,55 @@ name = "OrdinaryDiffEqTsit5" uuid = "b1df2697-797e-41e3-8120-5422d3b24e4a" authors = ["ParamThakkar123 "] -version = "1.1.0" +version = "1.5.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Preferences = "21216c6a-2e73-6563-6e65-726566657250" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -TruncatedStacktraces = "1.4.0" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +PrecompileTools = "1.2" +LinearAlgebra = "1.10" +TruncatedStacktraces = "1.4" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +Preferences = "1.4" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqTsit5/src/OrdinaryDiffEqTsit5.jl b/lib/OrdinaryDiffEqTsit5/src/OrdinaryDiffEqTsit5.jl index b6e147f7e2..1bc8fe1cf0 100644 --- a/lib/OrdinaryDiffEqTsit5/src/OrdinaryDiffEqTsit5.jl +++ b/lib/OrdinaryDiffEqTsit5/src/OrdinaryDiffEqTsit5.jl @@ -16,12 +16,12 @@ import MuladdMacro: @muladd import FastBroadcast: @.. import RecursiveArrayTools: recursivefill!, recursive_unitless_bottom_eltype import LinearAlgebra: norm -using TruncatedStacktraces -import DiffEqBase: @def +using TruncatedStacktraces: @truncate_stacktrace +import SciMLBase: @def import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqTsit5/src/algorithms.jl b/lib/OrdinaryDiffEqTsit5/src/algorithms.jl index c19efefcd3..1942bf78e4 100644 --- a/lib/OrdinaryDiffEqTsit5/src/algorithms.jl +++ b/lib/OrdinaryDiffEqTsit5/src/algorithms.jl @@ -1,6 +1,5 @@ @doc explicit_rk_docstring( - "A fifth-order explicit Runge-Kutta method with embedded error - estimator of Tsitouras. Free 4th order interpolant.", + "Tsitouras 5/4 Runge-Kutta method. (free 4th order interpolant). Recommended for most non-stiff problems. Good default choice for unknown stiffness. Highly efficient and generic. Very good performance for most non-stiff ODEs. Recommended as default method for unknown stiffness problems.", "Tsit5", references = "@article{tsitouras2011runge, title={Runge--Kutta pairs of order 5 (4) satisfying only the first column simplifying assumption}, @@ -18,7 +17,7 @@ Base.@kwdef struct Tsit5{StageLimiter, StepLimiter, Thread} <: step_limiter!::StepLimiter = trivial_limiter! thread::Thread = False() end -TruncatedStacktraces.@truncate_stacktrace Tsit5 3 +@truncate_stacktrace Tsit5 3 # for backwards compatibility function Tsit5(stage_limiter!, step_limiter! = trivial_limiter!) Tsit5(stage_limiter!, step_limiter!, False()) diff --git a/lib/OrdinaryDiffEqTsit5/src/interp_func.jl b/lib/OrdinaryDiffEqTsit5/src/interp_func.jl index b9c8e3cd95..9c37164ea4 100644 --- a/lib/OrdinaryDiffEqTsit5/src/interp_func.jl +++ b/lib/OrdinaryDiffEqTsit5/src/interp_func.jl @@ -1,4 +1,4 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{Tsit5Cache, Tsit5ConstantCache diff --git a/lib/OrdinaryDiffEqTsit5/test/allocation_tests.jl b/lib/OrdinaryDiffEqTsit5/test/allocation_tests.jl new file mode 100644 index 0000000000..b621dd4bf9 --- /dev/null +++ b/lib/OrdinaryDiffEqTsit5/test/allocation_tests.jl @@ -0,0 +1,46 @@ +using OrdinaryDiffEqTsit5 +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqTsit5 solvers using AllocCheck.jl. +These tests verify that the step! operation does not allocate during stepping. +""" + +@testset "Tsit5 Allocation Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported Tsit5 solvers for allocation-free behavior + tsit5_solvers = [Tsit5()] + + @testset "Tsit5 Solver Allocation Analysis" begin + for solver in tsit5_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test_broken length(allocs) == 0 + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqTsit5/test/jet.jl b/lib/OrdinaryDiffEqTsit5/test/jet.jl new file mode 100644 index 0000000000..4da23d6446 --- /dev/null +++ b/lib/OrdinaryDiffEqTsit5/test/jet.jl @@ -0,0 +1,37 @@ +import OrdinaryDiffEqTsit5 +using OrdinaryDiffEqTsit5 +using OrdinaryDiffEqCore +using JET +using Test + +@testset "JET Tests" begin + # Test package for typos - now passing + test_package( + OrdinaryDiffEqTsit5, target_defined_modules = true, mode = :typo) + + # Test individual solver type stability + @testset "Solver Type Stability Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported Tsit5 solvers + tsit5_solvers = [Tsit5()] + + for solver in tsit5_solvers + @testset "$(typeof(solver)) type stability" begin + try + @test_opt broken=true init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + @test_opt broken=true step!(integrator) + catch e + @test_broken false # Mark as broken if solver fails to initialize + println("$(typeof(solver)) failed with: $e") + end + end + end + end +end diff --git a/lib/OrdinaryDiffEqTsit5/test/qa.jl b/lib/OrdinaryDiffEqTsit5/test/qa.jl new file mode 100644 index 0000000000..85d2469c43 --- /dev/null +++ b/lib/OrdinaryDiffEqTsit5/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqTsit5 +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqTsit5 + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqTsit5/test/runtests.jl b/lib/OrdinaryDiffEqTsit5/test/runtests.jl index 8b13789179..126d95d1a8 100644 --- a/lib/OrdinaryDiffEqTsit5/test/runtests.jl +++ b/lib/OrdinaryDiffEqTsit5/test/runtests.jl @@ -1 +1,8 @@ +using SafeTestsets +# Only run QA, allocation, and type stability tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqVerner/Project.toml b/lib/OrdinaryDiffEqVerner/Project.toml index dffb73e28a..f8065f1c09 100644 --- a/lib/OrdinaryDiffEqVerner/Project.toml +++ b/lib/OrdinaryDiffEqVerner/Project.toml @@ -1,46 +1,57 @@ name = "OrdinaryDiffEqVerner" uuid = "79d7bb75-1356-48c1-b8c0-6832512096c2" authors = ["ParamThakkar123 "] -version = "1.1.1" +version = "1.6.0" [deps] -DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" MuladdMacro = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" -OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" +Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Preferences = "21216c6a-2e73-6563-6e65-726566657250" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" -Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -TruncatedStacktraces = "781d530d-4396-4725-bb49-402e4bee1e77" - -[compat] -DiffEqBase = "6.152.2" -DiffEqDevTools = "2.44.4" -FastBroadcast = "0.3.5" -LinearAlgebra = "<0.0.1, 1" -MuladdMacro = "0.2.4" -OrdinaryDiffEqCore = "1.1" -Polyester = "0.7.16" -PrecompileTools = "1.2.1" -Preferences = "1.4.3" -Random = "<0.0.1, 1" -RecursiveArrayTools = "3.27.0" -Reexport = "1.2.2" -SafeTestsets = "0.1.0" -Static = "1.1.1" -Test = "<0.0.1, 1" -TruncatedStacktraces = "1.4.0" -julia = "1.10" [extras] -DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +Test = "<0.0.1, 1" +FastBroadcast = "0.3" +Random = "<0.0.1, 1" +DiffEqDevTools = "2.44.4" +MuladdMacro = "0.2" +PrecompileTools = "1.2" +Polyester = "0.7" +LinearAlgebra = "1.10" +TruncatedStacktraces = "1.4" +SciMLBase = "2.99" +OrdinaryDiffEqCore = "1.29.0" +Static = "1.2" +Aqua = "0.8.11" +Preferences = "1.4" +julia = "1.10" +JET = "0.9.18, 0.10.4" +RecursiveArrayTools = "3.36" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SafeTestsets = "0.1.0" [targets] -test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test"] +test = ["DiffEqDevTools", "Random", "SafeTestsets", "Test", "JET", "Aqua", "AllocCheck"] + +[sources.OrdinaryDiffEqCore] +path = "../OrdinaryDiffEqCore" diff --git a/lib/OrdinaryDiffEqVerner/src/OrdinaryDiffEqVerner.jl b/lib/OrdinaryDiffEqVerner/src/OrdinaryDiffEqVerner.jl index ca6328e98c..389227688c 100644 --- a/lib/OrdinaryDiffEqVerner/src/OrdinaryDiffEqVerner.jl +++ b/lib/OrdinaryDiffEqVerner/src/OrdinaryDiffEqVerner.jl @@ -13,15 +13,15 @@ import OrdinaryDiffEqCore: alg_order, calculate_residuals!, _ode_interpolant!, _ode_addsteps!, @fold, @OnDemandTableauExtract, AutoAlgSwitch, DerivativeOrderNotPossibleError, - get_fsalfirstlast + get_fsalfirstlast, copyat_or_push! using FastBroadcast, Polyester, MuladdMacro, RecursiveArrayTools using DiffEqBase: @def, @tight_loop_macros using Static: False -using TruncatedStacktraces +using TruncatedStacktraces: @truncate_stacktrace using LinearAlgebra: norm import OrdinaryDiffEqCore using Reexport -@reexport using DiffEqBase +@reexport using SciMLBase include("algorithms.jl") include("alg_utils.jl") diff --git a/lib/OrdinaryDiffEqVerner/src/algorithms.jl b/lib/OrdinaryDiffEqVerner/src/algorithms.jl index e1fbb1fb16..19efb0d5bf 100644 --- a/lib/OrdinaryDiffEqVerner/src/algorithms.jl +++ b/lib/OrdinaryDiffEqVerner/src/algorithms.jl @@ -1,5 +1,5 @@ @doc explicit_rk_docstring( - "Verner's “Most Efficient” 6/5 Runge-Kutta method. (lazy 6th order interpolant).", + "Verner's most efficient 6/5 method (lazy 6th order interpolant).", "Vern6", references = "@article{verner2010numerically, title={Numerically optimal Runge--Kutta pairs with interpolants}, @@ -21,14 +21,14 @@ Base.@kwdef struct Vern6{StageLimiter, StepLimiter, Thread} <: thread::Thread = False() lazy::Bool = true end -TruncatedStacktraces.@truncate_stacktrace Vern6 3 +@truncate_stacktrace Vern6 3 # for backwards compatibility function Vern6(stage_limiter!, step_limiter! = trivial_limiter!; lazy = true) Vern6(stage_limiter!, step_limiter!, False(), lazy) end @doc explicit_rk_docstring( - "Verner's “Most Efficient” 7/6 Runge-Kutta method. (lazy 7th order interpolant).", + "Verner's most efficient 7/6 method (lazy 7th order interpolant). Good for problems requiring high accuracy. Slightly more computationally expensive than Tsit5. Performance best when parameter vector remains unchanged. Recommended for high-accuracy non-stiff problems.", "Vern7", references = "@article{verner2010numerically, title={Numerically optimal Runge--Kutta pairs with interpolants}, @@ -50,14 +50,14 @@ Base.@kwdef struct Vern7{StageLimiter, StepLimiter, Thread} <: thread::Thread = False() lazy::Bool = true end -TruncatedStacktraces.@truncate_stacktrace Vern7 3 +@truncate_stacktrace Vern7 3 # for backwards compatibility function Vern7(stage_limiter!, step_limiter! = trivial_limiter!; lazy = true) Vern7(stage_limiter!, step_limiter!, False(), lazy) end @doc explicit_rk_docstring( - "Verner's “Most Efficient” 8/7 Runge-Kutta method. (lazy 8th order interpolant).", + "Verner's most efficient 8/7 method (lazy 8th order interpolant).", "Vern8", references = "@article{verner2010numerically, title={Numerically optimal Runge--Kutta pairs with interpolants}, @@ -79,14 +79,14 @@ Base.@kwdef struct Vern8{StageLimiter, StepLimiter, Thread} <: thread::Thread = False() lazy::Bool = true end -TruncatedStacktraces.@truncate_stacktrace Vern8 3 +@truncate_stacktrace Vern8 3 # for backwards compatibility function Vern8(stage_limiter!, step_limiter! = trivial_limiter!; lazy = true) Vern8(stage_limiter!, step_limiter!, False(), lazy) end @doc explicit_rk_docstring( - "Verner's “Most Efficient” 9/8 Runge-Kutta method. (lazy9th order interpolant).", + "Verner's most efficient 9/8 method (lazy 9th order interpolant).", "Vern9", references = "@article{verner2010numerically, title={Numerically optimal Runge--Kutta pairs with interpolants}, @@ -107,7 +107,7 @@ Base.@kwdef struct Vern9{StageLimiter, StepLimiter, Thread} <: thread::Thread = False() lazy::Bool = true end -TruncatedStacktraces.@truncate_stacktrace Vern9 3 +@truncate_stacktrace Vern9 3 # for backwards compatibility function Vern9(stage_limiter!, step_limiter! = trivial_limiter!; lazy = true) Vern9(stage_limiter!, step_limiter!, False(), lazy) diff --git a/lib/OrdinaryDiffEqVerner/src/interp_func.jl b/lib/OrdinaryDiffEqVerner/src/interp_func.jl index 5df0533fec..1cca0adba3 100644 --- a/lib/OrdinaryDiffEqVerner/src/interp_func.jl +++ b/lib/OrdinaryDiffEqVerner/src/interp_func.jl @@ -1,4 +1,4 @@ -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{Vern6Cache, Vern6ConstantCache @@ -6,7 +6,7 @@ function DiffEqBase.interp_summary(::Type{cacheType}, dense ? "specialized 6th order lazy interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{Vern7Cache, Vern7ConstantCache @@ -14,7 +14,7 @@ function DiffEqBase.interp_summary(::Type{cacheType}, dense ? "specialized 7th order lazy interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{Vern8Cache, Vern8ConstantCache @@ -22,7 +22,7 @@ function DiffEqBase.interp_summary(::Type{cacheType}, dense ? "specialized 8th order lazy interpolation" : "1st order linear" end -function DiffEqBase.interp_summary(::Type{cacheType}, +function SciMLBase.interp_summary(::Type{cacheType}, dense::Bool) where { cacheType <: Union{Vern9Cache, Vern9ConstantCache diff --git a/lib/OrdinaryDiffEqVerner/test/allocation_tests.jl b/lib/OrdinaryDiffEqVerner/test/allocation_tests.jl new file mode 100644 index 0000000000..a26afd1d4d --- /dev/null +++ b/lib/OrdinaryDiffEqVerner/test/allocation_tests.jl @@ -0,0 +1,47 @@ +using OrdinaryDiffEqVerner +using OrdinaryDiffEqCore +using AllocCheck +using Test + +""" +Allocation tests for OrdinaryDiffEqVerner solvers using AllocCheck.jl. +These tests verify that the step! operation does not allocate during stepping. +""" + +@testset "Verner Allocation Tests" begin + # Test problem + function simple_system!(du, u, p, t) + du[1] = -0.5 * u[1] + du[2] = -1.5 * u[2] + end + prob = ODEProblem(simple_system!, [1.0, 1.0], (0.0, 1.0)) + + # Test all exported Verner solvers for allocation-free behavior + verner_solvers = [Vern6(), Vern7(), Vern8(), Vern9(), + AutoVern6(Vern6()), AutoVern7(Vern7()), AutoVern8(Vern8()), AutoVern9(Vern9())] + + @testset "Verner Solver Allocation Analysis" begin + for solver in verner_solvers + @testset "$(typeof(solver)) allocation check" begin + integrator = init(prob, solver, dt=0.1, save_everystep=false, abstol=1e-6, reltol=1e-6) + step!(integrator) # Setup step may allocate + + # Use AllocCheck to verify step! is allocation-free + allocs = check_allocs(step!, (typeof(integrator),)) + + # These solvers should be allocation-free, but mark as broken for now + # to verify with AllocCheck (more accurate than @allocated) + @test_broken length(allocs) == 0 + + if length(allocs) > 0 + println("AllocCheck found $(length(allocs)) allocation sites in $(typeof(solver)) step!:") + for (i, alloc) in enumerate(allocs[1:min(3, end)]) # Show first 3 + println(" $i. $alloc") + end + else + println("✓ $(typeof(solver)) appears allocation-free with AllocCheck") + end + end + end + end +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqVerner/test/jet.jl b/lib/OrdinaryDiffEqVerner/test/jet.jl new file mode 100644 index 0000000000..53c789473c --- /dev/null +++ b/lib/OrdinaryDiffEqVerner/test/jet.jl @@ -0,0 +1,7 @@ +import OrdinaryDiffEqVerner +using JET + +@testset "JET Tests" begin + test_package( + OrdinaryDiffEqVerner, target_defined_modules = true, mode = :typo) +end diff --git a/lib/OrdinaryDiffEqVerner/test/qa.jl b/lib/OrdinaryDiffEqVerner/test/qa.jl new file mode 100644 index 0000000000..1c75b70af1 --- /dev/null +++ b/lib/OrdinaryDiffEqVerner/test/qa.jl @@ -0,0 +1,8 @@ +using OrdinaryDiffEqVerner +using Aqua + +@testset "Aqua" begin + Aqua.test_all( + OrdinaryDiffEqVerner + ) +end \ No newline at end of file diff --git a/lib/OrdinaryDiffEqVerner/test/runtests.jl b/lib/OrdinaryDiffEqVerner/test/runtests.jl index 8b13789179..5ed6ac4c1c 100644 --- a/lib/OrdinaryDiffEqVerner/test/runtests.jl +++ b/lib/OrdinaryDiffEqVerner/test/runtests.jl @@ -1 +1,8 @@ +using SafeTestsets +# Only run QA and allocation tests on stable Julia versions +if isempty(VERSION.prerelease) + @time @safetestset "JET Tests" include("jet.jl") + @time @safetestset "Aqua" include("qa.jl") + @time @safetestset "Allocation Tests" include("allocation_tests.jl") +end \ No newline at end of file diff --git a/lib/SimpleImplicitDiscreteSolve/LICENSE b/lib/SimpleImplicitDiscreteSolve/LICENSE new file mode 100644 index 0000000000..abb594d1ed --- /dev/null +++ b/lib/SimpleImplicitDiscreteSolve/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 SciML + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/SimpleImplicitDiscreteSolve/Project.toml b/lib/SimpleImplicitDiscreteSolve/Project.toml new file mode 100644 index 0000000000..ebfe72ba31 --- /dev/null +++ b/lib/SimpleImplicitDiscreteSolve/Project.toml @@ -0,0 +1,30 @@ +name = "SimpleImplicitDiscreteSolve" +uuid = "8b67ef88-54bd-43ff-aca0-8be02588656a" +authors = ["vyudu "] +version = "1.2.0" + +[deps] +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7" + +[extras] +JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b" +OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" + +[compat] +JET = "0.9.18, 0.10.4" +julia = "1.10" +OrdinaryDiffEqSDIRK = "1.6.0" +Test = "1.10" +AllocCheck = "0.2" +DiffEqBase = "6.176" +Reexport = "1.2" +SciMLBase = "2.99" +SimpleNonlinearSolve = "2.7" + +[targets] +test = ["JET", "OrdinaryDiffEqSDIRK", "Test", "AllocCheck"] diff --git a/lib/SimpleImplicitDiscreteSolve/src/SimpleImplicitDiscreteSolve.jl b/lib/SimpleImplicitDiscreteSolve/src/SimpleImplicitDiscreteSolve.jl new file mode 100644 index 0000000000..d392ddfa50 --- /dev/null +++ b/lib/SimpleImplicitDiscreteSolve/src/SimpleImplicitDiscreteSolve.jl @@ -0,0 +1,94 @@ +module SimpleImplicitDiscreteSolve + +using SciMLBase +using SimpleNonlinearSolve +using Reexport +@reexport using SciMLBase + +""" + SimpleIDSolve() + +Simple solver for `ImplicitDiscreteSystems`. Uses `SimpleNewtonRaphson` to solve for the next state at every timestep. +""" +struct SimpleIDSolve <: SciMLBase.AbstractODEAlgorithm end + +function SciMLBase.__init(prob::ImplicitDiscreteProblem, alg::SimpleIDSolve; dt = 1) + u0 = prob.u0 + p = prob.p + f = prob.f + t = prob.tspan[1] + + nlf = isinplace(f) ? (out, u, p) -> f(out, u, u0, p, t) : (u, p) -> f(u, u0, p, t) + prob = NonlinearProblem{isinplace(f)}(nlf, u0, p) + sol = solve(prob, SimpleNewtonRaphson()) + sol, (sol.retcode != ReturnCode.Success) +end + +function SciMLBase.solve(prob::ImplicitDiscreteProblem, alg::SimpleIDSolve; + dt = 1, + save_everystep = true, + save_start = true, + adaptive = false, + dense = false, + save_end = true, + kwargs...) + @assert !adaptive + @assert !dense + (initsol, initfail) = SciMLBase.__init(prob, alg; dt) + if initfail + sol = SciMLBase.build_solution(prob, alg, prob.tspan[1], u0, k = nothing, + stats = nothing, calculate_error = false) + return SciMLBase.solution_new_retcode(sol, ReturnCode.InitialFailure) + end + + u0 = initsol.u + tspan = prob.tspan + f = prob.f + p = prob.p + t = tspan[1] + tf = prob.tspan[2] + ts = tspan[1]:dt:tspan[2] + + l = save_everystep ? length(ts) - 1 : 1 + save_start && (l = l + 1) + us = Vector{typeof(u0)}(undef, l) + + if save_start + us[1] = u0 + end + + u = u0 + convfail = false + for i in 2:length(ts) + uprev = u + t = ts[i] + nlf = isinplace(f) ? (out, u, p) -> f(out, u, uprev, p, t) : + (u, p) -> f(u, uprev, p, t) + nlprob = NonlinearProblem{isinplace(f)}(nlf, uprev, p) + nlsol = solve(nlprob, SimpleNewtonRaphson()) + u = nlsol.u + save_everystep && (us[i] = u) + convfail = (nlsol.retcode != ReturnCode.Success) + + if convfail + sol = SciMLBase.build_solution(prob, alg, ts[1:i], us[1:i], k = nothing, + stats = nothing, calculate_error = false) + sol = SciMLBase.solution_new_retcode(sol, ReturnCode.ConvergenceFailure) + return sol + end + end + + !save_everystep && save_end && (us[end] = u) + sol = SciMLBase.build_solution(prob, alg, ts, us, + k = nothing, stats = nothing, + calculate_error = false) + + SciMLBase.has_analytic(prob.f) && + SciMLBase.calculate_solution_errors!( + sol; timeseries_errors = true, dense_errors = false) + sol +end + +export SimpleIDSolve + +end diff --git a/lib/SimpleImplicitDiscreteSolve/test/jet.jl b/lib/SimpleImplicitDiscreteSolve/test/jet.jl new file mode 100644 index 0000000000..39a2254265 --- /dev/null +++ b/lib/SimpleImplicitDiscreteSolve/test/jet.jl @@ -0,0 +1,7 @@ +import SimpleImplicitDiscreteSolve +using JET + +@testset "JET Tests" begin + test_package( + SimpleImplicitDiscreteSolve, target_defined_modules = true, mode = :typo) +end \ No newline at end of file diff --git a/lib/SimpleImplicitDiscreteSolve/test/runtests.jl b/lib/SimpleImplicitDiscreteSolve/test/runtests.jl new file mode 100644 index 0000000000..3881b95186 --- /dev/null +++ b/lib/SimpleImplicitDiscreteSolve/test/runtests.jl @@ -0,0 +1,74 @@ +using Test +using SimpleImplicitDiscreteSolve +using OrdinaryDiffEqSDIRK + +# Test implicit Euler using ImplicitDiscreteProblem +@testset "Implicit Euler" begin + function lotkavolterra(u, p, t) + [1.5 * u[1] - u[1] * u[2], -3.0 * u[2] + u[1] * u[2]] + end + + function f!(resid, u_next, u, p, t) + lv = lotkavolterra(u_next, p, t) + resid[1] = u_next[1] - u[1] - 0.01 * lv[1] + resid[2] = u_next[2] - u[2] - 0.01 * lv[2] + nothing + end + u0 = [1.0, 1.0] + tspan = (0.0, 0.5) + + idprob = ImplicitDiscreteProblem(f!, u0, tspan, []) + idsol = solve(idprob, SimpleIDSolve(), dt = 0.01) + + oprob = ODEProblem(lotkavolterra, u0, tspan) + osol = solve(oprob, ImplicitEuler()) + + @test isapprox(idsol[end - 1], osol[end], atol = 0.1) + + ### free-fall + # y, dy + function ff(u, p, t) + [u[2], -9.8] + end + + function g!(resid, u_next, u, p, t) + f = ff(u_next, p, t) + resid[1] = u_next[1] - u[1] - 0.01 * f[1] + resid[2] = u_next[2] - u[2] - 0.01 * f[2] + nothing + end + u0 = [10.0, 0.0] + tspan = (0, 0.5) + + idprob = ImplicitDiscreteProblem(g!, u0, tspan, []) + idsol = solve(idprob, SimpleIDSolve(); dt = 0.01) + + oprob = ODEProblem(ff, u0, tspan) + osol = solve(oprob, ImplicitEuler()) + + @test isapprox(idsol[end - 1], osol[end], atol = 0.1) +end + +@testset "Solver initializes" begin + function periodic!(resid, u_next, u, p, t) + resid[1] = u_next[1] - u[1] - sin(t * π / 4) + resid[2] = 16 - u_next[2]^2 - u_next[1]^2 + end + + tsteps = 15 + u0 = [1.0, 3.0] + idprob = ImplicitDiscreteProblem(periodic!, u0, (0, tsteps), []) + initsol, initfail = SciMLBase.__init(idprob, SimpleIDSolve()) + @test initsol.u[1]^2 + initsol.u[2]^2 ≈ 16 + + idsol = solve(idprob, SimpleIDSolve()) + + for ts in 1:tsteps + step = idsol.u[ts] + @test step[1]^2 + step[2]^2 ≈ 16 + end +end + +if isempty(VERSION.prerelease) + include("jet.jl") +end diff --git a/src/OrdinaryDiffEq.jl b/src/OrdinaryDiffEq.jl index 503484ac33..9091a8e16d 100644 --- a/src/OrdinaryDiffEq.jl +++ b/src/OrdinaryDiffEq.jl @@ -3,93 +3,79 @@ $(DocStringExtensions.README) """ module OrdinaryDiffEq -using Reexport -@reexport using DiffEqBase +import Reexport: Reexport, @reexport +@reexport using SciMLBase -import OrdinaryDiffEqCore: trivial_limiter!, CompositeAlgorithm, alg_order, +# Explicit imports for functions that are re-exported +import CommonSolve: init, solve, solve!, step! +import SciMLBase: SciMLBase, addsteps!, savevalues!, terminate! + +import OrdinaryDiffEqCore: OrdinaryDiffEqCore, + CompositeAlgorithm, ShampineCollocationInit, BrownFullBasicInit, NoInit, - set_new_W!, set_W_γdt!, get_W, isfirstcall, isfirststage, - isJcurrent, get_new_W_γdt_cutoff, - DIRK, COEFFICIENT_MULTISTEP, NORDSIECK_MULTISTEP, GLM, - MethodType, Divergence, VerySlowConvergence, - SlowConvergence, Convergence, FastConvergence, NLStatus, - TryAgain, AbstractNLSolverCache, - AbstractNLSolverAlgorithm, AbstractNLSolver, - handle_discontinuities!, copyat_or_push!, du_cache, full_cache, isfsal, ode_interpolant, u_cache, - AutoSwitch, has_discontinuity, - first_discontinuity, pop_discontinuity!, _vec, loopfooter!, - _reshape, perform_step!, - _ode_addsteps!, get_current_alg_autodiff, default_controller, - isstandard, - ispredictive, beta2_default, beta1_default, gamma_default, - qmin_default, - qmax_default, qsteady_min_default, qsteady_max_default, - stepsize_controller!, - accept_step_controller, step_accept_controller!, - step_reject_controller!, - DummyController, issplit, calculate_residuals, - calculate_residuals!, - nlsolve_f, unwrap_cache, ode_addsteps!, get_chunksize, - handle_callback_modifiers!, - unwrap_alg, apply_step!, initialize_tstops, uses_uprev, - initialize_saveat, - isimplicit, initialize_d_discontinuities, isdtchangeable, - _searchsortedfirst, - _searchsortedlast, - @unpack, ismultistep, DEFAULT_PRECS, isautoswitch, - get_chunksize_int, - _unwrap_val, alg_autodiff, concrete_jac, alg_difftype, - standardtag, - alg_extrapolates, alg_maximum_order, alg_adaptive_order, - OrdinaryDiffEqCompositeAlgorithm, initialize_callbacks!, - PredictiveController, - get_differential_vars, alg_cache, AutoSwitchCache, - InterpolationData, - DEOptions, OrdinaryDiffEqAlgorithm, @cache, fsal_typeof, - OrdinaryDiffEqCache, - OrdinaryDiffEqAdaptiveAlgorithm, handle_dt!, - ode_determine_initdt, - loopheader!, OrdinaryDiffEqConstantCache, _loopfooter!, - isadaptive, - OrdinaryDiffEqMutableCache, current_interpolant!, - is_mass_matrix_alg, - False, True, _savevalues!, postamble!, recursivefill!, - _change_t_via_interpolation!, ODEIntegrator, _ode_interpolant!, - current_interpolant, resize_nlsolver!, _ode_interpolant, - handle_tstop!, _postamble!, update_uprev!, resize_J_W!, - DAEAlgorithm, get_fsalfirstlast, strip_cache - -export CompositeAlgorithm, ShampineCollocationInit, BrownFullBasicInit, NoInit -AutoSwitch - -import OrdinaryDiffEqDifferentiation -using OrdinaryDiffEqDifferentiation: _alg_autodiff, resize_grad_config!, dolinsolve, - wrapprecs, UJacobianWrapper, build_jac_config, - WOperator, FirstAutodiffJacError, calc_J!, calc_W!, - calc_J, calc_W, jacobian2W!, isnewton - -using OrdinaryDiffEqNonlinearSolve -using OrdinaryDiffEqNonlinearSolve: NLNewton, NLAnderson, NLFunctional, nlsolvefail, - initial_η, NonlinearSolveAlg, compute_step!, NLSolver, - nlsolve!, resize_jac_config!, anderson!, build_nlsolver, - markfirststage!, anderson -export NLNewton, NLAnderson, NLFunctional, NonlinearSolveAlg - -using OrdinaryDiffEqExtrapolation -export AitkenNeville, ExtrapolationMidpointDeuflhard, ExtrapolationMidpointHairerWanner, + AutoSwitch, + @unpack, + @cache + +export CompositeAlgorithm, ShampineCollocationInit, BrownFullBasicInit, NoInit, + AutoSwitch + +import OrdinaryDiffEqDifferentiation: OrdinaryDiffEqDifferentiation +using OrdinaryDiffEqDifferentiation: OrdinaryDiffEqDifferentiation +export OrdinaryDiffEqDifferentiation + +import OrdinaryDiffEqNonlinearSolve: OrdinaryDiffEqNonlinearSolve +using OrdinaryDiffEqNonlinearSolve: NLNewton, NLAnderson, NLFunctional, + NonlinearSolveAlg +export OrdinaryDiffEqNonlinearSolve, NLNewton, NLAnderson, NLFunctional, NonlinearSolveAlg + +import OrdinaryDiffEqExtrapolation: OrdinaryDiffEqExtrapolation +using OrdinaryDiffEqExtrapolation: AitkenNeville, ExtrapolationMidpointDeuflhard, + ExtrapolationMidpointHairerWanner, + ImplicitEulerExtrapolation, + ImplicitDeuflhardExtrapolation, + ImplicitHairerWannerExtrapolation, + ImplicitEulerBarycentricExtrapolation +export OrdinaryDiffEqExtrapolation, AitkenNeville, ExtrapolationMidpointDeuflhard, + ExtrapolationMidpointHairerWanner, ImplicitEulerExtrapolation, ImplicitDeuflhardExtrapolation, ImplicitHairerWannerExtrapolation, ImplicitEulerBarycentricExtrapolation -using OrdinaryDiffEqStabilizedRK -export ROCK2, ROCK4, RKC, ESERK4, ESERK5, SERK2 - -using OrdinaryDiffEqStabilizedIRK -export IRKC - -using OrdinaryDiffEqLowStorageRK -export ORK256, CarpenterKennedy2N54, SHLDDRK64, HSLDDRK64, DGLDDRK73_C, DGLDDRK84_C, +import OrdinaryDiffEqStabilizedRK: OrdinaryDiffEqStabilizedRK +using OrdinaryDiffEqStabilizedRK: ROCK2, ROCK4, RKC, ESERK4, ESERK5, SERK2 +export OrdinaryDiffEqStabilizedRK, ROCK2, ROCK4, RKC, ESERK4, ESERK5, SERK2 + +import OrdinaryDiffEqStabilizedIRK: OrdinaryDiffEqStabilizedIRK +using OrdinaryDiffEqStabilizedIRK: IRKC +export OrdinaryDiffEqStabilizedIRK, IRKC + +import OrdinaryDiffEqLowStorageRK: OrdinaryDiffEqLowStorageRK +using OrdinaryDiffEqLowStorageRK: ORK256, CarpenterKennedy2N54, SHLDDRK64, HSLDDRK64, + DGLDDRK73_C, DGLDDRK84_C, + DGLDDRK84_F, NDBLSRK124, NDBLSRK134, NDBLSRK144, + CFRLDDRK64, TSLDDRK74, CKLLSRK43_2, CKLLSRK54_3C, + CKLLSRK95_4S, CKLLSRK95_4C, + CKLLSRK95_4M, + CKLLSRK54_3C_3R, CKLLSRK54_3M_3R, CKLLSRK54_3N_3R, + CKLLSRK85_4C_3R, CKLLSRK85_4M_3R, + CKLLSRK85_4P_3R, + CKLLSRK54_3N_4R, CKLLSRK54_3M_4R, CKLLSRK65_4M_4R, + CKLLSRK85_4FM_4R, CKLLSRK75_4M_5R, + ParsaniKetchesonDeconinck3S32, + ParsaniKetchesonDeconinck3S82, + ParsaniKetchesonDeconinck3S53, + ParsaniKetchesonDeconinck3S173, + ParsaniKetchesonDeconinck3S94, + ParsaniKetchesonDeconinck3S184, + ParsaniKetchesonDeconinck3S105, + ParsaniKetchesonDeconinck3S205, + RDPK3Sp35, RDPK3SpFSAL35, RDPK3Sp49, RDPK3SpFSAL49, + RDPK3Sp510, RDPK3SpFSAL510, + RK46NL, SHLDDRK_2N, SHLDDRK52 +export OrdinaryDiffEqLowStorageRK, ORK256, CarpenterKennedy2N54, SHLDDRK64, HSLDDRK64, + DGLDDRK73_C, DGLDDRK84_C, DGLDDRK84_F, NDBLSRK124, NDBLSRK134, NDBLSRK144, CFRLDDRK64, TSLDDRK74, CKLLSRK43_2, CKLLSRK54_3C, CKLLSRK95_4S, CKLLSRK95_4C, CKLLSRK95_4M, @@ -103,106 +89,171 @@ export ORK256, CarpenterKennedy2N54, SHLDDRK64, HSLDDRK64, DGLDDRK73_C, DGLDDRK8 RDPK3Sp35, RDPK3SpFSAL35, RDPK3Sp49, RDPK3SpFSAL49, RDPK3Sp510, RDPK3SpFSAL510, RK46NL, SHLDDRK_2N, SHLDDRK52 -using OrdinaryDiffEqSSPRK -export SSPRK53_2N2, SSPRK22, SSPRK53, SSPRK63, SSPRK83, SSPRK43, SSPRK432, SSPRKMSVS32, +import OrdinaryDiffEqSSPRK: OrdinaryDiffEqSSPRK +using OrdinaryDiffEqSSPRK: SSPRK53_2N2, SSPRK22, SSPRK53, SSPRK63, SSPRK83, SSPRK43, + SSPRK432, SSPRKMSVS32, + SSPRK54, SSPRK53_2N1, SSPRK104, SSPRK932, SSPRKMSVS43, SSPRK73, + SSPRK53_H, + SSPRK33, KYKSSPRK42, KYK2014DGSSPRK_3S2 +export OrdinaryDiffEqSSPRK, SSPRK53_2N2, SSPRK22, SSPRK53, SSPRK63, SSPRK83, SSPRK43, + SSPRK432, SSPRKMSVS32, SSPRK54, SSPRK53_2N1, SSPRK104, SSPRK932, SSPRKMSVS43, SSPRK73, SSPRK53_H, SSPRK33, KYKSSPRK42, KYK2014DGSSPRK_3S2 -using OrdinaryDiffEqFeagin -export Feagin10, Feagin12, Feagin14 - -using OrdinaryDiffEqSymplecticRK -export SymplecticEuler, VelocityVerlet, VerletLeapfrog, PseudoVerletLeapfrog, - McAte2, Ruth3, McAte3, CandyRoz4, McAte4, McAte42, McAte5, +import OrdinaryDiffEqFeagin: OrdinaryDiffEqFeagin +using OrdinaryDiffEqFeagin: Feagin10, Feagin12, Feagin14 +export OrdinaryDiffEqFeagin, Feagin10, Feagin12, Feagin14 + +import OrdinaryDiffEqSymplecticRK: OrdinaryDiffEqSymplecticRK +using OrdinaryDiffEqSymplecticRK: SymplecticEuler, VelocityVerlet, VerletLeapfrog, + LeapfrogDriftKickDrift, + PseudoVerletLeapfrog, McAte2, Ruth3, McAte3, CandyRoz4, + McAte4, McAte42, McAte5, + CalvoSanz4, Yoshida6, KahanLi6, McAte8, KahanLi8, SofSpa10 +export OrdinaryDiffEqSymplecticRK, SymplecticEuler, VelocityVerlet, VerletLeapfrog, + LeapfrogDriftKickDrift, + PseudoVerletLeapfrog, McAte2, Ruth3, McAte3, CandyRoz4, McAte4, McAte42, McAte5, CalvoSanz4, Yoshida6, KahanLi6, McAte8, KahanLi8, SofSpa10 -using OrdinaryDiffEqRKN -export Nystrom4, FineRKN4, FineRKN5, Nystrom4VelocityIndependent, +import OrdinaryDiffEqRKN: OrdinaryDiffEqRKN +using OrdinaryDiffEqRKN: Nystrom4, FineRKN4, FineRKN5, Nystrom4VelocityIndependent, + Nystrom5VelocityIndependent, + IRKN3, IRKN4, DPRKN4, DPRKN5, DPRKN6, DPRKN6FM, DPRKN8, DPRKN12, + ERKN4, ERKN5, ERKN7, + RKN4 +export OrdinaryDiffEqRKN, Nystrom4, FineRKN4, FineRKN5, Nystrom4VelocityIndependent, Nystrom5VelocityIndependent, IRKN3, IRKN4, DPRKN4, DPRKN5, DPRKN6, DPRKN6FM, DPRKN8, DPRKN12, ERKN4, ERKN5, ERKN7, RKN4 -using OrdinaryDiffEqVerner -export Vern6, Vern7, Vern8, Vern9 - -using OrdinaryDiffEqSDIRK -import OrdinaryDiffEqSDIRK: ImplicitEulerConstantCache, ImplicitEulerCache -export ImplicitEuler, ImplicitMidpoint, Trapezoid, TRBDF2, SDIRK2, SDIRK22, +import OrdinaryDiffEqVerner: OrdinaryDiffEqVerner +using OrdinaryDiffEqVerner: Vern6, Vern7, Vern8, Vern9, AutoVern6, AutoVern7, AutoVern8, + AutoVern9 +export OrdinaryDiffEqVerner, Vern6, Vern7, Vern8, Vern9 + +import OrdinaryDiffEqHighOrderRK: OrdinaryDiffEqHighOrderRK +using OrdinaryDiffEqHighOrderRK: TanYam7, DP8, PFRK87, TsitPap8 +export OrdinaryDiffEqHighOrderRK, TanYam7, DP8, PFRK87, TsitPap8 + +import OrdinaryDiffEqSDIRK: OrdinaryDiffEqSDIRK +using OrdinaryDiffEqSDIRK: ImplicitEuler, ImplicitMidpoint, Trapezoid, TRBDF2, SDIRK2, + SDIRK22, + Kvaerno3, KenCarp3, Cash4, Hairer4, Hairer42, SSPSDIRK2, + Kvaerno4, + Kvaerno5, KenCarp4, KenCarp47, KenCarp5, KenCarp58, + ESDIRK54I8L2SA, SFSDIRK4, + SFSDIRK5, CFNLIRK3, SFSDIRK6, SFSDIRK7, SFSDIRK8, + ESDIRK436L2SA2, ESDIRK437L2SA, ESDIRK547L2SA2, ESDIRK659L2SA +export OrdinaryDiffEqSDIRK, ImplicitEuler, ImplicitMidpoint, Trapezoid, TRBDF2, SDIRK2, + SDIRK22, Kvaerno3, KenCarp3, Cash4, Hairer4, Hairer42, SSPSDIRK2, Kvaerno4, Kvaerno5, KenCarp4, KenCarp47, KenCarp5, KenCarp58, ESDIRK54I8L2SA, SFSDIRK4, - SFSDIRK5, CFNLIRK3, SFSDIRK6, SFSDIRK7, SFSDIRK8, Kvaerno5, KenCarp4, KenCarp5, - SFSDIRK4, SFSDIRK5, CFNLIRK3, SFSDIRK6, - SFSDIRK7, SFSDIRK8, ESDIRK436L2SA2, ESDIRK437L2SA, ESDIRK547L2SA2, ESDIRK659L2SA - -using OrdinaryDiffEqBDF -export ABDF2, QNDF1, QBDF1, QNDF2, QBDF2, QNDF, QBDF, FBDF, + SFSDIRK5, CFNLIRK3, SFSDIRK6, SFSDIRK7, SFSDIRK8, + ESDIRK436L2SA2, ESDIRK437L2SA, ESDIRK547L2SA2, ESDIRK659L2SA + +import OrdinaryDiffEqBDF: OrdinaryDiffEqBDF +using OrdinaryDiffEqBDF: ABDF2, QNDF1, QBDF1, QNDF2, QBDF2, QNDF, QBDF, FBDF, + SBDF2, SBDF3, SBDF4, MEBDF2, IMEXEuler, IMEXEulerARK, + DImplicitEuler, DABDF2, DFBDF +export OrdinaryDiffEqBDF, ABDF2, QNDF1, QBDF1, QNDF2, QBDF2, QNDF, QBDF, FBDF, SBDF2, SBDF3, SBDF4, MEBDF2, IMEXEuler, IMEXEulerARK, DImplicitEuler, DABDF2, DFBDF -using OrdinaryDiffEqTsit5 -export Tsit5, AutoTsit5 -import OrdinaryDiffEqTsit5: Tsit5ConstantCache, Tsit5Cache - -using OrdinaryDiffEqRosenbrock -export Rosenbrock23, Rosenbrock32, RosShamp4, Veldd4, Velds4, GRK4T, GRK4A, +import OrdinaryDiffEqTsit5: OrdinaryDiffEqTsit5 +using OrdinaryDiffEqTsit5: Tsit5, AutoTsit5 +export OrdinaryDiffEqTsit5, Tsit5, AutoTsit5 + +import OrdinaryDiffEqRosenbrock: OrdinaryDiffEqRosenbrock +using OrdinaryDiffEqRosenbrock: Rosenbrock23, Rosenbrock32, RosShamp4, Veldd4, Velds4, + GRK4T, GRK4A, + Ros4LStab, ROS3P, Rodas3, Rodas23W, Rodas3P, Rodas4, + Rodas42, Rodas4P, Rodas4P2, + Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, + RosenbrockW6S4OS, ROS34PW1a, ROS34PW1b, ROS34PW2, ROS34PW3, + ROS34PRw, ROS3PRL, + ROS3PRL2, ROK4a, + ROS2, ROS2PR, ROS2S, ROS3, ROS3PR, Scholz4_7 +export OrdinaryDiffEqRosenbrock, Rosenbrock23, Rosenbrock32, RosShamp4, Veldd4, Velds4, + GRK4T, GRK4A, Ros4LStab, ROS3P, Rodas3, Rodas23W, Rodas3P, Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, RosenbrockW6S4OS, ROS34PW1a, ROS34PW1b, ROS34PW2, ROS34PW3, ROS34PRw, ROS3PRL, ROS3PRL2, ROK4a, ROS2, ROS2PR, ROS2S, ROS3, ROS3PR, Scholz4_7 -import OrdinaryDiffEqRosenbrock: RosenbrockMutableCache - -using OrdinaryDiffEqDefault -export DefaultODEAlgorithm - -using OrdinaryDiffEqFIRK -export RadauIIA3, RadauIIA5, RadauIIA9 -using OrdinaryDiffEqQPRK -export QPRK98 - -using OrdinaryDiffEqPDIRK -export PDIRK44 - -using OrdinaryDiffEqPRK -export KuttaPRK2p5 - -using OrdinaryDiffEqHighOrderRK -export TanYam7, DP8, PFRK87, TsitPap8 -using OrdinaryDiffEqHighOrderRK: DP8ConstantCache, DP8Cache - -using OrdinaryDiffEqLowOrderRK -export Euler, SplitEuler, Heun, Ralston, Midpoint, RK4, +import OrdinaryDiffEqDefault: OrdinaryDiffEqDefault +using OrdinaryDiffEqDefault: DefaultODEAlgorithm +export OrdinaryDiffEqDefault, DefaultODEAlgorithm + +import OrdinaryDiffEqFIRK: OrdinaryDiffEqFIRK +using OrdinaryDiffEqFIRK: RadauIIA3, RadauIIA5, RadauIIA9 +export OrdinaryDiffEqFIRK, RadauIIA3, RadauIIA5, RadauIIA9 + +import OrdinaryDiffEqQPRK: OrdinaryDiffEqQPRK +using OrdinaryDiffEqQPRK: QPRK98 +export OrdinaryDiffEqQPRK, QPRK98 + +import OrdinaryDiffEqPDIRK: OrdinaryDiffEqPDIRK +using OrdinaryDiffEqPDIRK: PDIRK44 +export OrdinaryDiffEqPDIRK, PDIRK44 + +import OrdinaryDiffEqPRK: OrdinaryDiffEqPRK +using OrdinaryDiffEqPRK: KuttaPRK2p5 +export OrdinaryDiffEqPRK, KuttaPRK2p5 + +import OrdinaryDiffEqLowOrderRK: OrdinaryDiffEqLowOrderRK +using OrdinaryDiffEqLowOrderRK: Euler, SplitEuler, Heun, Ralston, Midpoint, RK4, + BS3, OwrenZen3, OwrenZen4, OwrenZen5, BS5, + DP5, Anas5, RKO65, FRK65, RKM, MSRK5, MSRK6, + PSRK4p7q6, PSRK3p5q4, PSRK3p6q5, Stepanov5, SIR54, + Alshina2, Alshina3, Alshina6, AutoDP5 +export OrdinaryDiffEqLowOrderRK, Euler, SplitEuler, Heun, Ralston, Midpoint, RK4, BS3, OwrenZen3, OwrenZen4, OwrenZen5, BS5, DP5, Anas5, RKO65, FRK65, RKM, MSRK5, MSRK6, PSRK4p7q6, PSRK3p5q4, PSRK3p6q5, Stepanov5, SIR54, Alshina2, Alshina3, Alshina6, AutoDP5 -using OrdinaryDiffEqLowOrderRK: BS3Cache, BS3ConstantCache, RK4ConstantCache, RK4Cache -using OrdinaryDiffEqFunctionMap -export FunctionMap +import OrdinaryDiffEqFunctionMap: OrdinaryDiffEqFunctionMap +using OrdinaryDiffEqFunctionMap: FunctionMap +export OrdinaryDiffEqFunctionMap, FunctionMap -using OrdinaryDiffEqAdamsBashforthMoulton -export AB3, AB4, AB5, ABM32, ABM43, ABM54, VCAB3, +import OrdinaryDiffEqAdamsBashforthMoulton: OrdinaryDiffEqAdamsBashforthMoulton +using OrdinaryDiffEqAdamsBashforthMoulton: AB3, AB4, AB5, ABM32, ABM43, ABM54, VCAB3, + VCAB4, VCAB5, VCABM3, VCABM4, VCABM5, VCABM +export OrdinaryDiffEqAdamsBashforthMoulton, AB3, AB4, AB5, ABM32, ABM43, ABM54, VCAB3, VCAB4, VCAB5, VCABM3, VCABM4, VCABM5, VCABM -using OrdinaryDiffEqNordsieck -export AN5, JVODE, JVODE_Adams, JVODE_BDF - -using OrdinaryDiffEqExplicitRK -using OrdinaryDiffEqExplicitRK: constructDormandPrince -export ExplicitRK - -using OrdinaryDiffEqLinear -export MagnusMidpoint, LinearExponential, MagnusLeapfrog, LieEuler, CayleyEuler, +import OrdinaryDiffEqNordsieck: OrdinaryDiffEqNordsieck +using OrdinaryDiffEqNordsieck: AN5, JVODE, JVODE_Adams, JVODE_BDF +export OrdinaryDiffEqNordsieck, AN5, JVODE, JVODE_Adams, JVODE_BDF + +import OrdinaryDiffEqExplicitRK: OrdinaryDiffEqExplicitRK +using OrdinaryDiffEqExplicitRK: ExplicitRK, constructDormandPrince +export OrdinaryDiffEqExplicitRK, ExplicitRK + +import OrdinaryDiffEqLinear: OrdinaryDiffEqLinear +using OrdinaryDiffEqLinear: MagnusMidpoint, LinearExponential, MagnusLeapfrog, LieEuler, + CayleyEuler, + MagnusGauss4, MagnusNC6, MagnusGL6, MagnusGL8, MagnusNC8, + MagnusGL4, + MagnusAdapt4, RKMK2, RKMK4, LieRK4, CG2, CG3, CG4a +export OrdinaryDiffEqLinear, MagnusMidpoint, LinearExponential, MagnusLeapfrog, LieEuler, + CayleyEuler, MagnusGauss4, MagnusNC6, MagnusGL6, MagnusGL8, MagnusNC8, MagnusGL4, MagnusAdapt4, RKMK2, RKMK4, LieRK4, CG2, CG3, CG4a -using OrdinaryDiffEqIMEXMultistep -export CNAB2, CNLF2 - -using OrdinaryDiffEqExponentialRK -export LawsonEuler, NorsettEuler, ETD1, ETDRK2, ETDRK3, ETDRK4, HochOst4, Exp4, EPIRK4s3A, +import OrdinaryDiffEqIMEXMultistep: OrdinaryDiffEqIMEXMultistep +using OrdinaryDiffEqIMEXMultistep: CNAB2, CNLF2 +export OrdinaryDiffEqIMEXMultistep, CNAB2, CNLF2 + +import OrdinaryDiffEqExponentialRK: OrdinaryDiffEqExponentialRK +using OrdinaryDiffEqExponentialRK: LawsonEuler, NorsettEuler, ETD1, ETDRK2, ETDRK3, ETDRK4, + HochOst4, Exp4, EPIRK4s3A, + EPIRK4s3B, + EPIRK5s3, EXPRB53s3, EPIRK5P1, EPIRK5P2, ETD2, Exprb32, + Exprb43 +export OrdinaryDiffEqExponentialRK, LawsonEuler, NorsettEuler, ETD1, ETDRK2, ETDRK3, ETDRK4, + HochOst4, Exp4, EPIRK4s3A, EPIRK4s3B, EPIRK5s3, EXPRB53s3, EPIRK5P1, EPIRK5P2, ETD2, Exprb32, Exprb43 @@ -216,7 +267,7 @@ const DEPRECATED_ADDSTEPS = true export solve, solve!, init, step! #Callback Necessary -export addsteps!, ode_interpolant, terminate!, savevalues!, copyat_or_push!, isfsal +export addsteps!, ode_interpolant, terminate!, savevalues!, isfsal export constructDormandPrince @@ -224,9 +275,11 @@ export constructDormandPrince export CompositeAlgorithm -export AutoSwitch, AutoTsit5, AutoDP5, - AutoVern6, AutoVern7, AutoVern8, AutoVern9 +export AutoSwitch, AutoVern6, AutoVern7, AutoVern8, AutoVern9 import OrdinaryDiffEqCore: IController, PIController, PIDController export IController, PIController, PIDController + +# Export Reexport and @reexport +export Reexport, @reexport end # module diff --git a/test/downstream/Project.toml b/test/downstream/Project.toml index 345d90f382..36f08b13c4 100644 --- a/test/downstream/Project.toml +++ b/test/downstream/Project.toml @@ -1,18 +1,19 @@ [deps] DDEProblemLibrary = "f42792ee-6ffc-4e2a-ae83-8ee2f22de800" DelayDiffEq = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" +Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" +Mooncake = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" -SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" -Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] DDEProblemLibrary = "0.1" DelayDiffEq = "5.42" +Enzyme = "0.13" Measurements = "2.9" -SciMLSensitivity = "7.30" +Mooncake = "0.4" +OrdinaryDiffEq = "6" StaticArrays = "1" StochasticDiffEq = "6.60.1" -Zygote = "0.6.61" diff --git a/test/downstream/delaydiffeq.jl b/test/downstream/delaydiffeq.jl index 6c2fcf5f1e..58228780d2 100644 --- a/test/downstream/delaydiffeq.jl +++ b/test/downstream/delaydiffeq.jl @@ -1,4 +1,4 @@ -using DelayDiffEq, DDEProblemLibrary +using DelayDiffEq, DDEProblemLibrary, ADTypes using Test @testset "Constant delays" begin @@ -24,8 +24,8 @@ using Test @test sol.errors[:l∞] < error sol_scalar = solve(prob_scalar, ddealg) - @test sol.t≈sol_scalar.t atol=1e-6 - @test sol[1, :] ≈ sol_scalar.u + @test sol.t≈sol_scalar.t atol=1e-3 + @test sol[1, :]≈sol_scalar.u atol=1e-3 end end @@ -43,4 +43,4 @@ h(p, t) = [1.0, 1.0] h(p, t; idxs = 1) = 1.0 p = [1.5, 1.0, 3.0, 1.0, 1.0] prob = DDEProblem(lotka_volterra!, uₒ, h, tspan, p, constant_lags = (p[end],)) -sol = solve(prob, MethodOfSteps(AutoTsit5(Rosenbrock23(autodiff = false)))) +sol = solve(prob, MethodOfSteps(AutoTsit5(Rosenbrock23(autodiff = AutoFiniteDiff())))) diff --git a/test/downstream/mooncake.jl b/test/downstream/mooncake.jl new file mode 100644 index 0000000000..8bffc9f8fd --- /dev/null +++ b/test/downstream/mooncake.jl @@ -0,0 +1,19 @@ +using Mooncake, OrdinaryDiffEq, StaticArrays + +function lorenz!(du, u, p, t) + du[1] = 10.0(u[2] - u[1]) + du[2] = u[1] * (28.0 - u[3]) - u[2] + du[3] = u[1] * u[2] - (8 / 3) * u[3] +end + +const _saveat = SA[0.0,0.25,0.5,0.75,1.0,1.25,1.5,1.75,2.0,2.25,2.5,2.75,3.0] + +function f(u0::Array{Float64}) + tspan = (0.0, 3.0) + prob = ODEProblem{true, SciMLBase.FullSpecialize}(lorenz!, u0, tspan) + sol = SciMLBase.solve(prob, Tsit5(), saveat = _saveat, sensealg = SciMLBase.SensitivityADPassThrough()) + sum(sol) +end; +u0 = [1.0; 0.0; 0.0] +mooncake_gradient(f, x) = Mooncake.value_and_gradient!!(Mooncake.build_rrule(f, x), f, x)[2][2] +@test_broken mooncake_gradient(f, u0) diff --git a/test/interface/sparsediff_tests.jl b/test/downstream/sparsediff_tests.jl similarity index 60% rename from test/interface/sparsediff_tests.jl rename to test/downstream/sparsediff_tests.jl index 63983ade09..12f652c839 100644 --- a/test/interface/sparsediff_tests.jl +++ b/test/downstream/sparsediff_tests.jl @@ -2,6 +2,15 @@ using Test using OrdinaryDiffEq using SparseArrays using LinearAlgebra +using LinearSolve +import DifferentiationInterface as DI +using SparseConnectivityTracer +using SparseMatrixColorings +using ADTypes + +if isempty(VERSION.prerelease) + using Enzyme +end ## in-place #https://github.com/JuliaDiffEq/SparseDiffTools.jl/blob/master/test/test_integration.jl @@ -47,24 +56,33 @@ colors = repeat(1:3, 10)[1:10] u0 = [1.0, 2.0, 3, 4, 5, 5, 4, 3, 2, 1] tspan = (0.0, 10.0) +adchoices = if isempty(VERSION.prerelease) + [AutoForwardDiff(), AutoFiniteDiff(), + AutoEnzyme(mode = Enzyme.Forward, function_annotation = Enzyme.Const)] +else + [AutoForwardDiff(), AutoFiniteDiff()] +end + for f in [f_oop, f_ip] odefun_std = ODEFunction(f) prob_std = ODEProblem(odefun_std, u0, tspan) - for ad in [true, false] - for Solver in [Rodas5, Rosenbrock23, Trapezoid, KenCarp4] + for ad in adchoices, linsolve in [nothing, LinearSolve.KrylovJL_GMRES()] + for Solver in [Rodas5, Rosenbrock23, Trapezoid, KenCarp4, FBDF] for tol in [nothing, 1e-10] - sol_std = solve(prob_std, Solver(autodiff = ad), reltol = tol, abstol = tol) + sol_std = solve(prob_std, Solver(autodiff = ad, linsolve = linsolve), reltol = tol, abstol = tol) @test sol_std.retcode == ReturnCode.Success for (i, prob) in enumerate(map(f -> ODEProblem(f, u0, tspan), [ ODEFunction(f, colorvec = colors, jac_prototype = jac_sp), + ODEFunction(f, colorvec = colors, + jac_prototype = jac_sp, mass_matrix = I(length(u0))), ODEFunction(f, jac_prototype = jac_sp), ODEFunction(f, colorvec = colors, sparsity = jac_sp) ])) - sol = solve(prob, Solver(autodiff = ad), reltol = tol, abstol = tol) + sol = solve(prob, Solver(autodiff = ad, linsolve = linsolve), reltol = tol, abstol = tol) @test sol.retcode == ReturnCode.Success if tol != nothing @test sol_std.u[end]≈sol.u[end] atol=tol @@ -77,3 +95,27 @@ for f in [f_oop, f_ip] end end end + +# test for https://github.com/SciML/OrdinaryDiffEq.jl/issues/2653#issuecomment-2778430025 + +using LinearAlgebra, SparseArrays +using OrdinaryDiffEq + +function f(du, u, p, t) + du[1] = u[1] + return du +end + +function jac(J::SparseMatrixCSC, u, p, t) + @assert nnz(J) == 1 # mirrors the strict behavior of SparseMatrixColorings + nonzeros(J)[1] = 1 + return J +end + +u0 = ones(10) +jac_prototype = sparse(Diagonal(vcat(1, zeros(9)))) + +fun = ODEFunction(f; jac, jac_prototype) +prob = ODEProblem(fun, u0, (0.0, 1.0)) +@test_nowarn sol = solve(prob, Rodas4(); reltol = 1e-8, abstol = 1e-8) + diff --git a/test/regression/time_derivative_test.jl b/test/downstream/time_derivative_test.jl similarity index 77% rename from test/regression/time_derivative_test.jl rename to test/downstream/time_derivative_test.jl index 99c9dc0fc9..41662c394b 100644 --- a/test/regression/time_derivative_test.jl +++ b/test/downstream/time_derivative_test.jl @@ -1,4 +1,8 @@ -using OrdinaryDiffEq, StaticArrays, Test +using OrdinaryDiffEq, StaticArrays, Test, ADTypes + +adchoices = if isempty(VERSION.prerelease) + using Enzyme +end function time_derivative(du, u, p, t) du[1] = -t @@ -10,6 +14,13 @@ function time_derivative_analytic(u0, p, t) u0 .- t .^ 2 ./ 2 end +adchoices = if isempty(VERSION.prerelease) + (AutoForwardDiff(), AutoFiniteDiff(), + AutoEnzyme(mode = Enzyme.Forward, function_annotation = Enzyme.Const)) +else + (AutoForwardDiff(), AutoFiniteDiff()) +end + const CACHE_TEST_ALGS = [Euler(), Midpoint(), RK4(), SSPRK22(), SSPRK33(), SSPRK53(), SSPRK63(), SSPRK73(), SSPRK83(), SSPRK43(), SSPRK432(), SSPRK932(), SSPRK54(), SSPRK104(), CarpenterKennedy2N54(), @@ -29,50 +40,57 @@ for (ff_time_derivative, u0) in ( prob = ODEProblem(ff_time_derivative, u0, tspan) - for _autodiff in (true, false) + for _autodiff in adchoices @info "autodiff=$(_autodiff)" + prec = !(_autodiff == AutoFiniteDiff()) + @show Rosenbrock23 sol = solve(prob, Rosenbrock32(autodiff = _autodiff), reltol = 1e-9, abstol = 1e-9) - @test sol.errors[:final] < 1e-5 * 10^(!_autodiff) + @test sol.errors[:final] < 1e-5 * 10^(!prec) sol = solve(prob, Rosenbrock23(autodiff = _autodiff), reltol = 1e-9, abstol = 1e-9) - @test sol.errors[:final] < 1e-10 * 10_000^(!_autodiff) + @test sol.errors[:final] < 1e-10 * 10_000^(!prec) @show Rodas4 sol = solve(prob, Rodas4(autodiff = _autodiff), reltol = 1e-9, abstol = 1e-9) - @test sol.errors[:final] < 1e-10 * 100_000^(!_autodiff) + @test sol.errors[:final] < 1e-10 * 100_000^(!prec) @show Rodas5 sol = solve(prob, Rodas5(autodiff = _autodiff), reltol = 1e-9, abstol = 1e-9) - @test sol.errors[:final] < 1e-10 * 1_000_000_000^(!_autodiff) + @test sol.errors[:final] < 1e-10 * 1_000_000_000^(!prec) @show Veldd4 sol = solve(prob, Veldd4(autodiff = _autodiff), reltol = 1e-9, abstol = 1e-9) - @test sol.errors[:final] < 1e-10 * 100_000^(!_autodiff) + @test sol.errors[:final] < 1e-10 * 100_000^(!prec) @show KenCarp3 sol = solve(prob, KenCarp3(autodiff = _autodiff), reltol = 1e-12, abstol = 1e-12) @test length(sol) > 2 + @test SciMLBase.successful_retcode(sol) @test sol.errors[:final] < 1e-10 @show KenCarp4 sol = solve(prob, KenCarp4(autodiff = _autodiff), reltol = 1e-12, abstol = 1e-12) @test length(sol) > 2 + @test SciMLBase.successful_retcode(sol) @test sol.errors[:final] < 1e-10 @show KenCarp47 sol = solve(prob, KenCarp47(autodiff = _autodiff), reltol = 1e-12, abstol = 1e-12) @test length(sol) > 2 + @test SciMLBase.successful_retcode(sol) @test sol.errors[:final] < 1e-10 @show KenCarp5 sol = solve(prob, KenCarp5(autodiff = _autodiff), reltol = 1e-12, abstol = 1e-12) @test length(sol) > 2 + @test SciMLBase.successful_retcode(sol) @test sol.errors[:final] < 1e-10 @show KenCarp58 sol = solve(prob, KenCarp58(autodiff = _autodiff), reltol = 1e-12, abstol = 1e-12) @test length(sol) > 2 + @test SciMLBase.successful_retcode(sol) @test sol.errors[:final] < 1e-10 @show TRBDF2 diff --git a/test/enzyme/Project.toml b/test/enzyme/Project.toml new file mode 100644 index 0000000000..20bf70ba66 --- /dev/null +++ b/test/enzyme/Project.toml @@ -0,0 +1,13 @@ +[deps] +Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[compat] +Enzyme = "0.13" +OrdinaryDiffEq = "6" +SciMLSensitivity = "7" +StaticArrays = "1" +Zygote = "0.6.61, 0.7" diff --git a/test/downstream/autodiff_events.jl b/test/enzyme/autodiff_events.jl similarity index 92% rename from test/downstream/autodiff_events.jl rename to test/enzyme/autodiff_events.jl index 2b7438aa82..12510b4b20 100644 --- a/test/downstream/autodiff_events.jl +++ b/test/enzyme/autodiff_events.jl @@ -1,5 +1,5 @@ using SciMLSensitivity -using OrdinaryDiffEq, OrdinaryDiffEqCore, Calculus, Test +using OrdinaryDiffEq, OrdinaryDiffEqCore, FiniteDiff, Test using Zygote function f(du, u, p, t) @@ -24,9 +24,9 @@ prob = ODEProblem(f, eltype(p).([1.0, 0.0]), eltype(p).((0.0, 1.0)), copy(p)) function test_f(p) _prob = remake(prob, p = p) solve(_prob, Tsit5(), abstol = 1e-14, reltol = 1e-14, callback = cb, - save_everystep = false)[end] + save_everystep = false).u[end] end -findiff = Calculus.finite_difference_jacobian(test_f, p) +findiff = FiniteDiff.finite_difference_jacobian(test_f, p) findiff using ForwardDiff diff --git a/test/enzyme/discrete_adjoints.jl b/test/enzyme/discrete_adjoints.jl new file mode 100644 index 0000000000..6235fa7713 --- /dev/null +++ b/test/enzyme/discrete_adjoints.jl @@ -0,0 +1,51 @@ +using Enzyme, OrdinaryDiffEqTsit5, StaticArrays, DiffEqBase, ForwardDiff, Test + +function lorenz!(du, u, p, t) + du[1] = 10.0(u[2] - u[1]) + du[2] = u[1] * (28.0 - u[3]) - u[2] + du[3] = u[1] * u[2] - (8 / 3) * u[3] +end + +const _saveat = SA[0.0,0.25,0.5,0.75,1.0,1.25,1.5,1.75,2.0,2.25,2.5,2.75,3.0] + +function f_dt(y::Array{Float64}, u0::Array{Float64}) + tspan = (0.0, 3.0) + prob = ODEProblem{true, SciMLBase.FullSpecialize}(lorenz!, u0, tspan) + sol = DiffEqBase.solve(prob, Tsit5(), saveat = _saveat, sensealg = DiffEqBase.SensitivityADPassThrough(), abstol=1e-12, reltol=1e-12) + y .= sol[1,:] + return nothing +end; + +function f_dt(u0) + tspan = (0.0, 3.0) + prob = ODEProblem{true, SciMLBase.FullSpecialize}(lorenz!, u0, tspan) + sol = DiffEqBase.solve(prob, Tsit5(), saveat = _saveat, sensealg = DiffEqBase.SensitivityADPassThrough(), abstol=1e-12, reltol=1e-12) + sol[1,:] +end; + +u0 = [1.0; 0.0; 0.0] +fdj = ForwardDiff.jacobian(f_dt, u0) + +ezj = stack(map(1:3) do i + d_u0 = zeros(3) + dy = zeros(13) + y = zeros(13) + d_u0[i] = 1.0 + Enzyme.autodiff(Forward, f_dt, Duplicated(y, dy), Duplicated(u0, d_u0)); + dy +end) + +@test ezj ≈ fdj + +function f_dt2(u0) + tspan = (0.0, 3.0) + prob = ODEProblem{true, SciMLBase.FullSpecialize}(lorenz!, u0, tspan) + sol = DiffEqBase.solve(prob, Tsit5(), dt=0.1, saveat = _saveat, sensealg = DiffEqBase.SensitivityADPassThrough(), abstol=1e-12, reltol=1e-12) + sum(sol[1,:]) +end + +fdg = ForwardDiff.gradient(f_dt2, u0) +d_u0 = zeros(3) +Enzyme.autodiff(Reverse, f_dt2, Active, Duplicated(u0, d_u0)); + +@test d_u0 ≈ fdg diff --git a/test/gpu/Project.toml b/test/gpu/Project.toml index b42a597fa8..82f4c178be 100644 --- a/test/gpu/Project.toml +++ b/test/gpu/Project.toml @@ -2,10 +2,17 @@ Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" +DiffEqBase = "2b5f629d-d688-5b77-993f-72d75c75574e" FastBroadcast = "7034ab61-46d4-4ed7-9d0f-46aef9175898" FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" [compat] +Adapt = "4" CUDA = "5" +ComponentArrays = "0.15" +DiffEqBase = "6.182" +FastBroadcast = "0.3" +FillArrays = "1" +OrdinaryDiffEq = "6" diff --git a/test/gpu/linear_exp.jl b/test/gpu/linear_exp.jl new file mode 100644 index 0000000000..41cb74e5d2 --- /dev/null +++ b/test/gpu/linear_exp.jl @@ -0,0 +1,34 @@ +using LinearAlgebra +using SparseArrays +using CUDA +using CUDA.CUSPARSE +using OrdinaryDiffEq + +# Linear exponential solvers +A = MatrixOperator([2.0 -1.0; -1.0 2.0]) +u0 = ones(2) + +A_gpu = MatrixOperator(cu([2.0 -1.0; -1.0 2.0])) +u0_gpu = cu(ones(2)) +prob_gpu = ODEProblem(A_gpu, u0_gpu, (0.0, 1.0)) + +sol_analytic = exp(1.0 * Matrix(A)) * u0 + +@test_broken sol1_gpu = solve(prob_gpu, LinearExponential(krylov = :off))(1.0) |> Vector +sol2_gpu = solve(prob_gpu, LinearExponential(krylov = :simple))(1.0) |> Vector +sol3_gpu = solve(prob_gpu, LinearExponential(krylov = :adaptive))(1.0) |> Vector + +@test_broken isapprox(sol1_gpu, sol_analytic, rtol = 1e-6) +@test isapprox(sol2_gpu, sol_analytic, rtol = 1e-6) +@test isapprox(sol3_gpu, sol_analytic, rtol = 1e-6) + +A2_gpu = MatrixOperator(cu(sparse([2.0 -1.0; -1.0 2.0]))) +prob2_gpu = ODEProblem(A2_gpu, u0_gpu, (0.0, 1.0)) + +@test_broken sol2_1_gpu = solve(prob2_gpu, LinearExponential(krylov = :off))(1.0) |> Vector +sol2_2_gpu = solve(prob2_gpu, LinearExponential(krylov = :simple))(1.0) |> Vector +sol2_3_gpu = solve(prob2_gpu, LinearExponential(krylov = :adaptive))(1.0) |> Vector + +@test_broken isapprox(sol2_1_gpu, sol_analytic, rtol = 1e-6) +@test isapprox(sol2_2_gpu, sol_analytic, rtol = 1e-6) +@test isapprox(sol2_3_gpu, sol_analytic, rtol = 1e-6) diff --git a/test/integrators/check_error.jl b/test/integrators/check_error.jl index 91615c8e1a..61ab159544 100644 --- a/test/integrators/check_error.jl +++ b/test/integrators/check_error.jl @@ -56,3 +56,6 @@ end @test sol.stats.naccept + sol.stats.nreject <= 30 @test_broken sol.retcode = ReturnCode.Success end + +@test_throws ArgumentError solve(prob, Euler(), dt = 0.1, adaptive = true) +@test_throws ArgumentError solve(prob, Euler()) diff --git a/test/integrators/event_detection_tests.jl b/test/integrators/event_detection_tests.jl index d2ae33ca03..2b0c09c82b 100644 --- a/test/integrators/event_detection_tests.jl +++ b/test/integrators/event_detection_tests.jl @@ -28,18 +28,21 @@ sol = solve(prob, Vern9(), abstol = 1e-14, reltol = 1e-14, save_everystep = false, save_start = false, save_end = false, maxiters = 1e6) @test length(sol) > 100 +@test SciMLBase.successful_retcode(sol) prob = ODEProblem(ż, z0, (0, 400.0), (A = 1, B = 0.55, D = 0.4), callback = cbf(3)) sol = solve(prob, Vern9(), abstol = 1e-14, reltol = 1e-14, save_everystep = false, save_start = false, save_end = false, maxiters = 2e4) @test length(sol) > 100 +@test SciMLBase.successful_retcode(sol) prob = ODEProblem(ż, z0, (0, 5000.0), (A = 1, B = 0.55, D = 0.4), callback = cbf(3)) sol = solve(prob, Vern9(), abstol = 1e-14, reltol = 1e-14, save_everystep = false, save_start = false, save_end = false, maxiters = 1e6) @test length(sol) > 1500 +@test SciMLBase.successful_retcode(sol) @info "Bouncing Ball" diff --git a/test/integrators/iterator_tests.jl b/test/integrators/iterator_tests.jl index 5f01a0925b..4870226c86 100644 --- a/test/integrators/iterator_tests.jl +++ b/test/integrators/iterator_tests.jl @@ -62,7 +62,7 @@ end A = integrator([1.0; 2.0]) B = integrator([1.0; 2.0], idxs = 1:2:5) -@test minimum([A[i][1:2:5] == B[i] for i in 1:length(A)]) +@test minimum([A[i][1:2:5] ≈ B[i] for i in 1:length(A)]) integrator(A[1], 0.5) @test A[1] == integrator(0.5) diff --git a/test/integrators/ode_cache_tests.jl b/test/integrators/ode_cache_tests.jl index 8e766a319b..1194c54256 100644 --- a/test/integrators/ode_cache_tests.jl +++ b/test/integrators/ode_cache_tests.jl @@ -1,5 +1,5 @@ -using OrdinaryDiffEq, OrdinaryDiffEqCore, DiffEqBase, Test -using Random, SparseDiffTools +using OrdinaryDiffEq, OrdinaryDiffEqCore, DiffEqBase, Test, ADTypes +using Random using OrdinaryDiffEqDefault using ElasticArrays, LinearSolve Random.seed!(213) @@ -79,9 +79,11 @@ for alg in broken_CACHE_TEST_ALGS @test_broken length(solve(prob, alg, callback = callback, dt = 1 / 2)[end]) > 1 end -sol = solve(prob, Rodas4(chunk_size = 1), callback = callback, dt = 1 / 2) +sol = solve(prob, Rodas4(autodiff = AutoForwardDiff(chunksize = 1)), + callback = callback, dt = 1 / 2) @test length(sol[end]) > 1 -sol = solve(prob, Rodas5(chunk_size = 1), callback = callback, dt = 1 / 2) +sol = solve(prob, Rodas5(autodiff = AutoForwardDiff(chunksize = 1)), + callback = callback, dt = 1 / 2) @test length(sol[end]) > 1 # cache tests resizing multidimensional arrays diff --git a/test/integrators/ode_event_tests.jl b/test/integrators/ode_event_tests.jl index 32995814b1..78c6496da7 100644 --- a/test/integrators/ode_event_tests.jl +++ b/test/integrators/ode_event_tests.jl @@ -22,6 +22,10 @@ callback = ContinuousCallback(condition, affect!) sol = solve(prob, Tsit5(), callback = callback) @test length(sol) < 20 +# Force integrator to step on event +sol = solve(prob, Tsit5(), callback = callback, tstops = [-2.95]) +@test sol(-2.95, continuity = :right) ≈ sol(-2.95, continuity = :left) + 2 + condition = function (out, u, t, integrator) # Event when event_f(u,t,k) == 0 out[1] = -t - 2.95 end @@ -36,6 +40,10 @@ callback = VectorContinuousCallback(condition, affect!, 1) sol = solve(prob, Tsit5(), callback = callback) +# Force integrator to step on event +sol = solve(prob, Tsit5(), callback = callback, tstops = [-2.95]) +@test sol(-2.95, continuity = :right) ≈ sol(-2.95, continuity = :left) + 2 + f = function (du, u, p, t) du[1] = -u[1] + sin(t) end @@ -54,6 +62,10 @@ callback = ContinuousCallback(condition, affect!) sol = solve(prob, Tsit5(), callback = callback, abstol = 1e-8, reltol = 1e-6) +# Force integrator to step on event +sol = solve(prob, Tsit5(), callback = callback, abstol = 1e-8, reltol = 1e-6, tstops = [2.95]) +@test sol(2.95, continuity = :right)[1] ≈ sol(2.95, continuity = :left)[1] + 2 + condition = function (out, u, t, integrator) # Event when event_f(u,t,k) == 0 out[1] = t - 2.95 end @@ -68,6 +80,10 @@ callback = VectorContinuousCallback(condition, affect!, 1) sol = solve(prob, Tsit5(), callback = callback, abstol = 1e-8, reltol = 1e-6) +# Force integrator to step on event +sol = solve(prob, Tsit5(), callback = callback, abstol = 1e-8, reltol = 1e-6, tstops = [2.95]) +@test sol(2.95, continuity = :right)[1] ≈ sol(2.95, continuity = :left)[1] + 2 + f = function (du, u, p, t) du[1] = u[2] du[2] = -9.81 @@ -411,23 +427,21 @@ step!(integrator, 1e-5, true) @test all(u -> u > 1.5, integrator.u) # https://github.com/SciML/OrdinaryDiffEq.jl/pull/1777 -if VERSION >= v"1.7" - @testset "Callbacks with LinearExponential" begin - A = sprand(ComplexF64, 100, 100, 0.5) - A += A' +@testset "Callbacks with LinearExponential" begin + A = Matrix(sprand(ComplexF64, 100, 100, 0.5)) + A += A' - t_l = LinRange(0, 1, 100) + t_l = LinRange(0, 1, 100) - saved_values = SavedValues(Float64, Float64) - function save_func(u, t, integrator) - real(u' * A * u) - end - cb = SavingCallback(save_func, saved_values, saveat = t_l) - - u0 = normalize(rand(ComplexF64, 100)) - A = MatrixOperator(-1im * A) - prob = ODEProblem(A, u0, (0, 1.0)) - solve(prob, LinearExponential(), dt = t_l[2] - t_l[1], callback = cb) - @test length(saved_values.saveval) == length(t_l) + saved_values = SavedValues(Float64, Float64) + function save_func(u, t, integrator) + real(u' * A * u) end + cb = SavingCallback(save_func, saved_values, saveat = t_l) + + u0 = normalize(rand(ComplexF64, 100)) + A = MatrixOperator(-1im * A) + prob = ODEProblem(A, u0, (0, 1.0)) + solve(prob, LinearExponential(), dt = t_l[2] - t_l[1], callback = cb) + @test length(saved_values.saveval) == length(t_l) end diff --git a/test/integrators/resize_tests.jl b/test/integrators/resize_tests.jl index fb5dc583de..94fe53170a 100644 --- a/test/integrators/resize_tests.jl +++ b/test/integrators/resize_tests.jl @@ -1,6 +1,8 @@ -using OrdinaryDiffEq, Test +using OrdinaryDiffEq, Test, ADTypes, SparseMatrixColorings, DiffEqBase, ForwardDiff, SciMLBase, LinearSolve +import OrdinaryDiffEqDifferentiation.DI + f(du, u, p, t) = du .= u -prob = ODEProblem(f, [1.0], (0.0, 1.0)) +prob = ODEProblem{true, SciMLBase.FullSpecialize}(f, [1.0], (0.0, 1.0)) i = init(prob, Tsit5()) resize!(i, 5) @@ -31,14 +33,14 @@ resize!(i, 5) @test size(i.cache.nlsolver.cache.J) == (5, 5) @test size(i.cache.nlsolver.cache.W) == (5, 5) @test length(i.cache.nlsolver.cache.du1) == 5 -@test length(i.cache.nlsolver.cache.jac_config.fx) == 5 -@test length(i.cache.nlsolver.cache.jac_config.dx) == 5 -@test length(i.cache.nlsolver.cache.jac_config.t) == 5 -@test length(i.cache.nlsolver.cache.jac_config.p) == 5 @test length(i.cache.nlsolver.cache.weight) == 5 +@test all(size(DI.jacobian( + (du, u) -> (i.f(du, u, nothing, nothing)), rand(5), i.cache.nlsolver.cache.jac_config[1], + AutoForwardDiff(tag = ForwardDiff.Tag(DiffEqBase.OrdinaryDiffEqTag(), Float64)), rand(5))) .== + 5) solve!(i) -i = init(prob, ImplicitEuler(; autodiff = false)) +i = init(prob, ImplicitEuler(; autodiff = AutoFiniteDiff())) resize!(i, 5) @test length(i.cache.atmp) == 5 @test length(i.cache.uprev) == 5 @@ -54,10 +56,10 @@ resize!(i, 5) @test size(i.cache.nlsolver.cache.J) == (5, 5) @test size(i.cache.nlsolver.cache.W) == (5, 5) @test length(i.cache.nlsolver.cache.du1) == 5 -@test length(i.cache.nlsolver.cache.jac_config.x1) == 5 -@test length(i.cache.nlsolver.cache.jac_config.fx) == 5 -@test length(i.cache.nlsolver.cache.jac_config.fx1) == 5 @test length(i.cache.nlsolver.cache.weight) == 5 +@test all(size(DI.jacobian( + (du, u) -> (i.f(du, u, nothing, nothing)), rand(5), i.cache.nlsolver.cache.jac_config[1], + AutoFiniteDiff(), rand(5))) .== 5) solve!(i) i = init(prob, Rosenbrock23()) @@ -77,13 +79,32 @@ resize!(i, 5) @test size(i.cache.J) == (5, 5) @test size(i.cache.W) == (5, 5) @test length(i.cache.linsolve_tmp) == 5 -@test length(i.cache.jac_config.fx) == 5 -@test length(i.cache.jac_config.dx) == 5 -@test length(i.cache.jac_config.t) == 5 -@test length(i.cache.jac_config.p) == 5 +@test all(size(DI.jacobian( + (du, u) -> (i.f(du, u, nothing, nothing)), rand(5), i.cache.jac_config[1], + AutoForwardDiff(tag = ForwardDiff.Tag(DiffEqBase.OrdinaryDiffEqTag(), Float64)), rand(5))) .== + 5) +solve!(i) + +i = init(prob, Rosenbrock23(autodiff = AutoForwardDiff(), linsolve = KrylovJL_GMRES())) +resize!(i, 5) +@test length(i.cache.u) == 5 +@test length(i.cache.uprev) == 5 +@test length(i.cache.k₁) == 5 +@test length(i.cache.k₂) == 5 +@test length(i.cache.k₃) == 5 +@test length(i.cache.du1) == 5 +@test length(i.cache.du2) == 5 +@test length(i.cache.f₁) == 5 +@test length(i.cache.fsalfirst) == 5 +@test length(i.cache.fsallast) == 5 +@test length(i.cache.dT) == 5 +@test length(i.cache.tmp) == 5 +@test size(i.cache.J) == (5, 5) +@test size(i.cache.W) == (5, 5) +@test length(i.cache.linsolve_tmp) == 5 solve!(i) -i = init(prob, Rosenbrock23(; autodiff = false)) +i = init(prob, Rosenbrock23(; autodiff = AutoFiniteDiff())) resize!(i, 5) @test length(i.cache.u) == 5 @test length(i.cache.uprev) == 5 @@ -100,9 +121,9 @@ resize!(i, 5) @test size(i.cache.J) == (5, 5) @test size(i.cache.W) == (5, 5) @test length(i.cache.linsolve_tmp) == 5 -@test length(i.cache.jac_config.x1) == 5 -@test length(i.cache.jac_config.fx) == 5 -@test length(i.cache.jac_config.fx1) == 5 +@test all(size(DI.jacobian( + (du, u) -> (i.f(du, u, nothing, nothing)), rand(5), i.cache.jac_config[1], + AutoFiniteDiff(), rand(5))) .== 5) solve!(i) function f(du, u, p, t) @@ -185,7 +206,7 @@ end runSim(BS3()) runSim(Rosenbrock23()) -runSim(Rosenbrock23(autodiff = false)) +runSim(Rosenbrock23(autodiff = AutoFiniteDiff())) # https://github.com/SciML/OrdinaryDiffEq.jl/issues/1990 @testset "resize! with SplitODEProblem" begin diff --git a/test/integrators/split_ode_tests.jl b/test/integrators/split_ode_tests.jl index d4d0194b76..b4a468d791 100644 --- a/test/integrators/split_ode_tests.jl +++ b/test/integrators/split_ode_tests.jl @@ -56,7 +56,7 @@ prob = ODEProblem(fun, h0, tspan) #Should be functionally equivalent to above, explicit_fun does nothing sfun = SplitFunction(fun, explicit_fun, jac_prototype = jac_proto) -sprob = ODEProblem(sfun, h0, tspan) +sprob = SplitODEProblem(sfun, h0, tspan) #CFNLIRK3 has same erroneous FSAL logic as KenCarp solvers #Can't efficiently test with stiff problem (to cause dtmin issue) because it requires constant dt diff --git a/test/integrators/step_limiter_test.jl b/test/integrators/step_limiter_test.jl index 566d5da527..690d36e557 100644 --- a/test/integrators/step_limiter_test.jl +++ b/test/integrators/step_limiter_test.jl @@ -1,4 +1,5 @@ using OrdinaryDiffEq, Test +using OrdinaryDiffEqFIRK: AdaptiveRadau, RadauIIA9, RadauIIA5, RadauIIA3 # define the counting variable const STEP_LIMITER_VAR = Ref(0) @@ -27,7 +28,8 @@ end KenCarp3, KenCarp4, KenCarp5, Kvaerno3, Kvaerno4, Kvaerno5, Rosenbrock23, Rosenbrock32, ROS3P, Rodas3, Rodas23W, Rodas3P, Rodas4, Rodas42, Rodas4P, Rodas4P2, Rodas5, Rodas5P, Rodas5Pe, Rodas5Pr, - RadauIIA5, RadauIIA3, SIR54, Alshina2, Alshina3, Heun, Ralston, Midpoint, RK4, + AdaptiveRadau, RadauIIA9, RadauIIA5, RadauIIA3, SIR54, + Alshina2, Alshina3, Heun, Ralston, Midpoint, RK4, OwrenZen3, OwrenZen4, OwrenZen5, BS3, DP5, Tsit5, DP8, TanYam7, TsitPap8, FRK65, PFRK87, BS5, Vern6, Vern7, Vern8, Vern9, QPRK98, SSPRKMSVS43, SSPRKMSVS32, SSPRK432, SSPRK43, diff --git a/test/interface/ad_tests.jl b/test/interface/ad_tests.jl index 1a85c97ad8..a7a509bb22 100644 --- a/test/interface/ad_tests.jl +++ b/test/interface/ad_tests.jl @@ -1,5 +1,5 @@ using Test -using OrdinaryDiffEq, Calculus, ForwardDiff, FiniteDiff, LinearAlgebra +using OrdinaryDiffEq, OrdinaryDiffEqCore, ForwardDiff, FiniteDiff, LinearAlgebra, ADTypes, DifferentiationInterface function f(du, u, p, t) du[1] = -p[1] @@ -21,7 +21,7 @@ for x in 0:0.001:5 end p = [2.0, x] called = false - findiff = Calculus.finite_difference_jacobian(test_f, p) + findiff = FiniteDiff.finite_difference_jacobian(test_f, p) @test called called = false fordiff = ForwardDiff.jacobian(test_f, p) @@ -48,7 +48,7 @@ for x in 2.1:0.001:5 solve!(integrator).u[end] end p = [2.0, x] - findiff = Calculus.finite_difference_jacobian(test_f2, p) + findiff = FiniteDiff.finite_difference_jacobian(test_f2, p) @test called called = false fordiff = ForwardDiff.jacobian(test_f2, p) @@ -70,7 +70,7 @@ function test_f2(p) end p = [2.0, x] -findiff = Calculus.finite_difference_jacobian(test_f2,p) +findiff = FiniteDiff.finite_difference_jacobian(test_f2,p) @test called called = false fordiff = ForwardDiff.jacobian(test_f2,p) @@ -106,7 +106,7 @@ for x in 1.0:0.001:2.5 solve!(integrator).u[end] end - findiff = Calculus.finite_difference_jacobian(test_lotka, p) + findiff = FiniteDiff.finite_difference_jacobian(test_lotka, p) @test called called = false fordiff = ForwardDiff.jacobian(test_lotka, p) @@ -205,7 +205,7 @@ of_a = p -> begin prob = ODEProblem(f_a, u0, tspan, p) # sol = solve(prob, Tsit5()) # works # sol = solve(prob, Rodas5(autodiff=false)) # works - sol = solve(prob, Rodas5(autodiff = true), abstol = 1e-14, reltol = 1e-14) # fails + sol = solve(prob, Rodas5(autodiff = AutoForwardDiff()), abstol = 1e-14, reltol = 1e-14) # fails return sum(t -> abs2(t[1]), sol([1.0, 2.0, 3.0])) end @@ -318,3 +318,39 @@ function f(x) end K_ = [-1.0 0.0; 1.0 -1.0] @test isapprox(ForwardDiff.jacobian(f, K_)[2], 0.00226999, atol = 1e-6) + +implicit_algs = [FBDF, + Rosenbrock23, + TRBDF2] + +@testset "deprecated AD keyword arguments still work with $alg" for alg in implicit_algs + f = (du, u, p, t) -> du .= -0.5 * u + alg1 = alg(autodiff = AutoForwardDiff()) + alg2 = alg(autodiff = true) + + alg3 = alg(autodiff = AutoFiniteDiff()) + alg4 = alg(autodiff = false) + + alg5 = alg(autodiff = AutoForwardDiff(chunksize = 5)) + alg6 = alg(autodiff = true, chunk_size = 5) + + alg7 = alg(autodiff = AutoFiniteDiff(fdtype = Val(:central))) + alg8 = alg(autodiff = false, diff_type = Val(:central)) + + alg9 = alg(autodiff = AutoForwardDiff(chunksize = 1)) + alg10 = alg(chunk_size = 1) + + @test OrdinaryDiffEqCore.alg_autodiff(alg1) == OrdinaryDiffEqCore.alg_autodiff(alg2) + @test OrdinaryDiffEqCore.alg_autodiff(alg3) == OrdinaryDiffEqCore.alg_autodiff(alg4) + @test OrdinaryDiffEqCore.alg_autodiff(alg5) == OrdinaryDiffEqCore.alg_autodiff(alg6) + @test OrdinaryDiffEqCore.alg_autodiff(alg7) == OrdinaryDiffEqCore.alg_autodiff(alg8) + @test OrdinaryDiffEqCore.alg_autodiff(alg9) == OrdinaryDiffEqCore.alg_autodiff(alg10) +end + +# https://github.com/SciML/OrdinaryDiffEq.jl/issues/2675 +x0 = [0.1] +DifferentiationInterface.gradient(AutoForwardDiff(), x0) do x + prob = ODEProblem{true}((du, u, p, t) -> (du[1] = -u[1]), x, (0.0, 1.0),) + sol = solve(prob, DefaultODEAlgorithm(), reltol = 1e-6) + sum(sol) +end ≈ [6.765310476296564] diff --git a/test/interface/algebraic_interpolation.jl b/test/interface/algebraic_interpolation.jl index 8e4a33b326..fdffe02761 100644 --- a/test/interface/algebraic_interpolation.jl +++ b/test/interface/algebraic_interpolation.jl @@ -35,10 +35,10 @@ sol_op = solve(prob_op, FBDF(), reltol = 1e-8, abstol = 1e-8) # make sure interpolation changes don't accidentally break this test suite # the intention is that ref uses a stiffness-aware interpolation, while sol uses hermite -@test DiffEqBase.interp_summary(sol_ip) == "3rd order Hermite" -@test DiffEqBase.interp_summary(sol_op) == "3rd order Hermite" -@test occursin("stiffness-aware", DiffEqBase.interp_summary(ref_ip)) -@test occursin("stiffness-aware", DiffEqBase.interp_summary(ref_op)) +@test SciMLBase.interp_summary(sol_ip) == "3rd order Hermite" +@test SciMLBase.interp_summary(sol_op) == "3rd order Hermite" +@test occursin("stiffness-aware", SciMLBase.interp_summary(ref_ip)) +@test occursin("stiffness-aware", SciMLBase.interp_summary(ref_op)) reltol = 1e-4 abstol = 1e-4 diff --git a/test/interface/aliasing_tests.jl b/test/interface/aliasing_tests.jl new file mode 100644 index 0000000000..83b26a26d8 --- /dev/null +++ b/test/interface/aliasing_tests.jl @@ -0,0 +1,10 @@ +using OrdinaryDiffEq, Test + +import ODEProblemLibrary: prob_ode_linear + +# Test that the old keyword works, and that the new AliasSpecier works. +u0_old_alias_kwarg_sol = solve(prob_ode_linear, Tsit5(), alias_u0 = true) +u0_new_alias_kwarg_sol = solve( + prob_ode_linear, Tsit5(), alias = ODEAliasSpecifier(alias_u0 = true)) + +@test u0_old_alias_kwarg_sol == u0_new_alias_kwarg_sol diff --git a/test/interface/autodiff_error_tests.jl b/test/interface/autodiff_error_tests.jl index 195c7bdab4..e3ffe24862 100644 --- a/test/interface/autodiff_error_tests.jl +++ b/test/interface/autodiff_error_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, Test +using OrdinaryDiffEq, Test, ADTypes using OrdinaryDiffEqDifferentiation const a = Float64[1.0] @@ -46,17 +46,16 @@ prob = ODEProblem(lorenz2!, u0, tspan) @test_throws OrdinaryDiffEqDifferentiation.FirstAutodiffTgradError solve( prob, Rosenbrock23()) -## Test that nothing is using duals when autodiff=false +## Test that nothing is using duals when autodiff=AutoFiniteDiff() ## https://discourse.julialang.org/t/rodas4-using-dual-number-for-time-with-autodiff-false/98256 for alg in [ - Rosenbrock23(autodiff = false), - Rodas4(autodiff = false), - Rodas5(autodiff = false), - QNDF(autodiff = false), - TRBDF2(autodiff = false), - KenCarp4(autodiff = false), - FBDF(autodiff = false) + Rosenbrock23(autodiff = AutoFiniteDiff()), + Rodas4(autodiff = AutoFiniteDiff()), + Rodas5(autodiff = AutoFiniteDiff()), + QNDF(autodiff = AutoFiniteDiff()), + TRBDF2(autodiff = AutoFiniteDiff()), + KenCarp4(autodiff = AutoFiniteDiff()) ] u = [0.0, 0.0] function f1(u, p, t) diff --git a/test/interface/autosparse_detection_tests.jl b/test/interface/autosparse_detection_tests.jl new file mode 100644 index 0000000000..1cadd52b3d --- /dev/null +++ b/test/interface/autosparse_detection_tests.jl @@ -0,0 +1,20 @@ +using Test, OrdinaryDiffEq, LinearSolve, ADTypes, ForwardDiff, SparseConnectivityTracer, + SparseMatrixColorings +import ODEProblemLibrary: prob_ode_2Dlinear + +ad = AutoSparse(AutoForwardDiff(), sparsity_detector = TracerSparsityDetector(), + coloring_algorithm = GreedyColoringAlgorithm()) + +prob = prob_ode_2Dlinear + +@test_nowarn solve(prob, Rodas5P(autodiff = ad)) + +@test_nowarn solve(prob, Rodas5P(autodiff = ad, linsolve = LinearSolve.KrylovJL_GMRES())) + +@test_nowarn solve(prob, FBDF(autodiff = ad)) + +# Test that no dense matrices are made sparse +diag_prob = ODEProblem((du, u, p, t) -> du .= -1.0 .* u, rand(Int(1e7)), (0, 1.0)) + +@test_nowarn solve(diag_prob, Rodas5P(autodiff = ad, linsolve = LinearSolve.KrylovJL_GMRES())) + diff --git a/test/interface/checkinit_tests.jl b/test/interface/checkinit_tests.jl index 8320449151..e71b412e2c 100644 --- a/test/interface/checkinit_tests.jl +++ b/test/interface/checkinit_tests.jl @@ -24,9 +24,9 @@ roberf_oop = ODEFunction{false}(rober, mass_matrix = M) prob_mm = ODEProblem(roberf, [1.0, 0.0, 0.2], (0.0, 1e5), (0.04, 3e7, 1e4)) prob_mm_oop = ODEProblem(roberf_oop, [1.0, 0.0, 0.2], (0.0, 1e5), (0.04, 3e7, 1e4)) -@test_throws OrdinaryDiffEqCore.CheckInitFailureError solve( +@test_throws SciMLBase.CheckInitFailureError solve( prob_mm, Rodas5P(), reltol = 1e-8, abstol = 1e-8, initializealg = SciMLBase.CheckInit()) -@test_throws OrdinaryDiffEqCore.CheckInitFailureError solve( +@test_throws SciMLBase.CheckInitFailureError solve( prob_mm_oop, Rodas5P(), reltol = 1e-8, abstol = 1e-8, initializealg = SciMLBase.CheckInit()) @@ -49,7 +49,7 @@ tspan = (0.0, 100000.0) differential_vars = [true, true, false] prob = DAEProblem(f, du₀, u₀, tspan, differential_vars = differential_vars) prob_oop = DAEProblem(f_oop, du₀, u₀, tspan, differential_vars = differential_vars) -@test_throws OrdinaryDiffEqCore.CheckInitFailureError solve( +@test_throws SciMLBase.CheckInitFailureError solve( prob, DFBDF(), reltol = 1e-8, abstol = 1e-8, initializealg = SciMLBase.CheckInit()) -@test_throws OrdinaryDiffEqCore.CheckInitFailureError solve( +@test_throws SciMLBase.CheckInitFailureError solve( prob_oop, DFBDF(), reltol = 1e-8, abstol = 1e-8, initializealg = SciMLBase.CheckInit()) diff --git a/test/interface/complex_tests.jl b/test/interface/complex_tests.jl index bf3a154d29..9d9092d71d 100644 --- a/test/interface/complex_tests.jl +++ b/test/interface/complex_tests.jl @@ -2,7 +2,7 @@ using Test using StaticArrays, LinearAlgebra -using OrdinaryDiffEq, DiffEqBase +using OrdinaryDiffEq, DiffEqBase, ADTypes H(t) = -im * (@SMatrix [t 1; 1 -t]) @@ -45,20 +45,20 @@ end @testset "Complex Tests on Implicit Finite Diff Methods. alg=$alg" for alg in implicit ψ0 = [1.0 + 0.0im; 0.0] prob = ODEProblem(fun_inplace, ψ0, (-T, T)) - sol = solve(prob, alg(autodiff = false)) + sol = solve(prob, alg(autodiff = AutoFiniteDiff())) @test norm(sol(T))≈1 atol=1e-2 end @testset "Complex Tests on Implicit Finite Diff Out-of-place Methods. alg=$alg" for alg in implicit ψ0 = [1.0 + 0.0im; 0.0] prob = ODEProblem(fun, ψ0, (-T, T)) - sol = solve(prob, alg(autodiff = false)) + sol = solve(prob, alg(autodiff = AutoFiniteDiff())) @test norm(sol(T))≈1 atol=1e-2 end @testset "Complex Tests on Implicit Finite Diff Out-of-place Methods SArray. alg=$alg" for alg in implicit ψ0 = @SArray [1.0 + 0.0im; 0.0] prob = ODEProblem(fun, ψ0, (-T, T)) - sol = solve(prob, alg(autodiff = false)) + sol = solve(prob, alg(autodiff = AutoFiniteDiff())) @test norm(sol(T))≈1 atol=1e-2 end diff --git a/test/interface/composite_algorithm_test.jl b/test/interface/composite_algorithm_test.jl index be3a496fcf..7123cb42cf 100644 --- a/test/interface/composite_algorithm_test.jl +++ b/test/interface/composite_algorithm_test.jl @@ -1,6 +1,6 @@ using OrdinaryDiffEq, OrdinaryDiffEqCore, Test, LinearAlgebra import ODEProblemLibrary: prob_ode_linear, prob_ode_2Dlinear -using DiffEqDevTools +using DiffEqDevTools, ADTypes prob = prob_ode_2Dlinear choice_function(integrator) = (Int(integrator.t < 0.5) + 1) @@ -27,7 +27,7 @@ solve!(integrator2) @test integrator1.sol.t == integrator2.sol.t sol = solve(prob, alg_switch) -@inferred DiffEqBase.__init(prob, alg_switch) +@inferred SciMLBase.__init(prob, alg_switch) v = @inferred OrdinaryDiffEqCore.ode_interpolant( 1.0, integrator1, integrator1.opts.save_idxs, Val{0}) @@ -47,11 +47,11 @@ v = @inferred OrdinaryDiffEqCore.ode_extrapolant( alg_mixed_r = CompositeAlgorithm((ABM54(), Tsit5()), reverse_choice) alg_mixed2 = CompositeAlgorithm((Tsit5(), ABM54()), reverse_choice) - @test_throws ErrorException solve(prob_ode_linear, alg_mixed) + @test_throws ArgumentError solve(prob_ode_linear, alg_mixed) sol2 = solve(prob_ode_linear, Tsit5()) - sol3 = solve(prob_ode_linear, alg_mixed; dt = 0.05) - sol4 = solve(prob_ode_linear, alg_mixed_r; dt = 0.05) - sol5 = solve(prob_ode_linear, alg_mixed2; dt = 0.05) + sol3 = solve(prob_ode_linear, alg_mixed; dt = 0.05, adaptive = false) + sol4 = solve(prob_ode_linear, alg_mixed_r; dt = 0.05, adaptive = false) + sol5 = solve(prob_ode_linear, alg_mixed2; dt = 0.05, adaptive = false) @test sol3.t == sol4.t && sol3.u == sol4.u @test sol3(0.8)≈sol2(0.8) atol=1e-4 @test sol5(0.8)≈sol2(0.8) atol=1e-4 @@ -78,7 +78,7 @@ sol = solve(prob, @test sol.t[end] == 1000.0 prob = remake(prob_ode_2Dlinear, u0 = rand(ComplexF64, 2, 2)) -sol = solve(prob, AutoTsit5(Rosenbrock23(autodiff = false))) # Complex and AD don't mix +sol = solve(prob, AutoTsit5(Rosenbrock23(autodiff = AutoFiniteDiff()))) # Complex and AD don't mix @test sol.retcode == ReturnCode.Success # https://github.com/SciML/ModelingToolkit.jl/issues/3043 diff --git a/test/interface/dae_initialization_tests.jl b/test/interface/dae_initialization_tests.jl index e00d8270e5..8e63d8caf6 100644 --- a/test/interface/dae_initialization_tests.jl +++ b/test/interface/dae_initialization_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, StaticArrays, LinearAlgebra, Test +using OrdinaryDiffEq, StaticArrays, LinearAlgebra, Test, ADTypes ## Mass Matrix @@ -15,7 +15,8 @@ M = [1.0 0 0 0 0 0] f_oop = ODEFunction(rober_oop, mass_matrix = M) prob_mm = ODEProblem(f_oop, [1.0, 0.0, 0.0], (0.0, 1e5), (0.04, 3e7, 1e4)) -sol = solve(prob_mm, Rosenbrock23(autodiff = false), reltol = 1e-8, abstol = 1e-8) +sol = solve( + prob_mm, Rosenbrock23(autodiff = AutoFiniteDiff()), reltol = 1e-8, abstol = 1e-8) @test sol[1] == [1.0, 0.0, 0.0] # Ensure initialization is unchanged if it works at the start! sol = solve(prob_mm, Rosenbrock23(), reltol = 1e-8, abstol = 1e-8, initializealg = ShampineCollocationInit()) @@ -25,7 +26,7 @@ prob_mm = ODEProblem(f_oop, [1.0, 0.0, 0.2], (0.0, 1e5), (0.04, 3e7, 1e4)) sol = solve(prob_mm, Rosenbrock23(), reltol = 1e-8, abstol = 1e-8) @test sum(sol[1]) ≈ 1 @test sol[1] ≈ [1.0, 0.0, 0.0] -for alg in [Rosenbrock23(autodiff = false), Trapezoid()] +for alg in [Rosenbrock23(autodiff = AutoFiniteDiff()), Trapezoid()] local sol sol = solve(prob_mm, alg, reltol = 1e-8, abstol = 1e-8, initializealg = ShampineCollocationInit()) @@ -45,7 +46,7 @@ M = [1.0 0 0 0 0 0] f = ODEFunction(rober, mass_matrix = M) prob_mm = ODEProblem(f, [1.0, 0.0, 0.0], (0.0, 1e5), (0.04, 3e7, 1e4)) -sol = solve(prob_mm, Rodas5(autodiff = false), reltol = 1e-8, abstol = 1e-8) +sol = solve(prob_mm, Rodas5(autodiff = AutoFiniteDiff()), reltol = 1e-8, abstol = 1e-8) @test sol[1] == [1.0, 0.0, 0.0] # Ensure initialization is unchanged if it works at the start! sol = solve(prob_mm, Rodas5(), reltol = 1e-8, abstol = 1e-8, initializealg = ShampineCollocationInit()) @@ -56,7 +57,7 @@ sol = solve(prob_mm, Rodas5(), reltol = 1e-8, abstol = 1e-8) @test sum(sol[1]) ≈ 1 @test sol[1] ≈ [1.0, 0.0, 0.0] -for alg in [Rodas5(autodiff = false), Trapezoid()] +for alg in [Rodas5(autodiff = AutoFiniteDiff()), Trapezoid()] local sol sol = solve(prob_mm, alg, reltol = 1e-8, abstol = 1e-8, initializealg = ShampineCollocationInit()) @@ -114,3 +115,30 @@ prob = ODEProblem(f, ones(3), (0.0, 1.0)) integrator = init(prob, Rodas5P(), initializealg = ShampineCollocationInit(1.0, BrokenNLSolve())) @test all(isequal(reinterpret(Float64, 0xDEADBEEFDEADBEEF)), integrator.u) + +@testset "`reinit!` reruns initialization" begin + initializeprob = NonlinearProblem(1.0, [0.0]) do u, p + return u^2 - p[1]^2 + end + initializeprobmap = function (nlsol) + return [nlsol.prob.p[1], nlsol.u] + end + update_initializeprob! = function (iprob, integ) + iprob.p[1] = integ.u[1] + end + initialization_data = SciMLBase.OverrideInitData( + initializeprob, update_initializeprob!, initializeprobmap, nothing) + fn = ODEFunction(; mass_matrix = [1 0; 0 0], initialization_data) do du, u, p, t + du[1] = u[1] + du[2] = u[1]^2 - u[2]^2 + end + prob = ODEProblem(fn, [2.0, 0.0], (0.0, 1.0)) + integ = init(prob, Rodas5P()) + @test integ.u≈[2.0, 2.0] atol=1e-8 + reinit!(integ) + @test integ.u≈[2.0, 2.0] atol=1e-8 + @test_nowarn step!(integ, 0.01, true) + reinit!(integ, reinit_dae = false) + @test integ.u ≈ [2.0, 0.0] + @test_warn ["dt", "forced below floating point epsilon"] step!(integ, 0.01, true) +end diff --git a/test/interface/differentiation_traits_tests.jl b/test/interface/differentiation_traits_tests.jl index d2c3c51d38..75742eb88e 100644 --- a/test/interface/differentiation_traits_tests.jl +++ b/test/interface/differentiation_traits_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, Test +using OrdinaryDiffEq, Test, ADTypes jac_called = Ref(false) tgrad_called = Ref(false) @@ -35,11 +35,11 @@ good_sol = solve(prob, Rosenbrock23()) prob2 = ODEProblem(Lotka, ones(2), (0.0, 10.0)) -sol = solve(prob2, Rosenbrock23(autodiff = true)) +sol = solve(prob2, Rosenbrock23(autodiff = AutoForwardDiff())) @test ≈(good_sol[:, end], sol[:, end], rtol = 1e-2) -sol = solve(prob2, Rosenbrock23(autodiff = true, chunk_size = 1)) +sol = solve(prob2, Rosenbrock23(autodiff = AutoForwardDiff(chunksize = 1))) @test ≈(good_sol[:, end], sol[:, end], rtol = 1e-2) -sol = solve(prob2, Rosenbrock23(autodiff = false)) +sol = solve(prob2, Rosenbrock23(autodiff = AutoFiniteDiff())) @test ≈(good_sol[:, end], sol[:, end], rtol = 1e-2) diff --git a/test/interface/enums.jl b/test/interface/enums.jl index 60b82afe18..f5996ec28a 100644 --- a/test/interface/enums.jl +++ b/test/interface/enums.jl @@ -1,4 +1,16 @@ -using OrdinaryDiffEq, PoissonRandom +using OrdinaryDiffEq, Random + +# Simple Poisson random number generator using Knuth's algorithm +function pois_rand(λ::Float64) + L = exp(-λ) + k = 0 + p = 1.0 + while p > L + k += 1 + p *= rand() + end + return k - 1 +end function rate_to_proportion(r::Float64, t::Float64) 1 - exp(-r * t) diff --git a/test/interface/export_tests.jl b/test/interface/export_tests.jl index 9d4659985c..d0797e1809 100644 --- a/test/interface/export_tests.jl +++ b/test/interface/export_tests.jl @@ -2,4 +2,4 @@ using DiffEqBase using OrdinaryDiffEq using Test -@test DiffEqBase.undefined_exports(OrdinaryDiffEq) == [] +@test SciMLBase.undefined_exports(OrdinaryDiffEq) == [] diff --git a/test/interface/gpu_autodiff_interface_tests.jl b/test/interface/gpu_autodiff_interface_tests.jl new file mode 100644 index 0000000000..aebface96f --- /dev/null +++ b/test/interface/gpu_autodiff_interface_tests.jl @@ -0,0 +1,22 @@ +using OrdinaryDiffEq, JLArrays, LinearAlgebra, Test, ADTypes + +@testset "GPU AutoDiff with JLArrays" begin + function f(u, p, t) + A = jl(-ones(3, 3)) + return A*u + end + function f!(du, u, p, t) + A = jl(-ones(3, 3)) + return mul!(du, A, u) + end + + u0 = jl([1.0; 0.0; 0.0]) + tspan = (0.0f0, 100.0f0) + prob = ODEProblem{false}(f, u0, tspan) + solve(prob, TRBDF2()) + solve(prob, Rodas5P()) + + prob2 = ODEProblem(f!, u0, tspan) + solve(prob, TRBDF2()) + solve(prob, Rodas5P()) +end \ No newline at end of file diff --git a/test/interface/inplace_interpolation.jl b/test/interface/inplace_interpolation.jl index 474ef15708..8003bac1b7 100644 --- a/test/interface/inplace_interpolation.jl +++ b/test/interface/inplace_interpolation.jl @@ -18,23 +18,23 @@ out_VMF = vecarrzero(ntt, size(prob_ode_2Dlinear.u0)) # Vector{Matrix{Float64} sol_ODE = solve(prob_ode_linear, alg; kwargs...) sol_ODE_2D = solve(prob_ode_2Dlinear, alg; kwargs...) - sol_ODE_interp = sol_ODE(tt) - sol_ODE_2D_interp = sol_ODE_2D(tt) + sol_ODE_interp = @inferred sol_ODE(tt) + sol_ODE_2D_interp = @inferred sol_ODE_2D(tt) @testset "1D" begin - @test_throws MethodError sol_ODE(out_VF, tt; idxs = 1:1) - @test sol_ODE(out_VF, tt) isa Vector{Float64} - @test sol_ODE(out_VVF_1, tt) isa Vector{Vector{Float64}} + @test_throws Union{MethodError, BoundsError} sol_ODE(out_VF, tt; idxs = 1:1) + @inferred Vector{Float64} sol_ODE(out_VF, tt) + @inferred Vector{Vector{Float64}} sol_ODE(out_VVF_1, tt) @test sol_ODE_interp.u ≈ out_VF end @testset "2D" begin - @test_throws MethodError sol_ODE_2D(out_VF, tt; idxs = 3:3) - @test sol_ODE_2D(out_VF, tt; idxs = 3) isa Vector{Float64} - @test sol_ODE_2D(out_VVF_1, tt; idxs = 3) isa Vector{Vector{Float64}} - @test sol_ODE_2D(out_VVF_1, tt; idxs = 3:3) isa Vector{Vector{Float64}} - @test sol_ODE_2D(out_VVF_2, tt; idxs = 2:3) isa Vector{Vector{Float64}} - @test sol_ODE_2D(out_VMF, tt) isa Vector{Matrix{Float64}} + @test_throws Union{MethodError, BoundsError} sol_ODE_2D(out_VF, tt; idxs = 3:3) + @inferred Vector{Float64} sol_ODE_2D(out_VF, tt; idxs = 3) + @inferred Vector{Vector{Float64}} sol_ODE_2D(out_VVF_1, tt; idxs = 3) + @inferred Vector{Vector{Float64}} sol_ODE_2D(out_VVF_1, tt; idxs = 3:3) + @inferred Vector{Vector{Float64}} sol_ODE_2D(out_VVF_2, tt; idxs = 2:3) + @inferred Vector{Matrix{Float64}} sol_ODE_2D(out_VMF, tt) @test sol_ODE_2D_interp.u ≈ out_VMF end end diff --git a/test/interface/linear_nonlinear_tests.jl b/test/interface/linear_nonlinear_tests.jl index b948996346..6930d59b4c 100644 --- a/test/interface/linear_nonlinear_tests.jl +++ b/test/interface/linear_nonlinear_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, Test, Random, LinearAlgebra, LinearSolve +using OrdinaryDiffEq, Test, Random, LinearAlgebra, LinearSolve, ADTypes Random.seed!(123) A = 0.01 * rand(3, 3) @@ -35,70 +35,71 @@ function precslr(W, du, u, p, t, newW, Plprev, Prprev, solverdata) Pr, Pr end -sol = @test_nowarn solve(prob, TRBDF2(autodiff = false)); +sol = @test_nowarn solve(prob, TRBDF2(autodiff = AutoFiniteDiff())); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES())); + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES())); @test length(sol.t) < 20 solref = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), smooth_est = false)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precsl, smooth_est = false, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precsr, smooth_est = false, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precslr, smooth_est = false, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - QNDF(autodiff = false, linsolve = KrylovJL_GMRES(), + QNDF(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), concrete_jac = true)); @test length(sol.t) < 25 sol = @test_nowarn solve(prob, - Rosenbrock23(autodiff = false, + Rosenbrock23(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precslr, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - Rodas4(autodiff = false, linsolve = KrylovJL_GMRES(), + Rodas4(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precslr, concrete_jac = true)); @test length(sol.t) < 20 -sol = @test_nowarn solve(prob, TRBDF2(autodiff = false)); +sol = @test_nowarn solve(prob, TRBDF2(autodiff = AutoFiniteDiff())); @test length(sol.t) < 20 -sol = @test_nowarn solve(prob, TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES())); +sol = @test_nowarn solve( + prob, TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES())); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), smooth_est = false)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precsl, smooth_est = false, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precsr, smooth_est = false, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - TRBDF2(autodiff = false, linsolve = KrylovJL_GMRES(), + TRBDF2(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precslr, smooth_est = false, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - QNDF(autodiff = false, linsolve = KrylovJL_GMRES(), + QNDF(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), concrete_jac = true)); @test length(sol.t) < 25 sol = @test_nowarn solve(prob, - Rosenbrock23(autodiff = false, linsolve = KrylovJL_GMRES(), + Rosenbrock23(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precslr, concrete_jac = true)); @test length(sol.t) < 20 sol = @test_nowarn solve(prob, - Rodas4(autodiff = false, linsolve = KrylovJL_GMRES(), + Rodas4(autodiff = AutoFiniteDiff(), linsolve = KrylovJL_GMRES(), precs = precslr, concrete_jac = true)); @test length(sol.t) < 20 diff --git a/test/interface/linear_solver_split_ode_test.jl b/test/interface/linear_solver_split_ode_test.jl index a959976899..ebc30f5b62 100644 --- a/test/interface/linear_solver_split_ode_test.jl +++ b/test/interface/linear_solver_split_ode_test.jl @@ -26,8 +26,8 @@ for algname in (:SBDF2, kwargs = (dt = dt,) solve(prob, alg0; kwargs...) - @test DiffEqBase.__solve(prob, alg0; kwargs...).retcode == ReturnCode.Success - @test DiffEqBase.__solve(prob, alg1; kwargs...).retcode == ReturnCode.Success + @test SciMLBase.__solve(prob, alg0; kwargs...).retcode == ReturnCode.Success + @test SciMLBase.__solve(prob, alg1; kwargs...).retcode == ReturnCode.Success end end @@ -44,7 +44,7 @@ for algname in (:SBDF2, kwargs = (dt = dt,) solve(prob, alg0; kwargs...) - @test DiffEqBase.__solve(prob, alg0; kwargs...).retcode == ReturnCode.Success + @test SciMLBase.__solve(prob, alg0; kwargs...).retcode == ReturnCode.Success end end diff --git a/test/interface/linear_solver_test.jl b/test/interface/linear_solver_test.jl index a615deb515..8ab92d1550 100644 --- a/test/interface/linear_solver_test.jl +++ b/test/interface/linear_solver_test.jl @@ -31,7 +31,7 @@ odef = ODEFunction(foop; jac = jac, jac_prototype = jac(u0, p, 0.0), paramjac = function g_helper(p; alg = Rosenbrock23(linsolve = LUFactorization())) prob = ODEProblem(odef, u0, tspan, p) soln = Array(solve(prob, alg; u0 = prob.u0, p = prob.p, abstol = 1e-4, reltol = 1e-4))[ - :, end] + :, end] return soln end function g(p; kwargs...) @@ -104,7 +104,7 @@ odef = ODEFunction{true}(fiip; jac = jac, jac_prototype = jac(u0, p, 0.0), function g_helper(p; alg = Rosenbrock23(linsolve = LUFactorization())) prob = ODEProblem(odef, u0, tspan, p) soln = Array(solve(prob, alg; u0 = prob.u0, p = prob.p, abstol = 1e-4, reltol = 1e-4))[ - :, end] + :, end] return soln end function g(p; kwargs...) @@ -158,27 +158,50 @@ end @test isapprox(exp.(p), g_helper(p; alg = KenCarp47(linsolve = KrylovJL_GMRES())); atol = 1e-1, rtol = 1e-1) -using OrdinaryDiffEq, StaticArrays, LinearSolve, ParameterizedFunctions +using OrdinaryDiffEq, StaticArrays, LinearSolve + +# In-place version +function hires!(du, u, p, t) + T = eltype(u) + du[1] = T(-1.71) * u[1] + T(0.43) * u[2] + T(8.32) * u[3] + T(0.0007) + T(1.0e-18) * t + du[2] = T(1.71) * u[1] - T(8.75) * u[2] + du[3] = T(-10.03) * u[3] + T(0.43) * u[4] + T(0.035) * u[5] + du[4] = T(8.32) * u[2] + T(1.71) * u[3] - T(1.12) * u[4] + du[5] = T(-1.745) * u[5] + T(0.43) * u[6] + T(0.43) * u[7] + du[6] = T(-280.0) * u[6] * u[8] + T(0.69) * u[4] + T(1.71) * u[5] - T(0.43) * u[6] + + T(0.69) * u[7] + du[7] = T(280.0) * u[6] * u[8] - T(1.81) * u[7] + du[8] = T(-280.0) * u[6] * u[8] + T(1.81) * u[7] +end -hires = @ode_def Hires begin - dy1 = -1.71f0 * y1 + 0.43f0 * y2 + 8.32f0 * y3 + 0.0007f0 + 1.0f-18 * t - dy2 = 1.71f0 * y1 - 8.75f0 * y2 - dy3 = -10.03f0 * y3 + 0.43f0 * y4 + 0.035f0 * y5 - dy4 = 8.32f0 * y2 + 1.71f0 * y3 - 1.12f0 * y4 - dy5 = -1.745f0 * y5 + 0.43f0 * y6 + 0.43f0 * y7 - dy6 = -280.0f0 * y6 * y8 + 0.69f0 * y4 + 1.71f0 * y5 - 0.43f0 * y6 + 0.69f0 * y7 - dy7 = 280.0f0 * y6 * y8 - 1.81f0 * y7 - dy8 = -280.0f0 * y6 * y8 + 1.81f0 * y7 +# Out-of-place version +function hires(u, p, t) + T = eltype(u) + du1 = T(-1.71) * u[1] + T(0.43) * u[2] + T(8.32) * u[3] + T(0.0007) + T(1.0e-18) * t + du2 = T(1.71) * u[1] - T(8.75) * u[2] + du3 = T(-10.03) * u[3] + T(0.43) * u[4] + T(0.035) * u[5] + du4 = T(8.32) * u[2] + T(1.71) * u[3] - T(1.12) * u[4] + du5 = T(-1.745) * u[5] + T(0.43) * u[6] + T(0.43) * u[7] + du6 = T(-280.0) * u[6] * u[8] + T(0.69) * u[4] + T(1.71) * u[5] - T(0.43) * u[6] + + T(0.69) * u[7] + du7 = T(280.0) * u[6] * u[8] - T(1.81) * u[7] + du8 = T(-280.0) * u[6] * u[8] + T(1.81) * u[7] + + if u isa SVector + return SVector(du1, du2, du3, du4, du5, du6, du7, du8) + else + return [du1, du2, du3, du4, du5, du6, du7, du8] + end end u0 = zeros(8) u0[1] = 1 u0[8] = 0.0057 -probiip = ODEProblem{true}(hires, u0, (0.0, 10.0)) +probiip = ODEProblem{true}(hires!, u0, (0.0, 10.0)) proboop = ODEProblem{false}(hires, u0, (0.0, 10.0)) probstatic = ODEProblem{false}(hires, SVector{8}(u0), (0.0, 10.0)) -probiipf32 = ODEProblem{true}(hires, Float32.(u0), (0.0f0, 10.0f0)) +probiipf32 = ODEProblem{true}(hires!, Float32.(u0), (0.0f0, 10.0f0)) proboopf32 = ODEProblem{false}(hires, Float32.(u0), (0.0f0, 10.0f0)) probstaticf32 = ODEProblem{false}(hires, SVector{8}(Float32.(u0)), (0.0f0, 10.0f0)) probs = (; probiip, proboop, probstatic) diff --git a/test/interface/mass_matrix_tests.jl b/test/interface/mass_matrix_tests.jl index 065ab6988d..82816682e9 100644 --- a/test/interface/mass_matrix_tests.jl +++ b/test/interface/mass_matrix_tests.jl @@ -1,6 +1,8 @@ using OrdinaryDiffEq, Test, LinearAlgebra, Statistics using OrdinaryDiffEqCore using OrdinaryDiffEqNonlinearSolve: NLFunctional, NLAnderson, NLNewton +using LinearAlgebra: Diagonal +using ADTypes: AutoForwardDiff # create mass matrix problems function make_mm_probs(mm_A, ::Val{iip}) where {iip} @@ -194,11 +196,10 @@ end u0 = [0.0, 1.0] tspan = (0.0, 1.0) - M = fill(0.0, 2, 2) - M[1, 1] = 1.0 + M = Diagonal([1.0, 0.0]) m_ode_prob = ODEProblem(ODEFunction(f!; mass_matrix = M), u0, tspan) - @test_nowarn sol = solve(m_ode_prob, Rosenbrock23()) + @test_nowarn sol = @inferred solve(m_ode_prob, Rosenbrock23(autodiff=AutoForwardDiff(chunksize=2))) M = [0.637947 0.637947 0.637947 0.637947] @@ -247,7 +248,7 @@ end function _norm_dsol2(alg, prob, prob2; kwargs...) sol = solve(prob, alg; kwargs...) sol2 = solve(prob2, alg; kwargs...) - norm(sol[end] .- sol2[end]) + norm(sol.u[end] .- sol2.u[end]) end @testset "Dependent Mass Matrix Tests" for mm in (dependent_M1, dependent_M2) # test each method for exactness @@ -323,14 +324,15 @@ function dynamics(u, p, t) end x0 = zeros(n, n) -M = zeros(n * n) |> Diagonal |> Matrix +M = zeros(n * n) |> Diagonal M[1, 1] = true # zero mass matrix breaks rosenbrock -f = ODEFunction(dynamics!, mass_matrix = M) +f = ODEFunction{true, SciMLBase.AutoSpecialize}(dynamics!, mass_matrix = M) tspan = (0, 10.0) +adalg = AutoForwardDiff(chunksize=n) prob = ODEProblem(f, x0, tspan) -foop = ODEFunction(dynamics, mass_matrix = M) +foop = ODEFunction{false, SciMLBase.AutoSpecialize}(dynamics, mass_matrix = M) proboop = ODEProblem(f, x0, tspan) -sol = solve(prob, Rosenbrock23()) -sol = solve(prob, Rodas4(), initializealg = ShampineCollocationInit()) -sol = solve(proboop, Rodas5()) -sol = solve(proboop, Rodas4(), initializealg = ShampineCollocationInit()) +@test_broken sol = @inferred solve(prob, Rosenbrock23(autodiff=adalg)) +@test_broken sol = @inferred solve(prob, Rodas4(autodiff=adalg), initializealg = ShampineCollocationInit()) +@test_broken sol = @inferred solve(proboop, Rodas5()) +@test_broken sol = @inferred solve(proboop, Rodas4(), initializealg = ShampineCollocationInit()) diff --git a/test/interface/nojac.jl b/test/interface/nojac.jl index 9a252ddfea..50644be664 100644 --- a/test/interface/nojac.jl +++ b/test/interface/nojac.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, LinearSolve, Test +using OrdinaryDiffEq, RecursiveFactorization, LinearSolve, Test, ADTypes const N = 32 const xyd_brusselator = range(0, stop = 1, length = N) @@ -48,8 +48,8 @@ nojac = @allocated init(prob_ode_brusselator_2d, save_everystep = false) jac = @allocated init(prob_ode_brusselator_2d, TRBDF2(), save_everystep = false) @test jac / nojac > 50 -@test integ1.cache.nlsolver.cache.jac_config !== nothing -@test integ2.cache.nlsolver.cache.jac_config === nothing +@test integ1.cache.nlsolver.cache.jac_config !== (nothing, nothing) +@test integ2.cache.nlsolver.cache.jac_config === (nothing, nothing) ## Test that no Jac Config is created @@ -246,13 +246,14 @@ u0[17] = 0.007 prob = ODEProblem(ODEFunction(pollu, jac = fjac), u0, (0.0, 60.0)) integ = init(prob, Rosenbrock23(), abstol = 1e-6, reltol = 1e-6) -@test integ.cache.jac_config === nothing +@test integ.cache.jac_config === (nothing, nothing) integ = init(prob, Rosenbrock23(linsolve = SimpleLUFactorization()), abstol = 1e-6, reltol = 1e-6) -@test integ.cache.jac_config === nothing +@test integ.cache.jac_config === (nothing, nothing) integ = init(prob, Rosenbrock23(linsolve = GenericLUFactorization()), abstol = 1e-6, reltol = 1e-6) -@test integ.cache.jac_config === nothing -integ = init(prob, Rosenbrock23(linsolve = RFLUFactorization(), chunk_size = Val{3}()), +@test integ.cache.jac_config === (nothing, nothing) +integ = init(prob, + Rosenbrock23(linsolve = RFLUFactorization(), autodiff = AutoForwardDiff(chunksize = 3)), abstol = 1e-6, reltol = 1e-6) -@test integ.cache.jac_config === nothing +@test integ.cache.jac_config === (nothing, nothing) diff --git a/test/interface/nonfulldiagonal_sparse.jl b/test/interface/nonfulldiagonal_sparse.jl index b0abb28f8d..72cec1349c 100644 --- a/test/interface/nonfulldiagonal_sparse.jl +++ b/test/interface/nonfulldiagonal_sparse.jl @@ -1,7 +1,6 @@ using OrdinaryDiffEq, SparseArrays, LinearSolve, LinearAlgebra using SimpleUnPack using ComponentArrays -using Symbolics function enclosethetimedifferential(parameters::NamedTuple)::Function @info "Enclosing the time differential" @@ -124,9 +123,12 @@ odeprob = ODEProblem(dudt, (0, 2.1), parameters.prior); du0 = copy(odeprob.u0); -jac_sparsity = Symbolics.jacobian_sparsity((du, u) -> dudt(du, u, parameters.prior, 0.0), - du0, - odeprob.u0); +# Hardcoded sparsity pattern for 15 spatial points + 3 state variables (18x18 matrix) +# Previously computed using: Symbolics.jacobian_sparsity((du, u) -> dudt(du, u, parameters.prior, 0.0), du0, odeprob.u0) +# This avoids the dependency on Symbolics in tests +I = [1, 2, 16, 18, 1, 2, 3, 18, 2, 3, 4, 18, 3, 4, 5, 18, 4, 5, 6, 18, 5, 6, 7, 18, 6, 7, 8, 18, 7, 8, 9, 18, 8, 9, 10, 18, 9, 10, 11, 18, 10, 11, 12, 18, 11, 12, 13, 18, 12, 13, 14, 18, 13, 14, 15, 18, 14, 15, 17, 18, 1, 16, 17, 15, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18] +J = [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18] +jac_sparsity = sparse(I, J, ones(Bool, length(I)), 18, 18); f = ODEFunction(dudt; jac_prototype = float.(jac_sparsity)); sparseodeprob = ODEProblem(f, diff --git a/test/interface/norecompile.jl b/test/interface/norecompile.jl index 4eee7b9e6e..30337d5316 100644 --- a/test/interface/norecompile.jl +++ b/test/interface/norecompile.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, Test +using OrdinaryDiffEq, Test, ADTypes function f(du, u, p, t) du[1] = 0.2u[1] du[2] = 0.4u[2] @@ -15,25 +15,23 @@ end lorenzprob = ODEProblem(lorenz, [1.0; 0.0; 0.0], (0.0, 1.0), Float64[]) t1 = @elapsed sol1 = solve(lorenzprob, Rosenbrock23()) -t2 = @elapsed sol2 = solve(lorenzprob, Rosenbrock23(autodiff = false)) +t2 = @elapsed sol2 = solve(lorenzprob, Rosenbrock23(autodiff = AutoFiniteDiff())) lorenzprob2 = ODEProblem{true, SciMLBase.FullSpecialize}(lorenz, [1.0; 0.0; 0.0], (0.0, 1.0), Float64[]) t3 = @elapsed sol3 = solve(lorenzprob2, Rosenbrock23()) -t4 = @elapsed sol4 = solve(lorenzprob2, Rosenbrock23(autodiff = false)) +t4 = @elapsed sol4 = solve(lorenzprob2, Rosenbrock23(autodiff = AutoFiniteDiff())) @test sol1.retcode === ReturnCode.Success @test sol2.retcode === ReturnCode.Success @test sol3.retcode === ReturnCode.Success @test sol4.retcode === ReturnCode.Success -if VERSION >= v"1.8" - @test t1 < t3 - @test t2 < t4 - integ = init(lorenzprob, Rosenbrock23()) - @test integ.f.f isa FunctionWrappersWrappers.FunctionWrappersWrapper -end +@test t1 < t3 +@test t2 < t4 +integ = init(lorenzprob, Rosenbrock23()) +@test integ.f.f isa FunctionWrappersWrappers.FunctionWrappersWrapper solve(prob, EPIRK4s3A(), dt = 1e-1) @@ -56,12 +54,12 @@ lorenzprob = ODEProblem(lorenz_oop, [1.0; 0.0; 0.0], (0.0, 1.0), Float64[]) # This is problem-dependent, so it is hard to deduce a priori @test_broken t1 = @elapsed sol = solve(lorenzprob, Rosenbrock23()) -t2 = @elapsed sol = solve(lorenzprob, Rosenbrock23(autodiff = false)) +t2 = @elapsed sol = solve(lorenzprob, Rosenbrock23(autodiff = AutoFiniteDiff())) lorenzprob2 = ODEProblem{false, SciMLBase.FullSpecialize}(lorenz_oop, [1.0; 0.0; 0.0], (0.0, 1.0), Float64[]) t3 = @elapsed sol = solve(lorenzprob2, Rosenbrock23()) -t4 = @elapsed sol = solve(lorenzprob2, Rosenbrock23(autodiff = false)) +t4 = @elapsed sol = solve(lorenzprob2, Rosenbrock23(autodiff = AutoFiniteDiff())) #@test 5t1 < t3 #@test t2 < t4 diff --git a/test/interface/ode_initdt_tests.jl b/test/interface/ode_initdt_tests.jl index 3e8b7c85e9..2bee803e1e 100644 --- a/test/interface/ode_initdt_tests.jl +++ b/test/interface/ode_initdt_tests.jl @@ -10,7 +10,7 @@ sol = solve(prob, ExplicitRK(tableau = constructBogakiShampine3())) dt₀ = sol.t[2] @test 1e-7 < dt₀ < 0.1 -@test_throws ErrorException local sol = solve(prob, Euler()) +@test_throws ArgumentError local sol = solve(prob, Euler()) #dt₀ = sol.t[2] sol3 = solve(prob, ExplicitRK(tableau = constructDormandPrince8_64bit())) @@ -64,3 +64,9 @@ sol = solve(prob, Rodas5()) # test that dtmin is set based on timespan prob = ODEProblem((u, p, t) -> 1e20 * sin(1e20 * t), 0.1, (0, 1e-19)) @test solve(prob, Tsit5()).retcode == ReturnCode.Success + +#test that we are robust to u0=0, t0!=0 +integ = init(ODEProblem(((u, p, t) -> u), 0.0f0, (20.0f0, 0.0f0)), Tsit5()) +@test abs(integ.dt) > eps(integ.t) +integ = init(ODEProblem(((du, u, p, t) -> du .= u), [0.0f0], (20.0f0, 0.0f0)), Tsit5()) +@test abs(integ.dt) > eps(integ.t) diff --git a/test/interface/ode_strip_test.jl b/test/interface/ode_strip_test.jl index ad5a794bd8..697332da2d 100644 --- a/test/interface/ode_strip_test.jl +++ b/test/interface/ode_strip_test.jl @@ -14,7 +14,7 @@ prob = ODEProblem(lorenz!, u0, tspan) rosenbrock_sol = solve(prob, Rosenbrock23()) TRBDF_sol = solve(prob, TRBDF2()) vern_sol = solve(prob, Vern7()) - +default_sol = solve(prob) @testset "Interpolation Stripping" begin @test isnothing(SciMLBase.strip_interpolation(rosenbrock_sol.interp).f) @test isnothing(SciMLBase.strip_interpolation(rosenbrock_sol.interp).cache.jac_config) @@ -22,20 +22,27 @@ vern_sol = solve(prob, Vern7()) end @testset "Rosenbrock Solution Stripping" begin - @test SciMLBase.strip_solution(rosenbrock_sol).prob isa NamedTuple + stripped_sol = SciMLBase.strip_solution(rosenbrock_sol) + @test stripped_sol.prob isa NamedTuple @test isnothing(SciMLBase.strip_solution(rosenbrock_sol, strip_alg = true).alg) - @test isnothing(SciMLBase.strip_solution(rosenbrock_sol).interp.f) - @test isnothing(SciMLBase.strip_solution(rosenbrock_sol).interp.cache.jac_config) - @test isnothing(SciMLBase.strip_solution(rosenbrock_sol).interp.cache.grad_config) - @test isnothing(SciMLBase.strip_solution(rosenbrock_sol).interp.cache.uf) - @test isnothing(SciMLBase.strip_solution(rosenbrock_sol).interp.cache.tf) + @test isnothing(stripped_sol.interp.f) + @test isnothing(stripped_sol.interp.cache.jac_config) + @test isnothing(stripped_sol.interp.cache.grad_config) + @test isnothing(stripped_sol.interp.cache.uf) + @test isnothing(stripped_sol.interp.cache.tf) end @testset "TRBDF Solution Stripping" begin - @test SciMLBase.strip_solution(TRBDF_sol).prob isa NamedTuple + stripped_sol = SciMLBase.strip_solution(TRBDF_sol) + @test stripped_sol.prob isa NamedTuple @test isnothing(SciMLBase.strip_solution(TRBDF_sol, strip_alg = true).alg) - @test isnothing(SciMLBase.strip_solution(TRBDF_sol).interp.f) - @test isnothing(SciMLBase.strip_solution(TRBDF_sol).interp.cache.nlsolver) + @test isnothing(stripped_sol.interp.f) + @test isnothing(stripped_sol.interp.cache.nlsolver) +end + +@testset "Default Solution Stripping" begin + stripped_sol = SciMLBase.strip_solution(default_sol) + @test isnothing(stripped_sol.interp.cache.args) end @test_throws SciMLBase.LazyInterpolationException SciMLBase.strip_solution(vern_sol) diff --git a/test/interface/ode_tstops_tests.jl b/test/interface/ode_tstops_tests.jl index ce85f0e859..a911ecfe8a 100644 --- a/test/interface/ode_tstops_tests.jl +++ b/test/interface/ode_tstops_tests.jl @@ -76,3 +76,15 @@ end prob = ODEProblem(ff, [0.0], (0.0f0, 1.0f0)) sol = solve(prob, Tsit5(), tstops = [tval], callback = cb) end + +@testset "Late binding tstops" begin + function rhs(u, p, t) + u * p + t + end + prob = ODEProblem(rhs, 1.0, (0.0, 1.0), 0.1; tstops = (p, tspan) -> tspan[1]:p:tspan[2]) + sol = solve(prob, Tsit5()) + @test 0.0:0.1:1.0 ⊆ sol.t + prob2 = remake(prob; p = 0.07) + sol2 = solve(prob2, Tsit5()) + @test 0.0:0.07:1.0 ⊆ sol2.t +end diff --git a/test/interface/precision_mixing.jl b/test/interface/precision_mixing.jl new file mode 100644 index 0000000000..727025c3e0 --- /dev/null +++ b/test/interface/precision_mixing.jl @@ -0,0 +1,21 @@ +using OrdinaryDiffEq +function ODE(du, u, t, R, K) + du .= u +end +params = BigFloat[1.0 0.91758707304098; 1.48439909482661 1.0] +u0 = BigFloat[0.1, 0.1] +tspan = (1.0, 31.0) +R = BigFloat[0.443280390004304303, 1.172917082211452] +K = BigFloat[13.470600276901400604, 12.52980757005] +ODE_ = (du, u, params, t) -> ODE(du, u, t, R, K) +odeProblem = ODEProblem(ODE_, u0, tspan, params) +for alg in [AutoVern8(Rodas5(), nonstifftol = 11 / 10) + FBDF() + QNDF() + Tsit5() + Rodas5P() + TRBDF2() + KenCarp4() + RadauIIA5()] + Solution = solve(odeProblem, alg, saveat = 1, abstol = 1.e-12, reltol = 1.e-6) +end diff --git a/test/interface/scalar_handling_tests.jl b/test/interface/scalar_handling_tests.jl index f7103a5d9a..c9d20773a0 100644 --- a/test/interface/scalar_handling_tests.jl +++ b/test/interface/scalar_handling_tests.jl @@ -1,4 +1,5 @@ -using OrdinaryDiffEq +using OrdinaryDiffEq, ADTypes # https://github.com/JuliaDiffEq/DifferentialEquations.jl/issues/390 -solve(ODEProblem((x, p, t) -> -x, 1.0, (0.0, 50.0)), Rosenbrock23(autodiff = false)) +solve(ODEProblem((x, p, t) -> -x, 1.0, (0.0, 50.0)), + Rosenbrock23(autodiff = AutoFiniteDiff())) diff --git a/test/interface/sized_matrix_tests.jl b/test/interface/sized_matrix_tests.jl index 79ba7b6e73..11d289bc76 100644 --- a/test/interface/sized_matrix_tests.jl +++ b/test/interface/sized_matrix_tests.jl @@ -14,23 +14,21 @@ p_giesekus = [η0, τ, α] prob_giesekus = ODEProblem(dudt!, σ0, (0.0, 2.0), p_giesekus) -if VERSION >= v"1.9" - solve_giesekus = solve(prob_giesekus, Rodas4(), saveat = 0.2, abstol = 1e-14, - reltol = 1e-14) - for alg in [ - Rosenbrock23(), - Rodas4(), - Rodas4P(), - Rodas5(), - Rodas5P(), - Tsit5(), - Vern6(), - Vern7(), - Vern8(), - Vern9(), - DP5() - ] - sol = solve(prob_giesekus, alg, saveat = 0.2, abstol = 1e-14, reltol = 1e-14) - @test Array(sol) ≈ Array(solve_giesekus) - end +solve_giesekus = solve(prob_giesekus, Rodas4(), saveat = 0.2, abstol = 1e-14, + reltol = 1e-14) +for alg in [ + Rosenbrock23(), + Rodas4(), + Rodas4P(), + Rodas5(), + Rodas5P(), + Tsit5(), + Vern6(), + Vern7(), + Vern8(), + Vern9(), + DP5() +] + sol = solve(prob_giesekus, alg, saveat = 0.2, abstol = 1e-14, reltol = 1e-14) + @test Array(sol) ≈ Array(solve_giesekus) end diff --git a/test/interface/static_array_tests.jl b/test/interface/static_array_tests.jl index 5849de74bd..c4ba0d8fdf 100644 --- a/test/interface/static_array_tests.jl +++ b/test/interface/static_array_tests.jl @@ -1,6 +1,6 @@ using StaticArrays, Test using OrdinaryDiffEq, OrdinaryDiffEqCore, OrdinaryDiffEqNonlinearSolve -using RecursiveArrayTools +using RecursiveArrayTools, ADTypes u0 = VectorOfArray([fill(2, MVector{2, Float64}), ones(MVector{2, Float64})]) g0(u, p, t) = SA[u[1] + u[2], u[1]] @@ -58,7 +58,7 @@ end u0 = @SVector [1.0, 0.0, 0.0] tspan = (0.0, 100.0) prob = ODEProblem(lorenz_static, u0, tspan) -solve(prob, dt = 0.1, Rosenbrock23(autodiff = false)) +solve(prob, dt = 0.1, Rosenbrock23(autodiff = AutoFiniteDiff())) # Check that ArrayPartitions of static vectors work #https://github.com/SciML/OrdinaryDiffEq.jl/issues/1308 @@ -94,8 +94,10 @@ function rober(u, p, t) end prob = ODEProblem{false}(rober, SA[1.0, 0.0, 0.0], (0.0, 1e5), SA[0.04, 3e7, 1e4]) # Defaults to reltol=1e-3, abstol=1e-6 -@test_nowarn sol = solve(prob, Rosenbrock23(chunk_size = Val{3}()), save_everystep = false) -@test_nowarn sol = solve(prob, Rodas4(chunk_size = Val{3}()), save_everystep = false) +@test_nowarn sol = solve( + prob, Rosenbrock23(autodiff = AutoForwardDiff(chunksize = 3)), save_everystep = false) +@test_nowarn sol = solve( + prob, Rodas4(autodiff = AutoForwardDiff(chunksize = 3)), save_everystep = false) function hires_4(u, p, t) y1, y2, y3, y4 = u @@ -109,8 +111,10 @@ end u0 = SA[1, 0, 0, 0.0057] prob = ODEProblem(hires_4, u0, (0.0, 321.8122)) # Defaults to reltol=1e-3, abstol=1e-6 -@test_nowarn sol = solve(prob, Rosenbrock23(chunk_size = Val{4}()), save_everystep = false) -@test_nowarn sol = solve(prob, Rodas5(chunk_size = Val{4}()), save_everystep = false) +@test_nowarn sol = solve( + prob, Rosenbrock23(autodiff = AutoForwardDiff(chunksize = 4)), save_everystep = false) +@test_nowarn sol = solve( + prob, Rodas5(autodiff = AutoForwardDiff(chunksize = 4)), save_everystep = false) function hires_5(u, p, t) y1, y2, y3, y4, y5 = u @@ -125,8 +129,10 @@ end u0 = SA[1, 0, 0, 0, 0.0057] prob = ODEProblem(hires_5, u0, (0.0, 321.8122)) # Defaults to reltol=1e-3, abstol=1e-6 -@test_nowarn sol = solve(prob, Rosenbrock23(chunk_size = Val{5}()), save_everystep = false) -@test_nowarn sol = solve(prob, Rodas4(chunk_size = Val{5}()), save_everystep = false) +@test_nowarn sol = solve( + prob, Rosenbrock23(autodiff = AutoForwardDiff(chunksize = 5)), save_everystep = false) +@test_nowarn sol = solve( + prob, Rodas4(autodiff = AutoForwardDiff(chunksize = 5)), save_everystep = false) function hires(u, p, t) y1, y2, y3, y4, y5, y6, y7, y8 = u @@ -145,8 +151,10 @@ end u0 = SA[1, 0, 0, 0, 0, 0, 0, 0.0057] prob = ODEProblem(hires, u0, (0.0, 321.8122)) # Defaults to reltol=1e-3, abstol=1e-6 -@test_nowarn sol = solve(prob, Rosenbrock23(chunk_size = Val{8}()), save_everystep = false) -@test_nowarn sol = solve(prob, Rodas5(chunk_size = Val{8}()), save_everystep = false) +@test_nowarn sol = solve( + prob, Rosenbrock23(autodiff = AutoForwardDiff(chunksize = 8)), save_everystep = false) +@test_nowarn sol = solve( + prob, Rodas5(autodiff = AutoForwardDiff(chunksize = 8)), save_everystep = false) const k1 = 0.35e0 const k2 = 0.266e2 @@ -235,8 +243,10 @@ u0[9] = 0.01 u0[17] = 0.007 u0 = SA[u0...] prob = ODEProblem(pollu, u0, (0.0, 60.0)) -@test_nowarn sol = solve(prob, Rosenbrock23(chunk_size = Val{8}()), save_everystep = false) -@test_nowarn sol = solve(prob, Rodas5(chunk_size = Val{8}()), save_everystep = false) +@test_nowarn sol = solve( + prob, Rosenbrock23(autodiff = AutoForwardDiff(chunksize = 8)), save_everystep = false) +@test_nowarn sol = solve( + prob, Rodas5(autodiff = AutoForwardDiff(chunksize = 8)), save_everystep = false) # DFBDF g1(du, u, p, t) = du .^ 2 - conj.(u) @@ -261,11 +271,11 @@ du0 = SA[-0.5051593302918506 - 0.87178524227302im, -0.5011616766671037 + 0.8651123244481334im, -0.5065728050401669 + 0.8738635859036186im] prob = DAEProblem(g1, du0, u0, (0.0, 10.0)) -sol1 = solve(prob, DFBDF(autodiff = false), reltol = 1e-8, abstol = 1e-8) +sol1 = solve(prob, DFBDF(autodiff = AutoFiniteDiff()), reltol = 1e-8, abstol = 1e-8) g2(resid, du, u, p, t) = resid .= du .^ 2 - conj.(u) prob = DAEProblem(g2, Array(du0), Array(u0), (0.0, 10.0)) -sol2 = solve(prob, DFBDF(autodiff = false), reltol = 1e-8, abstol = 1e-8) +sol2 = solve(prob, DFBDF(autodiff = AutoFiniteDiff()), reltol = 1e-8, abstol = 1e-8) @test all(iszero, sol1[:, 1] - sol2[:, 1]) @test all(abs.(sol1[:, end] .- sol2[:, end]) .< 1.5e-6) diff --git a/test/interface/stats_tests.jl b/test/interface/stats_tests.jl index 13f06cb127..90b672d8bc 100644 --- a/test/interface/stats_tests.jl +++ b/test/interface/stats_tests.jl @@ -1,5 +1,5 @@ # stats.nf tests -using OrdinaryDiffEq, Test +using OrdinaryDiffEq, Test, ADTypes x = Ref(0) function f(u, p, t) x[] += 1 @@ -23,12 +23,12 @@ probip = ODEProblem(g, u0, tspan) @test x[] == sol.stats.nf end @testset "$alg" for alg in [Rodas5P, KenCarp4] - @testset "$kwargs" for kwargs in [(autodiff = true,), - (autodiff = false, diff_type = Val{:forward}), - (autodiff = false, diff_type = Val{:central}), - (autodiff = false, diff_type = Val{:complex}),] + @testset "$kwargs" for kwargs in [(autodiff = AutoForwardDiff(),)] + #(autodiff = AutoFiniteDiff(fdtype = Val{:forward}()),), + #(autodiff = AutoFiniteDiff(fdtype = Val{:central}()),), + #(autodiff = AutoFiniteDiff(fdtype = Val{:complex}()),)] x[] = 0 - sol = solve(prob, alg(;kwargs...)) + sol = solve(prob, alg(; kwargs...)) @test x[] == sol.stats.nf end end diff --git a/test/interface/stiffness_detection_test.jl b/test/interface/stiffness_detection_test.jl index 4ae725c460..d3bbd4e96c 100644 --- a/test/interface/stiffness_detection_test.jl +++ b/test/interface/stiffness_detection_test.jl @@ -1,33 +1,39 @@ -using OrdinaryDiffEq, Test -import ODEProblemLibrary: van +using OrdinaryDiffEq, Test, ADTypes +import ODEProblemLibrary: prob_ode_vanderpol using ForwardDiff: Dual -prob1 = ODEProblem(van, [0, 2.0], (0.0, 6), inv(0.003)) +# Create Van der Pol problem with same structure as the new ODEProblemLibrary implementation +# New implementation uses: u[1] = x, u[2] = y, p[1] = μ +# Van der Pol equations: dx/dt = y, dy/dt = μ * ((1 - x^2) * y - x) +# Initial conditions: [x, y] = [2.0, 0] (matching the original [sys.x => 2.0, sys.y => 0]) function __van(du, u, p, t) + x, y = u[1], u[2] μ = p[1] - du[1] = μ * ((1 - u[2]^2) * u[1] - u[2]) - du[2] = 1 * u[1] + du[1] = y # dx/dt = y + du[2] = μ * ((1 - x^2) * y - x) # dy/dt = μ * ((1 - x^2) * y - x) end -prob2 = ODEProblem(__van, [0, 2.0], (0.0, 6), inv(0.003)) +prob1 = ODEProblem(__van, [2.0, 0.0], (0.0, 6), [inv(0.003)]) +prob2 = ODEProblem(__van, [2.0, 0.0], (0.0, 6), [inv(0.003)]) # out-of-place test function _van(u, p, t) + x, y = u[1], u[2] μ = p[1] - [μ * ((1 - u[2]^2) * u[1] - u[2]), - 1 * u[1]] + [y, # dx/dt = y + μ * ((1 - x^2) * y - x)] # dy/dt = μ * ((1 - x^2) * y - x) end -prob3 = ODEProblem(_van, [0, 2.0], (0.0, 6), inv(0.003)) +prob3 = ODEProblem(_van, [2.0, 0.0], (0.0, 6), [inv(0.003)]) probArr = [prob1, prob2, prob3] for prob in [prob2, prob3], u0 in [prob.u0, Dual.(prob.u0, prob.u0)] prob′ = remake(prob3, u0 = u0) - @test_nowarn solve(prob′, AutoTsit5(Rosenbrock23(autodiff = false))) + @test_nowarn solve(prob′, AutoTsit5(Rosenbrock23(autodiff = AutoFiniteDiff()))) end # Test if switching back and forth is_switching_fb(sol) = all(i -> count(isequal(i), sol.alg_choice[2:end]) > 5, (1, 2)) for (i, prob) in enumerate(probArr) println(i) - sol = @test_nowarn solve(prob, AutoTsit5(Rosenbrock23(autodiff = false)), + sol = solve(prob, AutoTsit5(Rosenbrock23(autodiff = AutoFiniteDiff())), maxiters = 1000) @test is_switching_fb(sol) alg = AutoTsit5(Rodas5(); maxstiffstep = 5, maxnonstiffstep = 5, stiffalgfirst = true) @@ -35,6 +41,7 @@ for (i, prob) in enumerate(probArr) sol2 = solve(prob, alg, maxiters = 1000) @test sol.t == sol2.t # test reinitialization @test length(sol.t) < 280 + @test SciMLBase.successful_retcode(sol) @test alg.algs[sol.alg_choice[1]] isa Rodas5 i == 1 || @test is_switching_fb(sol) # fails due to eigenvalue estimate of J sol = solve(prob, @@ -42,27 +49,33 @@ for (i, prob) in enumerate(probArr) stifftol = 11 // 10, nonstifftol = 9 / 10), reltol = 1e-5, abstol = 1e-5, maxiters = 1000) @test length(sol.t) < 625 + @test SciMLBase.successful_retcode(sol) @test is_switching_fb(sol) sol = solve(prob, AutoVern6(Kvaerno3(); maxstiffstep = 4, maxnonstiffstep = 2), maxiters = 1000) @test length(sol.t) < 700 + @test SciMLBase.successful_retcode(sol) @test is_switching_fb(sol) sol = solve(prob, AutoVern7(Hairer42(); maxstiffstep = 4, maxnonstiffstep = 2), maxiters = 1000) @test length(sol.t) < 610 + @test_skip SciMLBase.successful_retcode(sol) @test is_switching_fb(sol) sol = solve(prob, AutoVern8(Rosenbrock23(); maxstiffstep = 4, maxnonstiffstep = 4), maxiters = 1000) @test length(sol.t) < 910 + @test SciMLBase.successful_retcode(sol) @test is_switching_fb(sol) sol = solve(prob, AutoVern9(KenCarp3(); maxstiffstep = 4, maxnonstiffstep = 1), maxiters = 1000) @test length(sol.t) < 570 + @test SciMLBase.successful_retcode(sol) @test is_switching_fb(sol) sol = solve(prob, - AutoVern9(KenCarp3(autodiff = false); maxstiffstep = 4, + AutoVern9(KenCarp3(autodiff = AutoFiniteDiff()); maxstiffstep = 4, maxnonstiffstep = 1), maxiters = 1000) @test length(sol.t) < 570 + @test SciMLBase.successful_retcode(sol) @test is_switching_fb(sol) end diff --git a/test/interface/units_tests.jl b/test/interface/units_tests.jl index 280116dba2..cad23ebc91 100644 --- a/test/interface/units_tests.jl +++ b/test/interface/units_tests.jl @@ -1,5 +1,5 @@ using OrdinaryDiffEq, RecursiveArrayTools, Unitful -using LinearAlgebra, Test +using LinearAlgebra, Test, ADTypes @testset "Algorithms" begin algs = [ @@ -55,10 +55,10 @@ end sol = solve(prob, alg) end - for alg in [AutoVern6(Rodas5(autodiff = false)), - AutoVern7(Rodas5(autodiff = false)), - AutoVern8(Rodas5(autodiff = false)), - AutoVern9(Rodas5(autodiff = false))] + for alg in [AutoVern6(Rodas5(autodiff = AutoFiniteDiff())), + AutoVern7(Rodas5(autodiff = AutoFiniteDiff())), + AutoVern8(Rodas5(autodiff = AutoFiniteDiff())), + AutoVern9(Rodas5(autodiff = AutoFiniteDiff()))] @show alg @test_broken sol = solve(prob, alg) end diff --git a/test/interface/utility_tests.jl b/test/interface/utility_tests.jl index 2a8ba62c8f..68acef6162 100644 --- a/test/interface/utility_tests.jl +++ b/test/interface/utility_tests.jl @@ -10,7 +10,7 @@ using OrdinaryDiffEq.OrdinaryDiffEqDifferentiation: WOperator, calc_W, calc_W!, tspan = (0.0, 1.0) dt = 0.01 dtgamma = 0.5dt - concrete_W = A - inv(dtgamma)*mm + concrete_W = A - inv(dtgamma) * mm # Out-of-place fun = ODEFunction((u, p, t) -> A * u; @@ -58,8 +58,7 @@ end fun1_ip = ODEFunction(_f_ip; mass_matrix = mm) fun2_ip = ODEFunction(_f_ip; mass_matrix = mm, jac_prototype = MatrixOperator(similar(A); - update_func! = (J, u, p, t) -> J .= t .* - A)) + update_func! = (J, u, p, t) -> J .= t .* A)) for Alg in [ImplicitEuler, Rosenbrock23, Rodas5] println(Alg) diff --git a/test/interface/wprototype_tests.jl b/test/interface/wprototype_tests.jl index 29a564875e..0fada74956 100644 --- a/test/interface/wprototype_tests.jl +++ b/test/interface/wprototype_tests.jl @@ -49,6 +49,12 @@ for prob in (prob_ode_vanderpol_stiff,) sol_W = solve(prob_W, alg) rtol = 1e-2 + + @test prob_J.f.sparsity.A == prob_W.f.sparsity.A + + @test all(isapprox.(sol_J.t, sol_W.t; rtol)) + @test all(isapprox.(sol_J.u, sol_W.u; rtol)) + @test all(isapprox.(sol_J.t, sol.t; rtol)) @test all(isapprox.(sol_J.u, sol.u; rtol)) @test all(isapprox.(sol_W.t, sol.t; rtol)) diff --git a/test/modelingtoolkit/Project.toml b/test/modelingtoolkit/Project.toml new file mode 100644 index 0000000000..857bbcab3f --- /dev/null +++ b/test/modelingtoolkit/Project.toml @@ -0,0 +1,17 @@ +[deps] +DiffEqDevTools = "f3b72e0c-5b89-59e1-b016-84e28bfd966d" +ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +OrdinaryDiffEqBDF = "6ad6398a-0878-4a85-9266-38940aa047c8" +OrdinaryDiffEqNonlinearSolve = "127b3ac7-2247-4354-8eb6-78cf4e7c58e8" +OrdinaryDiffEqSDIRK = "2d112036-d095-4a1e-ab9a-08536f3ecdbf" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[compat] +DiffEqDevTools = "2" +ModelingToolkit = "10.10" +NonlinearSolve = "4.10" +OrdinaryDiffEqBDF = "1" +OrdinaryDiffEqNonlinearSolve = "1" +OrdinaryDiffEqSDIRK = "1" \ No newline at end of file diff --git a/test/interface/dae_initialize_integration.jl b/test/modelingtoolkit/dae_initialize_integration.jl similarity index 51% rename from test/interface/dae_initialize_integration.jl rename to test/modelingtoolkit/dae_initialize_integration.jl index 85a119d859..f9500be362 100644 --- a/test/interface/dae_initialize_integration.jl +++ b/test/modelingtoolkit/dae_initialize_integration.jl @@ -1,18 +1,18 @@ using ModelingToolkit, OrdinaryDiffEq, NonlinearSolve, Test +using ModelingToolkit: D_nounits as D, t_nounits as t -@parameters t g e b +@parameters g e b @variables v(t) w(t) F(t) -@derivatives D' ~ t single_neuron_eqs = [ D(v) ~ min(max(-2 - v, v), 2 - v) - w + F, # add the flux term D(w) ~ e * (v - g * w + b) ] -n1 = ODESystem(single_neuron_eqs, t, [v, w, F], [g, e, b], name = :n1) -n2 = ODESystem(single_neuron_eqs, t, [v, w, F], [g, e, b], name = :n2) -@parameters D Dk -connections = [0 ~ n1.F - D * Dk * max(n1.v - n2.v, 0) - 0 ~ n2.F - D * max(n2.v - n1.v, 0)] -connected = ODESystem(connections, t, [], [D, Dk], systems = [n1, n2], name = :connected) +n1 = System(single_neuron_eqs, t, [v, w, F], [g, e, b], name = :n1) +n2 = System(single_neuron_eqs, t, [v, w, F], [g, e, b], name = :n2) +@parameters Di Dk +connections = [0 ~ n1.F - Di * Dk * max(n1.v - n2.v, 0) + 0 ~ n2.F - Di * max(n2.v - n1.v, 0)] +connected = System(connections, t, [], [Di, Dk], systems = [n1, n2], name = :connected) connected = complete(connected) u0 = [ @@ -31,11 +31,11 @@ p0 = [ n2.g => 0.8, n2.e => 0.04, n2.b => 0.2, - D => 0.047, + Di => 0.047, Dk => 1 ] -prob = ODEProblem(connected, u0, tspan, p0) +prob = ODEProblem(connected, [u0; p0], tspan) sol = solve(prob, Rodas5(), initializealg = BrownFullBasicInit()) @test prob.u0 == sol[1] sol = solve(prob, Rodas5(), initializealg = ShampineCollocationInit()) @@ -62,17 +62,37 @@ _f = ODEFunction(testsys; initializeprob = nlprob, initializeprobmap = initprobm prob = ODEProblem(_f, [0.0], (0.0, 1.0)) sol = solve(prob, Tsit5()) @test SciMLBase.successful_retcode(sol) -@test sol[1] == [1.0] +@test sol.u[1] == [1.0] prob = ODEProblem(_f, [0.0], (0.0, 1.0)) sol = solve(prob, Tsit5(), dt = 1e-10) @test SciMLBase.successful_retcode(sol) -@test sol[1] == [1.0] -@test sol[2] ≈ [0.9999999998] -@test sol[end] ≈ [-1.0] +@test sol.u[1] == [1.0] +@test sol.u[2] ≈ [0.9999999998] +@test sol.u[end] ≈ [-1.0] sol = solve(prob, Rodas5P(), dt = 1e-10) @test SciMLBase.successful_retcode(sol) -@test sol[1] == [1.0] -@test sol[2] ≈ [0.9999999998] -@test sol[end] ≈ [-1.0] +@test sol.u[1] == [1.0] +@test sol.u[2] ≈ [0.9999999998] +@test sol.u[end] ≈ [-1.0] + +@testset "`reinit!` updates initial parameters" begin + # https://github.com/SciML/ModelingToolkit.jl/issues/3451 + # https://github.com/SciML/ModelingToolkit.jl/issues/3504 + @variables x(t) y(t) + @parameters c1 c2 + @mtkcompile sys = System([D(x) ~ -c1 * x + c2 * y, D(y) ~ c1 * x - c2 * y], t) + prob = ODEProblem(sys, [x => 1.0, y => 2.0, c1 => 1.0, c2 => 2.0], (0.0, 1.0)) + @test prob.ps[Initial(x)] ≈ 1.0 + @test prob.ps[Initial(y)] ≈ 2.0 + integ = init(prob, Tsit5()) + @test integ.ps[Initial(x)] ≈ 1.0 + @test integ.ps[Initial(y)] ≈ 2.0 + new_u0 = ModelingToolkit.get_u0(sys, Dict(x => 2.0, y => 3.0)) + reinit!(integ, new_u0) + @test integ.ps[Initial(x)] ≈ 2.0 + @test integ.ps[Initial(y)] ≈ 3.0 + @test integ[x] ≈ 2.0 + @test integ[y] ≈ 3.0 +end diff --git a/test/interface/jacobian_tests.jl b/test/modelingtoolkit/jacobian_tests.jl similarity index 94% rename from test/interface/jacobian_tests.jl rename to test/modelingtoolkit/jacobian_tests.jl index d23d29d642..eb73c8a5f4 100644 --- a/test/interface/jacobian_tests.jl +++ b/test/modelingtoolkit/jacobian_tests.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, ForwardDiff, Test +using OrdinaryDiffEq, ForwardDiff, Test, ADTypes function d_alembert(du, u, p, t) du[1] = p[1] - p[2] * u[1] + p[3] * t @@ -56,7 +56,7 @@ end prob = ODEProblem(lotka, [1.0, 1.0], (0.0, 1.0), [1.5, 1.0, 3.0, 1.0]) de = ModelingToolkit.modelingtoolkitize(prob) |> complete -prob2 = ODEProblem(de; jac = true) +prob2 = ODEProblem(de, [], prob.tspan; jac = true) sol = solve(prob, TRBDF2()) @@ -86,7 +86,7 @@ function rober(du, u, p, t) nothing end prob1 = ODEProblem(rober, [1.0, 0.0, 0.0], (0.0, 1e5), (0.04, 3e7, 1e4, true)) -sol1 = solve(prob1, TRBDF2(chunk_size = chunksize)) +sol1 = solve(prob1, TRBDF2(autodiff = AutoForwardDiff(chunksize = chunksize))) prob = ODEProblem(rober, [1.0, 0.0, 0.0], (0.0, 1e5), (0.04, 3e7, 1e4, false)) sol = solve(prob, TRBDF2()) @test sol.u[end] == sol1.u[end] diff --git a/test/modelingtoolkit/nlstep_tests.jl b/test/modelingtoolkit/nlstep_tests.jl new file mode 100644 index 0000000000..6d3d96a88b --- /dev/null +++ b/test/modelingtoolkit/nlstep_tests.jl @@ -0,0 +1,104 @@ +using ModelingToolkit +using ModelingToolkit: t_nounits as t, D_nounits as D +using NonlinearSolve, OrdinaryDiffEqBDF, OrdinaryDiffEqSDIRK, DiffEqDevTools +using OrdinaryDiffEqNonlinearSolve: NonlinearSolveAlg +using Test + +@parameters k₁ k₂ k₃ +@variables y₁(t) y₂(t) y₃(t) + +eqs = [D(y₁) ~ -k₁ * y₁ + k₃ * y₂ * y₃, + D(y₂) ~ k₁ * y₁ - k₂ * y₂^2 - k₃ * y₂ * y₃, + D(y₃) ~ k₂ * y₂^2] +@mtkcompile rober = ODESystem(eqs, t) +prob = ODEProblem(rober, [[y₁, y₂, y₃] .=> [1.0; 0.0; 0.0]; [k₁, k₂, k₃] .=> (0.04, 3e7, 1e4)], (0.0, 1e5), jac = true) +prob2 = ODEProblem(rober, [[y₁, y₂, y₃] .=> [1.0; 0.0; 0.0]; [k₁, k₂, k₃] .=> (0.04, 3e7, 1e4)], (0.0, 1e5), jac = true, nlstep = true) + +@test prob2.f.nlstep_data !== nothing + +nlalg = NonlinearSolveAlg(NewtonRaphson(autodiff = AutoFiniteDiff())); +nlalgrobust = NonlinearSolveAlg(TrustRegion(autodiff = AutoFiniteDiff())); +sol1 = solve(prob, FBDF(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); +sol2 = solve(prob2, FBDF(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); + +@test sol1.t != sol2.t +@test sol1 != sol2 +@test sol1(sol1.t) ≈ sol2(sol1.t) atol=1e-3 + +sol1 = solve(prob, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); +sol2 = solve(prob2, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); + +@test sol1.t != sol2.t +@test sol1.u != sol2.u +@test sol1(sol1.t) ≈ sol2(sol1.t) atol=1e-3 + +testprob = ODEProblem(rober, [[y₁, y₂, y₃] .=> [1.0; 0.0; 0.0]; [k₁, k₂, k₃] .=> (0.04, 3e7, 1e4)], (0.0, 1.0), nlstep = true) +@test testprob.f.nlstep_data !== nothing +sol2 = solve(testprob, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalg), adaptive=false, dt= 2.0^-15); + +test_setup = Dict(:alg => FBDF(), :reltol => 1e-14, :abstol => 1e-14) +dts = 2.0 .^ (-10:-1:-15) +sim = analyticless_test_convergence(dts, testprob, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 2) < 0.2 + +dts = 2.0 .^ (-10:-1:-12) +sim = analyticless_test_convergence(dts, testprob, KenCarp4(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 4) < 0.2 + +dts = 2.0 .^ (-12:-1:-15) +sim = analyticless_test_convergence(dts, testprob, ABDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 2) < 0.2 + +dts = 2.0 .^ (-13:-1:-16) +sim = analyticless_test_convergence(dts, testprob, QNDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 2.5) < 0.2 # Superconvergence + +dts = 2.0 .^ (-15:-1:-18) +sim = analyticless_test_convergence(dts, testprob, FBDF(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 1) < 0.3 # Only first order because adaptive order starts with Euler! + +eqs_nonaut = [D(y₁) ~ -k₁ * y₁ + (t+1) * k₃ * y₂ * y₃, + D(y₂) ~ k₁ * y₁ - (t+1) * k₂ * y₂^2 - (t+1) * k₃ * y₂ * y₃, + D(y₃) ~ (t+1) * k₂ * y₂^2] +@mtkcompile rober_nonaut = ODESystem(eqs_nonaut, t) +prob = ODEProblem(rober_nonaut, [[y₁, y₂, y₃] .=> [1.0; 0.0; 0.0]; [k₁, k₂, k₃] .=> (0.04, 3e7, 1e4)], (0.0, 1e5), jac = true) +prob2 = ODEProblem(rober_nonaut, [[y₁, y₂, y₃] .=> [1.0; 0.0; 0.0]; [k₁, k₂, k₃] .=> (0.04, 3e7, 1e4)], (0.0, 1e5), jac = true, nlstep = true) + +sol1 = solve(prob, FBDF(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); +sol2 = solve(prob2, FBDF(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); + +@test sol1.t != sol2.t +@test sol1.u != sol2.u +@test sol1(sol1.t) ≈ sol2(sol1.t) atol=1e-3 + +sol1 = solve(prob, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); +sol2 = solve(prob2, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalg)); + +@test sol1.t != sol2.t +@test sol1 != sol2 +@test sol1(sol1.t) ≈ sol2(sol1.t) atol=1e-4 + +testprob = ODEProblem(rober_nonaut, [[y₁, y₂, y₃] .=> [1.0; 0.0; 0.0]; [k₁, k₂, k₃] .=> (0.04, 3e7, 1e4)], (0.0, 1.0), nlstep = true) +@test testprob.f.nlstep_data !== nothing +sol2 = solve(testprob, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalg), adaptive=false, dt= 2.0^-15) + +test_setup = Dict(:alg => FBDF(), :reltol => 1e-14, :abstol => 1e-14) +dts = 2.0 .^ (-10:-1:-15) +sim = analyticless_test_convergence(dts, testprob, TRBDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 2) < 0.2 + +dts = 2.0 .^ (-10:-1:-12) +sim = analyticless_test_convergence(dts, testprob, KenCarp4(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 4) < 0.2 + +dts = 2.0 .^ (-12:-1:-15) +sim = analyticless_test_convergence(dts, testprob, ABDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 2) < 0.2 + +dts = 2.0 .^ (-13:-1:-16) +sim = analyticless_test_convergence(dts, testprob, QNDF2(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 2.5) < 0.2 # Superconvergence + +dts = 2.0 .^ (-15:-1:-18) +sim = analyticless_test_convergence(dts, testprob, FBDF(autodiff=AutoFiniteDiff(), nlsolve = nlalgrobust), test_setup); +@test abs(sim.𝒪est[:l∞] - 1) < 0.35 # Only first order because adaptive order starts with Euler! diff --git a/test/interface/preconditioners.jl b/test/modelingtoolkit/preconditioners.jl similarity index 96% rename from test/interface/preconditioners.jl rename to test/modelingtoolkit/preconditioners.jl index 53188d1a12..85a54a30db 100644 --- a/test/interface/preconditioners.jl +++ b/test/modelingtoolkit/preconditioners.jl @@ -20,13 +20,8 @@ function brusselator_2d_loop(du, u, p, t) x, y = xyd_brusselator[I[1]], xyd_brusselator[I[2]] ip1, im1, jp1, jm1 = limit(i + 1, N), limit(i - 1, N), limit(j + 1, N), limit(j - 1, N) - du[i, j, 1] = alpha * (u[im1, j, 1] + u[ip1, j, 1] + u[i, jp1, 1] + u[i, jm1, 1] - - 4u[i, j, 1]) + - B + u[i, j, 1]^2 * u[i, j, 2] - (A + 1) * u[i, j, 1] + - brusselator_f(x, y, t) - du[i, j, 2] = alpha * (u[im1, j, 2] + u[ip1, j, 2] + u[i, jp1, 2] + u[i, jm1, 2] - - 4u[i, j, 2]) + - A * u[i, j, 1] - u[i, j, 1]^2 * u[i, j, 2] + du[i, j, 1] = alpha * (u[im1, j, 1] + u[ip1, j, 1] + u[i, jp1, 1] + u[i, jm1, 1] - 4u[i, j, 1]) + B + u[i, j, 1]^2 * u[i, j, 2] - (A + 1) * u[i, j, 1] + brusselator_f(x, y, t) + du[i, j, 2] = alpha * (u[im1, j, 2] + u[ip1, j, 2] + u[i, jp1, 2] + u[i, jm1, 2] - 4u[i, j, 2]) + A * u[i, j, 1] - u[i, j, 1]^2 * u[i, j, 2] end nothing end diff --git a/test/multithreading/ode_extrapolation_tests.jl b/test/multithreading/ode_extrapolation_tests.jl index 765471eb9e..9a875a5beb 100644 --- a/test/multithreading/ode_extrapolation_tests.jl +++ b/test/multithreading/ode_extrapolation_tests.jl @@ -1,5 +1,7 @@ # Import packages -using OrdinaryDiffEqExtrapolation, DiffEqDevTools, Test, Random +using OrdinaryDiffEqExtrapolation, RecursiveFactorization, DiffEqDevTools, Test, Random + +println("Running on $(Threads.nthreads()) thread(s).") # Define test problems # Note that the time span in ODEProblemLibrary is given by @@ -47,10 +49,13 @@ testTol = 0.2 AitkenNeville(max_order = 9, min_order = 1, init_order = 9, threading = false), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) sol = solve(prob, AitkenNeville(max_order = 9, min_order = 1, init_order = 9, threading = false), reltol = 1e-6) @test length(sol.u) < 18 + @test SciMLBase.successful_retcode(sol) end end @testset "Testing threaded AitkenNeville" begin @@ -71,10 +76,13 @@ testTol = 0.2 AitkenNeville(max_order = 9, min_order = 1, init_order = 9, threading = true), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) sol = solve(prob, AitkenNeville(max_order = 9, min_order = 1, init_order = 9, threading = true), reltol = 1e-6) @test length(sol.u) < 18 + @test SciMLBase.successful_retcode(sol) end end end # AitkenNeville @@ -103,6 +111,7 @@ testTol = 0.2 init_order = 9, sequence = seq, threading = false), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) end end @@ -127,6 +136,7 @@ testTol = 0.2 init_order = 9, sequence = seq, threading = true), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) end end @@ -154,6 +164,7 @@ testTol = 0.2 threading = false), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) end end @@ -187,6 +198,7 @@ testTol = 0.2 threading = true), reltol = 1e-3) @test length(sol.u) < 15 + @test SciMLBase.successful_retcode(sol) end end @@ -212,6 +224,7 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end @@ -236,6 +249,7 @@ testTol = 0.2 threading = OrdinaryDiffEqExtrapolation.BaseThreads()) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end @@ -259,6 +273,7 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end @@ -283,6 +298,7 @@ testTol = 0.2 threading = true) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) end end @@ -310,6 +326,8 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) end end @testset "Testing threaded ExtrapolationMidpointDeuflhard" begin @@ -333,6 +351,8 @@ testTol = 0.2 threading = true) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) end end end # ExtrapolationMidpointDeuflhard @@ -361,6 +381,8 @@ testTol = 0.2 threading = false) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) end end @testset "Testing threaded ExtrapolationMidpointHairerWanner" begin @@ -385,6 +407,8 @@ testTol = 0.2 threading = true) sol = solve(prob, alg, reltol = 1e-3) @test length(sol.u) < 10 + @test SciMLBase.successful_retcode(sol) + @test SciMLBase.successful_retcode(sol) end end end # ExtrapolationMidpointHairerWanner @@ -408,4 +432,35 @@ testTol = 0.2 s2 = solve(prob_ode_2Dlinear, ExtrapolationMidpointDeuflhard()) @test all(all(s1[i] - s2[i] .< 5e-6) for i in 1:length(s1)) end + + # Test for Julia 1.12 threading compatibility (Issue #2612) + @testset "Threading compatibility test" begin + # Simple problem for threading test + simple_prob = ODEProblem((u, p, t) -> u, 0.1, (0.0, 1.0)) + + # Test extrapolation methods with threading enabled + @testset "ExtrapolationMidpointDeuflhard with threading" begin + sol = solve(simple_prob, + ExtrapolationMidpointDeuflhard(threading = true), + reltol = 1e-3) + @test SciMLBase.successful_retcode(sol) + @test length(sol) > 0 + end + + @testset "ImplicitEulerExtrapolation with threading" begin + sol = solve(simple_prob, + ImplicitEulerExtrapolation(threading = true), + reltol = 1e-3) + @test SciMLBase.successful_retcode(sol) + @test length(sol) > 0 + end + + @testset "ImplicitDeuflhardExtrapolation with threading" begin + sol = solve(simple_prob, + ImplicitDeuflhardExtrapolation(threading = true), + reltol = 1e-3) + @test SciMLBase.successful_retcode(sol) + @test length(sol) > 0 + end + end end # Extrapolation methods diff --git a/test/odeinterface/Project.toml b/test/odeinterface/Project.toml index 5b5d969ecc..9a1f9e58f2 100644 --- a/test/odeinterface/Project.toml +++ b/test/odeinterface/Project.toml @@ -6,3 +6,4 @@ OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" [compat] ODEInterface = "0.5" ODEInterfaceDiffEq = "3.13" +OrdinaryDiffEq = "6" diff --git a/test/qa/qa_tests.jl b/test/qa/qa_tests.jl new file mode 100644 index 0000000000..7e5d1221c8 --- /dev/null +++ b/test/qa/qa_tests.jl @@ -0,0 +1,12 @@ +using ExplicitImports, OrdinaryDiffEq +using Test + +@testset "ExplicitImports" begin + @test check_no_implicit_imports( + OrdinaryDiffEq; skip = (Base, Core, SciMLBase) + ) === nothing + + @test check_no_stale_explicit_imports(OrdinaryDiffEq) === nothing + + @test check_all_qualified_accesses_via_owners(OrdinaryDiffEq) === nothing +end \ No newline at end of file diff --git a/test/regression/hard_dae.jl b/test/regression/hard_dae.jl index 302de87d2a..727b5ca989 100644 --- a/test/regression/hard_dae.jl +++ b/test/regression/hard_dae.jl @@ -218,7 +218,7 @@ prob = ODEProblem(f, deepcopy(res.zero), (0, 20.0), deepcopy(p_inv)) refsol = solve(prob, Rodas4(), saveat = 0.1, callback = cb, tstops = [1.0], reltol = 1e-12, abstol = 1e-17) -for solver in (Rodas4, Rodas4P, Rodas5, Rodas5P, FBDF, QNDF, Rosenbrock23) +for solver in (Rodas4, Rodas4P, Rodas5, Rodas5P, FBDF, QNDF) @show solver prob = ODEProblem(f, deepcopy(res.zero), (0, 20.0), deepcopy(p_inv)) sol = solve( @@ -270,6 +270,6 @@ for prob in [prob1, prob2], alg in [simple_implicit_euler, alg_switch] sol = solve(prob, alg, callback = cb, dt = 1 / 2^10, adaptive = false) @test sol.retcode == ReturnCode.Success @test sol(0, idxs = 1) == 5 - @test sol(2, idxs = 1) == 0 + @test abs(sol(2-2^-10, idxs = 1)) <= 1e-4 @test sol(4, idxs = 1) > 10 end diff --git a/test/regression/iipvsoop_tests.jl b/test/regression/iipvsoop_tests.jl index e3f2756410..b316f5bb31 100644 --- a/test/regression/iipvsoop_tests.jl +++ b/test/regression/iipvsoop_tests.jl @@ -1,5 +1,5 @@ using OrdinaryDiffEq, Test -using OrdinaryDiffEqCore +using OrdinaryDiffEqCore, ADTypes f(u, p, t) = 0.98u u0 = 1.0 @@ -10,28 +10,35 @@ sol = solve(prob, Tsit5()) # Make sure various differentiation forms work on scalars sol1 = solve(prob, Rosenbrock23(), abstol = 1e-12, reltol = 1e-12) -sol2 = solve(prob, Rosenbrock23(autodiff = false), abstol = 1e-12, reltol = 1e-12) -sol3 = solve(prob, Rosenbrock23(autodiff = false, diff_type = Val{:central}), +sol2 = solve( + prob, Rosenbrock23(autodiff = AutoFiniteDiff()), abstol = 1e-12, reltol = 1e-12) +sol3 = solve(prob, Rosenbrock23(autodiff = AutoFiniteDiff(fdtype = Val(:central))), abstol = 1e-12, reltol = 1e-12) -sol4 = solve(prob, Rosenbrock23(autodiff = false, diff_type = Val{:complex}), +sol4 = solve(prob, Rosenbrock23(autodiff = AutoFiniteDiff(fdtype = Val(:complex))), abstol = 1e-12, reltol = 1e-12) sol5 = solve(prob, KenCarp4(), abstol = 1e-12, reltol = 1e-12) -sol6 = solve(prob, KenCarp4(autodiff = false), abstol = 1e-12, reltol = 1e-12) -sol7 = solve(prob, KenCarp4(autodiff = false, diff_type = Val{:central}), abstol = 1e-12, +sol6 = solve(prob, KenCarp4(autodiff = AutoFiniteDiff()), abstol = 1e-12, reltol = 1e-12) +sol7 = solve( + prob, KenCarp4(autodiff = AutoFiniteDiff(fdtype = Val(:central))), abstol = 1e-12, reltol = 1e-12) -sol8 = solve(prob, KenCarp4(autodiff = false, diff_type = Val{:complex}), abstol = 1e-12, +sol8 = solve( + prob, KenCarp4(autodiff = AutoFiniteDiff(fdtype = Val(:complex))), abstol = 1e-12, reltol = 1e-12) sol9 = solve(prob, KenCarp47(), abstol = 1e-12, reltol = 1e-12) -sol10 = solve(prob, KenCarp47(autodiff = false), abstol = 1e-12, reltol = 1e-12) -sol11 = solve(prob, KenCarp47(autodiff = false, diff_type = Val{:central}), abstol = 1e-12, +sol10 = solve(prob, KenCarp47(autodiff = AutoFiniteDiff()), abstol = 1e-12, reltol = 1e-12) +sol11 = solve( + prob, KenCarp47(autodiff = AutoFiniteDiff(fdtype = Val(:central))), abstol = 1e-12, reltol = 1e-12) -sol12 = solve(prob, KenCarp47(autodiff = false, diff_type = Val{:complex}), abstol = 1e-12, +sol12 = solve( + prob, KenCarp47(autodiff = AutoFiniteDiff(fdtype = Val(:complex))), abstol = 1e-12, reltol = 1e-12) sol13 = solve(prob, KenCarp58(), abstol = 1e-12, reltol = 1e-12) -sol14 = solve(prob, KenCarp58(autodiff = false), abstol = 1e-12, reltol = 1e-12) -sol15 = solve(prob, KenCarp58(autodiff = false, diff_type = Val{:central}), abstol = 1e-12, +sol14 = solve(prob, KenCarp58(autodiff = AutoFiniteDiff()), abstol = 1e-12, reltol = 1e-12) +sol15 = solve( + prob, KenCarp58(autodiff = AutoFiniteDiff(fdtype = Val(:central))), abstol = 1e-12, reltol = 1e-12) -sol16 = solve(prob, KenCarp58(autodiff = false, diff_type = Val{:complex}), abstol = 1e-12, +sol16 = solve( + prob, KenCarp58(autodiff = AutoFiniteDiff(fdtype = Val(:complex))), abstol = 1e-12, reltol = 1e-12) ts = 0.0:0.1:1.0 @@ -87,7 +94,7 @@ end working_sdirk_algs = [ImplicitMidpoint(), ImplicitEuler(), - ImplicitMidpoint(autodiff = false), + ImplicitMidpoint(autodiff = AutoFiniteDiff()), SSPSDIRK2()] sdirk_algs = [Trapezoid(), diff --git a/test/regression/ode_adaptive_tests.jl b/test/regression/ode_adaptive_tests.jl index c2abd99119..2a8545d001 100644 --- a/test/regression/ode_adaptive_tests.jl +++ b/test/regression/ode_adaptive_tests.jl @@ -18,6 +18,9 @@ sol4 = solve(prob, Stepanov5()) val4 = maximum(abs.(sol3.u[end] - sol3.u_analytic[end])) @test length(sol.t) > length(sol2.t) >= length(sol3.t) +@test SciMLBase.successful_retcode(sol) +@test SciMLBase.successful_retcode(sol2) +@test SciMLBase.successful_retcode(sol3) @test max(val1, val2, val3, val4) < 2e-3 function lorenz(u, p, t) @@ -30,8 +33,10 @@ tspan = (0.0, 100.0) prob = ODEProblem{false}(lorenz, u0, tspan) sol = solve(prob, QNDF()) @test length(sol.t) < 5000 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, FBDF()) @test length(sol.t) < 6600 +@test SciMLBase.successful_retcode(sol) function lorenz(du, u, p, t) du[1] = 10.0(u[2] - u[1]) @@ -43,8 +48,10 @@ tspan = (0.0, 100.0) prob = ODEProblem{true}(lorenz, u0, tspan) sol = solve(prob, QNDF()) @test length(sol.t) < 5000 +@test SciMLBase.successful_retcode(sol) sol = solve(prob, FBDF()) @test length(sol.t) < 6600 +@test SciMLBase.successful_retcode(sol) function lorenz(out, du, u, p, t) out[1] = 10.0(u[2] - u[1]) - du[1] @@ -58,6 +65,7 @@ differential_vars = [true, true, true] prob = DAEProblem(lorenz, du0, u0, tspan, differential_vars = differential_vars) sol = solve(prob, DFBDF()) @test length(sol.t) < 6600 +@test SciMLBase.successful_retcode(sol) function lorenz(du, u, p, t) [10.0(u[2] - u[1]) - du[1] @@ -71,6 +79,7 @@ differential_vars = [true, true, true] prob = DAEProblem{false}(lorenz, du0, u0, tspan, differential_vars = differential_vars) sol = solve(prob, DFBDF()) @test length(sol.t) < 6600 +@test SciMLBase.successful_retcode(sol) rr(x1, x2) = (x1 * (-2.1474936f0 * (x2 + x1))) possibly_singular(u, p, t) = [-rr(u...), rr(u...)] @@ -109,33 +118,41 @@ prob_lorenz = ODEProblem{true}(lorenz, u0, tspan) sol_linear = solve(prob_linear, ESDIRK436L2SA2()) @test length(sol_linear.u) < 10 +@test SciMLBase.successful_retcode(sol_linear) sol_lorenz = solve(prob_lorenz, ESDIRK436L2SA2()) @test length(sol_lorenz.u) < 1500 +@test SciMLBase.successful_retcode(sol_lorenz) # ESDIRK437L2SA sol_linear = solve(prob_linear, ESDIRK437L2SA()) @test length(sol_linear.u) < 10 +@test SciMLBase.successful_retcode(sol_linear) sol_lorenz = solve(prob_lorenz, ESDIRK437L2SA()) @test length(sol_lorenz.u) < 1000 +@test SciMLBase.successful_retcode(sol_lorenz) # ESDIRK547L2SA2 sol_linear = solve(prob_linear, ESDIRK547L2SA2()) @test length(sol_linear.u) < 10 +@test SciMLBase.successful_retcode(sol_linear) sol_lorenz = solve(prob_lorenz, ESDIRK547L2SA2()) @test length(sol_lorenz.u) < 1000 +@test SciMLBase.successful_retcode(sol_lorenz) # ESDIRK659L2SA sol_linear = solve(prob_linear, ESDIRK659L2SA()) @test_broken length(sol_linear.u) < 10 +@test SciMLBase.successful_retcode(sol_linear) sol_lorenz = solve(prob_lorenz, ESDIRK659L2SA()) @test length(sol_lorenz.u) < 1000 +@test SciMLBase.successful_retcode(sol_lorenz) # Adaptivity tests for Alshina2, 3 diff --git a/test/regression/ode_dense_tests.jl b/test/regression/ode_dense_tests.jl index 753177957b..c8eaf84357 100644 --- a/test/regression/ode_dense_tests.jl +++ b/test/regression/ode_dense_tests.jl @@ -1,6 +1,6 @@ using OrdinaryDiffEq, Test, DiffEqBase using OrdinaryDiffEqCore -using ForwardDiff, Printf +using ForwardDiff import ODEProblemLibrary: prob_ode_linear, prob_ode_2Dlinear, prob_ode_bigfloatlinear, prob_ode_bigfloat2Dlinear @@ -8,7 +8,7 @@ import ODEProblemLibrary: prob_ode_linear, const PRINT_TESTS = false print_results(x) = if PRINT_TESTS - @printf("%s \n", x) + println(x) end # points and storage arrays used in the interpolation tests @@ -36,6 +36,10 @@ end const deriv_test_points = range(0, stop = 1, length = 5) +# left continuous derivative \lim{ϵ->0⁺}\frac{f(x)-f(x-ϵ)}{ϵ} +function LeftDeriv(f, x) + ForwardDiff.derivative(t -> -f(-t), -x) +end # perform the regression tests # NOTE: If you want to add new tests (for new algorithms), you have to run the # commands below to get numerical values for `tol_ode_linear` and @@ -63,7 +67,7 @@ function regression_test(alg, tol_ode_linear, tol_ode_2Dlinear; test_diff1 = fal @test interpolation_results_1d[1] ≈ der for t in deriv_test_points deriv = sol(t, Val{N}) - @test deriv≈ForwardDiff.derivative(t -> sol(t, Val{N - 1}), t) rtol=dertol + @test deriv≈LeftDeriv(t -> sol(t, Val{N - 1}), t) rtol=dertol end end end @@ -84,7 +88,7 @@ function regression_test(alg, tol_ode_linear, tol_ode_2Dlinear; test_diff1 = fal @test interpolation_results_1d_inplace[1] ≈ der for t in deriv_test_points deriv = sol(t, Val{N}, idxs = 1) - @test deriv≈ForwardDiff.derivative(t -> sol(t, Val{N - 1}; idxs = 1), t) rtol=dertol + @test deriv≈LeftDeriv(t -> sol(t, Val{N - 1}; idxs = 1), t) rtol=dertol end end end @@ -122,7 +126,7 @@ end interpd_idxs = sol(0:(1 // 2^(4)):1, idxs = 1:2:5) -@test minimum([interpd_idxs[i] == interpd[i][1:2:5] for i in 1:length(interpd)]) +@test minimum([isapprox(interpd_idxs[i], interpd[i][1:2:5], rtol=1e-14) for i in 1:length(interpd)]) interpd_single = sol(0:(1 // 2^(4)):1, idxs = 1) diff --git a/test/regression/ode_unrolled_comparison_tests.jl b/test/regression/ode_unrolled_comparison_tests.jl index 88821f1959..28592ff89f 100644 --- a/test/regression/ode_unrolled_comparison_tests.jl +++ b/test/regression/ode_unrolled_comparison_tests.jl @@ -36,6 +36,8 @@ sol1 = solve(prob, tabalg, dt = 1 / 2^6) sol2 = solve(prob, BS3(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### BS5() println("BS5") @@ -60,6 +62,8 @@ sol1 = solve(prob, tabalg, dt = 1 / 2^6) sol2 = solve(prob, BS5(), dt = 1 / 2^6) @test length(sol1) <= length(sol2) # Dual error estimators is more strict +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### Tsit5() @@ -85,6 +89,8 @@ sol1 = solve(prob, tabalg, dt = 1 / 2^6) sol2 = solve(prob, Tsit5(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### Vern6() @@ -110,6 +116,8 @@ sol1 = solve(probbig, tabalg, dt = 1 / 2^6) sol2 = solve(probbig, Vern6(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### Vern7() @@ -135,6 +143,8 @@ sol1 = solve(probbig, tabalg, dt = 1 / 2^6) sol2 = solve(probbig, Vern7(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### TanYam7() @@ -161,6 +171,8 @@ sol1 = solve(prob, tabalg, dt = 1 / 2^6) sol2 = solve(prob, TanYam7(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### Vern8() @@ -186,6 +198,8 @@ sol1 = solve(prob, tabalg, dt = 1 / 2^6) sol2 = solve(prob, Vern8(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### TsitPap8() @@ -211,6 +225,8 @@ sol1 = solve(prob, tabalg, dt = 1 / 2^6) sol2 = solve(prob, TsitPap8(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) ### Vern9() @@ -236,3 +252,5 @@ sol1 = solve(probbig, tabalg, dt = 1 / 2^6) sol2 = solve(probbig, Vern9(), dt = 1 / 2^6) @test length(sol1) == length(sol2) +@test SciMLBase.successful_retcode(sol1) +@test SciMLBase.successful_retcode(sol2) diff --git a/test/regression/psos_and_energy_conservation.jl b/test/regression/psos_and_energy_conservation.jl index 6858e6eb05..537c08bf7f 100644 --- a/test/regression/psos_and_energy_conservation.jl +++ b/test/regression/psos_and_energy_conservation.jl @@ -1,4 +1,4 @@ -using OrdinaryDiffEq, Test, Random, LinearAlgebra, SparseArrays +using OrdinaryDiffEq, ADTypes, Test, Random, LinearAlgebra, SparseArrays # Parameters Nc = 22 @@ -62,7 +62,7 @@ for i=2:Ntraj end =# -using OrdinaryDiffEq, DiffEqCallbacks, Test +using OrdinaryDiffEq, NonlinearSolve, DiffEqCallbacks, Test # Initial state u0 = [0, -0.25, 0.42081, 0] @@ -84,13 +84,12 @@ end const E = Hhh(u0) function ghh(resid, u, p) - resid[1] = Hhh(u[1], u[2], u[3], u[4]) - E - resid[2:4] .= 0 + resid[1] = -Hhh(u[1], u[2], u[3], u[4]) + E end # energy conserving callback: # important to use save = false, I don't want rescaling points -cb = ManifoldProjection(ghh, abstol = 1e-13, save = false) +cb = ManifoldProjection(ghh, resid_prototype = ones(1), nlsolve = TrustRegion(), abstol = 1e-9, save = false, autodiff = AutoForwardDiff()) # Callback for Poincare surface of section function psos_callback(j, direction = +1, offset::Real = 0, @@ -101,7 +100,7 @@ function psos_callback(j, direction = +1, offset::Real = 0, cond = (u, t, integrator) -> s * (u - offset) affect! = (integrator) -> nothing - cb = DiffEqBase.ContinuousCallback(cond, nothing, affect!; callback_kwargs..., + cb = SciMLBase.ContinuousCallback(cond, nothing, affect!; callback_kwargs..., save_positions = (true, false), idxs = j) end @@ -113,7 +112,7 @@ totalcb = CallbackSet(poincarecb, cb) prob = ODEProblem(hheom!, u0, (0.0, 100.0), callback = totalcb) extra_kw = Dict(:save_start => false, :save_end => false) -DEFAULT_DIFFEQ_KWARGS = Dict{Symbol, Any}(:abstol => 1e-9, :reltol => 1e-9) +DEFAULT_DIFFEQ_KWARGS = Dict{Symbol, Any}(:abstol => 1e-10, :reltol => 1e-10) sol = solve(prob, Vern9(); extra_kw..., DEFAULT_DIFFEQ_KWARGS..., save_everystep = false) diff --git a/test/runtests.jl b/test/runtests.jl index 821c48615d..09c0af2144 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,12 +23,24 @@ function activate_odeinterface_env() Pkg.instantiate() end +function activate_enzyme_env() + Pkg.activate("enzyme") + Pkg.develop(PackageSpec(path = dirname(@__DIR__))) + Pkg.instantiate() +end + +function activate_modelingtoolkit_env() + Pkg.activate("modelingtoolkit") + Pkg.develop(PackageSpec(path = dirname(@__DIR__))) + Pkg.instantiate() +end + #Start Test Script @time begin - if contains(GROUP, "OrdinaryDiffEq") - Pkg.develop(path = "../lib/$GROUP") - Pkg.test(GROUP) + if contains(GROUP, "OrdinaryDiffEq") || GROUP == "ImplicitDiscreteSolve" || GROUP == "SimpleImplicitDiscreteSolve" + Pkg.activate(joinpath(dirname(@__DIR__), "lib", GROUP)) + Pkg.test(GROUP, julia_args=["--check-bounds=auto", "--compiled-modules=yes", "--depwarn=yes"], force_latest_compatible_version=false, allow_reresolve=true) elseif GROUP == "All" || GROUP == "InterfaceI" || GROUP == "Interface" @time @safetestset "Discrete Algorithm Tests" include("interface/discrete_algorithm_test.jl") @time @safetestset "Tstops Tests" include("interface/ode_tstops_tests.jl") @@ -37,7 +49,6 @@ end @time @safetestset "Linear Tests" include("interface/ode_twodimlinear_tests.jl") @time @safetestset "Differentiation Trait Tests" include("interface/differentiation_traits_tests.jl") @time @safetestset "Inf Tests" include("interface/inf_handling.jl") - @time @safetestset "Jacobian Tests" include("interface/jacobian_tests.jl") @time @safetestset "saveat Tests" include("interface/ode_saveat_tests.jl") @time @safetestset "save_idxs Tests" include("interface/ode_saveidxs_tests.jl") @time @safetestset "Scalar Handling Tests" include("interface/scalar_handling_tests.jl") @@ -56,6 +67,7 @@ end @time @safetestset "Inplace Interpolation Tests" include("interface/inplace_interpolation.jl") @time @safetestset "Algebraic Interpolation Tests" include("interface/algebraic_interpolation.jl") @time @safetestset "Interpolation and Cache Stripping Tests" include("interface/ode_strip_test.jl") + @time @safetestset "Aliasing Tests" include("interface/aliasing_tests.jl") end if !is_APPVEYOR && (GROUP == "All" || GROUP == "InterfaceII" || GROUP == "Interface") @@ -63,7 +75,7 @@ end @time @safetestset "Linear Nonlinear Solver Tests" include("interface/linear_nonlinear_tests.jl") @time @safetestset "Linear Solver Tests" include("interface/linear_solver_test.jl") @time @safetestset "Linear Solver Split ODE Tests" include("interface/linear_solver_split_ode_test.jl") - @time @safetestset "Sparse Diff Tests" include("interface/sparsediff_tests.jl") + @time @safetestset "AutoSparse Detection Tests" include("interface/autosparse_detection_tests.jl") @time @safetestset "Enum Tests" include("interface/enums.jl") @time @safetestset "CheckInit Tests" include("interface/checkinit_tests.jl") @time @safetestset "Get du Tests" include("interface/get_du.jl") @@ -77,7 +89,6 @@ end @time @safetestset "No Index Tests" include("interface/noindex_tests.jl") @time @safetestset "Events + DAE addsteps Tests" include("interface/event_dae_addsteps.jl") @time @safetestset "No Jac Tests" include("interface/nojac.jl") - @time @safetestset "Preconditioner Tests" include("interface/preconditioners.jl") @time @safetestset "Units Tests" include("interface/units_tests.jl") @time @safetestset "Non-Full Diagonal Sparsity Tests" include("interface/nonfulldiagonal_sparse.jl") end @@ -85,6 +96,7 @@ end if !is_APPVEYOR && (GROUP == "All" || GROUP == "InterfaceIV" || GROUP == "Interface") @time @safetestset "Autodiff Error Tests" include("interface/autodiff_error_tests.jl") @time @safetestset "Ambiguity Tests" include("interface/ambiguity_tests.jl") + @time @safetestset "Precision Mixing Tests" include("interface/precision_mixing.jl") @time @safetestset "Sized Matrix Tests" include("interface/sized_matrix_tests.jl") @time @safetestset "Second Order with First Order Solver Tests" include("interface/second_order_with_first_order_solvers.jl") end @@ -92,7 +104,7 @@ end if !is_APPVEYOR && (GROUP == "All" || GROUP == "InterfaceV" || GROUP == "Interface") @time @safetestset "Interpolation Derivative Error Tests" include("interface/interpolation_derivative_error_tests.jl") @time @safetestset "AD Tests" include("interface/ad_tests.jl") - @time @safetestset "DAE Initialize Integration" include("interface/dae_initialize_integration.jl") + @time @safetestset "GPU AutoDiff Interface Tests" include("interface/gpu_autodiff_interface_tests.jl") @time @safetestset "DAE Initialization Tests" include("interface/dae_initialization_tests.jl") end @@ -132,7 +144,6 @@ end if !is_APPVEYOR && (GROUP == "All" || GROUP == "Regression_II" || GROUP == "Regression") @time @safetestset "PSOS Energy Conservation Tests" include("regression/psos_and_energy_conservation.jl") @time @safetestset "Unrolled Tests" include("regression/ode_unrolled_comparison_tests.jl") - @time @safetestset "Time derivative Tests" include("regression/time_derivative_test.jl") @time @safetestset "IIP vs OOP Tests" include("regression/iipvsoop_tests.jl") @time @safetestset "Inference Tests" include("regression/inference.jl") end @@ -145,14 +156,34 @@ end @time @safetestset "Split Methods Tests" include("algconvergence/split_methods_tests.jl") end + if !is_APPVEYOR && GROUP == "ModelingToolkit" + activate_modelingtoolkit_env() + @time @safetestset "NLStep Tests" include("modelingtoolkit/nlstep_tests.jl") + @time @safetestset "Jacobian Tests" include("modelingtoolkit/jacobian_tests.jl") + @time @safetestset "Preconditioner Tests" include("modelingtoolkit/preconditioners.jl") + @time @safetestset "DAE Initialize Integration" include("modelingtoolkit/dae_initialize_integration.jl") + end + if !is_APPVEYOR && GROUP == "Downstream" activate_downstream_env() @time @safetestset "DelayDiffEq Tests" include("downstream/delaydiffeq.jl") - @time @safetestset "Autodiff Events Tests" include("downstream/autodiff_events.jl") @time @safetestset "Measurements Tests" include("downstream/measurements.jl") + if VERSION >= v"1.11" && isempty(VERSION.prerelease) + @time @safetestset "Mooncake Tests" include("downstream/mooncake.jl") + end + @time @safetestset "Sparse Diff Tests" include("downstream/sparsediff_tests.jl") + @time @safetestset "Time derivative Tests" include("downstream/time_derivative_test.jl") end - if !is_APPVEYOR && GROUP == "ODEInterfaceRegression" + # Don't run Enzyme tests on prerelease + if !is_APPVEYOR && GROUP == "Enzyme" && isempty(VERSION.prerelease) + activate_enzyme_env() + @time @safetestset "Autodiff Events Tests" include("enzyme/autodiff_events.jl") + @time @safetestset "Discrete Adjoint Tests" include("enzyme/discrete_adjoints.jl") + end + + # Don't run ODEInterface tests on prerelease + if !is_APPVEYOR && GROUP == "ODEInterfaceRegression" && isempty(VERSION.prerelease) activate_odeinterface_env() @time @safetestset "Init dt vs dorpri tests" include("odeinterface/init_dt_vs_dopri_tests.jl") @time @safetestset "ODEInterface Regression Tests" include("odeinterface/odeinterface_regression.jl") @@ -171,7 +202,12 @@ end end @time @safetestset "Autoswitch GPU" include("gpu/autoswitch.jl") @time @safetestset "Linear LSRK GPU" include("gpu/linear_lsrk.jl") + @time @safetestset "Linear Exponential GPU" include("gpu/linear_exp.jl") @time @safetestset "Reaction-Diffusion Stiff Solver GPU" include("gpu/reaction_diffusion_stiff.jl") @time @safetestset "Scalar indexing bug bypass" include("gpu/hermite_test.jl") end + + if !is_APPVEYOR && GROUP == "QA" + @time @safetestset "Quality Assurance Tests" include("qa/qa_tests.jl") + end end # @time