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 Sense Minimization
Objective Function TotalCost
Objective Type Linear
   
Number of Variables 75
Bounded Above 0
Bounded Below 20
Bounded Below and Above 54
Free 0
Fixed 1
Binary 20
Integer 30
   
Number of Constraints 55
Linear LE (<=) 15
Linear EQ (=) 5
Linear GE (>=) 35
Linear Range 0
   
Constraint Coefficients 190

Performance Information
Execution Mode Single-Machine
Number of Threads 4

Solution Summary
Solver MILP
Algorithm Branch and Cut
Objective Function TotalCost
Solution Status Optimal
Objective Value 986630
   
Relative Gap 0
Absolute Gap 0
Primal Infeasibility 1.219944E-15
Bound Infeasibility 0
Integer Infeasibility 0
   
Best Bound 986630
Nodes 48
Iterations 843
Presolve Time 0.00
Solution Time 0.05

[1] [2] NumWorking NumStartup Excess Output
1 1 12 0 0 10200
1 2 3 0 1500 5250
1 3 0 0 0 0
2 1 12 0 4050 14250
2 2 9 6 4500 15750
2 3 0 0 0 0
3 1 12 0 365 10565
3 2 9 0 4500 15750
3 3 0 0 0 0
4 1 12 0 11150 21350
4 2 9 0 4500 15750
4 3 1 1 0 1500
5 1 12 0 0 10200
5 2 9 0 4500 15750
5 3 0 0 0 0

[1] [2] HydroNumWorking HydroNumStartup HydroOutput
1 A 0 0 0
1 B 0 0 0
2 A 0 0 0
2 B 0 0 0
3 A 0 0 0
3 B 0 0 0
4 A 0 0 0
4 B 1 1 1400
5 A 0 0 0
5 B 1 0 1400

[1] Pump Depth
1 450 16.00
2 0 16.90
3 1315 16.90
4 0 19.53
5 350 18.12