Martin A
Martin A

Reputation: 45

Use Gekko and Python to fit a numerical ODE solution to data

Use Gekko to fit a numerical ODE solution to data.

Hi everyone! I was wondering, if it is possible to fit coefficients of an ODE using GEKKO. I unsuccessfully tried to replicate the example given here.

This is what I have come up with (but is flawed – and I should perhaps mention that my math skills are unfortunately rather poor):

import numpy as np
from gekko import GEKKO

tspan = [0, 0.1, 0.2, 0.4, 0.8, 1]
Ca_data = [2.0081,  1.5512,  1.1903,  0.7160,  0.2562,  0.1495]

m = GEKKO(remote=False)

t = m.Param(value=tspan)
m.time = t
Ca_m = m.Param(value=Ca_data)

Ca = m.Var()

k = m.FV(value=1.3)
k.STATUS = 1

m.Equation( Ca.dt() == -k * Ca)

m.Obj( ((Ca-Ca_m)**2)/Ca_m )

m.options.IMODE = 2
m.solve(disp=True)
print(k.value[0]) #2.58893455 is the solution

Can someone help me out here? Thank you very much, Martin

(This is my first post here – please be gentle, if I have done something not appropriate.)

Upvotes: 4

Views: 489

Answers (1)

John Hedengren
John Hedengren

Reputation: 14346

Your solution was close but you needed:

  • More NODES (default=2) to improve the accuracy. Gekko only adds that points that you define. See additional information on collocation.
  • Define Ca as m.CV() to use built-in error model instead of m.Var() and m.Obj with NODES>=3. Otherwise, the internal nodes of each collocation interval are also matched to the measurements and this gives a slightly wrong answer.
  • Set EV_TYPE=2 to use a squared error. An absolute value objective EV_TYPE=1 (default) gives a correct but slightly different answer.
import numpy as np
from gekko import GEKKO

m = GEKKO(remote=False)
m.time = [0, 0.1, 0.2, 0.4, 0.8, 1]
Ca_data = [2.0081,  1.5512,  1.1903, 0.7160,  0.2562,  0.1495]
Ca = m.CV(value=Ca_data); Ca.FSTATUS = 1 # fit to measurement
k = m.FV(value=1.3); k.STATUS = 1        # adjustable parameter
m.Equation(Ca.dt()== -k * Ca)            # differential equation

m.options.IMODE = 5   # dynamic estimation
m.options.NODES = 5   # collocation nodes
m.options.EV_TYPE = 2 # squared error
m.solve(disp=True)    # display solver output
print(k.value[0])     # 2.58893455 is the curve_fit solution

The solution is k=2.5889717102. A plot shows the match to the measured values.

import matplotlib.pyplot as plt  # plot solution
plt.plot(m.time,Ca_data,'ro')
plt.plot(m.time,Ca.value,'bx')
plt.show()

Parameter Estimation Solution

There are additional tutorials and course material on parameter estimation with differential and algebraic equation models.

Upvotes: 1

Related Questions