I am new to GEKKO and also to modeling bioreactors, so I might be missing something obvious.
I have a system of 10 ODEs that describe a fed-batch bioreactor. All constants are given. The picture below shows the expected behavior of this model (extracted from a paper). However, the only feasible solution I found is when Viable Cells Density (XV) = 0, and stays 0 for all time t, or if time T is really small (<20). If a lower boundary >= 0 or initial value is set to XV and t > 20, the system becomes infeasible.
Equations and constants were checked multiple times. I tried giving initial values to my variables, but it didn't work either. I can only think of two problems: I am not initiating variables properly, or I am not using GEKKO properly. Any ideas? Thanks!!
import numpy as np
from gekko import GEKKO
import matplotlib.pyplot as plt
m = GEKKO(remote=False) # create GEKKO model
#constants 3L continuous fed-batch
KdQ = 0.001 #degree of degradation of glutamine (1/h)
mG = 1.1*10**-10 #glucose maintenance coefficient (mmol/cell/hour)
YAQ = 0.90 #yield of ammonia from glutamine
YLG = 2 #yield of lactate from glucose
YXG = 2.2*10**8 #yield of cells from glucose (cells/mmol)
YXQ = 1.5*10**9 #yield of cells from glutamine (cells/mmol)
KL = 150 #lactate saturation constant (mM)
KA = 40 #ammonia saturation constant (mM)
Kdmax = 0.01 #maximum death rate (1/h)
mumax = 0.044 #maximum growth rate (1/h)
KG = 1 #glucose saturation constant (mM)
KQ = 0.22 #glutamine saturation constant (mM)
mQ = 0 #glutamine maintenance coefficient (mmol/cell/hour)
kmu = 0.01 #intrinsic death rate (1/h)
Klysis = 2*10**-2 #rate of cell lysis (1/h)
Ci_star = 100 #inhibitor saturation concentration (mM)
qi = 2.5*10**-10 #specific inhibitor production rate (1/h)
#Flow, volume and concentration
Fo = 0.001 #feed-rate (L/h)
Fi = 0.001 #feed-rate (L/h)
V = 3 #volume (L)
SG = 653 #glucose concentration in the feed (mM)
SQ = 58.8 #glutamine concentration in the feed (mM)
# create GEKKO parameter
t = np.linspace(0,120,121)
m.time = t
XT = m.Var(name='XT') #total cell density (cells/L)
XV = m.Var(lb=0, name='XV') #viable cell density (cells/L)
XD = m.Var(name='XD') #dead cell density (cells/L)
G = m.Var(value = 30, name='G') #glucose concentration (mM)
Q = m.Var(value = 4.5, name='Q') #glutamine concentration (mM)
L = m.Var(name='L') #lactate concentration (mM)
A = m.Var(name='A') #ammonia concentration (mM)
Ci = m.Var(name='Ci') #inhibitor concentration (mM)
mu = m.Var(name='mu') #growth rate (1/h)
Kd = m.Var(name='Kd') #death rate(1/h)
# create GEEKO equations
m.Equation(XT.dt() == mu*XV - Klysis*XD - XT*Fo/V)
m.Equation(XV.dt() == (mu - Kd)*XV - XV*Fo/V)
m.Equation(XD.dt() == Kd*XV - Klysis*XD - XV*Fo/V)
m.Equation(G.dt() == (Fi/V)*SG - (Fo/V)*G + (-mu/YXG - mG)*XV)
m.Equation(Q.dt() == (Fi/V)*SQ - (Fo/V)*Q + (-mu/YXQ - mQ)*XV - KdQ*Q)
m.Equation(L.dt() == -YLG*(-mu/YXG -mG)*XV-(Fo/V)*L)
m.Equation(A.dt() == -YAQ*(-mu/YXQ - mQ)*XV +KdQ*Q-(Fo/V)*A)
m.Equation(Ci.dt() == qi*XV - (Fo/V)*Ci)
m.Equation(mu.dt() == (mumax*G*Q*(Ci_star-Ci)) / (Ci_star*(KG+G)*(KQ+Q)*(L/KL + 1)*(A/KA + 1)))
m.Equation(Kd.dt() == Kdmax*(kmu/(mu+kmu)))
# solve ODE
m.options.IMODE = 4
m.open_folder()
m.solve(display = False)
plt.plot(m.time, XV.value)
Articles that used the exact same model:
1) Master thesis using GEKKO "MODELING OF MAMMALIAN CELL CULTURE" link:
2) Original paper describing the equations: "Process Model Comparison and Transferability Across Bioreactor Scales and Modes of Operation for a Mammalian Cell Bioprocess"
link: https://sci-hub.tw/10.1002/btpr.1664
3) Paper with a control sytem using that model: "Glucose concentration control of a fed-batch mammalian cell bioprocess using a nonlinear model predictive controller"
link: https://sci-hub.tw/https://doi.org/10.1016/j.jprocont.2014.02.007