I plan to use GEKKO to solve a dynamic production scheduling problem involving a supply, process, consume process flow with hold-up (storage) between some steps. I want to maximise some objective over the horizon. However, at some timesteps there may be pre-defined limitations on processing capacities of some unit operations. While I can use the fix(var,val,pos)
function to fix the variable entirely at pos
, constraining it on the UPPER
side better represent what I want to accomplish and will probably yield a different solution in some scenarios.
Here are some toy problem code, that does not contain the dynamics yet):
"""
Simple toy problem to test flexibillity of limiting MV's at certain time points in the
horizon without fixing them specifically, i.e. leave one bound unconstrained.
"""
from gekko import GEKKO
m=GEKKO(remote=False)
m.time=[0,1,2,3,4] #Use 5 discrete points
m.options.CV_TYPE = 1
supply2=m.Param(5.5) #Supply of stream2 available to a separation unit op
recovery=m.Const(value=0.92) #Extraction efficiency of unit op
feed1=m.MV(20,lb=15,ub=40) #define feed 1 as an independent variable
feed2=m.MV(5,lb=0,ub=10) #define feed 2 as an independent variable
feed1.COST=1 #cost of feed stream 1
feed2.COST=1.5 #cost of feed stream 2
feed1.STATUS=1 #use feed1 in optimisation
feed2.STATUS=1 #use feed2 in optimisation
ovhds=m.CV(30) #define ovhds of unit op as dependent variable
ovhds.STATUS=1 #use in Objective function
ovhds.SPLO=40 #low limit for dependent variable
ovhds.SPHI=50 #high limit for dependenent variable
ovhds.COST=-2 # negative cost (aka profit) from extracted stream
feed1.UPPER=48 #set overall upper limit of 48 for feed1 MV
m.fix(feed1,47,2) #fix feed 1 at a point pos=2 in the horizon
#TODO: add dynamics e.g. differential equations to model inventory volumes.
supply2_flared=m.Intermediate(feed2-supply2) #another independent variable
total_feed=m.Intermediate(feed1+feed2) #the total intake of feed
m.Equation(ovhds==total_feed*recovery) #define relationship between dependent and independent variable
m.options.IMODE=6 #dynamic control, dynamics and dynamic constraints to be added as Equations later.
m.solve()
print("Feed1",feed1.value)
print("Feed2", feed2.value)
print("Product", ovhds.value)
Define a time-varying parameter such as feed1_ub
and include an inequality constraint with m.Equation()
.
feed1_ub = m.Param([48,48,30,48,48])
m.Equation(feed1<=feed1_ub)
Here is a complete script:
from gekko import GEKKO
m=GEKKO(remote=False)
m.time=[0,1,2,3,4] #Use 5 discrete points
m.options.CV_TYPE = 1
supply2=m.Param(5.5) #Supply of stream2 available to a separation unit op
recovery=m.Const(value=0.92) #Extraction efficiency of unit op
feed1=m.MV(20,lb=15,ub=40) #define feed 1 as an independent variable
feed2=m.MV(5,lb=0,ub=10) #define feed 2 as an independent variable
feed1.COST=1 #cost of feed stream 1
feed2.COST=1.5 #cost of feed stream 2
feed1.STATUS=1 #use feed1 in optimisation
feed2.STATUS=1 #use feed2 in optimisation
ovhds=m.CV(30) #define ovhds of unit op as dependent variable
ovhds.STATUS=1 #use in Objective function
ovhds.SPLO=40 #low limit for dependent variable
ovhds.SPHI=50 #high limit for dependenent variable
ovhds.COST=-2 # negative cost (aka profit) from extracted stream
feed1.UPPER=48 #set overall upper limit of 48 for feed1 MV
supply2_flared=m.Intermediate(feed2-supply2) #another independent variable
total_feed=m.Intermediate(feed1+feed2) #the total intake of feed
m.Equation(ovhds==total_feed*recovery) #define relationship between dependent and independent variable
feed1_ub = m.Param([48,48,30,48,48])
m.Equation(feed1<=feed1_ub)
m.options.IMODE=6 #dynamic control, dynamics and dynamic constraints to be added as Equations later.
m.solve()
print("Feed1",feed1.value)
print("Feed2", feed2.value)
print("Product", ovhds.value)
Solution
EXIT: Optimal Solution Found.
The solution was found.
The final value of the objective function is -92.03399437705355
---------------------------------------------------
Solver : IPOPT (v3.12)
Solution time : 0.043 sec
Objective : -92.03399324684949
Successful solution
---------------------------------------------------
Feed1 [20.0, 48.0, 30.000000009, 48.0, 48.0]
Feed2 [5.0, 6.3478260396, 10.0, 6.3478260399, 6.3478260394]
Product [30.0, 49.999999965, 36.8000001, 49.999999965, 49.999999965]