Hydro Power: How to Generate and Combine Hydro and Thermal Electricity Generation

PROC OPTMODEL Statements and Output

For completeness, all statements are shown. Statements that are new or changed from Chapter 15 are indicated.

proc optmodel;
   set PERIODS;
   num length {PERIODS};
   num demand {PERIODS};
   read data period_data into PERIODS=[_N_] length demand;

   set TYPES;
   num num_avail {TYPES};
   num min_level {TYPES};
   num max_level {TYPES};
   num unit_cost {TYPES};
   num excess_cost {TYPES};
   num startup_cost {TYPES};
   read data type_data into TYPES=[_N_]
      num_avail min_level max_level unit_cost excess_cost startup_cost;

   var NumWorking {PERIODS, type in TYPES} >= 0 <= num_avail[type] integer;
   var Excess {PERIODS, TYPES} >= 0;
   var NumStartup {PERIODS, type in TYPES} >= 0 <= num_avail[type] integer;
   impvar Output {period in PERIODS, type in TYPES} =
      min_level[type] * NumWorking[period,type] + Excess[period,type];

The following statements declare the additional index set and parameters and then read the additional input data:

   set <str> HYDROS;
   num hydro_level {HYDROS};
   num hydro_unit_cost {HYDROS};
   num hydro_depth_rate {HYDROS};
   num hydro_startup_cost {HYDROS};
   read data hydro_data into HYDROS=[hydro]
      hydro_level=level hydro_unit_cost=unit_cost hydro_depth_rate=depth_rate
      hydro_startup_cost=startup_cost;

The following statements declare additional variables and fix the value of Depth[1]:

   var HydroNumWorking {PERIODS, HYDROS} binary;
   var HydroNumStartup {PERIODS, HYDROS} binary;
   var Depth {PERIODS} >= &min_depth <= &max_depth;
   fix Depth[1] = &midnight_depth;
   var Pump {PERIODS} >= 0;

The following IMPVAR statement declares HydroOutput as a new implicit variable:

   impvar HydroOutput {period in PERIODS, hydro in HYDROS} =
      hydro_level[hydro] * HydroNumWorking[period,hydro];

The following MIN statement is a modification of the objective declaration from Chapter 15:

   min TotalCost =
      sum {period in PERIODS, type in TYPES} (
         unit_cost[type] * length[period] * NumWorking[period,type]
         + excess_cost[type] * length[period] * Excess[period,type]
         + startup_cost[type] * NumStartup[period,type])
      + sum {period in PERIODS, hydro in HYDROS} (
         hydro_unit_cost[hydro] * length[period] *
            HydroNumWorking[period,hydro]
         + hydro_startup_cost[hydro] * HydroNumStartup[period,hydro]);

The following two CON statements are modified from Chapter 15:

   con Demand_con {period in PERIODS}:
      sum {type in TYPES} Output[period,type]
    + sum {hydro in HYDROS} HydroOutput[period,hydro]
    - Pump[period]
   >= demand[period];

   con Reserve_con {period in PERIODS}:
      sum {type in TYPES} max_level[type] * NumWorking[period,type]
    + sum {hydro in HYDROS} hydro_level[hydro] *
         HydroNumWorking[period,hydro].ub
   >= (1 + &reserve) * demand[period];

   con Excess_ub {period in PERIODS, type in TYPES}:
      Excess[period,type]
   <= (max_level[type] - min_level[type]) * NumWorking[period,type];

   con Startup_con {period in PERIODS, type in TYPES}:
      NumStartup[period,type]
   >= NumWorking[period,type]
    - (if period - 1 in PERIODS then NumWorking[period-1,type]
       else NumWorking[card(PERIODS),type]);

The following two CON statements declare the final two additional constraints:

   con Hydro_startup_con {period in PERIODS, hydro in HYDROS}:
      HydroNumStartup[period,hydro]
   >= HydroNumWorking[period,hydro]
    - (if period - 1 in PERIODS then HydroNumWorking[period-1,hydro]
       else HydroNumWorking[card(PERIODS),hydro]);

   con Depth_con {period in PERIODS}:
      (if period + 1 in PERIODS then Depth[period+1] else Depth[1])
    = Depth[period]
    + &meters_per_mwh * length[period] * Pump[period]
    - sum {hydro in HYDROS} hydro_depth_rate[hydro] * length[period] *
         HydroNumWorking[period,hydro];

The following statements call the mixed integer linear programming solver, print the optimal solution, and create several data sets that contain various parts of the optimal solution, with variables grouped according to their index sets:

   solve;
   print NumWorking NumStartup Excess Output;
   print HydroNumWorking HydroNumStartup HydroOutput;
   print Pump Depth;
   create data sol_data1 from [period type]
      NumWorking NumStartup Excess Output;
   create data sol_data2 from [period hydro]
      HydroNumWorking HydroNumStartup HydroOutput;
   create data sol_data3 from [period] Pump Depth;
quit;

Figure 16.1 shows the output from the mixed integer linear programming solver.

Figure 16.1: Output from Mixed Integer Linear Programming Solver

The OPTMODEL Procedure

Problem Summary
Objective SenseMinimization
Objective FunctionTotalCost
Objective TypeLinear
  
Number of Variables75
Bounded Above0
Bounded Below20
Bounded Below and Above54
Free0
Fixed1
Binary20
Integer30
  
Number of Constraints55
Linear LE (<=)15
Linear EQ (=)5
Linear GE (>=)35
Linear Range0
  
Constraint Coefficients190

Performance Information
Execution ModeSingle-Machine
Number of Threads4

Solution Summary
SolverMILP
AlgorithmBranch and Cut
Objective FunctionTotalCost
Solution StatusOptimal
Objective Value986630
  
Relative Gap0
Absolute Gap0
Primal Infeasibility1.554312E-15
Bound Infeasibility0
Integer Infeasibility0
  
Best Bound986630
Nodes24
Iterations623
Presolve Time0.01
Solution Time0.05

[1][2]NumWorkingNumStartupExcessOutput
1112036510565
123015005250
130000
21120405014250
2296450015750
230000
31120010200
3290450015750
330000
411201115021350
4290450015750
431101500
51120010200
5290450015750
530000

[1][2]HydroNumWorkingHydroNumStartupHydroOutput
1A000
1B000
2A000
2B000
3A000
3B000
4A000
4B111400
5A000
5B101400

[1]PumpDepth
181516.00
2017.63
395017.63
4019.53
535018.12