Lindo Systems

SETS:     ! (unitcom5);
! Electrical generator unit commitment planning;
! Keywords: Electricity generation, Hydro electric, 
  Multi-period planning, Unit commitment;

! The set of all generators;
 GENR: CF, CG, CS, MXG, INITY;
 PERIOD: DEM;
 GXP( GENR, PERIOD): X, YON, YOF, Z;
!  Units with time varying capacity;
 VGEN( GENR);
 VXP( VGEN, PERIOD): VMXG;
!  Hydro and pumped storage units;
 HNP( GENR): FLO, IMX, INI;
 HXP( HNP, PERIOD): INV, SPILL;
!  Pumped storage units;
 STORE( GENR): PF, PMX;
 SXP( STORE, PERIOD): W;
ENDSETS
DATA:
 GENR = COAL01 GAS001 GAS002 WIND01 HYDRO1 PUMP01;! The units;
  CF  =   2775   5980   5290      1    2.0    1.9;! Fixed cost/period if spinning;
  CG  =     14     22     25      1    1.1      2;! Cost/MWH generated;
  CS  =  90000  12900   8000   1700    800    790;! Cost to start spinning;
 MXG  =   1100    760    680    600    900    660;! Max gen capacity in period;
 INITY  =     0     0      0      0      0      0;! Initially spinning or not;
 PERIOD = 1..24;
  DEM =   900 1790 2380 2490 1520 1298 2200 1030
         1900 2360 1900 1790 1690 1650 1600 1600
         1700 1800 1900 1600 1400 1200 1100 1000; ! Demand in MWH;

 ! Units with variable capacity;
  VGEN = WIND01;  ! Capacity in each period;
  VMXG =   180  210  270  280 310  200 300 250
           150  100  100  100 100   90  90 100
           120  120  130  130 130  140 150 170; 

 ! Hydro and pumped storage units;
  HNP = HYDRO1 PUMP01;! Name of the hydro and pumped units;
  FLO =  220     0;  ! Inflow per period;
  IMX = 1000   970;  ! Max inventory level;
  INI =   200    0;  ! Initial inventory;

 ! Pumped storage;
  STORE = PUMP01;
     PF = 1.3; ! MWH needed to put 1 MWH in storage;
    PMX = 320; ! Max pumped into storage/period;

 ! Here the data are stored directly in the model file. Alternatively,
  attribute DEM can be read from a spreadsheet by the statement:
     DEM = @OLE( );
! if: 
       a) there is only one spreadsheet open in Excel,
       b) there is a range in the spreadsheet of the appropriate
          shape with name DEM;
 ! Similarly, answers can be sent back to the spreadsheet with
   statements like:
    @OLE( ) = X;

ENDDATA
SUBMODEL UnitCom:
! X(i,t) = amount generated by i in period t;
! Z(i,t) = 1 if i is running in t;
! YON(i,t) = 1 if i is started in t;
! YOF(i,t) = 1 if i is turned off in t;
! W(i,t) = amount pumped into i in period t;

! Minimize sum of start-up, spinning, and energy costs;
MIN = @SUM( GXP( I, T): CS(I)*YON(I,T) + CF(I)* Z(I,T) + CG(I)*X(I,T));

! Constraints applicable to all generators;
! Must satisfy demand + used for pumping;
@FOR( PERIOD( T):
   @SUM( GENR( I): X(I,T)) = DEM(T) + @SUM(STORE(I): PF(I)*W(I,T)) ;
     ); 

@FOR( GENR( I):
! Generator I has to be spinning (Z(I,T) =1) to get any power;
 @FOR( PERIOD( T):
       X(I,T) <= MXG( I) * Z(I,T);
      );
 @FOR( PERIOD( T):
      @BIN(Z(I,T));
      );

! Turn on YON(I,T) if generator I starts at the beginning of period T,
  and YOF(I,T) if generator stops at the beginning of period T;
    YON(I,1) - YOF(I,1) = Z(I,1) - INITY( I); ! Period 1 is special;
  @FOR( PERIOD(T) | T #GT# 1:
    YON(I,T) - YOF(I,T) = Z(I,T) - Z(I,T-1);
    YON(I,T) + YOF(I,T) <= 1; ! Cannot both turn on and off in a period;
      );
     );

! These constraints apply to variable capacity units;
@FOR( VXP( I,T): 
    X(I,T) <= VMXG(I,T);
    );

! For plain hydro, we have the inventory equations;
@FOR( HNP(I)| #NOT# @IN(STORE, I ):
! For period 1;
   INI( I) + FLO(I) = INV(I,1) + X(I,1) + SPILL(I,1);
   INV(I,1) <= IMX(I);
! Remaining periods;
   @FOR( PERIOD(T)| T #GT# 1:
    INV(I,T-1) + FLO(I) = INV(I,T) + X(I,T) + SPILL(I,T);
    INV(I,T) <= IMX(I);
       );
    );

! For pumped storage;
@FOR( STORE(I):
! Beginning Inv + flow in + pumped in
       = ending inv + generated + spilled;
! For period 1;
   INI( I) + FLO(I) + W(I,1) = INV(I,1) + X(I,1) + SPILL(I,1);
   INV(I,1) <= IMX(I);
   W(I,1) <= PMX(I);
! Remaining periods;
   @FOR( PERIOD(T)| T #GT# 1:
    INV(I,T-1) + FLO(I)+ W(I,T) = INV(I,T) + X(I,T) + SPILL(I,T);
    INV(I,T) <= IMX(I);
    W(I,T) <= PMX( I)
       );
    );
ENDSUBMODEL

CALC:
 @SET( 'TERSEO', 2); ! Set output level to TERSE;
 @SOLVE(UnitCom);

 @WRITE(@NEWLINE(1), ' Here is a simple report:', @NEWLINE(1));
 @WRITE('Prd  Demand ');
! List the names of the generators at the top;
 @FOR( GENR(i):
   @WRITE('  ',GENR(i));
     );
  @WRITE(@NEWLINE(1));
! Loop over the periods;
 @FOR( PERIOD(t):
    @WRITE(@FORMAT(t,'2.0f'),'   ',@FORMAT(DEM(t),'6.1f'),' ');
    @FOR( GENR(i):
      @IFC(X(i,t) #GT# 0.001:
         @WRITE(' ',@FORMAT(X(i,t),'7.2f'));
        @ELSE
         @WRITE('        '); ! Show blank if zero;
         );
        );
     @WRITE(@NEWLINE(1));
     );
ENDCALC