Resources

Hydro Power (mpex16)

/***************************************************************/
/*                                                             */
/*          S A S   S A M P L E   L I B R A R Y                */
/*                                                             */
/*    NAME: mpex16                                             */
/*   TITLE: Hydro Power (mpex16)                               */
/* PRODUCT: OR                                                 */
/*  SYSTEM: ALL                                                */
/*   PROCS: OPTMODEL                                           */
/*    DATA:                                                    */
/*                                                             */
/* SUPPORT:                             UPDATE:                */
/*     REF:                                                    */
/*    MISC: Example 16 from the Mathematical Programming       */
/*          Examples book.                                     */
/*                                                             */
/***************************************************************/

data period_data;
   input length demand;
   datalines;
6 15000
3 30000
6 25000
3 40000
6 27000
;

data type_data;
   input num_avail min_level max_level unit_cost excess_cost startup_cost;
   datalines;
12  850 2000 1000 2    2000
10 1250 1750 2600 1.30 1000
 5 1500 4000 3000 3     500
;

data hydro_data;
   input hydro $ level unit_cost depth_rate startup_cost;
   datalines;
A  900  90 0.31 1500
B 1400 150 0.47 1200
;

%let reserve = 0.15;
%let min_depth = 15;
%let max_depth = 20;
%let midnight_depth = 16;
%let meters_per_mwh = 1/3000;

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];

   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;

   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;

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

   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]);

   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]);

   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];

   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;