unit uObtenerEnergiasDeFallaAnuales;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, uDTResultados, StdCtrls, ExtCtrls, xMatDefs, uAuxiliares, uFechas,
  ComCtrls, uDemandas;

type
  TDAOfDAOfDAOfNReal = array of TDAOfDAofNReal;

  TObtenerEnergiasDeFallaAnuales = class(TForm)
    Timer1: TTimer;
    StatusBar1: TStatusBar;
    ProgressBar1: TProgressBar;
    procedure Timer1Timer(Sender: TObject);
  private
    archiEnt: String;
    datosSim: DTResultadoSim;
    aniosSim, aniosConsiderados: Integer;

    nEscalonesFalla: Integer;
    colsP,                //Columnas de las potencias demandadas en el archivo
    colsPF: TDAofNInt;    //Columnas de las Potencias de Falla despachadas en el archivo
    matricesDeFalla: TDAOfDAOfDAOfNReal;//nEscalonesDeFalla * nCronicas + 1 * nAniosSim
    matrizDeDemanda: TDAOfDAofNReal;    //(nCronicas + 1) * nAniosSim
    efsTotales: TDAOfDAofNReal;         //(nCronicas + 1) * nAniosSim

    function hallarColumnasDeP : TDAofNInt;
    function hallarColumnasDePF : TDAofNInt;
    procedure obtenerEyEFAnuales(var matricesDeFalla : TDAOfDAOfDAOfNReal; var matDeDemandaEnergetica: TDAOfDAofNReal);
    function obtenerTotales(const matricesDeFalla : TDAOfDAOfDAOfNReal) : TDAOfDAofNReal;
    procedure escribirResultados(const matricesDeFalla : TDAOfDAOfDAOfNReal ; efsTotales : TDAOfDAofNReal);
    procedure run;

    function trasponer(const matMporN: TDAOfDAofNReal) : TDAOfDAofNReal;
    function trasponerIgnorandoUltimaFila(const matMporN: TDAOfDAofNReal) : TDAOfDAofNReal;
    procedure ordenarFilasCreciente(var mat: TDAOfDAofNReal);

    procedure liberarArregloDeMatrices(var m: TDAOfDAOfDAOfNReal);
    procedure liberarMatriz(var m: TDAOfDAofNReal);
  public
    Constructor Create(owner : TComponent ; nArch: String); reintroduce;
    class function filtrosDeArchivos: String;
  end;

var
  ObtenerEnergiasDeFallaAnuales: TObtenerEnergiasDeFallaAnuales;

implementation

{$R *.dfm}

Constructor TObtenerEnergiasDeFallaAnuales.Create(owner : TComponent ; nArch: String);
begin
  inherited Create(owner);
  archiEnt:= nArch;

  Self.Caption:= 'Obtener Energías De Falla Anuales - ' + nArch;
  timer1.Enabled:= true;
//  PromediarYAgrupar:= self;
end;

class function TObtenerEnergiasDeFallaAnuales.filtrosDeArchivos: String;
begin
  result:= 'Archivos de Resultado de Simulación (simres_*.xlt)|simres_*.xlt';
end;

procedure TObtenerEnergiasDeFallaAnuales.run;
begin
  datosSim:= DTResultadoSim.Create(archiEnt);
  datosSim.read_DatosSim;

  ProgressBar1.Step:= 1;
  colsP:= hallarColumnasDeP;
  colsPF:= hallarColumnasDePF;
  obtenerEyEFAnuales(matricesDeFalla, matrizDeDemanda);
  efsTotales:= obtenerTotales(matricesDeFalla);
  escribirResultados(matricesDeFalla, efsTotales);

  StatusBar1.SimpleText:= 'Terminado';

  SetLength(colsPF, 0);
  liberarArregloDeMatrices(matricesDeFalla);
  liberarMatriz(efsTotales);
  liberarMatriz(matrizDeDemanda);
end;

function TObtenerEnergiasDeFallaAnuales.trasponer(const matMporN: TDAOfDAofNReal) : TDAOfDAofNReal;
var
  iFila, iColumna: Integer;
  m, n: Integer;
  filaIRes: TDAofNReal;
  res: TDAOfDAofNReal;
begin
  m:= length(matMporN);
  n:= Length(matMporN[0]);

  SetLength(res, n);
  for iFila:= 0 to n - 1 do
  begin
    SetLength(res[iFila], m);
    filaIRes:= res[iFila];
    for iColumna:= 0 to m - 1 do
      filaIRes[iColumna]:= matMporN[iColumna][iFila];
  end;
  result:= res;
end;

function TObtenerEnergiasDeFallaAnuales.trasponerIgnorandoUltimaFila(const matMporN: TDAOfDAofNReal) : TDAOfDAofNReal;
var
  iFila, iColumna: Integer;
  m, n: Integer;
  filaIRes: TDAofNReal;
  res: TDAOfDAofNReal;
begin
  m:= length(matMporN) - 1;
  n:= Length(matMporN[0]);

  SetLength(res, n);
  for iFila:= 0 to n - 1 do
  begin
    SetLength(res[iFila], m);
    filaIRes:= res[iFila];
    for iColumna:= 0 to m - 1 do
      filaIRes[iColumna]:= matMporN[iColumna][iFila];
  end;
  result:= res;
end;

procedure TObtenerEnergiasDeFallaAnuales.ordenarFilasCreciente(var mat: TDAOfDAofNReal);
var
  iFila: Integer;
begin
  for iFila:= 0 to High(mat) do
    QuickSort_Creciente(mat[iFila]);
end;

procedure TObtenerEnergiasDeFallaAnuales.liberarArregloDeMatrices(var m: TDAOfDAOfDAOfNReal);
var
  i: Integer;
begin
  for i:= 0 to high(m) do
    liberarMatriz(m[i]);
  SetLength(m, 0);
end;

procedure TObtenerEnergiasDeFallaAnuales.liberarMatriz(var m: TDAOfDAofNReal);
var
  i: Integer;
begin
  for i:= 0 to high(m) do
    SetLength(m[i], 0);
  SetLength(m, 0);
end;

procedure TObtenerEnergiasDeFallaAnuales.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled:= false;
  run;
end;

function TObtenerEnergiasDeFallaAnuales.hallarColumnasDeP : TDAofNInt;
var
  res: TDAofNInt;
  i, nPs: Integer;
begin
  SetLength(res, datosSim.variablesPorColumnas.Count);
  nPs:= 0;
  for i:= 2 to datosSim.variablesPorColumnas.Count -1 do
  begin
    if datosSim.esActorDeTipo(i, TDemanda) and
       (pos('P_P', datosSim.variablesPorColumnas[i]) <> 0) then
    begin
      res[nPs]:= i;
      inc(nPs);
    end;
  end;
  result:= copy(res, 0, nPs);
end;

function TObtenerEnergiasDeFallaAnuales.hallarColumnasDePF : TDAofNInt;
var
  res: TDAofNInt;
  i, nFallas: Integer;
begin
  SetLength(res, datosSim.variablesPorColumnas.Count);
  nFallas:= 0;
  for i:= 2 to datosSim.variablesPorColumnas.Count -1 do
  begin
    if datosSim.esActorDeTipo(i, TDemanda) and
       (pos('PF', datosSim.variablesPorColumnas[i]) <> 0) then
    begin
      res[nFallas]:= i;
      inc(nFallas);
    end;
  end;
  nEscalonesFalla:= nFallas div datosSim.nPostes;
  result:= copy(res, 0, nFallas);
end;

procedure TObtenerEnergiasDeFallaAnuales.obtenerEyEFAnuales(var matricesDeFalla : TDAOfDAOfDAOfNReal; var matDeDemandaEnergetica: TDAOfDAofNReal);
var
  iCronica, iPoste, iAnio, iCol, iFalla: Integer;
  dtIniPaso: TDateTime;
  anio1, anio2, anioIniSim, mes, dia: word;
  MatrizI: TDAOfDAofNReal;
  filaProm: TDAofNReal;

  sumEnergiaDelAnio: NReal;
  sumFallasDelEscalon, invNCronicas: NReal;
  sumFallasDelAnio: TDAOfNReal;

  f: TextFile;
  linea: String;
begin
  StatusBar1.SimpleText:= 'Obteniendo Energía Anual Demandada y Energías de Falla Anuales Por Crónica...';
  ProgressBar1.Position:= 0;
  ProgressBar1.Max:= datosSim.nCronicas;
  try
    AssignFile(f, archiEnt);
    Reset(f);

    DecodeDate(datosSim.FechaIni, anio1, mes, dia);
    DecodeDate(datosSim.FechaFin, anio2, mes, dia);
    anioIniSim:= anio1;
    aniosSim:= anio2 - anio1 + 1;
    aniosConsiderados:= aniosSim - 3;

    SetLength(sumFallasDelAnio, nEscalonesFalla);
    for iFalla:= 0 to high(sumFallasDelAnio) do
      sumFallasDelAnio[iFalla]:= 0;
    sumEnergiaDelAnio:= 0;

    //Inicializo las estructuras para los resultados
    SetLength(matricesDeFalla, nEscalonesFalla);
    for iFalla:= 0 to high(matricesDeFalla) do
    begin
      SetLength(matricesDeFalla[iFalla], datosSim.nCronicas + 1);//la ultima es para el promedio de las crónicas
      MatrizI:= matricesDeFalla[iFalla];
      for iCronica:= 0 to high(MatrizI) do
      begin
        SetLength(MatrizI[iCronica], aniosConsiderados);
      end;
    end;
    SetLength(matDeDemandaEnergetica, datosSim.nCronicas + 1);
    for iCronica:= 0 to high(matDeDemandaEnergetica) do
      SetLength(matDeDemandaEnergetica[iCronica], aniosConsiderados);

    //Empiezo la lectura
    datosSim.pararseEnCronicaI(1, f);
    for iCronica:= 0 to datosSim.nCronicas - 1 do
    begin
      //Cronica
      Readln(f, linea);
      //Encab Actores
      Readln(f, linea);
      //Encab Unidades
      Readln(f, linea);
      //Encab Variables
      Readln(f, linea);

      iAnio:= 0;
      anio1:= anioIniSim;
      while iAnio < aniosConsiderados do
      begin
        Readln(f, linea);
        nextTab(linea);
        dtIniPaso:= IsoStrToDateTime(nextTab(linea));

        DecodeDate(dtIniPaso, anio2, mes, dia);
        if anio1 <> anio2 then
        begin
          for iFalla:= 0 to nEscalonesFalla - 1 do
          begin
            matricesDeFalla[iFalla][iCronica][iAnio]:= sumFallasDelAnio[iFalla];
            matricesDeFalla[iFalla][high(matricesDeFalla[iFalla])][iAnio]:= matricesDeFalla[iFalla][high(matricesDeFalla[iFalla])][iAnio] + sumFallasDelAnio[iFalla];//promedio
            //Vuelvo a 0 los contadores
            sumFallasDelAnio[iFalla]:= 0;
          end;
          matDeDemandaEnergetica[iCronica][iAnio]:= sumEnergiaDelAnio;
          matDeDemandaEnergetica[high(matDeDemandaEnergetica)][iAnio]:= matDeDemandaEnergetica[high(matDeDemandaEnergetica)][iAnio] + sumEnergiaDelAnio;
          sumEnergiaDelAnio:= 0;
          anio1:= anio2;
          inc(iAnio);
          if iAnio = aniosConsiderados then
            break;
        end;
        iCol:= 3;
        while iCol <= colsP[0] do
        begin
          nextTab(linea);
          inc(iCol);
        end;
        for iPoste:= 0 to datosSim.nPostes - 1 do
          sumEnergiaDelAnio:= sumEnergiaDelAnio + StrToFloat(nextTab(linea)) * datosSim.durpos[iPoste];
        inc(iCol, datosSim.nPostes);

        while iCol <= colsPF[0] do
        begin
          nextTab(linea);
          inc(iCol);
        end;
        for iFalla:= 0 to nEscalonesFalla - 1 do
        begin
          sumFallasDelEscalon:= 0;
          for iPoste:= 0 to datosSim.nPostes - 1 do
            sumFallasDelEscalon:= sumFallasDelEscalon + StrToFloat(nextTab(linea)) * datosSim.durpos[iPoste];

          if sumFallasDelEscalon <> 0 then
            sumFallasDelAnio[iFalla]:= sumFallasDelAnio[iFalla] + sumFallasDelEscalon
          else
            break;
        end;
//        inc(iCol, nEscalonesFalla * datosSim.nPostes);
      end;

      while (linea <> '') and not Eof(f) do
        readln(f, linea);
      ProgressBar1.StepIt;
      Application.ProcessMessages;
    end;

    invNCronicas:= 1 / datosSim.nCronicas;
    for iFalla:= 0 to high(matricesDeFalla) do
    begin
      filaProm:= matricesDeFalla[iFalla][high(matricesDeFalla[iFalla])];
      for iAnio:= 0 to high(filaProm) do
        filaProm[iAnio]:= filaProm[iAnio] * invNCronicas;
    end;

    filaProm:= matDeDemandaEnergetica[high(matDeDemandaEnergetica)];
    for iAnio:= 0 to high(filaProm) do
      filaProm[iAnio]:= filaProm[iAnio] * invNCronicas
  finally
    CloseFile(f);
  end;
end;

function TObtenerEnergiasDeFallaAnuales.obtenerTotales(const matricesDeFalla : TDAOfDAOfDAOfNReal) : TDAOfDAofNReal;
var
  efsTotalesAnuales: TDAOfDAofNReal;  //nAniosSim * nCronicas
  iAnio, iCronica, iFalla: Integer;
  filaITot, filaIef: TDAofNReal;
  MatrizI: TDAOfDAofNReal;
begin
  ProgressBar1.Position:= 0;
  ProgressBar1.Max:= nEscalonesFalla;
  StatusBar1.SimpleText:= 'Sumando Energías de Falla Totales Anuales Por Crónica...';

  SetLength(efsTotalesAnuales, datosSim.nCronicas + 1);//+1 por el promedio
  for iCronica:= 0 to high(efsTotalesAnuales) do
  begin
    SetLength(efsTotalesAnuales[iCronica], aniosConsiderados);
    filaITot:= efsTotalesAnuales[iCronica];
    for iAnio:= 0 to high(filaITot) do
      filaITot[iAnio]:= 0;
  end;

  //Voy sumando por falla, primero toda la falla 1, luego la 2...
  for iFalla:= 0 to nEscalonesFalla - 1 do
  begin
    MatrizI:= matricesDeFalla[iFalla]; //(nCronicas + 1) * nAniosSim
    for iCronica:= 0 to high(efsTotalesAnuales) do
    begin
      filaITot:= efsTotalesAnuales[iCronica];//nAniosSim * 1
      filaIef:= MatrizI[iCronica];
      for iAnio:= 0 to high(filaITot) do
        filaITot[iAnio]:= filaITot[iAnio] + filaIef[iAnio];
    end;
    ProgressBar1.StepIt;
    Application.ProcessMessages;
  end;
  result:= efsTotalesAnuales;
end;

procedure TObtenerEnergiasDeFallaAnuales.escribirResultados(const matricesDeFalla : TDAOfDAOfDAOfNReal ; efsTotales : TDAOfDAofNReal);
var
  f: TextFile;
  iFalla, iCronica, iAnio: Integer;
  matrizI: TDAOfDAofNReal;
  Histos: TDAOfDAofNReal;
  filaI: TDAofNReal;
  anioIniSim, mes, dia: word;
  invNCronicas, unMilesimo: NReal;
begin
{    matricesDeFalla : TDAOfDAOfDAOfNReal;//nEscalonesDeFalla * nCronicas + 1 * nAniosSim
    efsTotales,                          //nAniosSim * (nCronicas + 1)
    histogramas: TDAOfDAofNReal;         //nAniosSim * nCronicas  }

  ProgressBar1.Position:= 0;
  ProgressBar1.Max:= nEscalonesFalla + 1;
  StatusBar1.SimpleText:= 'Guardando Resultados...';
  
  DecodeDate(datosSim.FechaIni, anioIniSim, mes, dia);
  invNCronicas:= 100 / datosSim.nCronicas;
  unMilesimo:= 1 / 1000;

  for iFalla:= 0 to high(matricesDeFalla) do
  try
    AssignFile(f, ExtractFilePath(archiEnt) + 'EF' + IntToStr(iFalla + 1) + '.xlt');
    Rewrite(f);

    matrizI:= matricesDeFalla[iFalla];        //nCronicas + 1 * nAniosSim
    Writeln(f, 'Valores Anuales Por Crónica[GW]:');
    write(f, 'Crónica\Año');
    for iAnio:= 0 to aniosConsiderados -1 do
      write(f, #9, anioIniSim + iAnio);
    Writeln(f);

    for iCronica:= 0 to High(matrizI) - 1 do
    begin
      filaI:= matrizI[iCronica];
      write(f, iCronica + 1);
      for iAnio:= 0 to high(filaI) do
        Write(f, #9, filaI[iAnio] * unMilesimo);
      Writeln(f);
    end;

    filaI:= matrizI[high(matrizI)];
    write(f, 'Promedios');
    for iAnio:= 0 to high(filaI) do
      Write(f, #9, filaI[iAnio] * unMilesimo);
    Writeln(f);

    Writeln(f);

    histos:= trasponerIgnorandoUltimaFila(matrizI);//nAniosSim * nCronicas
    ordenarFilasCreciente(histos);

    Writeln(f, 'Histogramas Anuales Por Probabilidad de Ocurrencia:');
    write(f, 'Probabilidad\Año');
    for iAnio:= 0 to aniosConsiderados -1 do
      write(f, #9, anioIniSim + iAnio);
    Writeln(f);

    for iCronica:= 0 to datosSim.nCronicas -1 do
    begin
      write(f, FloatToStrF((iCronica + 1) * invNCronicas, ffFixed, 10, 2), '%');
      for iAnio:= 0 to aniosConsiderados - 1 do
        Write(f, #9, histos[iAnio][iCronica] * unMilesimo);
      writeln(f);
    end;
    liberarMatriz(histos);

    ProgressBar1.StepIt;
    Application.ProcessMessages;
  finally
    CloseFile(f);
  end;

  try
    AssignFile(f, 'EF_Totales.xlt');            // efsTotales (nCronicas + 1) * nAniosSim
    Rewrite(f);

    Writeln(f, 'Valores Anuales Por Crónica[GW]:');
    write(f, 'Crónica\Año');
    for iAnio:= 0 to aniosConsiderados -1 do
      write(f, #9, anioIniSim + iAnio);
    Writeln(f);

    for iCronica:= 0 to datosSim.nCronicas - 1  do
    begin
      write(f, iCronica + 1);
      filaI:= efsTotales[iCronica];
      for iAnio:= 0 to aniosConsiderados - 1 do
        Write(f, #9, filaI[iAnio] * unMilesimo);
      Writeln(f);
    end;

    write(f, 'Promedios');
    filaI:= efsTotales[high(efsTotales)];
    for iAnio:= 0 to aniosConsiderados - 1 do
      Write(f, #9, filaI[iAnio] * unMilesimo);
    Writeln(f);
    Writeln(f);

    histos:= trasponerIgnorandoUltimaFila(efsTotales);
    ordenarFilasCreciente(histos);

    Writeln(f, 'Histogramas Anuales Por Probabilidad de Ocurrencia:');
    write(f, 'Probabilidad\Año');
    for iAnio:= 0 to aniosConsiderados -1 do
      write(f, #9, anioIniSim + iAnio);
    Writeln(f);

    for iCronica:= 0 to datosSim.nCronicas -1 do
    begin
      write(f, FloatToStrF((iCronica + 1) * invNCronicas, ffFixed, 10, 2), '%');
      for iAnio:= 0 to aniosConsiderados - 1 do
        Write(f, #9, histos[iAnio][iCronica] * unMilesimo);
      writeln(f);
    end;
    liberarMatriz(histos);

    Writeln(f);
    Writeln(f, 'Energía Anual Demandada Por Crónica[GW]:');
    write(f, 'Crónica\Año');
    for iAnio:= 0 to aniosConsiderados -1 do
      write(f, #9, anioIniSim + iAnio);
    Writeln(f);

    for iCronica:= 0 to datosSim.nCronicas - 1  do
    begin
      write(f, iCronica + 1);
      filaI:= matrizDeDemanda[iCronica];
      for iAnio:= 0 to aniosConsiderados - 1 do
        Write(f, #9, filaI[iAnio] * unMilesimo);
      Writeln(f);
    end;

    write(f, 'Promedios');
    filaI:= matrizDeDemanda[high(matrizDeDemanda)];
    for iAnio:= 0 to aniosConsiderados - 1 do
      Write(f, #9, filaI[iAnio] * unMilesimo);
    Writeln(f);

    ProgressBar1.StepIt;
    Application.ProcessMessages;
  finally
    CloseFile(f);
  end;
end;

end.
