-
-
Notifications
You must be signed in to change notification settings - Fork 6
3rd and 4th order methods #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
7a03460
0594c49
adcbcd5
5615f47
aa18c94
8e837e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,8 +146,9 @@ end | |
|
|
||
| This example is written for exactly two operators. A scheme that works for any number | ||
| of them loops over `children` with `Unrolled.@unroll`, as the built-in algorithms in | ||
| `src/solver.jl` do; a plain `for` loop over the heterogeneously typed tuple would be | ||
| type unstable. | ||
| `src/solvers/` do; a plain `for` loop over the heterogeneously typed tuple would be | ||
| type unstable. `advance_one_child!` above is `src/solvers/common.jl`'s | ||
| `_advance_child!`, which the built-in schemes share. | ||
|
|
||
| ### Adaptive algorithms | ||
|
|
||
|
|
@@ -177,9 +178,94 @@ end | |
| OrdinaryDiffEqCore interface for the estimate; go through them rather than touching | ||
| the `EEst` field, whose location on the integrator is an implementation detail. | ||
|
|
||
| See [`PalindromicPairLieTrotterGodunov`](@ref) in `src/solver.jl` for a complete | ||
| example, and [Adaptive time stepping](@ref) for how the two layers of adaptivity | ||
| interact. | ||
| See [`PalindromicPairLieTrotterGodunov`](@ref) in `src/solvers/adjoint_pair.jl` for a | ||
| complete example, and [Adaptive time stepping](@ref) for how the two layers of | ||
| adaptivity interact. | ||
|
|
||
| ## Coefficient tables | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this PR we can automatically generate all the schemes with real coefficients here http://www.othmar-koch.org/splitting/index.php?rc=0&ab=am-32-ab&name=AM%203-2 right? What machinery is missing for complex time schemes?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not much (if anything). I think the complex coords are just complex solutions to the same constraint equations. The only tricky part is it makes all your stages complex. |
||
|
|
||
| Schemes of order three and above are not written out as passes over the children. | ||
| They are described by a table of coefficients and stepped by one shared traversal, | ||
| which lives in `src/solvers/coefficients.jl`; the schemes themselves | ||
| (`src/solvers/tables.jl`) are then little more than the table plus two interface | ||
| methods. See [Higher order splittings](@ref theory_higher-order) for where the | ||
| tables come from. | ||
|
|
||
| ```@docs | ||
| OrdinaryDiffEqOperatorSplitting.SplittingCoefficients | ||
| OrdinaryDiffEqOperatorSplitting.coefficients | ||
| OrdinaryDiffEqOperatorSplitting.order | ||
| ``` | ||
|
|
||
| A table-driven scheme is added by giving it a struct, a table, `coefficients`, | ||
| `order`, and an `init_cache` returning the shared | ||
| `SplittingCoefficientsCache` — no stepping code of its own: | ||
|
|
||
| ```julia | ||
| struct MyThirdOrder{AlgTupleType <: Tuple} <: | ||
| OrdinaryDiffEqOperatorSplitting.AbstractOperatorSplittingAlgorithm | ||
| inner_algs::AlgTupleType | ||
| end | ||
|
|
||
| const MY_COEFFICIENTS = OrdinaryDiffEqOperatorSplitting.SplittingCoefficients( | ||
| (7 // 24, 2 // 3), (3 // 4, -2 // 3), (-1 // 24, 1 // 1) | ||
| ) | ||
|
|
||
| OrdinaryDiffEqOperatorSplitting.coefficients(::MyThirdOrder) = MY_COEFFICIENTS | ||
| OrdinaryDiffEqOperatorSplitting.order(::MyThirdOrder) = 3 | ||
|
|
||
| function OrdinaryDiffEqOperatorSplitting.init_cache( | ||
| f::GenericSplitFunction, alg::MyThirdOrder; | ||
| uprev::AbstractArray, u::AbstractVector, | ||
| ) | ||
| return OrdinaryDiffEqOperatorSplitting.SplittingCoefficientsCache( | ||
| u, uprev, OrdinaryDiffEqOperatorSplitting.coefficients(alg)) | ||
| end | ||
| ``` | ||
|
|
||
| Only the consistency condition is checked when the table is built, so a table that | ||
| constructs successfully can still fail to reach the order it claims; a convergence | ||
| test is the only real check. | ||
|
|
||
| Two properties of the traversal are worth knowing when reading or extending it: | ||
|
|
||
| - **A zero coefficient is skipped entirely**, synchronization included, since the | ||
| flow is the identity. `Yoshida4`'s last stage relies on this. | ||
| - **The first flow of a step is always synchronized.** Strang-Marchuk skips that | ||
| sync because its reverse pass ends on operator 1, leaving that child's buffer | ||
| current; a general table ends on operator `N`, so operator 1's buffer is stale and | ||
| the same shortcut would silently corrupt every step after the first. | ||
|
|
||
| Because a table with negative coefficients steps some children backward, a | ||
| table-driven scheme also depends on the direction reversal described under | ||
| [Backward sub-steps](@ref devdocs_backward-substeps). | ||
|
|
||
| If the scheme's order is odd, wrapping it in `AdjointPair` makes it adaptive for | ||
| free: the adjoint is the same table traversed backwards, so nothing further is | ||
| needed from the scheme. | ||
|
|
||
| Any published two- or three-operator table with real coefficients — the `AB`/`ABC` | ||
| tables of [AuzHofKetKoc:2017:psm](@cite) and the collections derived from them — can | ||
| be added this way, needing nothing but the coefficients themselves. | ||
|
|
||
| The [complex-coefficient schemes](@ref theory_higher-order) are the exception. The | ||
| traversal would not change for them, but everything downstream of `coefficient * dt` | ||
| would: the sub-problems, their states and their inner integrators would all have to | ||
| be complex, as would the error norms and step size controllers. That is a property of | ||
| the problem being split rather than of the table, so it is not something a table | ||
| alone can opt into. | ||
|
|
||
| ## [Backward sub-steps](@id devdocs_backward-substeps) | ||
|
|
||
| An inner integrator fixes its direction of integration when it is constructed, and | ||
| a scheme with negative coefficients has to step it the other way. Rather than build | ||
| two integrators per child, a sub-step against the child's direction reverses the | ||
| child in place, steps, and reverses it back: | ||
|
|
||
| ```@docs | ||
| OrdinaryDiffEqOperatorSplitting.reverse_direction! | ||
| OrdinaryDiffEqOperatorSplitting.tstops_and_saveat_heaps | ||
| ``` | ||
|
|
||
| ## Dense output | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Devdocs on the tables is missing. Also, do we want to expand the theory section a bit for interested readers in the higher order theory and the connection with the tables?