Example: ODEModels as subproblems using CallableNumericalModel

Imagine that you want to use ODE fitting, but your data aren’t directly linked to an ODE variable. In this case, you can use the class :class:symfit.core.models.CallableNumericalModel.

Given are the variables x, y and z. x and y and the parameter a form an ODE model, where the derivative contains (due to the e-function) y. z is the result of a function with y and the additional parameter b.

a and b must be optimized, as shown below. The class uses the given model dictionary and the information about the variable and the parameters to fit the data.

[1]:
from symfit import variables, Parameter, Fit, D, ODEModel, CallableNumericalModel
import numpy as np
import matplotlib.pyplot as plt

# Create data
x_data = np.linspace(0.0, 10.0, 1000)
a_expected = 0.6
b_expected = 10.0
z_data = 2 * np.exp(a_expected * x_data) + b_expected

# Initialise variables and parameters
x, y, z = variables('x, y, z')
a = Parameter('a', 0.0)
b = Parameter('b', 0.0)

# Define model
ode_model = ODEModel({D(y, x): a * y}, initial={x: 0.0, y: 1.0})
model_dict = {
    z: 2 * y + b,
    y: lambda x, a: ode_model(x=x, a=a).y,
}
model = CallableNumericalModel(model_dict, connectivity_mapping={z: {y, b}, y: {x, a}})

# Apply model
fit = Fit(model, x=x_data, z=z_data)
fit_result = fit.execute()
[2]:
print('a =', fit_result.value(a))
a = 0.5999999794526922
[3]:
print('b =', fit_result.value(b))
b = 10.000011508837998