I'm trying to simulate a basic biological system: growth of activated sludge in a reactor fed by wastewater.
It has two variables and two reactions. This is a very basic model and used extensively (more elaborate) in wastewater engineering.
The solver seems very unstable: frequently doesn't find a solution of goes haywire (large overshoots). The model is very smooth, no rapid changes after an initial little jump.
I tried the IMODE = 4 (dynamic simultaneous) but fails most of the time. Currently running with IMODE = 7 (dynamic sequential). Works for time interval from 0.1 - 4 days, but fails with larger period (5 days and up). This while the system is more or less stable after 0.2 days (see below).
The solver also takes quiet a long time to solve. While I was hoping to use it for much larger work.
My questions: Is there something wrong with my code, or is it the solver? Can the code be improved to speed up the simulation?
This test ran in a Jupyter notebook (chrome) with following packages installed: gekko, numpy, matplotlib.
# Basic setup:
# two variables: S en X
# two reaction: aerobic growth and decay
# one reactor: in and out
# ASM parameters (activated sludge model)
Y = 0.67 # g/g COD
fp = 0.08 # -
mu_h = 6.0 # /d
Ks = 20 # g/m3 COD
b_h = 0.62 # /d
# setup parameters
V = 100 # m3, reactor volume
Q = 50 # m3/d, flow rate to reactor
Sin = 1000 # g/m3
Xin = 0 # g/m3
# Build gekko model:
m = GEKKO()
m.options.IMODE = 7 # dynamic, sequential, simulation
m.time = np.linspace(start=0, stop=3, num=100) # FAILS AT LARGER TIME FRAME
# create state variables
S = m.Var(value=100) # substrate
X = m.Var(value=500) # biomass
# intermediates: reaction rates
r_ag = m.Intermediate(mu_h*S/(Ks + S)*X) # reaction rate, aerobic growth
r_ad = m.Intermediate(b_h*X) # rate, aerobic decay
# constraint equations
m.Equation(V*S.dt() == Q*Sin - Q*S +(-1/Y*r_ag + (1-fp)*r_ad)*V) # mass balance for S
m.Equation(V*X.dt() == Q*Xin - Q*X + (1*r_ag -1*r_ad)*V) # mass balance for X
# solve
m.solve(disp=False)
# plot results
plt.plot(m.time, S, 'g:', label='S')
plt.plot(m.time, X, 'b-', label='X')
plt.legend(loc='best')

