Version:

tanksize.gms : Tank Size Design Problem

**Description**

We discuss a tank design problem for a multi product plant, in which the optimal cycle time and the optimal campaign size are unknown. A mixed in- teger nonlinear programming formulation is presented, where non-convexities are due to the tank investment cost, storage cost, campaign setup cost and variable production rates. The objective of the optimization model is to minimize the sum of the production cost per ton per product produced. A continuous-time mathematical programming formulation for the problem is implemented with a fixed number of event points.

**Small Model of Type :** MINLP

**Category :** GAMS Model library

**Main file :** tanksize.gms

```
$title Tank Size Design Problem - (TANKSIZE,SEQ=350)
$onText
We discuss a tank design problem for a multi product plant, in which the
optimal cycle time and the optimal campaign size are unknown. A mixed in-
teger nonlinear programming formulation is presented, where non-convexities
are due to the tank investment cost, storage cost, campaign setup cost and
variable production rates. The objective of the optimization model is to
minimize the sum of the production cost per ton per product produced. A
continuous-time mathematical programming formulation for the problem is
implemented with a fixed number of event points.
Rebennack, S, Kallrath, J, and Pardalos, P M, Optimal Storage Design
for a Multi-Product Plant: A Non-Convex MINLP Formulation. Tech. rep.,
University of Florida, 2009. Submitted to Computers and Chemical
Engineering
Keywords: mixed integer nonlinear programming, storage design, global optimization
continuous-time model, chemical engineering
$offText
$eolCom //
$sTitle Define the Model Size and Data
Set
p 'products' / P1*P3 /
n 'event points' / N1*N3 /;
Parameter
PRMIN(p) 'volume flow of products in m^3 per day'
PRMAX(p) 'volume flow of products in m^3 per day'
SLB(p) 'lower bound on inventory in m^3'
SUB(p) 'upper bound on inventory in m^3'
SI(p) 'initial inventory in m^3 (10% of the lower bound)'
DLB(p) 'lower bound on PRODUCTION length d(n)'
DUB(p) 'upper bound on PRODUCTION length d(n)'
DEMAND(p) 'volume flow of products in m^3 per year!!'
TS(p) 'campaign setup times in days'
CSTI(p) 'tank variable cost per ton'
CSTC(p) 'campaign setup cost'
B 'variable part of the tank investment cost' / 0.3271 /;
Table pdata(p,*)
prmin prmax slb sub si dlb dub demand ts csti cstc
P1 15.0 50.0 643.0 4018.36 707.0 1 40 4190 0.4 18.8304 10
P2 15.0 50.0 536.0 3348.63 589.0 1 40 3492 0.2 19.2934 20
P3 7.0 50.0 214.0 1339.45 235.0 1 40 1397 0.1 19.7563 30;
$onEchoV > assignpar.gms
$label start
%1(p) = pdata(p,'%1');
$shift
$if not x%1 == x $goto start
$offEcho
$batInclude assignpar prmin prmax slb sub si dlb dub demand ts csti cstc
* Derived data
Parameter
DPD(p) 'compute the demand per day per product [tons per day]'
L 'compute the demand per day [tons per day]'
CAL 'longest campain'
PRL 'maximum production length'
CSTCMin 'minimum setup cost'
CSTCMax 'maximum setup cost';
DPD(p) = DEMAND(p)/365;
L = sum(p, DPD(p));
CSTI(p) = CSTI(p)/365; // scale the storage cost
CAL = max(0, smax(p, DUB(p) + TS(p)));
PRL = max(0, smax(p, DUB(p)));
CSTCMin = smin(p, CSTC(p));
CSTCMax = smax(p, CSTC(p));
$sTitle Model Formulation
Alias (p,pp);
Positive Variable
d(n) 'duration of the campaigns'
pC(p,n) 'amount of product p produced in campaign n'
s(p,n) 'amount of product p stored at the beginning of campaign n'
sM(p) 'size of the product tanks in tons'
sH(p,n) 'auxiliary variables'
cI 'investment costs'
cC 'campaign setup costs'
cS 'variable storage costs'
T 'cycle time';
Binary Variable
omega(p,n) 'binary variable indicating product in campaign';
Variable
cPT 'cost per ton: the objective variable to minimize';
Equation
TIMECAP 'time capacity'
UNIQUE(n) 'at most one product per campaign'
MATBAL(p,n) 'material balance constraint'
TANKCAP(p,n) 'tank capacity constraint'
PPN1(p,n) 'compute the nonlinear products pR(rp)*d(n)*omega'
PPN2(p,n) 'compute the nonlinear products pR(rp)*d(n)*omega'
SCCam1(n) 'semi-continuous bound on campaigns'
SCCam2(n) 'semi-continuous bound on campaigns'
DEFcC 'campaign setup costs'
DEFcI 'investment cost'
DEFcS 'variable storage costs'
DefsH(p,n) 'define the auxiliary variables'
DEFcPT 'total costs per ton produced'
NONIDLE(n) 'force not to be idle';
* time balance constraint with unknown cycle time T
TIMECAP.. sum(n, d(n) + sum (p, TS(p)*omega(p,n))) =e= T;
* at most one product per campaign
UNIQUE(n).. sum(p, omega(p,n)) =l= 1;
* no idle states are allowed
NONIDLE(n).. sum(p, DUB(p)*omega(p,n)) =g= d(n);
* material balance equation (steady state):
* storage at end of n for product p = storage at start of n+1 for product p
* storage at end of n for product p = storage at start of n
* + total production of product p in n
* - total demand in period n
MATBAL(p,n)..
s(p,n++1) =e= s(p,n) + pC(p,n) - DPD(p)*(d(n) + sum(pp, TS(pp)*omega(pp,n)));
* tank capacity constraint:
* this connects the tank desing capacity variable with the storage level
TANKCAP(p,n).. s(p,n) =l= sM(p);
* compute the nonlinear products: pR(p,n)*d(n)*omega
* connects the production of product p in period n with
* -> the omega variables
* -> the lenght of the PRODUCTION period
* -> the production rate
* PPN(p,n).. pC(p,nbl(n)) =e= pR(p,n)*d(n)*omega(p,n);
PPN1(p,n).. pC(p,n) =l= PRMAX(p)*d(n)*omega(p,n);
PPN2(p,n).. pC(p,n) =g= PRMIN(p)*d(n)*omega(p,n);
* semi-continuous lower and upper bound on campaigns
SCCam2(n).. d(n) =g= sum(p, DLB(p)*omega(p,n));
SCCam1(n).. d(n) =l= sum(p, DUB(p)*omega(p,n));
* define the total costs per ton: cPT
DEFcPT.. (cPT*L - cI )*T =e= cC + cS;
* define the campaign setup costs
DEFcC.. cC =e= sum((p,n), CSTC(p)*omega(p,n));
* define the tank investment costs
DEFcI.. cI =e= B*sum(p, sqrt(sM(p)));
* define the variable tank costs
DEFcS.. cS =e= sum((p,n), CSTI(p)*sH(p,n)
*(d(n) + sum(pp, TS(pp)*omega(pp,n))));
* auxiliary variables for the objective
DefsH(p,n).. sH(p,n) =e= 0.5*(s(p,n++1) + s(p,n)) - SLB(p);
* additional constraints to break symmetry
Equation
SEQUENCE(p,n) 'redundant consteraint on the omega'
SYMMETRY(n) 'break the symmetry of active campaigns';
* if a product is produced during period n, then it cannot be produced during
* period n+1
SEQUENCE(p,n).. 1 - omega(p,n) =g= omega(p,n+1);
* break symmetry buy shift empty periods to the end
SYMMETRY(n).. sum(p, omega(p,n)) =g= sum(p, omega(p,n+1));
* lower und upper bound on inventory
s.lo(p,n) = SLB(p);
s.up(p,n) = SUB(p);
* initial storage
s.fx('P1','N1') = SLB('P1');
* the initial storage has some implications
omega.fx(p,'N1') = 0;
omega.fx('P1','N1') = 1;
omega.fx('P1','N2') = 0;
* lower and upper bound on tank size
sM.lo(p) = SLB(p);
sM.up(p) = SUB(p);
Model Sequenz / all /;
* Get out of the poor starting point
omega.l(p,n) = uniform(0,1);
solve Sequenz using minlp minimizing cPT;
```