{----------------------------------------------------------------------------}
{                                                                            }
{      Program :  UNITCOMM.PAS                                               }
{ Last Revised :  April 25, 1994                                             }
{      Version :  1.0                                                        }
{                                                                            }
{       Author :  David F. Gadberry                                          }
{                 Graduate Student - Electrical Engineering                  }
{                 Rose-Hulman Institute of Technology                        }
{                 5500 Wabash Avenue Box #391                                }
{                 Terre Haute, IN  47803                                     }
{                 (812) 235-9309                                             }
{                                                                            }
{      Purpose :  Performs generation scheduling using dynamic programming.  }
{                                                                            }
{----------------------------------------------------------------------------}
PROGRAM UNITCOMM;
USES CRT, DOS, UTIL, UNITLIB, STRINGS, WINDOS;
VAR
  A            : REAL;                             { TEMP. WORK VARIABLE  }
  AA           : INTEGER;                          { TEMP. LOOP VARIABLE  }
  B            : REAL;                             { TEMP. WORK VARIABLE  }
  BB           : INTEGER;                          { TEMP. VARIABLE       }
  C            : REAL;                             { TEMP. WORK VARIABLE  }
  CC           : INTEGER;                          { TEMP. LOOP VARIABLE  }
  CFG_PATH     : STRING [40];                      { PATH FOR CONFIG FILE }
  CHEAP        : ARRAY [1..168, 1..12] OF REAL;    { RECORD OF CHEAP SCHED}
  CHEAPEST     : REAL;                             { CHEAPEST COST        }
  CHOICE       : CHAR;                             { USED FOR PROMPTS     }
  CCHOICE      : CHAR;                             { USED FOR PROMPTS     }
  COL          : ARRAY [1..10] OF INTEGER;         { USED IN LIST_CREATE  }
  COL_D        : ARRAY [1..10] OF INTEGER;         { USED IN LIST_CREATE  }
  COL_T        : ARRAY [1..10] OF INTEGER;         { USED IN LIST_CREATE  }
  COST         : REAL;                             { ENERGY COST          }
  COST_MAT     : ARRAY [1..10, 1..4] OF REAL;      { COST FUNCTION MATRIX }
  COST_MAT_ALL : ARRAY [1..10, 1..4] OF REAL;      { COST FUNC FOR ALL GEN}
  COST_TOTAL   : REAL;                             { TOTAL COST           }
  D            : REAL;                             { TEMP. WORK VARIABLE  }
  DD           : INTEGER;                          { TEMP. LOOP VARIABLE  }
  DATAFILE     : TEXT;                             { USED FOR SAVING DATA }
  DEF_PATH     : STRING [40];                      { DEFAULT FILE PATH    }
  DOWN_TIME    : ARRAY [1..9] OF REAL;             { DOWN TIME RESTRICTION}
  E            : REAL;                             { TEMP. WORK VARIABLE  }
  EE           : INTEGER;                          { TEMP. WORK VARIABLE  }
  ENG_COST     : ARRAY [1..9] OF REAL;             { ARRAY OF ENG. COST   }
  F            : REAL;                             { TEMP. WORK VARIABLE  }
  FC           : INTEGER;                          { FLAG FOR FILE_CHECK  }
  FILE_NAME    : STRING [70];                      { USED FOR SAVING DATA }
  FLAG1        : INTEGER;                          { FLAG FOR TEMP. WORK  }
  FLAG2        : INTEGER;                          { FLAG FOR TEMP. WORK  }
  FLAG3        : INTEGER;                          { FLAG FOR TEMP. WORK  }
  GEN_TIME     : ARRAY [1..9] OF INTEGER;          { ON & OFF TIMES OF GEN}
  GEN_TIME_I   : ARRAY [1..9] OF INTEGER;          { INIT. GEN. TIMES     }
  H1, M1       : WORD;                             { USED TO TIME PROC.   }
  S1, SS1      : WORD;                             { USED TO TIME PROC.   }
  H2, M2       : WORD;                             { USED TO TIME PROC.   }
  S2, SS2      : WORD;                             { USED TO TIME PROC.   }
  I            : INTEGER;                          { LOOP VARIABLE        }
  INIT_POINT   : INTEGER;                          { INITIAL POINTER      }
  INIT_COST    : REAL;                             { INITIAL COST         }
  J            : INTEGER;                          { LOOP VARIABLE        }
  K            : INTEGER;                          { LOOP VARIABLE        }
  KEEP         : INTEGER;                          { # OF COMB. TO KEEP   }
  L            : INTEGER;                          { LOOP VARIABLE        }
  LAST_STATE   : ARRAY [1..9] OF INTEGER;          { INITIAL SYSTEM STATE }
  M            : INTEGER;                          { LOOP VARIABLE        }
  LAMBDA       : REAL;                             { SEARCH LAMBDA        }
  LIST_STATE   : ARRAY [1..512] OF CHAR;           { STATUS OF EACH LIST  }
  LIST_S_OLD   : ARRAY [1..512] OF CHAR;           { OLD STATE CONDITION  }
  LL           : INTEGER;                          { MAIN LOOP VARIABLE   }
  LOAD_PAT_MAT : ARRAY [1..168, 1..2] OF REAL;     { LOAD PATTERN MATRIX  }
  ML           : INTEGER;                          { MAIN LOOP VARIABLE   }
  MAX_GEN      : REAL;                             { MAX. GENERATION      }
  MAX_LAM      : ARRAY [1..9] OF REAL;             { MATRIX OF MAX LAMBDAS}
  MAXP_MAT     : ARRAY [1..9] OF REAL;             { MAX POWER OF GEN UNIT}
  MAXP_MAT_ALL : ARRAY [1..9] OF REAL;             { MAX POWER OF ALL UNIT}
  MAX_MIN      : ARRAY [1..512, 1..2] OF REAL;     { MAX-MIN GEN OF P LIST}
  MIN_GEN      : REAL;                             { MIN. GENERATION      }
  MIN_LAM      : ARRAY [1..9] OF REAL;             { MATRIX OF MIN LAMBDAS}
  MINP_MAT     : ARRAY [1..9] OF REAL;             { MIN POWER OF GEN UNIT}
  MINP_MAT_ALL : ARRAY [1..9] OF REAL;             { MIN POWER OF ALL UNIT}
  NAME         : STRING [12];                      { USED FOR SAVING DATA }
  NF           : INTEGER;                          { FLAG FOR NO_FILE     }
  NUM          : INTEGER;                          { # OF GEN IN LIST_CREA}
  NUM_DIS      : INTEGER;                          { # OF GEN FOR DISPATCH}
  NUM_GEN      : INTEGER;                          { TOTAL # OF GENERATORS}
  NUM_LIST     : INTEGER;                          { # IN PRIORITY LIST   }
  NUM_LOAD_PAT : INTEGER;                          { # OF LOAD PATTERNS   }
  OFFSET       : INTEGER;                          { OFFSET USED IN SHOW  }
  ORIGMODE     : INTEGER;                          { LAST STATE OF VIDEO  }
  PAIRS        : INTEGER;                          { COUNT VAR IN SORT    }
  PATH_NAME    : STRING [40];                      { USED FOR SAVING DATA }
  PEN_FAC      : ARRAY [1..9] OF REAL;             { PEN. FAC. OF EACH UNI}
  PRI_LIST     : ARRAY [1..512, 1..10] OF INTEGER; { PRIORITY LIST MATRIX }
  POW_GEN      : REAL;                             { POWER GENERATED      }
  POW_OUT      : ARRAY [1..9] OF REAL;             { POWER OUT OF EACH UNI}
  POW_REQ      : REAL;                             { POWER REQUESTED      }
  S            : STRING [1];                       { TEMP STRING VARIABLE }
  SCH_LIST     : ARRAY [1..168] OF INTEGER;        { RECORD OF SCHED.     }
  SCOST        : REAL;                             { COST + STARTUP COST  }
  SDCOST       : REAL;                             { SHUTDOWN COST        }
  SEARCH       : INTEGER;                          { # OF COMB. TO SEARCH }
  SM           : REAL;                             { SCREEN MODE          }
  SSTG         : STRING [5];                       { FILE VARIABLE        }
  STARTUP_MAT  : ARRAY [1..9, 1..3] OF REAL;       { STARTUP COSTS & RESC.}
  STEMP1       : ARRAY [1..511] OF INTEGER;        { SORT TEMP. VARIABLE  }
  STEMP2       : ARRAY [1..511] OF REAL;           { SORT TEMP. VARIABLE  }
  ST           : REAL;                             { SORT TEMP. VARIABLE  }
  STI          : INTEGER;                          { SORT TEMP. VARIABLE  }
  TCOST        : REAL;                             { TOTAL COST           }
  TEMP         : ARRAY [1..20] OF INTEGER;         { TEMP. WORK MATRIX    }
  TEMP1        : INTEGER;                          { TEMP. VARIABLE       }
  TIME         : REAL;                             { TIME OF COMPUTATIONS }
  TIME_OLD     : ARRAY [1..511, 1..9] OF INTEGER;  { OLD TIME ARRAY       }
  TIME_NEW     : ARRAY [1..511, 1..9] OF INTEGER;  { TIME ARRAY           }
  TOTAL        : INTEGER;                          { TOTAL # OF LISTS     }
  UP_TIME      : ARRAY [1..9] OF REAL;             { UP TIME RESTRICTIONS }
  VERSION      : REAL;                             { CURRENT VERSION      }
  XX           : INTEGER;                          { LOOP VARIABLE        }

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : DISPATCH                                                   }
{  Last Revised : April 12, 1994                                             }
{       Purpose : Performs economic dispatch for the given generators.       }
{                                                                            }
{----------------------------------------------------------------------------}
  
PROCEDURE DISPATCH;
VAR
  ACCUR         : REAL;                             { DETER ACC OF ITER    }
  DER_MAT       : ARRAY [1..9, 1..3] OF REAL;       { DERIV. OF COST MATRIX}
  GEN_STATE     : ARRAY [1..9] OF CHAR;             { STATUS OF EACH GEN.  }
  LAM_STEP      : REAL;                             { STEP VALUE OF LAMBDA }
  MAX_GEN       : REAL;                             { TOTAL MAX. GENERATION}
  MAX_LAMBDA    : REAL;                             { MAX LAMBDA FOR SEARCH}
  MIN_GEN       : REAL;                             { TOTAL MIN. GENERATION}
  MIN_LAMBDA    : REAL;                             { MIN LAMBDA FOR SEARCH}
  OLD_GEN_STATE : ARRAY [1..9] OF CHAR;             { SAVES OLD GEN. STATES}
  OLD_LAMBDA    : REAL;                             { SAVES VALUE FOR LAMBD}
  WORK_MAT      : ARRAY [1..9, 1..4] OF REAL;       { WORK MAT FOR DIS ROUT}
BEGIN
  MIN_GEN := 0;
  MAX_GEN := 0;
  MAX_LAMBDA := 0;
  MIN_LAMBDA := 1000;
  FOR I := 1 TO NUM_DIS DO
    BEGIN
    POW_OUT [I] := 0;
    GEN_STATE [I] := 'R';
    DER_MAT [I, 1] := 3 * COST_MAT [I, 1];
    DER_MAT [I, 2] := 2 * COST_MAT [I, 2];
    DER_MAT [I, 3] := 1 * COST_MAT [I, 3];
    A := DER_MAT [I, 1];
    B := DER_MAT [I, 2];
    C := DER_MAT [I, 3];
    WORK_MAT [I, 1] := 0;
    WORK_MAT [I, 2] := 0;
    IF A <> 0 THEN
      BEGIN
      WORK_MAT [I, 1] := - B / (2 * A);
      WORK_MAT [I, 2] := 1 / (2 * A);
      END;
    WORK_MAT [I, 3] := B * B;
    WORK_MAT [I, 4] := 4 * A;
    MAX_GEN := MAX_GEN + MAXP_MAT [I];
    MIN_GEN := MIN_GEN + MINP_MAT [I];
    D := MINP_MAT [I];
    E := MAXP_MAT [I];
    MIN_LAM [I] := A * D * D + B * D + C;
    MAX_LAM [I] := A * E * E + B * E + C;
    IF MIN_LAM [I] < MIN_LAMBDA THEN
      MIN_LAMBDA := MIN_LAM [I];
    IF MAX_LAM [I] > MAX_LAMBDA THEN
      MAX_LAMBDA := MAX_LAM [I];
    END;
  
  LAMBDA := (MIN_LAMBDA + MAX_LAMBDA) / 2;
  LAM_STEP := (MAX_LAMBDA - MIN_LAMBDA) / 4;
  ACCUR := 1000;
  WHILE ABS (ACCUR) > 0.001 DO
    BEGIN
    POW_GEN := 0;
    FOR I := 1 TO NUM_DIS DO
      BEGIN
      IF LAMBDA < MIN_LAM [I] THEN
        BEGIN
        GEN_STATE [I] := 'L';
        POW_OUT [I] := MINP_MAT [I];
        END;
      IF LAMBDA > MAX_LAM [I] THEN
        BEGIN
        GEN_STATE [I] := 'H';
        POW_OUT [I] := MAXP_MAT [I];
        END;
      A := WORK_MAT [I, 1];
      B := WORK_MAT [I, 2];
      C := WORK_MAT [I, 3];
      D := WORK_MAT [I, 4];
      E := DER_MAT [I, 3];
      IF ( (DER_MAT [I, 1] = 0) AND (GEN_STATE [I] = 'R') ) THEN
        BEGIN
        POW_OUT [I] := (LAMBDA - DER_MAT [I, 3]) / DER_MAT [I, 2];
        END;
      IF ( (DER_MAT [I, 1] <> 0) AND (GEN_STATE [I] = 'R') ) THEN
        BEGIN
        POW_OUT [I] := A + B * SQRT (C - D * (E - LAMBDA) );
        END;
      POW_GEN := POW_GEN + POW_OUT [I];
      OLD_GEN_STATE [I] := GEN_STATE [I];
      GEN_STATE [I] := 'R';
      END;
    ACCUR := POW_GEN - POW_REQ;
    OLD_LAMBDA := LAMBDA;
    IF ACCUR < 0 THEN
      LAMBDA := LAMBDA + LAM_STEP;
    IF ACCUR > 0 THEN
      LAMBDA := LAMBDA - LAM_STEP;
    LAM_STEP := LAM_STEP / 2;
    END;
  LAMBDA := OLD_LAMBDA;
  COST := 0;
  FOR I := 1 TO NUM_DIS DO
    BEGIN
    A := POW_OUT [I];
    COST:= COST+A*A*A*COST_MAT[I,1]+A*A*COST_MAT[I,2]+A*COST_MAT[I,3]+COST_MAT[I,4];
    GEN_STATE [I] := OLD_GEN_STATE [I];
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : LOAD_GEN_DATA                                              }
{  Last Revised : April 11, 1994                                             }
{       Purpose : Loads information from the data files.                     }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE LOAD_GEN_DATA;
BEGIN
  WHILE CHOICE <> '9' DO
    BEGIN
    TITLE (VERSION);
    GOTOXY (1, 25);
    WRITE ('                              ');
    GOTOXY (1, 25);
    WRITE ('PATH:  ', PATH_NAME);
    GOTOXY (1, 5);
    WRITELN ('LOAD DATA MENU:');
    WRITELN;
    WRITELN ('      1 - Load generator data.        *.GEN');
    IF FLAG1 = 1 THEN
      BEGIN
      WRITELN ('      2 - Load priority list.         *.LST');
      END
    ELSE
      BEGIN
      WRITELN ('                                           ');
      END;
    WRITELN ('      3 - Load pattern of loading.    *.LDP');
    WRITELN;
    WRITELN;
    WRITELN ('      8 - Change PATH.');
    WRITELN ('      9 - Exit.');
    WRITELN;
    WRITE ('Please enter your choice: ');
    CHOICE := READKEY;
    IF CHOICE = '1' THEN
      BEGIN
      SSTG := '*.GEN';
      IF PATH_NAME <> 'C:\' THEN
        DELETE (PATH_NAME, (LENGTH (PATH_NAME) ), 1);
      CHDIR (PATH_NAME);
      FILE_NAME := SELECTFROMDIR (SSTG, 1, 3);
      IF PATH_NAME <> 'C:\' THEN
        PATH_NAME := PATH_NAME + '\';
      TEXTCOLOR (LIGHTGRAY);
      IF FILE_CHECK (FILE_NAME, FC) THEN
        BEGIN
        ASSIGN (DATAFILE, FILE_NAME);
        RESET (DATAFILE);
        READLN (DATAFILE, NUM_GEN);
        FOR I := 1 TO NUM_GEN DO
          BEGIN
          READ (DATAFILE, MINP_MAT_ALL [I]);
          READ (DATAFILE, MAXP_MAT_ALL [I]);
          READ (DATAFILE, ENG_COST [I]);
          READ (DATAFILE, PEN_FAC [I]);
          READ (DATAFILE, UP_TIME [I]);
          READ (DATAFILE, DOWN_TIME [I]);
          READ (DATAFILE, STARTUP_MAT [I, 1]);
          READ (DATAFILE, STARTUP_MAT [I, 2]);
          READLN (DATAFILE, STARTUP_MAT [I, 3]);
          END;
        FOR I := 1 TO NUM_GEN DO
          BEGIN
          READ (DATAFILE, COST_MAT_ALL [I, 1]);
          READ (DATAFILE, COST_MAT_ALL [I, 2]);
          READ (DATAFILE, COST_MAT_ALL [I, 3]);
          READLN (DATAFILE, COST_MAT_ALL [I, 4]);
          END;
        CLOSE (DATAFILE);
        GOTOXY (1, 18);
        WRITELN (FILE_NAME, ' loaded.');
        WRITELN;
        WRITE ('PRESS ANY KEY TO CONTINUE.....');
        CHOICE := READKEY;
        GOTOXY (1, 18);
        WRITE ('                                                        ');
        GOTOXY (1, 20);
        WRITE ('                                                        ');
        CHOICE := ' ';
        FLAG1 := 1;
        FOR I := 1 TO NUM_GEN DO
          BEGIN
          COST_MAT_ALL[I,1]:=COST_MAT_ALL[I,1]*ENG_COST[I]*1/(1-PEN_FAC[I]);
          COST_MAT_ALL[I,2]:=COST_MAT_ALL[I,2]*ENG_COST[I]*1/(1-PEN_FAC[I]);
          COST_MAT_ALL[I,3]:=COST_MAT_ALL[I,3]*ENG_COST[I]*1/(1-PEN_FAC[I]);
          COST_MAT_ALL[I,4]:=COST_MAT_ALL[I,4]*ENG_COST[I]*1/(1-PEN_FAC[I]);
          END;
        END
      ELSE
        BEGIN
        NO_FILE (NF);
        END;
      END;
    IF CHOICE = '2' THEN
      BEGIN
      IF FLAG1 = 0 THEN
        BEGIN
        BELL (3500, 300);
        WINDOW (18, 9, 62, 18);
        STOREALPHAWINDOW;
        VIDEO (INV, FALSE);
        WINDOWFRAME (3);
        CLRSCR;
        WRITELN (' When the priority list data is loaded');
        WRITELN (' into the program, calculations are');
        WRITELN (' performed to determine the maximum and');
        WRITELN (' minimum generation possible for each entry.');
        WRITELN (' Since these calculations are based on the');
        WRITELN (' generator specifications, the generator');
        WRITELN (' data must be loaded first.');
        WRITELN;
        WRITELN;
        WRITE ('        PRESS ANY KEY TO CONTINUE...');
        CHOICE := READKEY;
        VIDEO (LOW, FALSE);
        TEXTCOLOR (LIGHTGRAY);
        RELOADALPHAWINDOW (FALSE);
        WINDOW (1, 1, 80, 25);
        END
      ELSE
        BEGIN
        SSTG := '*.LST';
        IF PATH_NAME <> 'C:\' THEN
          DELETE (PATH_NAME, (LENGTH (PATH_NAME) ), 1);
        CHDIR (PATH_NAME);
        FILE_NAME := SELECTFROMDIR (SSTG, 1, 3);
        IF PATH_NAME <> 'C:\' THEN
          PATH_NAME := PATH_NAME + '\';
        TEXTCOLOR (LIGHTGRAY);
        IF FILE_CHECK (FILE_NAME, FC) THEN
          BEGIN
          ASSIGN (DATAFILE, FILE_NAME);
          RESET (DATAFILE);
          AA := NUM_GEN + 1;
          READLN (DATAFILE, NUM_LIST);
          FOR I := 1 TO NUM_LIST DO
            BEGIN
            FOR J := 1 TO AA DO
              BEGIN
              IF J < AA THEN
                READ (DATAFILE, PRI_LIST [I, J]);
              IF J = AA THEN
                READLN (DATAFILE, PRI_LIST [I, J]);
              END;
            END;
          CLOSE (DATAFILE);
          GOTOXY (1, 18);
          WRITELN (FILE_NAME, ' loaded.');
          WRITELN;
          WRITE ('PRESS ANY KEY TO CONTINUE.....');
          CHOICE := READKEY;
          GOTOXY (1, 18);
          WRITE ('                                                        ');
          GOTOXY (1, 20);
          WRITE ('                                                        ');
          END
        ELSE
          BEGIN
          NO_FILE (NF);
          END;
        END;
      CHOICE := ' ';
      FOR I := 1 TO NUM_LIST DO
        BEGIN
        MAX_MIN [I, 1] := 0;
        MAX_MIN [I, 2] := 0;
        END;
      MIN_GEN := 999999999;
      MAX_GEN := 0;
      FOR I := 1 TO NUM_LIST DO
        BEGIN
        FOR J := 2 TO AA DO
          BEGIN
          BB := J - 1;
          IF PRI_LIST [I, J] = 1 THEN
            MAX_MIN [I, 1] := MAX_MIN [I, 1] + MINP_MAT_ALL [BB];
          IF PRI_LIST [I, J] = 1 THEN
            MAX_MIN [I, 2] := MAX_MIN [I, 2] + MAXP_MAT_ALL [BB];
          END;
        IF MAX_MIN [I, 1] < MIN_GEN THEN
          MIN_GEN := MAX_MIN [I, 1];
        IF MAX_MIN [I, 2] > MAX_GEN THEN
          MAX_GEN := MAX_MIN [I, 2];
        END;
      END;
    IF CHOICE = '3' THEN
      BEGIN
      SSTG := '*.LDP';
      IF PATH_NAME <> 'C:\' THEN
        DELETE (PATH_NAME, (LENGTH (PATH_NAME) ), 1);
      CHDIR (PATH_NAME);
      FILE_NAME := SELECTFROMDIR (SSTG, 1, 3);
      IF PATH_NAME <> 'C:\' THEN
        PATH_NAME := PATH_NAME + '\';
      TEXTCOLOR (LIGHTGRAY);
      IF FILE_CHECK (FILE_NAME, FC) THEN
        BEGIN
        ASSIGN (DATAFILE, FILE_NAME);
        RESET (DATAFILE);
        READLN (DATAFILE, NUM_LOAD_PAT);
        FOR I := 1 TO NUM_LOAD_PAT DO
          BEGIN
          READ (DATAFILE, LOAD_PAT_MAT [I, 1]);
          READLN (DATAFILE, LOAD_PAT_MAT [I, 2]);
          END;
        CLOSE (DATAFILE);
        GOTOXY (1, 18);
        WRITELN (FILE_NAME, ' loaded.');
        WRITELN;
        WRITE ('PRESS ANY KEY TO CONTINUE.....');
        CHOICE := READKEY;
        GOTOXY (1, 18);
        WRITE ('                                                        ');
        GOTOXY (1, 20);
        WRITE ('                                                        ');
        END
      ELSE
        BEGIN
        NO_FILE (NF);
        END;
      CHOICE := ' ';
      END;
    IF CHOICE = '8' THEN
      BEGIN
      DEF_PATH := READ_PATH (PATH_NAME);
      PATH_NAME := DEF_PATH;
      END;
    END;
  CHOICE := ' ';
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : READ_CONFIG                                                }
{  Last Revised : January  4, 1994                                           }
{       Purpose : Reads information from the config file (UNITCOMM.CFG).     }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE READ_CONFIG;
VAR
  TFILE        : STRING [40];                      { TEMP STRING VARIABLE }

BEGIN
  IF CFG_PATH [LENGTH (CFG_PATH) ] = '\' THEN
    BEGIN
    TFILE := CFG_PATH + 'UNITCOMM.CFG';
    END
  ELSE
    BEGIN
    TFILE := CFG_PATH + '\' + 'UNITCOMM.CFG';
    END;
  IF FILE_CHECK (TFILE, FC) THEN
    BEGIN
    ASSIGN (DATAFILE, 'UNITCOMM.CFG');
    RESET (DATAFILE);
    READLN (DATAFILE, DEF_PATH);
    CLOSE (DATAFILE);
    END
  ELSE
    BEGIN
    DEF_PATH := 'C:\';
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : CREATE_DATA                                                }
{  Last Revised : September 19, 1993                                         }
{       Purpose : Creates data to be used in UNITCOMM.PAS                    }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE CREATE_DATA;
VAR
  T_LIST     : ARRAY [1..515, 1..13] OF INTEGER; { TEMP. PRIORITY LST MAT  }
  
BEGIN
  {$M 32768,0,655360}
  FC := 1;
  WHILE CHOICE <> '9' DO
    BEGIN
    TITLE (VERSION);
    GOTOXY (1, 25);
    WRITE ('                                       ');
    GOTOXY (1, 25);
    WRITE ('PATH:  ', PATH_NAME);
    GOTOXY (1, 5);
    WRITELN ('CREATE DATA MENU:');
    WRITELN;
    WRITELN ('      1 - Create a priority list file.         *.LST');
    WRITELN ('      2 - Create a pattern of loading file.    *.LDP');
    WRITELN;
    WRITELN;
    WRITELN;
    WRITELN ('      8 - Change PATH.');
    WRITELN ('      9 - Exit.');
    WRITELN;
    WRITE ('Please enter your choice: ');
    CHOICE := READKEY;
    IF CHOICE = '1' THEN
      BEGIN
      TITLE (VERSION);
      FLAG2 := 0;
      GOTOXY (1, 5);
      WRITE ('Enter file name (Do not include .LST): ');
      READLN (NAME);
      FILE_NAME := PATH_NAME + NAME + '.LST';
      IF FILE_CHECK (FILE_NAME, FC) THEN
        BEGIN
        GOTOXY (1, 5);
        WRITE ('                                                        ');
        GOTOXY (1, 7);
        WRITE ('                                                        ');
        NUM := 20;
        WHILE (NUM > 9) OR (NUM < 1) DO
          BEGIN
          GOTOXY (1, 5);
          WRITE ('Please enter the number of generators (MAX=9): ');
          READLN (NUM);
          GOTOXY (1, 5);
          WRITELN ('                                                               ');
          END;
        A := 999999;
        B := - 1;
        GOTOXY (1, 5);
        WRITE ('Filter priority list with max load? (Y/N): ');
        CHOICE := UPCASE (READKEY);
        GOTOXY (1, 5);
        WRITELN ('                                                ');
        IF CHOICE = 'Y' THEN
          BEGIN
          GOTOXY (1, 5);
          WRITE ('Enter max load: ');
          READLN (A);
          GOTOXY (1, 5);
          WRITELN ('                                                ');
          FLAG2 := 1;
          END;
        GOTOXY (1, 5);
        WRITE ('Filter priority list with min load? (Y/N): ');
        CHOICE := UPCASE (READKEY);
        GOTOXY (1, 5);
        WRITELN ('                                                ');
        IF CHOICE = 'Y' THEN
          BEGIN
          GOTOXY (1, 5);
          WRITE ('Enter min load: ');
          READLN (B);
          GOTOXY (1, 5);
          WRITELN ('                                                ');
          FLAG2 := 1;
          END;
        IF (FLAG2 = 1) AND (NUM_GEN <> NUM) THEN
          BEGIN
          NO_GENDATA;
          END
        ELSE
          BEGIN
          COL [NUM] := 1;
          FOR I := (NUM - 1) DOWNTO 1 DO
            BEGIN
            COL [I] := 2 * COL [I + 1];
            END;
          FOR I := 1 TO NUM DO
            BEGIN
            COL_T [I] := COL [I];
            COL_D [I] := 0;
            END;
          TOTAL := 2 * COL_T [1] - 1;
          FOR I := 1 TO NUM DO
            BEGIN
            COL_T [I] := COL_T [I] - 1;
            END;
          L := 1;
          FOR I := 1 TO TOTAL DO
            BEGIN
            FOR J := 1 TO NUM DO
              BEGIN
              IF COL_T [J] <> 0 THEN
                TEMP [J] := COL_D [J];
              IF COL_T [J] = 0 THEN
                BEGIN
                IF COL_D [J] = 1 THEN
                  BEGIN
                  COL_D [J] := 0;
                  END
                ELSE
                  BEGIN
                  COL_D [J] := 1;
                  END;
                TEMP [J] := COL_D [J];
                COL_T [J] := COL [J];
                END;
              END;
            FOR K := 1 TO NUM DO
              COL_T [K] := COL_T [K] - 1;
            C := 0;
            D := 0;
            FOR AA := 1 TO NUM DO
              BEGIN
              IF TEMP [AA] = 1 THEN
                BEGIN
                C := C + MAXP_MAT_ALL [AA];
                D := D + MINP_MAT_ALL [AA];
                END;
              END;
            IF (A >= D) AND (C >= B) THEN
              BEGIN
              FOR M := 1 TO NUM DO
                BEGIN
                BB := M + 1;
                T_LIST [L, BB] := TEMP [M];
                END;
              L := L + 1;
              END;
            END;
          ASSIGN (DATAFILE, FILE_NAME);
          REWRITE (DATAFILE);
          AA := L - 1;
          WRITELN (DATAFILE, AA);
          BB := NUM + 1;
          FOR I := 1 TO AA DO
            BEGIN
            WRITE (DATAFILE, I : 3, ' ');
            FOR J := 2 TO BB DO
              BEGIN
              IF J < BB THEN
                WRITE (DATAFILE, T_LIST [I, J], ' ');
              IF J = BB THEN
                WRITELN (DATAFILE, T_LIST [I, J]);
              END;
            END;
          CLOSE (DATAFILE);
          GOTOXY (1, 5);
          WRITELN (FILE_NAME, ' created.');
          WRITELN;
          WRITELN (AA, ' acceptable schedule(s) saved.');
          WRITELN;
          WRITE ('PRESS ANY KEY TO CONTINUE.....');
          CHOICE := READKEY;
          GOTOXY (1, 5);
          WRITE ('                                                        ');
          GOTOXY (1, 7);
          WRITE ('                                                        ');
          GOTOXY (1, 9);
          WRITE ('                                                        ');
          END;
        END
      ELSE
        BEGIN
        NF := 1;
        NO_FILE (NF);
        NF := 0;
        END;
      END;
    IF CHOICE = '2' THEN
      BEGIN
      TITLE (VERSION);
      GOTOXY (1, 5);
      WRITE ('Enter file name (Do not include .LDP): ');
      READLN (NAME);
      FILE_NAME := PATH_NAME + NAME + '.LDP';
      IF FILE_CHECK (FILE_NAME, FC) THEN
        BEGIN
        GOTOXY (1, 5);
        WRITE ('                                                        ');
        GOTOXY (1, 7);
        WRITE ('                                                        ');
        ASSIGN (DATAFILE, FILE_NAME);
        REWRITE (DATAFILE);
        NUM := - 1;
        WHILE (NUM > 100) OR (NUM < 1) DO
          BEGIN
          GOTOXY (1, 5);
          WRITE ('Please enter the number of loading periods (MAX=100): ');
          READLN (NUM);
          GOTOXY (1, 5);
          WRITELN ('                                                               ');
          END;
        WRITELN (DATAFILE, NUM);
        FOR I := 1 TO NUM DO
          BEGIN
          GOTOXY (1, 5);
          WRITE ('Please enter the load for period #', I, ': ');
          READLN (A);
          WRITE (DATAFILE, I, '  ');
          WRITELN (DATAFILE, A : 8 : 2);
          GOTOXY (1, 5);
          WRITELN ('                                                    ');
          END;
        CLOSE (DATAFILE);
        END
      ELSE
        BEGIN
        NF := 1;
        NO_FILE (NF);
        NF := 0;
        END;
      END;
    IF CHOICE = '8' THEN
      BEGIN
      DEF_PATH := READ_PATH (PATH_NAME);
      PATH_NAME := DEF_PATH;
      END;
    END;
  CHOICE := ' ';
  FC := 0;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : SHOW_HEADER                                                }
{  Last Revised : December 15, 1993                                          }
{       Purpose : Shows header information.                                  }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE SHOW_HEADER;
BEGIN
  TITLE (VERSION);
  GOTOXY (35, 4);
  TEXTCOLOR (YELLOW);
  WRITE ('MAXIMUM    ');
  TEXTCOLOR (RED);
  WRITE ('MINIMUM    ');
  TEXTCOLOR (WHITE);
  WRITE ('REGULATING    ');
  TEXTCOLOR (LIGHTBLUE);
  WRITE ('OFF-LINE');
  TEXTCOLOR (GREEN);
  GOTOXY (1, 6);
  WRITELN ('     LOAD  SCH ');
  WRITE (' #   POWER  #      COST   LAMBDA');
  FOR AA := 1 TO NUM_GEN DO
    BEGIN
    BB := 30 + AA * 5;
    GOTOXY (BB, 7);
    STR (AA : 1, S);
    WRITE ('U ', S);
    END;
  TEXTCOLOR (LIGHTGRAY);
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : SHOW                                                       }
{  Last Revised : April 13, 1994                                             }
{       Purpose : Shows information from unit committment calculations.      }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE SHOW;
BEGIN
  COST_TOTAL := 0;
  FOR EE := 1 TO NUM_LOAD_PAT DO
    BEGIN
    COST_TOTAL := COST_TOTAL + CHEAP [EE, 2];
    END;
  WHILE CCHOICE <> '9' DO
    BEGIN
    TITLE (VERSION);
    GOTOXY (1, 25);
    WRITE ('                                       ');
    GOTOXY (1, 25);
    WRITE ('PATH:  ', PATH_NAME);
    GOTOXY (1, 5);
    WRITELN ('OUTPUT MENU:');
    WRITELN;
    WRITELN ('      1 - Send output to screen.');
    WRITELN ('      2 - Send output to a file....');
    WRITELN;
    WRITELN;
    WRITELN ('      8 - Change PATH.');
    WRITELN ('      9 - Exit.');
    WRITELN;
    WRITE ('Please enter your choice: ');
    CCHOICE := READKEY;
    IF (CCHOICE = '1') THEN
      BEGIN
      OFFSET := 0;
      ORIGMODE := LASTMODE;
      TEXTMODE (C80 + FONT8X8);
      SHOW_HEADER;
      FOR EE := 1 TO NUM_LOAD_PAT DO
        BEGIN
        AA := EE - OFFSET;
        BB := 2 * AA + 7;
        GOTOXY (1, BB);
        WRITE (EE : 2);
        GOTOXY (5, BB);
        WRITE (CHEAP [EE, 1] : 5 : 0);
        GOTOXY (12, BB);
        WRITE (SCH_LIST [EE] : 3);
        GOTOXY (17, BB);
        WRITE (CHEAP [EE, 2] : 8 : 2);
        GOTOXY (27, BB);
        WRITE (CHEAP [EE, 3] : 6 : 3);
        IF EE = NUM_LOAD_PAT THEN
          BEGIN
          GOTOXY (16, (BB + 1) );
          WRITE ('----------');
          GOTOXY (15, (BB + 2) );
          WRITE (COST_TOTAL : 10 : 2);
          END;
        FOR CC := 1 TO NUM_GEN DO
          BEGIN
          DD := 29 + 5 * CC;
          GOTOXY (DD, BB);
          TEXTCOLOR (WHITE);
          IF ABS (CHEAP [EE, (CC + 3) ] - MAXP_MAT_ALL [CC]) < 0.5 THEN
            TEXTCOLOR (YELLOW);
          IF ABS (CHEAP [EE, (CC + 3) ] - MINP_MAT_ALL [CC]) < 0.5 THEN
            TEXTCOLOR (RED);
          IF CHEAP [EE, (CC + 3) ] = 0 THEN
            TEXTCOLOR (LIGHTBLUE);
          WRITE (CHEAP [EE, (CC + 3) ] : 4 : 0);
          TEXTCOLOR (LIGHTGRAY);
          END;
        A := NUM_LOAD_PAT / 19;
        IF ( (INT (EE / 19) ) = (EE / 19) ) AND ( (INT (A) ) <> A) THEN
          BEGIN
          GOTOXY (1, (BB + 5) );
          WRITE ('PRESS ANY KEY TO CONTINUE...');
          CHOICE := READKEY;
          SHOW_HEADER;
          OFFSET := OFFSET + 19;
          END;
        END;
      GOTOXY (1, (BB + 5) );
      WRITE ('PRESS ANY KEY TO CONTINUE...');
      CHOICE := READKEY;
      TEXTMODE (ORIGMODE);
      END;
    IF CCHOICE = '2' THEN
      BEGIN
      TITLE (VERSION);
      GOTOXY (1, 5);
      WRITE ('Enter file name: ');
      READLN (NAME);
      FILE_NAME := PATH_NAME + NAME;
      ASSIGN (DATAFILE, FILE_NAME);
      REWRITE (DATAFILE);
      WRITELN (DATAFILE, 'UNITCOMM  V', VERSION : 2 : 1);
      WRITELN (DATAFILE, '');
      WRITELN (DATAFILE, '         TIME: ', TIME : 5 : 2, ' SECONDS');
      WRITELN (DATAFILE, ' INITIAL COST: ', INIT_COST : 10 : 2);
      WRITELN (DATAFILE, '       SEARCH: ', SEARCH : 3, '  (MAX = ', NUM_LIST, ')');
      WRITELN (DATAFILE, '         KEEP: ', KEEP : 3, '  (MAX = ', NUM_LIST, ')');
      WRITE (DATAFILE, ' INITIAL TIME:                  ');
      FOR EE := 1 TO NUM_GEN DO
        BEGIN
        WRITE (DATAFILE, '  ', GEN_TIME_I [EE] : 3);
        END;
      WRITELN (DATAFILE, '');
      WRITE (DATAFILE, 'INITIAL STATE:                  ');
      FOR EE := 1 TO NUM_GEN DO
        BEGIN
        IF GEN_TIME_I [EE] > 0 THEN
          WRITE (DATAFILE, '    1');
        IF GEN_TIME_I [EE] < 0 THEN
          WRITE (DATAFILE, '    0');
        END;
      WRITELN (DATAFILE, '');
      WRITELN (DATAFILE, '');
      WRITELN (DATAFILE, '     LOAD  SCH');
      WRITE (DATAFILE, ' #   POWER  #     COST    LAMBDA');
      FOR EE := 1 TO NUM_GEN DO
        BEGIN
        WRITE (DATAFILE, '  U ', EE);
        END;
      WRITELN (DATAFILE, '');
      WRITELN (DATAFILE, '');
      FOR EE := 1 TO NUM_LOAD_PAT DO
        BEGIN
        WRITE (DATAFILE, EE : 3);
        WRITE (DATAFILE, CHEAP [EE, 1] : 6 : 0);
        WRITE (DATAFILE, SCH_LIST [EE] : 5);
        WRITE (DATAFILE, CHEAP [EE, 2] : 10 : 2);
        WRITE (DATAFILE, CHEAP [EE, 3] : 8 : 3);
        FOR CC := 1 TO NUM_GEN DO
          BEGIN
          IF CC < NUM_GEN THEN
            WRITE (DATAFILE, CHEAP [EE, (CC + 3) ] : 5 : 0);
          IF CC = NUM_GEN THEN
            WRITELN (DATAFILE, CHEAP [EE, (CC + 3) ] : 5 : 0);
          END;
        IF EE = NUM_LOAD_PAT THEN
          BEGIN
          WRITELN (DATAFILE, '               ----------');
          WRITELN (DATAFILE, '              ', COST_TOTAL : 10 : 2);
          END;
        END;
      CLOSE (DATAFILE);
      WRITELN;
      WRITELN (FILE_NAME, ' created.');
      WRITELN;
      WRITELN;
      WRITELN;
      WRITELN ('PRESS ANY KEY TO CONTINUE.....');
      CHOICE := READKEY;
      END;
    IF CCHOICE = '8' THEN
      BEGIN
      DEF_PATH := READ_PATH (PATH_NAME);
      PATH_NAME := DEF_PATH;
      END;
    END;
  CHOICE := ' ';
  CCHOICE := ' ';
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : GET_TIME                                                   }
{  Last Revised : April 18, 1994                                             }
{       Purpose : Gets initial conditions of each generator.                 }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE GET_TIME;
BEGIN
  WHILE CHOICE <> '9' DO
    BEGIN
    TITLE (VERSION);
    GOTOXY (1, 20);
    TEXTCOLOR (WHITE);
    WRITE ('       GEN. #:  ');
    TEXTCOLOR (GREEN);
    FOR EE := 1 TO NUM_GEN DO
      BEGIN
      WRITE ('  ', EE : 3);
      END;
    WRITELN;
    TEXTCOLOR (WHITE);
    WRITE (' INITIAL TIME:  ');
    TEXTCOLOR (YELLOW);
    FOR EE := 1 TO NUM_GEN DO
      BEGIN
      WRITE ('  ', GEN_TIME_I [EE] : 3);
      END;
    WRITELN;
    TEXTCOLOR (WHITE);
    WRITE ('INITIAL STATE:  ');
    TEXTCOLOR (YELLOW);
    FOR EE := 1 TO NUM_GEN DO
      BEGIN
      IF GEN_TIME_I [EE] > 0 THEN
        WRITE ('    1');
      IF GEN_TIME_I [EE] < 0 THEN
        WRITE ('    0');
      END;
    WRITELN;
    TEXTCOLOR (WHITE);
    WRITE (' INITIAL COST: ');
    TEXTCOLOR (YELLOW);
    WRITELN (INIT_COST : 10 : 2);
    TEXTCOLOR (WHITE);
    WRITE ('SHUTDOWN COST: ');
    TEXTCOLOR (YELLOW);
    WRITELN (SDCOST : 10 : 2);
    TEXTCOLOR (LIGHTGRAY);
    GOTOXY (1, 5);
    WRITELN ('INITIAL CONDITION MENU:');
    WRITELN;
    WRITELN ('      1 - Change the initial conditions of the generators.');
    WRITELN ('      2 - Change the initial cost of the system.');
    WRITELN ('      3 - Change the shutdown cost for the generators.');
    WRITELN;
    WRITELN;
    WRITELN;
    WRITELN ('      9 - Exit.');
    WRITELN;
    WRITE ('Please enter your choice: ');
    CHOICE := READKEY;
    IF CHOICE = '1' THEN
      BEGIN
      TITLE (VERSION);
      GOTOXY (1, 5);
      WRITELN ('+  UP-TIME');
      WRITELN ('-  DOWN-TIME');
      FOR I := 1 TO NUM_GEN DO
        BEGIN
        GEN_TIME_I [I] := 0;
        WHILE GEN_TIME_I [I] = 0 DO
          BEGIN
          GOTOXY (1, 9);
          WRITE ('Please enter the intial condition for generator #', I, ': ');
          READLN (GEN_TIME_I [I]);
          GOTOXY (1, 9);
          WRITELN ('                                                                 ');
          IF GEN_TIME_I [I] > 0 THEN
            LAST_STATE [I] := 1;
          IF GEN_TIME_I [I] < 0 THEN
            LAST_STATE [I] := 0;
          IF GEN_TIME_I [I] = 0 THEN
            BEGIN
            GOTOXY (1, 9);
            WRITE ('Initial condition for generators cannot equal 0!');
            GOTOXY (1, 11);
            WRITE ('        PRESS ANY KEY TO CONTINUE....');
            CHOICE := READKEY;
            GOTOXY (1, 9);
            WRITE ('                                                 ');
            GOTOXY (1, 11);
            WRITE ('                                                 ');
            END;
          END;
        END;
      FOR AA := 1 TO NUM_LIST DO
        BEGIN
        TEMP1 := 0;
        FOR BB := 1 TO NUM_GEN DO
          BEGIN
          IF LAST_STATE [BB] <> PRI_LIST [AA, (BB + 1) ] THEN
            TEMP1 := 1;
          END;
        IF TEMP1 = 0 THEN
          INIT_POINT := AA;
        END;
      CHOICE := ' ';
      END;
    IF CHOICE = '2' THEN
      BEGIN
      TITLE (VERSION);
      GOTOXY (1, 5);
      INIT_COST := 0;
      WRITE ('Please enter the initial cost of the system: ');
      READLN (INIT_COST);
      GOTOXY (1, 11);
      IF INIT_COST < 0 THEN
        INIT_COST := 0;
      END;
    IF CHOICE = '3' THEN
      BEGIN
      TITLE (VERSION);
      GOTOXY (1, 5);
      SDCOST := 0;
      WRITE ('Please enter the shutdown cost for the generators: ');
      READLN (SDCOST);
      GOTOXY (1, 11);
      IF SDCOST < 0 THEN
        SDCOST := 0;
      END;
    END;
  CHOICE := ' ';
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : CHECK_FEAS_TIME;                                           }
{  Last Revised : March 18, 1994                                             }
{       Purpose : Checks the feasibility of combination #LL with respect to  }
{                 power requirements and time constraints.                   }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE CHECK_FEAS_TIME;
BEGIN
  FOR AA := 1 TO NUM_GEN DO
    BEGIN
    BB := AA + 1;
    IF (PRI_LIST [LL, BB] = 1) AND (GEN_TIME [AA] < 0) THEN
      BEGIN
      IF ABS (GEN_TIME [AA]) < DOWN_TIME [AA] THEN
        LIST_STATE [LL] := 'N';
      END;
    IF (PRI_LIST [LL, BB] = 0) AND (GEN_TIME [AA] > 0) THEN
      BEGIN
      IF GEN_TIME [AA] < UP_TIME [AA] THEN
        LIST_STATE [LL] := 'N';
      END;
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : UPDATE_TIME;                                               }
{  Last Revised : March 11, 1994                                             }
{       Purpose : Updates generator times.                                   }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE UPDATE_TIME;
BEGIN
  FOR BB := 1 TO NUM_GEN DO
    BEGIN
    GEN_TIME [BB] := TIME_OLD [TEMP1, BB];
    END;
  FOR BB := 1 TO NUM_GEN DO
    BEGIN
    CC := BB + 1;
    IF PRI_LIST [LL, CC] = 1 THEN
      BEGIN
      IF GEN_TIME [BB] > 0 THEN
        TIME_NEW [LL, BB] := GEN_TIME [BB] + 1;
      IF GEN_TIME [BB] < 0 THEN
        TIME_NEW [LL, BB] := 1;
      END;
    IF PRI_LIST [LL, CC] = 0 THEN
      BEGIN
      IF GEN_TIME [BB] < 0 THEN
        TIME_NEW [LL, BB] := GEN_TIME [BB] - 1;
      IF GEN_TIME [BB] > 0 THEN
        TIME_NEW [LL, BB] := - 1;
      END;
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : STARTUP_COST;                                              }
{  Last Revised : April 12, 1994                                             }
{       Purpose : Checks for startup of generators and adds corresponding    }
{                 cost.                                                      }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE STARTUP_COST;
BEGIN
  SCOST := 0;
  FOR AA := 1 TO NUM_GEN DO
    BEGIN
    IF (LAST_STATE [AA] = 0) AND (PRI_LIST [LL, (AA + 1) ] = 1) THEN
      BEGIN
      IF ABS (GEN_TIME [AA]) >= STARTUP_MAT [AA, 3] THEN
        BEGIN
        SCOST := SCOST + STARTUP_MAT [AA, 2];
        END
      ELSE
        BEGIN
        SCOST := SCOST + STARTUP_MAT [AA, 1];
        END;
      END;
    IF (LAST_STATE [AA] = 1) AND (PRI_LIST [LL, (AA + 1) ] = 0) THEN
      SCOST := SCOST + SDCOST;
    END;
  TCOST := COST + SCOST;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : MOVE_GEN                                                   }
{  Last Revised : January 30, 1994                                           }
{       Purpose : Moves specified (by priority list) generators to COST_MAT  }
{                 for the DISPATCH.                                          }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE MOVE_GEN;
BEGIN
  NUM_DIS := 0;
  FOR AA := 1 TO NUM_GEN DO
    BEGIN
    BB := AA + 1;
    IF PRI_LIST [LL, BB] = 1 THEN
      BEGIN
      NUM_DIS := NUM_DIS + 1;
      FOR CC := 1 TO 4 DO
        BEGIN
        COST_MAT [NUM_DIS, CC] := COST_MAT_ALL [AA, CC];
        END;
      MINP_MAT [NUM_DIS] := MINP_MAT_ALL [AA];
      MAXP_MAT [NUM_DIS] := MAXP_MAT_ALL [AA];
      END;
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : SHIFT_TIME;                                                }
{  Last Revised : March 10, 1994                                             }
{       Purpose : Shifts references of generator up-times for DYN_COMMIT.    }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE SHIFT_TIME;
BEGIN
  FOR AA := 1 TO NUM_GEN DO
    BEGIN
    GEN_TIME [AA] := TIME_OLD [EE, AA];
    IF GEN_TIME [AA] > 0 THEN
      LAST_STATE [AA] := 1;
    IF GEN_TIME [AA] < 0 THEN
      LAST_STATE [AA] := 0;
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : INIT_SHOW;                                                 }
{  Last Revised : April 13, 1994                                             }
{       Purpose : Initializes data to be used in SHOW.                       }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE INIT_SHOW;
TYPE
  DATA_TYPE = RECORD
                D_COST  : REAL;
                D_POINT : INTEGER;
                D_TCOST : REAL;
              END;
  
VAR
  DATA         : DATA_TYPE;
  D_FILE       : FILE OF DATA_TYPE;
  NUM_GEN      : INTEGER;
  NUM_LIST     : INTEGER;
  NUM_LOAD     : INTEGER;
  POINTERS     : ARRAY [1..128] OF INTEGER;
  POS          : LONGINT;

BEGIN
  ASSIGN (D_FILE, 'UC_DATA.TMP');
  RESET (D_FILE);
  READ (D_FILE, DATA);
  NUM_GEN := TRUNC (DATA.D_COST);
  NUM_LIST := TRUNC (DATA.D_TCOST);
  NUM_LOAD := DATA.D_POINT;
  POS := NUM_LIST * (NUM_LOAD - 1) + 1;
  CHEAPEST := 9999999;
  ML := NUM_LOAD_PAT;
  FOR AA := POS TO (POS + (NUM_LIST - 1) ) DO
    BEGIN
    SEEK (D_FILE, AA);
    READ (D_FILE, DATA);
    IF (DATA.D_TCOST < CHEAPEST) AND (DATA.D_TCOST <> - 1) THEN
      BEGIN
      CHEAPEST := DATA.D_TCOST;
      SCH_LIST [ML] := AA - (POS - 1);
      CHEAP [ML, 2] := INT (DATA.D_TCOST * 100 + 0.5) / 100;
      POINTERS [ML] := DATA.D_POINT;
      END;
    END;
  FOR ML := (NUM_LOAD_PAT - 1) DOWNTO 1 DO
    BEGIN
    POS := NUM_LIST * (ML - 1) + POINTERS [ML + 1];
    SEEK (D_FILE, POS);
    READ (D_FILE, DATA);
    SCH_LIST [ML] := POINTERS [ML + 1];
    CHEAP [ML, 2] := INT (DATA.D_TCOST * 100 + 0.5) / 100;
    POINTERS [ML] := DATA.D_POINT;
    END;
  CLOSE (D_FILE);
  FOR ML := 1 TO NUM_LOAD_PAT DO
    BEGIN
    LL := SCH_LIST [ML];
    POW_REQ := CHEAP [ML, 1];
    MOVE_GEN;
    DISPATCH;
    CHEAP [ML, 3] := LAMBDA;
    CC := 1;
    FOR AA := 1 TO NUM_GEN DO
      BEGIN
      BB := AA + 3;
      IF PRI_LIST [LL, (AA + 1) ] = 1 THEN
        BEGIN
        CHEAP [ML, BB] := POW_OUT [CC];
        CC := CC + 1;
        END;
      IF PRI_LIST [LL, (AA + 1) ] = 0 THEN
        CHEAP [ML, BB] := 0;
      END;
    END;
  CHEAP [1, 2] := CHEAP [1, 2] + INIT_COST;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : SORT;                                                      }
{  Last Revised : April 25, 1994                                             }
{       Purpose : Sort routine for keep part of dynamic programming.         }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE SORT;
VAR
  DONE      : CHAR;
  
BEGIN
  PAIRS := NUM_LIST - 1;
  DONE := 'F';
  WHILE DONE <> 'T' DO
    BEGIN
    DONE := 'T';
    FOR XX := 1 TO PAIRS DO
      BEGIN
      IF STEMP2 [XX] > STEMP2 [ (XX + 1) ] THEN
        BEGIN
        ST := STEMP2 [XX];
        STEMP2 [XX] := STEMP2 [ (XX + 1) ];
        STEMP2 [ (XX + 1) ] := ST;
        STI := STEMP1 [XX];
        STEMP1 [XX] := STEMP1 [ (XX + 1) ];
        STEMP1 [ (XX + 1) ] := STI;
        DONE := 'F';
        END;
      END;
    PAIRS := PAIRS - 1;
    END;
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : DYN_COMMIT;                                                }
{  Last Revised : April 25, 1994                                             }
{       Purpose : Performs unit commitment using dynamic programming.        }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE DYN_COMMIT;
TYPE
  DATA_TYPE = RECORD
                D_COST  : REAL;
                D_POINT : INTEGER;
                D_TCOST : REAL;
              END;
  
VAR
  COST_A    : ARRAY [1..511] OF REAL;
  COST_B    : ARRAY [1..511] OF REAL;
  DATA      : DATA_TYPE;
  D_FILE    : FILE OF DATA_TYPE;
  POINT_A   : ARRAY [1..511] OF INTEGER;
  
BEGIN
  ASSIGN (D_FILE, PATH_NAME + 'UC_DATA.TMP');
  REWRITE (D_FILE);
  DATA.D_COST := NUM_GEN;
  DATA.D_TCOST := NUM_LIST;
  DATA.D_POINT := NUM_LOAD_PAT;
  WRITE (D_FILE, DATA);
  FOR ML := 1 TO NUM_LIST DO
    BEGIN
    LIST_S_OLD [ML] := 'F';
    COST_A [ML] := 0;
    POINT_A [ML] := INIT_POINT;
    FOR AA := 1 TO NUM_GEN DO
      BEGIN
      TIME_OLD [ML, AA] := GEN_TIME_I [AA];
      END;
    END;
  TITLE (VERSION);
  GOTOXY (1, 4);
  WRITE ('Enter the # of states (MAX = ', NUM_LIST, ') to search each period: ');
  READLN (SEARCH);
  WRITELN;
  WRITELN;
  WRITE ('Enter the # of strategies (MAX = ', NUM_LIST, ') to save each period: ');
  READLN (KEEP);
  TITLE (VERSION);
  GOTOXY (1, 4);
  WRITE ('Please wait...');
  GETTIME (H1, M1, S1, SS1);
  FOR ML := 1 TO NUM_LOAD_PAT DO
    BEGIN
    GOTOXY (1, 6);
    WRITE ('Working on load #', ML, ' of ', NUM_LOAD_PAT, '.');
    CHEAP [ML, 1] := LOAD_PAT_MAT [ML, 2];
    POW_REQ := LOAD_PAT_MAT [ML, 2];
    FOR LL := 1 TO NUM_LIST DO
      BEGIN
      LIST_STATE [LL] := 'N';
      IF LL > (NUM_LIST - SEARCH) THEN
        LIST_STATE [LL] := 'F';
      MOVE_GEN;
      IF (POW_REQ < MAX_MIN [LL, 1]) OR (POW_REQ > MAX_MIN [LL, 2]) THEN
        LIST_STATE [LL] := 'N';
      STEMP2 [LL] := 9999999;
      STEMP1 [LL] := LL;
      DATA.D_COST := - 1;
      DATA.D_TCOST := - 1;
      DATA.D_POINT := - 1;
      CHEAPEST := 0;
      IF LIST_STATE [LL] = 'F' THEN
        BEGIN
        DISPATCH;
        CHEAPEST := 9999999;
        FOR EE := 1 TO NUM_LIST DO
          BEGIN
          LIST_STATE [LL] := 'F';
          SCOST := 0;
          IF LIST_S_OLD [EE] = 'F' THEN
            BEGIN
            SHIFT_TIME;
            CHECK_FEAS_TIME;
            IF LIST_STATE [LL] = 'F' THEN
              BEGIN
              STARTUP_COST;
              IF (TCOST + COST_A [EE]) < CHEAPEST THEN
                BEGIN
                CHEAPEST := TCOST + COST_A [EE];
                DATA.D_COST := TCOST + COST_A [EE];
                DATA.D_TCOST := TCOST;
                DATA.D_POINT := EE;
                STEMP2 [LL] := CHEAPEST;
                IF ML = 1 THEN
                  DATA.D_POINT := INIT_POINT;
                TEMP1 := EE;
                END;
              END;
            END;
          END;
        UPDATE_TIME;
        END;
      COST_B [LL] := CHEAPEST;
      WRITE (D_FILE, DATA);
      END;
    FOR AA := 1 TO NUM_LIST DO
      BEGIN
      LIST_S_OLD [AA] := 'F';
      IF AA < (NUM_LIST - SEARCH + 1) THEN
        LIST_S_OLD [AA] := 'N';
      COST_A [AA] := COST_B [AA];
      IF (POW_REQ < MAX_MIN [AA, 1]) OR (POW_REQ > MAX_MIN [AA, 2]) THEN
        LIST_S_OLD [AA] := 'N';
      END;
    IF KEEP <> NUM_LIST THEN
      BEGIN
      SORT;
      FOR XX := (KEEP + 1) TO NUM_LIST DO
        BEGIN
        STI := STEMP1 [XX];
        LIST_S_OLD [STI] := 'N';
        END;
      END;
    FOR AA := 1 TO NUM_LIST DO
      BEGIN
      FOR BB := 1 TO NUM_GEN DO
        BEGIN
        TIME_OLD [AA, BB] := TIME_NEW [AA, BB];
        TIME_NEW [AA, BB] := 0;
        END;
      END;
    END;
  CLOSE (D_FILE);
  BELL (3500, 300);
  GETTIME (H2, M2, S2, SS2);
  TIME := (M2 * 60 + S2 + SS2 / 100) - (M1 * 60 + S1 + SS1 / 100);
  WRITELN;
  WRITELN;
  WRITELN ('Elapsed time in seconds : ', TIME : 5 : 2);
  WRITELN;
  WRITE ('        PRESS ANY KEY TO CONTINUE....');
  READKEY;
  INIT_SHOW;
  SHOW;
  CHOICE := ' ';
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : ECON_HEADER;                                               }
{  Last Revised : December 16, 1993                                          }
{       Purpose : Header for ECON routine.                                   }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE ECON_HEADER;
BEGIN
  TITLE (VERSION);
  TEXTCOLOR (GREEN);
  WRITELN ('SCH #    COST       LAMBDA');
  FOR AA := 1 TO NUM_GEN DO
    BEGIN
    GOTOXY ( (24 + 5 * AA), 4);
    WRITE ('U ', AA);
    END;
  WRITELN;
  WRITELN;
  TEXTCOLOR (LIGHTGRAY);
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : ECON;                                                      }
{  Last Revised : December 17, 1993                                          }
{       Purpose : Performs economic dispatch.                                }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE ECON;
BEGIN
  POW_REQ := 1;
  WHILE POW_REQ <> 0 DO
    BEGIN
    TITLE (VERSION);
    WRITELN ('       Max: ', MAX_GEN : 5 : 0, '      Min: ', MIN_GEN : 5 : 0);
    WRITELN;
    WRITE ('Enter power (0 to quit): ');
    READLN (POW_REQ);
    IF POW_REQ <> 0 THEN
      BEGIN
      ORIGMODE := LASTMODE;
      TEXTMODE (C80 + FONT8X8);
      ECON_HEADER;
      OFFSET := 0;
      FOR LL := 1 TO NUM_LIST DO
        BEGIN
        EE := LL - OFFSET;
        IF (POW_REQ < MAX_MIN [LL, 1]) OR (POW_REQ > MAX_MIN [LL, 2]) THEN
          BEGIN
          WRITELN (LL : 3, '    --------    -------');
          FOR AA := 1 TO NUM_GEN DO
            BEGIN
            GOTOXY ( (24 + 5 * AA), (EE + 5) );
            WRITE ('---');
            END;
          GOTOXY (1, (EE + 6) );
          END
        ELSE
          BEGIN
          MOVE_GEN;
          DISPATCH;
          WRITELN (LL : 3, '    ', COST : 8 : 2, '    ', LAMBDA : 7 : 4);
          CC := 1;
          FOR AA := 1 TO NUM_GEN DO
            BEGIN
            GOTOXY ( (24 + 5 * AA), (EE + 5) );
            IF PRI_LIST [LL, (AA + 1) ] = 1 THEN
              BEGIN
              WRITE (POW_OUT [CC] : 3 : 0);
              CC := CC + 1;
              END
            ELSE
              BEGIN
              WRITE ('  0');
              END;
            END;
          GOTOXY (1, (EE + 6) );
          END;
        A := NUM_LIST / 40;
        IF ( (INT (LL / 40) ) = (LL / 40) ) AND (INT (A) <> A) THEN
          BEGIN
          WRITELN;
          WRITELN;
          WRITE ('PRESS ANY KEY TO CONTINUE...');
          CHOICE := READKEY;
          OFFSET := OFFSET + 40;
          ECON_HEADER;
          END;
        END;
      WRITELN;
      WRITELN;
      WRITE ('PRESS ANY KEY TO CONTINUE...');
      CHOICE := READKEY;
      TEXTMODE (ORIGMODE);
      END;
    END;
  CHOICE := ' ';
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : ABOUT;                                                     }
{  Last Revised : March 18, 1994                                             }
{       Purpose : About screen giving author information.                    }
{                                                                            }
{----------------------------------------------------------------------------}
PROCEDURE ABOUT;
BEGIN
  WINDOW (18, 7, 62, 19);
  STOREALPHAWINDOW;
  VIDEO (INV, FALSE);
  WINDOWFRAME (3);
  CLRSCR;
  WRITELN (' UNITCOMM');
  WRITELN (' Version ', VERSION : 2 : 1, ' - 1993, 94');
  WRITELN;
  WRITELN (' Written by:');
  WRITELN;
  WRITELN (' David F. Gadberry');
  WRITELN (' Rose-Hulman Institute of Technology');
  WRITELN (' 5500 Wabash Avenue, Box #391');
  WRITELN (' Terre Haute, Indiana 47803');
  WRITELN;
  WRITELN;
  WRITE ('        PRESS ANY KEY TO CONTINUE...');
  CHOICE := READKEY;
  VIDEO (LOW, FALSE);
  TEXTCOLOR (LIGHTGRAY);
  RELOADALPHAWINDOW (FALSE);
  WINDOW (1, 1, 80, 25);
  CHOICE := ' ';
END;

{----------------------------------------------------------------------------}
{                                                                            }
{     Procedure : MAIN                                                       }
{  Last Revised : April 25, 1994                                             }
{       Purpose : Ties all procedures together to solve the problem.         }
{                                                                            }
{----------------------------------------------------------------------------}
BEGIN
  CHOICE := ' ';
  NF := 0;
  FC := 0;
  GETDIR (0, CFG_PATH);
  READ_CONFIG;
  PATH_NAME := DEF_PATH;
  FLAG1 := 0;
  FOR AA := 1 TO 9 DO
    BEGIN
    GEN_TIME_I [AA] := 1;
    LAST_STATE [AA] := 1;
    END;
  VERSION := 1.0;
  TEXTCOLOR (LIGHTGRAY);
  TEXTBACKGROUND (BLACK);
  
  WHILE CHOICE <> '9' DO
    BEGIN
    TITLE (VERSION);
    GOTOXY (1, 5);
    WRITELN ('MAIN MENU:');
    WRITELN;
    WRITELN ('      1 - Load data files....');
    WRITELN ('      2 - Create data files....');
    WRITELN ('      3 - Enter initial conditions....');
    WRITELN ('      4 - Perform unit commitment.');
    WRITELN ('      5 - Perform economic dispatch.');
    WRITELN;
    WRITELN;
    WRITELN ('      8 - About....');
    WRITELN ('      9 - Exit.');
    WRITELN;
    WRITE ('Please enter your choice: ');
    CHOICE := READKEY;
    IF CHOICE = '1' THEN
      LOAD_GEN_DATA;
    IF CHOICE = '2' THEN
      CREATE_DATA;
    IF CHOICE = '3' THEN
      GET_TIME;
    IF CHOICE = '4' THEN
      DYN_COMMIT;
    IF CHOICE = '5' THEN
      ECON;
    IF CHOICE = '8' THEN
      ABOUT;
    END;
  IF (PARAMSTR (1) <> 'ND') AND (PARAMSTR (1) <> 'nd') THEN
    BEGIN
    ASSIGN (DATAFILE, PATH_NAME + 'UC_DATA.TMP');
    {$I-}
    RESET (DATAFILE);
    {$I+}
    IF IORESULT = 0 THEN
      ERASE (DATAFILE);
    END;
  CHDIR (CFG_PATH);
  CLRSCR;
END.