nefeli
nefeli

Reputation: 53

Python GEKKO ODE unexpected results

I've been trying to implement an ODE model for simulation of the insulin signaling pathway, as it is presented in the supplementary material of this paper, using python's GEKKO.

The model variation implemented was the ‘Md3’, with the following equations, constant and initial values:

equations

Even though the paper does not provide the supplementary code’s outcome, one would expect the results to be curves, instead of the ones that result from my code:enter image description here

I have checked the equations and constant values, tried adding lower and upper bounds to the variables and experimented with the m.options.IMODE and m.options.NODES parameters, but these didn't seem to help.

Any piece of advice would be much appreciated.

def insulin_pathway_CM(time_interval, insulin=0): 

    m = GEKKO()
    t = np.linspace(0, time_interval-1, time_interval)
    m.time = np.insert(t,1,[1e-5,1e-4,1e-3,1e-2,0.1])

    # initialization of variables
    ins = m.Param(value=insulin)
    IR = m.Var(10)
    IRp = m.Var()
    IRS = m.Var(10)
    IRSp = m.Var()
    PKB = m.Var(10)
    PKBp = m.Var()
    GLUT4_C = m.Var(10)
    GLUT4_M = m.Var()
  
    # initialization of constants                                                                                                                                                 
    k1aBasic = 1863.78                                                                   
    k1f = 38668.300000000003                                                             
    k1b = 40229000                                                                       
    k2f = 401394                                                                         
    k2b = 36704300                                                                       
    k4f = 336782                                                                         
    k4b = 187399  
    k5Basic = 85530.899999999994  
    k5f = 11264.799999999999 
    k5b = 26389900   

    # equations
    m.Equation(IR.dt() == k1b*IRp - (k1f*ins*1000*IR + k1aBasic*IR))
    m.Equation(IRp.dt() == -k1b*IRp + k1f*ins*1000*IR + k1aBasic*IR)
    m.Equation(IRS.dt() == k2b*IRSp - (k2f*IRp*IRS))
    m.Equation(IRSp.dt() == -k2b*IRSp + k2f*IRp*IRS)
    m.Equation(PKB.dt() == k4b*PKBp - k4f*IRSp*PKB)
    m.Equation(PKBp.dt() == -k4b*PKBp + k4f*IRSp*PKB)
    m.Equation(GLUT4_C.dt() == k5b*GLUT4_M - (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))
    m.Equation(GLUT4_M.dt() == -k5b*GLUT4_M + (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))

    m.options.IMODE = 7
    m.options.OTOL  = 1e-8
    m.options.RTOL  = 1e-8
    m.options.NODES = 3
    m.solve(disp=False)

    # plotting
    fig, axs = plt.subplots(4, 2, figsize=(20, 20))
    axs[0, 0].plot(m.time, IR)
    axs[0, 0].set_title('IR(t)')
    axs[0, 1].plot(m.time, IRp)
    axs[0, 1].set_title('IRp(t)')
    axs[1, 0].plot(m.time, IRS, 'tab:orange')
    axs[1, 0].set_title('IRS(t)')
    axs[1, 1].plot(m.time, IRSp, 'tab:green')
    axs[1, 1].set_title('IRSp(t)')
    axs[2, 0].plot(m.time, PKB, 'tab:red')
    axs[2, 0].set_title('PKB(t)')
    axs[2, 1].plot(m.time, PKBp, 'tab:purple')
    axs[2, 1].set_title('PKBp(t)')
    axs[3, 0].plot(m.time, GLUT4_C, 'tab:olive')
    axs[3, 0].set_title('GLUT4_C(t)')
    axs[3, 1].plot(m.time, GLUT4_M, 'tab:cyan')
    axs[3, 1].set_title('GLUT4_M(t)')
    
    plt.figure()
    plt.show()
    return

time_interval = 60
insulin = 100
insulin_pathway_CM(time_interval, insulin)

Upvotes: 3

Views: 62

Answers (1)

John Hedengren
John Hedengren

Reputation: 14346

Lutz Lehmann is correct. A plot of the derivatives with an ending time of 1e-5 shows that most of the action happens in a short period of time.

derivatives

Try a shorter time span.

m.time = np.linspace(0,1e-5,100)

This shows the fast dynamics.

fast dynamics

There is likely an error with the equations such as a units issue (time in days or years?) or the authors forgot to include some type of volume factor for the patient such as blood volume or body volume.

# equations
V1 = 1e9  # hypothetical volume 1
V2 = 10   # hypothetical volume 2
m.Equation(V1*IR.dt() == k1b*IRp - (k1f*ins*1000*IR + k1aBasic*IR))
m.Equation(V1*IRp.dt() == -k1b*IRp + k1f*ins*1000*IR + k1aBasic*IR)
m.Equation(V1*IRS.dt() == k2b*IRSp - (k2f*IRp*IRS))
m.Equation(V1*IRSp.dt() == -k2b*IRSp + k2f*IRp*IRS)
m.Equation(V2*PKB.dt() == k4b*PKBp - k4f*IRSp*PKB)
m.Equation(V2*PKBp.dt() == -k4b*PKBp + k4f*IRSp*PKB)
m.Equation(V2*GLUT4_C.dt() == k5b*GLUT4_M - (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))
m.Equation(V2*GLUT4_M.dt() == -k5b*GLUT4_M + (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))

Here are more reasonable dynamics with the original time scale (0-60 hrs).

Original time scale

from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt

def insulin_pathway_CM(time_interval, insulin=0): 

    m = GEKKO()
    t = np.linspace(0, time_interval-1, time_interval)
    m.time = np.insert(t,1,[1e-5,1e-4,1e-3,1e-2,0.1])

    # initialization of variables
    ins = m.Param(value=insulin)
    IR = m.Var(10)
    IRp = m.Var()
    IRS = m.Var(10)
    IRSp = m.Var()
    PKB = m.Var(10)
    PKBp = m.Var()
    GLUT4_C = m.Var(10)
    GLUT4_M = m.Var()
  
    # initialization of constants
    k1aBasic = 1863.78      
    k1f = 38668.300000000003  
    k1b = 40229000  
    k2f = 401394 
    k2b = 36704300 
    k4f = 336782
    k4b = 187399  
    k5Basic = 85530.899999999994  
    k5f = 11264.799999999999 
    k5b = 26389900   

    # calculate derivatives
    d = m.Array(m.Var,8)
    m.Equation(d[0] == k1b*IRp - (k1f*ins*1000*IR + k1aBasic*IR))
    m.Equation(d[1] == -k1b*IRp + k1f*ins*1000*IR + k1aBasic*IR)
    m.Equation(d[2] == k2b*IRSp - (k2f*IRp*IRS))
    m.Equation(d[3] == -k2b*IRSp + k2f*IRp*IRS)
    m.Equation(d[4] == k4b*PKBp - k4f*IRSp*PKB)
    m.Equation(d[5] == -k4b*PKBp + k4f*IRSp*PKB)
    m.Equation(d[6] == k5b*GLUT4_M - (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))
    m.Equation(d[7] == -k5b*GLUT4_M + (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))    

    # equations
    V1 = 1e9  # hypothetical volume 1
    V2 = 10   # hypothetical volume 2
    m.Equation(V1*IR.dt() == k1b*IRp - (k1f*ins*1000*IR + k1aBasic*IR))
    m.Equation(V1*IRp.dt() == -k1b*IRp + k1f*ins*1000*IR + k1aBasic*IR)
    m.Equation(V1*IRS.dt() == k2b*IRSp - (k2f*IRp*IRS))
    m.Equation(V1*IRSp.dt() == -k2b*IRSp + k2f*IRp*IRS)
    m.Equation(V2*PKB.dt() == k4b*PKBp - k4f*IRSp*PKB)
    m.Equation(V2*PKBp.dt() == -k4b*PKBp + k4f*IRSp*PKB)
    m.Equation(V2*GLUT4_C.dt() == k5b*GLUT4_M - (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))
    m.Equation(V2*GLUT4_M.dt() == -k5b*GLUT4_M + (k5f*PKBp*GLUT4_C + k5Basic*GLUT4_C))

    m.options.IMODE = 4
    m.options.OTOL  = 1e-8
    m.options.RTOL  = 1e-8
    m.options.NODES = 3
    m.solve(disp=True)

    # plotting
    fig, axs = plt.subplots(4, 2, figsize=(20, 20))
    axs[0, 0].plot(m.time, IR)
    axs[0, 0].set_title('IR(t)')
    axs[0, 1].plot(m.time, IRp)
    axs[0, 1].set_title('IRp(t)')
    axs[1, 0].plot(m.time, IRS, 'tab:orange')
    axs[1, 0].set_title('IRS(t)')
    axs[1, 1].plot(m.time, IRSp, 'tab:green')
    axs[1, 1].set_title('IRSp(t)')
    axs[2, 0].plot(m.time, PKB, 'tab:red')
    axs[2, 0].set_title('PKB(t)')
    axs[2, 1].plot(m.time, PKBp, 'tab:purple')
    axs[2, 1].set_title('PKBp(t)')
    axs[3, 0].plot(m.time, GLUT4_C, 'tab:olive')
    axs[3, 0].set_title('GLUT4_C(t)')
    axs[3, 1].plot(m.time, GLUT4_M, 'tab:cyan')
    axs[3, 1].set_title('GLUT4_M(t)')

    plt.figure()
    for i in range(8):
        plt.plot(m.time,d[i].value)
    
    plt.show()
    return

time_interval = 60
insulin = 100
insulin_pathway_CM(time_interval, insulin)

For reference, here is a simplified blood glucose response model (similar to Bergman model) for your reference. Richard Bergman and Claudio Cobelli proposed a minimal model in 1979 to describe blood glucose and insulin dynamics.

Upvotes: 3

Related Questions