program calibradorCEGHconEnsembles;

{$mode delphi}
{GFlieller@2019-05-31
--------------------------------------------------------------------------------
Al calibrador se le pasa un conjunto de ensembles en el formato xlt de
TEnsembles y una sala empaquetada.
El archivo de ensembles en el encabezado debe tener el nombre de la fuente de la
sala a la que corresponde.

El calibrador lee el archivo de ensembles y ajusta el CEGH correspondiente para
que el cono de las realizaciones del CEGH imiten al ensemble de pronosticos.

1-  Leer el archivo xlt con la funcion TEnsembles.CreateFromArchiXLT.
2-  Obtener el CEGH desde la sala proporcionada
3-  Calibrar el CEGH con el ensemble TcalibrarConoEnsemble.calibrarConoEnsemble
4-  Guardar la sala
*opcional* 5-  Simular con el CEGH y comparar las cronicas con el ensemble
*opcional* 6-  Graficar resultados

Parametros de Entrada:
1-  ArchiEnsembles: String. Path del archivo xlt que de los ensembles de pronosticos.
2-  ArchiSala: String. Path de la sala (de SimSEE) enmpaquetada en .zip
3-  SIMULAR_CEGH: Booleano. Indica si se simula luego de la calibracion para
    obtener una serie de cronicas sinteticas a partir del CEGH calibrado. Por
    defecto es false.
4-  GRAFICAR_RES: Booleano. Indica si los datos simulados se grafican junto con
    los ensembles de pronosticos. Por defecto es false
5-  nombreSala: String. Nombre de la sala, en caso que la sala dentro del .zip
    no este guardada con el nombre 'sala.ese'. Por defecto 'sala.ese'.
--------------------------------------------------------------------------------
}


//------------------------------------------------------------------------------
uses
  Classes,
//  Dialogs,
  graphics,
  Interfaces,
  matreal,
  uauxiliares,
  ucalibrarconoensamble,
  ucalibrarconopronosticos,
  ucosa,
  ucosaconnombre,
  uempaquetar,
  uensembles,
  ufechas,
  uFuenteSintetizador,
  ugraficador,
  uInicioYFinal,
  usalasdejuego,
  SysUtils,
  xmatdefs,
  zipper;

//------------------------------------------------------------------------------
var
  nombreZip,dirTmp, nombreSala, archiEnsembles, archiSalaZipOrig,
    archiSalaZip, ArchiSala, archiResultados :String;
  lst: TListaDeCosasConNombre;
  ensembles, EnsemblesCEGH, ensemblesCEGHPE: TEnsembles;
  sala: TSalaDeJuego;
  f: TArchiTexto;
  acegh: TFuenteSintetizadorCEGH;
  fechaIniProno, fechaIniSim, fechaFinSim: TFecha;
  calibracion: TcalibrarConoEnsamble;
  convergencia, SIMULAR_CEGH, GRAFICAR_RES, dummy: Boolean;
  tExecCalib, tExecGuardar, tExecSim, tExecGraficar, durPaso: TDateTime;
  funzip: TUnZipper;
  catalogo: TCatalogoReferencias;
  SeriesConPron: TSeriesConoPronostico;
  SeriesSimCEGH: array of TMatR;
  NcronSim, hcanal: integer;
  cortesPECEGH : array of NReal;
//------------------------------------------------------------------------------

begin

  //  0- Lectura de parametros de ejecucion. archiEnsembles.xlt y sala.zip son
  //     campos obligatorios. Si no se carga ningun valor como nombreSala se
  //     asume que se llama 'sala.ese'.
  if ParamCount> 2 then
     begin
     archiEnsembles:=Paramstr(1);
     archiSalaZipOrig:=ParamStr(2);
     end
  else
     begin
     writeln('NO SE PUEDE EJECUTAR LA CALIBRACION!!!');
     writeln('DEBE INGRESAR UN CONJUNTO DE ENSEMBLES Y UNA SALA');
     halt(1);
     end;


  if ParamCount>3 then
     SIMULAR_CEGH := StrToBool( ParamStr(3) )
  else
     SIMULAR_CEGH := false;

{$IFDEF GRAFICAR_ENSEMBLES}
  if SIMULAR_CEGH then
  begin
     if ParamCount>4 then
        GRAFICAR_RES := StrToBool( ParamStr(4) )
     else
        GRAFICAR_RES := false;
  end;

  if ParamCount>5 then
     nombreSala:= ParamStr(5)
  else
     nombreSala:= 'sala.ese';


  if ParamCount>6 then
     NcronSim:= StrToInt( ParamStr(6) )
  else
     NcronSim:= 1000;
{$ELSE}

  if ParamCount>4 then
     nombreSala:= ParamStr(4)
  else
     nombreSala:= 'sala.ese';


  if ParamCount>5 then
     NcronSim:= StrToInt( ParamStr(5) )
  else
     NcronSim:= 1000;
{$ENDIF}

//------------------------------------------------------------------------------
setSeparadoresGlobales;
uInicioYFinal.AlInicio;

  //  1  Leer ensembles desde xlt
  ensembles:= TEnsembles.CreateFromArchiXLT(archiEnsembles);

//------------------------------------------------------------------------------

  //  2
  //  2.1  copiar a temporal y desempaquetar la sala
  dirTmp:= '/home' + DirectorySeparator+GetEnvironmentVariable('USER')+ DirectorySeparator+
           'basura'+DirectorySeparator+'tmp';
  if not DirectoryExists(dirTmp) then
     mkdir(dirTmp);

  nombreZip := ExtractFileName(archiSalaZipOrig);
  archiSalaZip := dirTmp + DirectorySeparator + nombreZip;
  cp( archiSalaZipOrig, archiSalaZip);
  funzip := TUnZipper.Create;
  funzip.OutputPath := dirTmp;
  funzip.UnZipAllFiles(archiSalaZip);
  funzip.Free;

  //  2.2  Cargar la sala
  ArchiSala := dirTmp + DirectorySeparator + nombreSala;
  sala := usalasdejuego.cargarSala(0,ArchiSala,'', True);
  chdir(sala.dirSala);

  //  2.3  Buscar el CEGH segun el nombre del TEnsembles
  acegh := sala.BuscarPorNombre(ensembles.Nombre, lst) as TFuenteSintetizadorCEGH;
  catalogo := TCatalogoReferencias.Create;
  f := TArchiTexto.CreateForRead(0, catalogo, ArchiSala, False);
  sala.Prepararse_(TCatalogoReferencias(f.CatalogoReferencias));
  f.Free;


//------------------------------------------------------------------------------

  //  3
  //  3.1  Cargar la fecha de inicio del pronostico
  fechaIniProno:= TFecha.Create_Dt(ensembles.dtPrimeraMuestra);

  tExecCalib:=now;
  //  3.2  Crear el calibrador
  calibracion := TcalibrarConoEnsamble.Create(aCEGH, ensembles.EnsemblesMat,fechaIniProno);
  //  3.3  Calibrar
  convergencia := calibracion.calibrarConoEnsamble();
  if convergencia then
     write('Calibrado con exito! ')
  else
     write('ATENCION! No se ha podido calibrar correctamente.');


  writeln('Tiempo empleado calibrando el CEGH: '+ TimeToStr(Now-tExecCalib)+'.');

//------------------------------------------------------------------------------

   //  4    Guardando sala
   tExecGuardar := Now;
   writeln('Guardando pronosticos en el CEGH.');

   //  4.1  Guardar el pronostico dentro de los pronosticos del CEGH
   acegh.escenariosDePronosticos.prepararse(acegh.durPasoDeSorteoEnHoras);
   acegh.escenariosDePronosticos.setItem(0,calibracion.aPronosticos);
   //  4.2  Guardar la sala
   writeln('Guardando sala modificada.');

   //  4.3  Fijar fecha ini y fecha fin
   fechaIniSim:= TFecha.Create_Dt( ensembles.dtPrimeraMuestra ) ;
   fechaFinSim:= TFecha.Create_Dt( ensembles.dtPrimeraMuestra +
                                   ensembles.dtPaso*ensembles.Npasos );

   acegh.escenariosDePronosticos[0].fechaIniCono := fechaIniSim;

   //  4.4  Guardar la sala
   sala.guardarSala;

   //  4.5  Empaquetar la sala
   dummy:=true;

   EmpaquetarSalaEnZip(sala, nil, dummy);
   RenameFile( sala.nombre+'.zip' , archiSalaZip);

   writeln( 'Tiempo empleado guardando la sala: '
            + TimeToStr(Now-tExecGuardar)+'.');


//------------------------------------------------------------------------------

   //  5
   if SIMULAR_CEGH then
   begin

     writeln('Creando series sinteticas con CEGH.');
     tExecSim:=Now;

     //  5.1  Simular cronicas
     SeriesConPron := TSeriesConoPronostico.CreateFromSim(1,aCEGH,fechaIniSim,
                                            fechaFinSim,NCronSim,0.01,0.99);
     SeriesSimCEGH := SeriesConPron.preview_datos_desordenados;

     EnsemblesCEGH := TEnsembles.Create( ensembles.Nombre + '_CEGH',
                  ensembles.NCanales, NcronSim, round(fechaFinSim.dt-fechaIniSim.dt)*24,
                  fechaIniSim.dt,ensembles.dtPaso);
     for hcanal:=0 to ensembles.NCanales-1 do
         EnsemblesCEGH.EnsembleDesdeMatR( ensembles.nombresEnsembles[hcanal],
                                          hcanal, SeriesSimCEGH[hcanal]);

     //  5.2  Escribir Salida
     archiResultados := sala.dirSala + DirectorySeparator + ensembles.Nombre +
                        '_CEGH_vs_Ensembles.ods';
     WriteToArchiEnsembles(ensembles,EnsemblesCEGH,archiResultados);

     //  5.3  Liberar memoria
     for hcanal:=0 to high(SeriesSimCEGH) do
         SeriesSimCEGH[hcanal].free;
     setlength(SeriesSimCEGH,0);
     writeln('Tiempo simulacion: '+ TimeToStr(Now - tExecSim)+'.');

   end;

//------------------------------------------------------------------------------

{$IFDEF GRAFICAR_ENSEMBLES}
   //  6  Graficar
   if GRAFICAR_RES then
   begin
     tExecGraficar:=Now;

     SetLength(cortesPECEGH,5);
     cortesPECEGH[0] := 0.05;
     cortesPECEGH[1] := 0.20;
     cortesPECEGH[2] := 0.50;
     cortesPECEGH[3] := 0.80;
     cortesPECEGH[4] := 0.95;
     ensemblesCEGHPE := EnsemblesCEGH.ToCortesDePE(cortesPECEGH);

     ensembles.GraficarComparar( ensembles,ensemblesCEGHPE, -1,'/home/gflieller/basura');
     ensemblesCEGHPE.free;
     writeln('Tiempo creacion de graficos: '+ TimeToStr(Now - tExecGraficar)+'.');
   end;
{$ENDIF}
//------------------------------------------------------------------------------

//   calibracion.free;
   ensembles.free;
   ensemblesCEGH.free;
   sala.Free;

//------------------------------------------------------------------------------
writeln('The End.');

end.

