Adding a new package to the common interface

Adding a new package to the common interface

DiffEq's distributed infrastructure allows anyone to add new packages to the common interface. This set of the documentation explains how this is done. An example package is DASRK.jl whose full common interface bindings are contained in common.jl.

Defining the types

You should start by defining a common supertype for all your algorithm types. DASKR has DAE algorithms, so it defines

abstract type DASKRDAEAlgorithm{LinearSolver} <: AbstractDAEAlgorithm end

that its algorithms are all AbstractDAEAlgorithms and gives them a possible type parameter as well. Then the concrete algorithms are specified. Special options (i.e. non-common interface options) for the algorithm go in this type. Here there is a choice for a linear solver internally, so we allow the user to set this but use @pure on the constructor so that way the type is inferred:

immutable daskr{LinearSolver} <: DASKRDAEAlgorithm{LinearSolver} end
Base.@pure daskr(;linear_solver=:Dense) = daskr{linear_solver}()

In many (most?) cases, no extra constructor is needed since there are no extra options.

Defining the overloads

Now you need to add DiffEqBase. The package should reexport DiffEqBase.jl to make using it alone act naturally, and this is done by:

using Reexport
@reexport using DiffEqBase

now we overload solve from DiffEqBase.jl to act on our algorithm. Here's a possible signature:

import DiffEqBase: solve
function solve{uType,duType,tType,isinplace,LinearSolver}(
    timeseries = [], ts = [], ks = [];

    callback = nothing, abstol = 1/10^6, reltol = 1/10^3,
    saveat = Float64[], adaptive = true, maxiters = Int(1e5),
    timeseries_errors = true, save_everystep = isempty(saveat), dense = save_everystep,
    save_start = true, save_timeseries = nothing,
    userdata = nothing,

Basically you just dispatch on your algorithm supertype (and refine the Problem choice as well so it errors on the wrong problem types), then list the common interface options. timeseries = [], ts = [], ks = []; are for pre-allocation of arrays, and this may change in the near future but you can use this to pre-allocate the t, u, and k arrays (k being internal steps if saved).

Defining the solution

In solve you do option handling and call your solver. At the end, you return the solution via:

               du = dures,
               dense = dense,
               timeseries_errors = timeseries_errors,
               retcode = :Success)

Giving du is only currently allowed for DAEs and is optional. The errors flags (timeseries_errors and dense_errors) are flags for allowing the solution to calculate errors which should be passed through the solve function if applicable. A proper retcode should be placed or it will default to :Default.