Skip to content

Speeding up condition-specific parameters

Some models include parameters whose values differ across simulation conditions. For such problems, when gradients are computed with automatic differentiation (gradient_method = :ForwardDiff or gradient_method = :ForwardEquations), runtime can often be reduced substantially by setting split_over_conditions = true when constructing a PEtabODEProblem.

This page explains when and why this helps, and assumes familiarity with condition-specific parameters (see Simulation condition-specific parameters). As a working example, the published Beer model [27] available in the PEtab standard format is used (see Importing PEtab problems). Given the PEtab files (downloadable from here), the problem can be imported with:

julia
using PEtab
# path_yaml depends on where the problem is saved
path_yaml = joinpath(@__DIR__, "beer", "Beer_MolBioSystems2014.yaml")
model = PEtabModel(path_yaml)

Efficient handling of condition-specific parameters

The Beer problem has 4 species and 9 ODE parameters, but 72 parameters are estimated because many parameters are simulation condition-specific. For example, cond1 has τ_cond1 and cond2 has τ_cond2, which both map to the ODE parameter τ. This is reflected by the model statistics are:

julia
using Catalyst
petab_prob = PEtabODEProblem(model)
println("Number of ODE model species      = ", length(unknowns(model.sys)))
println("Number of ODE model parameters   = ", length(parameters(model.sys)))
println("Number of parameters to estimate = ", length(petab_prob.xnames))
Number of ODE model species      = 4
Number of ODE model parameters   = 9
Number of parameters to estimate = 72

For small ODE systems, gradient_method = :ForwardDiff is typically fastest, and hessian_method = :ForwardDiff is often feasible. By default, PEtab.jl computes derivatives with a single ForwardDiff.gradient call over all simulation conditions. For condition-specific parameters this can be wasteful: if n directional passes are needed for the full parameter vector, condition i may only require n_i < n passes because many parameters are inactive in that condition.

To reduce this overhead, split_over_conditions = true computes derivatives per condition (one ForwardDiff call per simulation condition). Here, the effect on gradient runtime is noticeable:

julia
using Printf
petab_prob1 = PEtabODEProblem(model; split_over_conditions = true)
petab_prob2 = PEtabODEProblem(model; split_over_conditions = false)
x = get_x(petab_prob1)
g1, g2 = similar(x), similar(x)
b1 = @elapsed petab_prob1.grad!(g1, x)
b2 = @elapsed petab_prob2.grad!(g2, x)
@printf("Runtime split_over_conditions = true: %.2fs\n", b1)
@printf("Runtime split_over_conditions = false: %.2fs\n", b2)
Runtime split_over_conditions = true: 0.15s
Runtime split_over_conditions = false: 0.92s

For the Hessian, the difference is typically even larger:

julia
h1, h2 = zeros(length(x), length(x)), zeros(length(x), length(x))
b1 = @elapsed petab_prob1.hess!(h1, x)
b2 = @elapsed petab_prob2.hess!(h2, x)
@printf("Runtime split_over_conditions = true: %.1fs\n", b1)
@printf("Runtime split_over_conditions = false: %.1fs\n", b2)
Runtime split_over_conditions = true: 1.6s
Runtime split_over_conditions = false: 67.9s

A natural question is why split_over_conditions = true is not always the default. The reason is overhead: evaluating ForwardDiff separately per condition can be slower when there are few or no condition-specific parameters due to overhead. PEtab.jl therefore uses a heuristic and enables split_over_conditions by default when the number of condition-specific parameters is at least twice the number of ODE parameters. This heuristic is conservative, so for models with many condition-specific parameters it is recommended to benchmark split_over_conditions = true vs false.

References

  1. R. Beer, K. Herbst, N. Ignatiadis, I. Kats, L. Adlung, H. Meyer, D. Niopek, T. Christiansen, F. Georgi, N. Kurzawa and others. Creating functional engineered variants of the single-module non-ribosomal peptide synthetase IndC by T domain exchange. Molecular BioSystems 10, 1709–1718 (2014).