I am new to Gekko and I am trying to model a production process. The model is working as expected, but I am failing to understand how to implement an equation that constraints the minimum output of my output variable. My code:
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
maxspeed = 30 # rev/hr
minspeed = 2 #rev/hr
lowrev = 1/(maxspeed/3600) # how fast can we go as sec/rev
highrev = 1/(minspeed/3600) # ow slow can we go as sec/rev
batchsize = 0.5
m = GEKKO(remote=False)
m.time = np.linspace(0,200,201)
tfr = m.Param(value=54.2)
subf = m.Param(value=13.47)
drumd = m.Param(value=2.9)
a1m = m.Param(value=1814.28)
dl = m.Param(value=0.42)
drumspeed = m.MV(value=400, lb=lowrev, ub=highrev)
drumspeed.STATUS = 1
drumspeed.DMAX = 2
filtrationvol = m.Var(value=0, lb=0)
m.Equation(filtrationvol == tfr*(m.sqrt(4*a1m*m.acos(1-
2*dl/drumd)*drumspeed/drumd))/(2*a1m*subf*drumspeed)) # output model
m.Maximize(filtrationvol)
m.options.IMODE = 6 # control mode
m.solve(disp=True)
I want to limit the total output of variable filtrationvol to a maximum of 0.5, meaning I want to maximize the output but only up to a certain point. I have been playing around with m.sum and m.vsum but without success.
Use the integral function to get the total filtration volume.
m.Equation(total_Vfilt == m.integral(filtrationvol))
You can either include a hard constraint with total_Vfilt<0.5
or you can set up a soft constraint (objective function) with a CV
type. A rearrangement of the equation makes it easier for the solver because it avoids m.sqrt()
and a potential divide by zero if the drum speed ever needs to go to zero.
m.Equation((2*a1m*subf*drumspeed*filtrationvol/tfr)**2 \
==(4*a1m*m.acos(1-2*dl/drumd)*drumspeed/drumd))
An initialization strategy with COLDSTART=1
also helps the solver because it sets the STATUS=0
to simulate and obtain a better initial guess before optimizing.
m.options.COLDSTART = 1
m.solve(disp=False)
m.options.TIME_SHIFT= 0
m.options.COLDSTART = 0
m.solve(disp=True)
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
maxspeed = 30 # rev/hr
minspeed = 2 #rev/hr
lowrev = 1/(maxspeed/3600) # how fast can we go as sec/rev
highrev = 1/(minspeed/3600) # ow slow can we go as sec/rev
batchsize = 0.5
m = GEKKO(remote=False)
m.time = np.linspace(0,200,201)
tfr = m.Param(value=54.2)
subf = m.Param(value=13.47)
drumd = m.Param(value=2.9)
a1m = m.Param(value=1814.28)
dl = m.Param(value=0.42)
drumspeed = m.MV(value=400, lb=lowrev, ub=highrev)
drumspeed.STATUS = 1
drumspeed.DMAX = 2
filtrationvol = m.Var(value=0.0, lb=0)
m.Equation((2*a1m*subf*drumspeed*filtrationvol/tfr)**2 \
==(4*a1m*m.acos(1-2*dl/drumd)*drumspeed/drumd))
m.Maximize(filtrationvol)
# summation with an integral
total_Vfilt = m.CV(0,lb=0) # hard constraint with ub=0.5
# total_Vfilt.UPPER = 0.5 # or adjust .UPPER
m.Equation(total_Vfilt == m.integral(filtrationvol))
# soft constraint with abs() value penalty for exceeding limit
total_Vfilt.SPHI = 0.5; total_Vfilt.SPLO = 0.0
total_Vfilt.WSPHI = 1000
total_Vfilt.STATUS = 1
m.options.IMODE = 6 # control mode
m.options.SOLVER = 3 # IPOPT solver
m.options.COLDSTART = 1
m.solve(disp=False)
m.options.TIME_SHIFT= 0
m.options.COLDSTART = 0
m.solve(disp=True)
plt.figure(figsize=(12,6))
plt.subplot(4,1,1)
plt.plot(m.time,drumspeed.value,'r-',label='Sdrum')
plt.legend()
plt.subplot(4,1,2)
plt.plot(m.time,drumspeed.value,'r-',label='Sdrum')
plt.plot([0,200],[lowrev,lowrev],'k:',label='Limits')
plt.plot([0,200],[highrev,highrev],'k:')
plt.legend()
plt.subplot(4,1,3)
plt.plot(m.time,filtrationvol.value,'b--',label='Vfilt')
plt.legend()
plt.subplot(4,1,4)
plt.plot(m.time,total_Vfilt.value,'b:',\
label=r'$\int(Vfilt)$')
plt.plot([0,200],[0.5,0.5],'k-',label='Limit')
plt.legend()
plt.xlabel('Batch / Time')
plt.show()