//====Modificado metodos: CreateDataColumnList y CreateDataConversionList===
//====Micho@27/5==mvarela@adme.com.uy=======================================
unit ugter_arranqueparadaV2;

{$DEFINE PROBANDO_OPTROT}
{$DEFINE HISTERESIS_AP}

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

interface

uses
  SysUtils, Classes, xmatdefs, uGTer, unodos, Math,
  uglobs,
  uEstados,
  umipsimplex,
  usimplex,
  ufichasLPD,
  ufechas,
  ucosa,
  uconstantesSimSEE,
  uFuentesAleatorias
  {$IFDEF COMBUSTIBLES}
  , uCombustible
  {$ENDIF}  ;

resourcestring
  rsGeneradorTermicoConCostoArranqueParada = 'GTer con costos arranque/parada V2';

type

  { TFichaGTer_ArranqueParadaV2 }

  TFichaGTer_ArranqueParadaV2 = class(TFichaLPD)
protected
    




















public
     
      PMin, PMax: NReal; // [MW] Potencias Mínima y Máxima Por maquina
      indicePreciosPorCombustible: TFuenteAleatoria;
      bornePreciosPorCombustible: string;
      disp: NReal; // disponibilidad (fortuita)
      tRepHoras: NReal;
      costo_arranque, costo_parada: NReal;
      HayRestriccionEmaxPasoDeTiempo: boolean; // indica si se aplica la restricción
      EmaxPasoDeTiempo: NReal; // Energía maxima generable en un paso de tiempo

      disponibleCombustible: array[1..3] of boolean;
      rendimientoPN: array[1..3] of NReal;
      rendimientoMT: array[1..3] of NReal;
      combustible: array[1..3] of TCombustible;

        {$IFDEF HISTERESIS_AP}
          MinHorasON, MinHorasOFF: integer; // valor mínimo entre arranques y paradas.
          PenalidadONOFF: NReal;
        {$ENDIF}
    

    nroBornePreciosPorCombustible: integer;

      constructor Create(fecha: TFecha; periodicidad: TPeriodicidad;
      PMin, PMax: NReal; indicePreciosPorCombustible: TFuenteAleatoria;
      bornePreciosPorCombustible: string; disp: NReal; tRepHoras: NReal;
      costo_arranque, costo_parada: Nreal; HayRestriccionEmaxPasoDeTiempo: boolean;
      EmaxPasoDeTiempo: NReal; disponibleCombustible: array of boolean;
      rendimientoPN: array of NReal; rendimientoMT: array of NReal;
      combustible: array of TCombustible
      {$IFDEF HISTERESIS_AP}      ; xMinHorasON, xMinHorasOFF: integer;
    // valor mínimo entre arranques y paradas.
      xPenalidadONOFF: NReal
    // penalidad a sumar al costo de la desición de transición
      {$ENDIF}
      ); overload;

    constructor Create(fecha: TFecha; periodicidad: TPeriodicidad;
      PMin, PMax: NReal; indicePreciosPorCombustible: TFuenteAleatoria;
      bornePreciosPorCombustible: string; disp: NReal; tRepHoras: NReal;
      costo_arranque, costo_parada: Nreal; HayRestriccionEmaxPasoDeTiempo: boolean;
      EmaxPasoDeTiempo: NReal
      {$IFDEF HISTERESIS_AP}      ; xMinHorasON, xMinHorasOFF: integer;
    // valor mínimo entre arranques y paradas.
      xPenalidadONOFF: NReal
    // penalidad a sumar al costo de la desición de transición
      {$ENDIF}
      ); overload;

    constructor Create_ReadFromText(f: TArchiTexto); override;
    procedure WriteToText(f: TArchiTexto); override;
    procedure generarLineaResumen(var archi: TextFile); override;
    function infoAd_: string; override;
    procedure Free; override;

    class function CreateDataColumnList(xClaseDeCosa: TClaseDeCosa; xVersion: Integer=-2
      ): TDataColumnListOfCosa; override;
    class function CreateDataConversionList: TListDataConversion; override;

published
      





















  end;

  // TGTer_OnOffPorPaso es una potencia minima y maxima constante en todos los postes
  // y un costo variable cv [USD/MWh] tambien igual en todos los postes
  // y un costo variable cv_min "hasta el minimo" igual al costo de produccion en USD/MWh cuando
  // la central esta generado en el minimo.

  { TGTer_ArranqueParadaV2 }

  TGTer_ArranqueParadaV2 = class(TGTer)
protected
  






public
    pa: TFichaGTer_ArranqueParadaV2;

    // NMaquinasDespachadas_AlInicioDelPaso: Integer;
    X_NMaquinasDespachadas, Xs_NMaquinasDespachadas: integer;
    // cantidad de máquinas despachadas ( variable de Acople )

     
    encendidoAlInicio: boolean;
    

    {$IFDEF HISTERESIS_AP}
    // introduzco para la simulación la posibilidad de especificar
    // horas de histérisis entre arranques y paradas.
    // esto intenta evitar la conmutación de las turbo vapor entre pasos consecutivos
    // sobre todo en simulaciones horarias.
    X_HorasHisteresisAP, Xs_HorasHisterisisAP: integer;

     
    FechaCambioEstado_ini: TFecha;
    
{$ENDIF}


{$IFDEF PROBANDO_OPTROT}
    // se actualiza en sortesodelpaso. Esta variable se utiliza
    // durante la Optimización para determinar la disponibilidad de la máquina
    // dado que se encuentre encendida.
    Romperse: boolean;
{$ENDIF}

    c0: NReal; //Costo en USD/h por máquina por estar operando en el mínimo técnico
    cv: NReal; // USD/MWh usado para la optimización del paso.
    cvPN: array[1..3] of NReal;
    cvMT: array[1..3] of NReal;

    PMin: NReal; //MW, mínimo
    PxMax: NReal; // MW, cota sup de P-Pmin


    // resultado de los sorteos de disponibilidad y del mantenimiento programado
    NMaquinasDisponibles_: integer;
    PMaxDisponible: NReal;

    //Cuanta potencia despacho en cada hora el generador en promedio
    potMedia_despachada: NReal;

    //Variación de costo futuro por transición de estado en USD
    dCF: NReal;

    constructor Create(nombre: string; nacimiento, muerte: TFecha;
      lpdUnidades, lpd: TFichasLPD; nodo: TNodo; encendidoAlInicio: boolean
      {$IFDEF HISTERESIS_AP}      ; xFechaCambioEstado_ini: TFecha
      {$ENDIF}
      );
      reintroduce;

    constructor Create_ReadFromText(f: TArchiTexto); override;
    procedure WriteToText(f: TArchiTexto); override;
    procedure PrepararMemoria(globs: TGlobs); override;
    procedure RegistrarParametrosDinamicos; override;

    function PotenciaFirme: NReal; override;

    function InfoAd_: string; override;
    class function DescClase: string; override;

    procedure PosicionarseEnEstrellita; override;
    procedure ActualizarEstadoGlobal; override;

    //      procedure Sim_Inicio; override;
    procedure Sim_Cronica_Inicio; override;
    procedure SorteosDelPaso(sortear: boolean); override;
    procedure PrepararPaso_ps; override;
    procedure Sim_Paso_Fin; override;
    //      procedure Sim_Cronica_Fin; override;
    //      procedure Sim_Fin; override;

    procedure opt_nvers(var ivar, ivae, ires: integer); override;
    procedure optx_nvxs(var ixr, ixd, iauxNReal, iauxInt: integer); override;
    procedure optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados); override;

    procedure opt_cargue(s: TSimplex); override;
    procedure opt_fijarRestriccionesDeCaja(s: TSimplex); override;
    procedure opt_leerSolucion(s: TSimplex); override;
    procedure EvolucionarEstado; override;

{$IFDEF SPXCONLOG}
    procedure spx_NombrarVariables(s: TSimplex); override;
{$ENDIF}
    function getNombreVar(ivar: integer; var nombre: string): boolean; override;
    function getNombreRes(ires: integer; var nombre: string): boolean; override;

    procedure Free; override;

    procedure PubliVars; override;
    // imprime tabla de delta costo futuro de la transición USD/MWh
    procedure opt_PrintResultados_Encab(var fsal: textfile); override;
    procedure opt_PrintResultados(var fsal: textfile); override;

    procedure dump_Variables(var f: TextFile; charIndentacion: char); override;

    class function TipoFichaLPD: TClaseDeFichaLPD; override;


    function NMaquinasDisponibles_x: integer;

    class function CreateDataColumnList(xClaseDeCosa: TClaseDeCosa; xVersion: Integer=-2
      ): TDataColumnListOfCosa; override;

    procedure AfterInstantiation; override;

    published
    





  end;


procedure AlInicio;
procedure AlFinal;

implementation


//-------------------------------------
// Métodos de TFichaGTer_ArranqueParada
//=====================================

constructor TFichaGTer_ArranqueParadaV2.Create(fecha: TFecha;
  periodicidad: TPeriodicidad; PMin, PMax: NReal;
  indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string;
  disp: NReal; tRepHoras: NReal; costo_arranque, costo_parada: Nreal;
  HayRestriccionEmaxPasoDeTiempo: boolean; EmaxPasoDeTiempo: NReal;
  disponibleCombustible: array of boolean; rendimientoPN: array of NReal;
  rendimientoMT: array of NReal; combustible: array of TCombustible
  {$IFDEF HISTERESIS_AP}  ; xMinHorasON, xMinHorasOFF: integer;
  // valor mínimo entre arranques y paradas.
  xPenalidadONOFF: NReal
  {$ENDIF}
  );
begin
  inherited Create(fecha, periodicidad);
  self.PMin := PMin;
  self.PMax := PMax;
  self.disp := disp;
  self.tRepHoras := tRepHoras;
  self.costo_arranque := costo_arranque;
  self.costo_parada := costo_parada;
  self.HayRestriccionEmaxPasoDeTiempo := HayRestriccionEmaxPasoDeTiempo;
  self.EmaxPasoDeTiempo := EmaxPasoDeTiempo;
  self.indicePreciosPorCombustible := indicePreciosPorCombustible;
  self.bornePreciosPorCombustible := bornePreciosPorCombustible;
  self.disponibleCombustible := disponibleCombustible;
  self.rendimientoPN := rendimientoPN;
  self.rendimientoMT := rendimientoMT;
  self.combustible := combustible;
  {$IFDEF HISTERESIS_AP}
  MinHorasON := xMinHorasON;
  MinHorasOFF := xMinHorasOFF;
  PenalidadONOFF := xPenalidadONOFF;
  {$ENDIF}
end;


constructor TFichaGTer_ArranqueParadaV2.Create(fecha: TFecha;
  periodicidad: TPeriodicidad; PMin, PMax: NReal;
  indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string;
  disp: NReal; tRepHoras: NReal; costo_arranque, costo_parada: Nreal;
  HayRestriccionEmaxPasoDeTiempo: boolean; EmaxPasoDeTiempo: NReal
  {$IFDEF HISTERESIS_AP}  ; xMinHorasON, xMinHorasOFF: integer;
  // valor mínimo entre arranques y paradas.
  xPenalidadONOFF: NReal
  {$ENDIF}
  );
begin
  inherited Create(fecha, periodicidad);
  self.PMin := PMin;
  self.PMax := PMax;
  self.disp := disp;
  self.tRepHoras := tRepHoras;
  self.costo_arranque := costo_arranque;
  self.costo_parada := costo_parada;
  self.HayRestriccionEmaxPasoDeTiempo := HayRestriccionEmaxPasoDeTiempo;
  self.EmaxPasoDeTiempo := EmaxPasoDeTiempo;
  self.indicePreciosPorCombustible := indicePreciosPorCombustible;
  self.bornePreciosPorCombustible := bornePreciosPorCombustible;
  {$IFDEF HISTERESIS_AP}
  MinHorasON := xMinHorasON;
  MinHorasOFF := xMinHorasOFF;
  PenalidadONOFF := xPenalidadONOFF;
  {$ENDIF}
end;


constructor TFichaGTer_ArranqueParadaV2.Create_ReadFromText(f: TArchiTexto);
var
  i: integer;
begin
  inherited Create_ReadFromText(f);
  f.IniciarLecturaRetrasada;
  f.rd('PMin', PMin);
  f.rd('PMax', PMax);
  f.rdReferencia('indicePreciosPorCombustible',
    TCosa(indicePreciosPorCombustible), Self);
  f.rd('bornePreciosPorCombustible', bornePreciosPorCombustible);
  f.rd('disp', disp);
  f.rd('tRepHoras', tRepHoras);
  f.rd('costo_arranque', costo_arranque);
  f.rd('costo_parada', costo_parada);
  f.rd('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
  f.rd('EmaxPasoDeTiempo', EmaxPasoDeTiempo);

  for i := 1 to 3 do
  begin
    f.rd('disponibleCombustible' + IntToStr(i), disponibleCombustible[i]);
    f.rd('rendimientoPN' + IntToStr(i), rendimientoPN[i]);
    f.rd('rendimientoMT' + IntToStr(i), rendimientoMT[i]);
    f.rdReferencia('combustible' + IntToStr(i), TCosa(combustible[i]), Self);
  end;

  {$IFDEF HISTERESIS_AP}
  f.rd('MinHorasON', MinHorasOn);
  f.rd('MinHorasOFF', MinHorasOFF);
  f.rd('PenalidadONOFF', PenalidadONOFF);
  {$ENDIF}

  f.EjecutarLectura;
end;

procedure TFichaGTer_ArranqueParadaV2.WriteToText(f: TArchiTexto);
var
  i: integer;
begin
  inherited WriteToText(f);
  f.wr('PMin', PMin, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('PMax', PMax, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wrReferencia('indicePreciosPorCombustible', indicePreciosPorCombustible);
  f.wr('bornePreciosPorCombustible', bornePreciosPorCombustible);
  f.wr('disp', disp, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALESPU);
  f.wr('tRepHoras', tRepHoras, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wr('costo_arranque', costo_arranque, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wr('costo_parada', costo_parada, uconstantesSimSEE.CF_PRECISION,
    uconstantesSimSEE.CF_DECIMALES);
  f.wr('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
  f.wr('EmaxPasoDeTiempo', EmaxPasoDeTiempo);

  for i := 1 to 3 do
  begin
    f.wr('disponibleCombustible' + IntToStr(i), disponibleCombustible[i]);
    f.wr('rendimientoPN' + IntToStr(i), rendimientoPN[i]);
    f.wr('rendimientoMT' + IntToStr(i), rendimientoMT[i]);
    f.wrReferencia('combustible' + IntToStr(i), combustible[i]);
  end;

  {$IFDEF HISTERESIS_AP}
  f.wr('MinHorasON', MinHorasOn);
  f.wr('MinHorasOFF', MinHorasOFF);
  f.wr('PenalidadONOFF', PenalidadONOFF);
  {$ENDIF}
end;

procedure TFichaGTer_ArranqueParadaV2.generarLineaResumen(var archi: TextFile);
begin
  Write(archi, FloatToStrF(PMin, formatoReales, 8, 1), #9,
    //PMín
    FloatToStrF(PMax, formatoReales, 8, 1), #9,
    //PMáx
    FloatToStrF(disp, formatoReales, 8, 2), #9,
    //FDisp
    FloatToStrF(costo_arranque, formatoReales, 8, 2), #9,
    //Costo Arranque
    FloatToStrF(costo_parada, formatoReales, 8, 2), #9,
    //Costo Parada
    '-', #9,
    //mínNPasosOn
    '-', #9,
    //mínNPasosOff
    '-', #9,
    //desiciónPasosOnPorCiclo
    '-', #9,
    //desiciónPasosOffPorCiclo
    '-', #9,
    //costoPorCicloOn
    '-', #9);
  //costoPorCicloOff
end;

function TFichaGTer_ArranqueParadaV2.infoAd_: string;
begin
  Result := 'PMín= ' + FloatToStrF(PMin, ffGeneral, 10, 1) + ' MW, ' +
    'PMáx= ' + FloatToStrF(PMax, ffGeneral, 10, 1) + ' MW, ' +
    ' USD/MWh, ' + 'fDisp= ' + FloatToStrF(disp, ffGeneral, 10, 2) +
    ' p.u., ' + 'tRep= ' + FloatToStrF(tRepHoras, ffGeneral, 10, 1) +
    'h, ' + 'CostoArranque= ' + FloatToStrF(costo_arranque, ffGeneral, 10, 1) +
    ' USD, ' + 'CostoParada= ' + FloatToStrF(costo_parada, ffGeneral, 10, 1) + ' USD';
end;

procedure TFichaGTer_ArranqueParadaV2.Free;
begin
  inherited Free;
end;

class function TFichaGTer_ArranqueParadaV2.CreateDataColumnList(
  xClaseDeCosa: TClaseDeCosa; xVersion: Integer): TDataColumnListOfCosa;
begin
  











































end;

class function TFichaGTer_ArranqueParadaV2.CreateDataConversionList: TListDataConversion;
begin
  Result:=inherited CreateDataConversionList;
  Result.Add(uConversions.VERSION_MIGRACION_PERSISTENCIA,
    ['disponibleCombustible1', 'disponibleCombustible2' , 'disponibleCombustible3'],
    ['disponibleCombustible'], Result.ConversionPrimitivesToOneDynArray());

  Result.Add(uConversions.VERSION_MIGRACION_PERSISTENCIA,
    ['rendimientoPN1', 'rendimientoPN2' , 'rendimientoPN3'],
    ['rendimientoPN'], Result.ConversionPrimitivesToOneDynArray());

  Result.Add(uConversions.VERSION_MIGRACION_PERSISTENCIA,
    ['rendimientoMT1', 'rendimientoMT2' , 'rendimientoMT3'],
    ['rendimientoMT'], Result.ConversionPrimitivesToOneDynArray());

  Result.Add(uConversions.VERSION_MIGRACION_PERSISTENCIA,
    ['combustible1', 'combustible2' , 'combustible3'],
    ['combustible'], Result.ConversionPrimitivesToOneDynArray());
end;

//--------------------------------
// Métodos de TGTer_ArranqueParada
//================================
procedure TGTer_ArranqueParadaV2.opt_PrintResultados_Encab(var fsal: textfile);
begin
  Write(fsal, #9, IntToStr(X_NMaquinasDespachadas));
end;

procedure TGTer_ArranqueParadaV2.opt_PrintResultados(var fsal: textfile);
begin
  Write(fsal, #9, FloatToStrF(dCF, ffgeneral, 6, 3));
end;

procedure TGTer_ArranqueParadaV2.dump_Variables(var f: TextFile;
  charIndentacion: char);
begin
  inherited dump_Variables(f, charIndentacion);
  writeln(f, charIndentacion, 'c0[USD/MWh]= ', FloatToStrF(c0, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'cv[USD/MWh]= ', FloatToStrF(cv, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'costo_arranque[USD]= ',
    FloatToStrF(pa.costo_arranque, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'costo_parada[USD]= ',
    FloatToStrF(pa.costo_parada, ffFixed, 10, 3));

  writeln(f, charIndentacion, 'PMin[MW]= ', FloatToStrF(PMin, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'PMAx[MW]= ', FloatToStrF(pa.PMax, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'PxMax[MW]= ', FloatToStrF(PxMax, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'PMaxDisponible[MW]= ',
    FloatToStrF(PMaxDisponible, ffFixed, 10, 3));

  writeln(f, charIndentacion, 'NMaquinasDisponibles= ', NMaquinasDisponibles_);
  writeln(f, charIndentacion, 'X_NMaquinasDespachadas= ', X_NMaquinasDespachadas);
  writeln(f, charIndentacion, 'Xs_NMaquinasDespachadas= ', Xs_NMaquinasDespachadas);

  writeln(f, charIndentacion, 'HayRestrEMaxPasoDeTiempo= ',
    pa.hayRestriccionEmaxPasoDeTiempo);
  writeln(f, charIndentacion, 'EMaxPasoDeTiempo[MW/h]= ',
    FloatToStrF(pa.EmaxPasoDeTiempo, ffFixed, 10, 3));

  writeln(f);
end;

class function TGTer_ArranqueParadaV2.TipoFichaLPD: TClaseDeFichaLPD;
begin
  Result := TFichaGTer_ArranqueParadaV2;
end;

constructor TGTer_ArranqueParadaV2.Create(nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  encendidoAlInicio: boolean
  {$IFDEF HISTERESIS_AP}  ; xFechaCambioEstado_ini: TFecha
  {$ENDIF}
  );
begin
  inherited Create(nombre, nacimiento, muerte, lpdUnidades, lpd, nodo);
  self.encendidoAlInicio := encendidoAlInicio;
  {$IFDEF HISTERESIS_AP}
  FechaCambioEstado_ini := xFechaCambioEstado_ini;
  {$ENDIF}
end;

constructor TGTer_ArranqueParadaV2.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  f.IniciarLecturaRetrasada;
  f.rd('encendidoAlInicio', encendidoAlInicio);

{$IFDEF HISTERESIS_AP}
  if f.version >= 51 then
    f.rd('FechaCambioEstado_ini', self.FechaCambioEstado_ini)
  else
    FechaCambioEstado_ini := TFecha.Create_Dt(0);
{$ENDIF}

  f.EjecutarLectura;
  pa := nil;
  nodo := nil;
end;

procedure TGTer_ArranqueParadaV2.PrepararMemoria(globs: TGlobs);
begin
  inherited prepararMemoria(globs);
end;

procedure TGTer_ArranqueParadaV2.RegistrarParametrosDinamicos;
var
  i: integer;
  ficha: TFichaGTer_ArranqueParadaV2;
begin
  inherited registrarParametrosDinamicos;
  lpd.expandirFichas(globs);
  lpd.RegistrarFichasAActualizar(Self, globs.ActualizadorLPD, @pA, nil);
  for i := 0 to lpd.Count - 1 do
  begin
    ficha := TFichaGTer_ArranqueParadaV2(lpd[i]);
    if ficha.indicePreciosPorCombustible <> nil then
      ficha.nroBornePreciosPorCombustible :=
        ficha.indicePreciosPorCombustible.IdBorne(ficha.bornePreciosPorCombustible);
  end;
end;

function TGTer_ArranqueParadaV2.PotenciaFirme: NReal;
begin
  Result := (paUnidades.nUnidades[0]) * pa.PMax * pa.disp;
end;

function TGTer_ArranqueParadaV2.InfoAd_: string;
begin
  Result := '';
end;

class function TGTer_ArranqueParadaV2.DescClase: string;
begin
  Result := rsGeneradorTermicoConCostoArranqueParada;
end;

procedure TGTer_ArranqueParadaV2.PosicionarseEnEstrellita;
begin
  Self.X_NMaquinasDespachadas := globs.CF.xd[ixd];
end;

procedure TGTer_ArranqueParadaV2.ActualizarEstadoGlobal;
begin
  globs.CF.xd[ixd] := Self.X_NMaquinasDespachadas;
end;

procedure TGTer_ArranqueParadaV2.Sim_Cronica_Inicio;
{$IFDEF HISTERESIS_AP}
var
  horasUltimoCambioEstado: integer;
{$ENDIF}

begin
  inherited Sim_Cronica_Inicio;
  if encendidoAlInicio then
    X_NMaquinasDespachadas := 1
  else
    X_NMaquinasDespachadas := 0;

{$IFDEF HISTERESIS_AP}
  horasUltimoCambioEstado := self.FechaCambioEstado_ini.HorasHasta(globs.fechaIniSim);
  if X_NMaquinasDespachadas > 0 then
    X_HorasHisteresisAP := max(0, pa.MinHorasON - horasUltimoCambioEstado)
  else
    X_HorasHisteresisAP := max(0, pa.MinHorasOFF - horasUltimoCambioEstado);
  // aquí habria  que cargar del Actor el valor
{$ENDIF}
end;

procedure TGTer_ArranqueParadaV2.SorteosDelPaso(sortear: boolean);
begin
{$IFDEF PROBANDO_OPTROT}
  Romperse := False;
{$ENDIF}
  if globs.ObligarDisponibilidad_1_ then
  begin
    NMaquinasDisponibles_ := paUnidades.nUnidades[0];
    PMaxDisponible := pa.PMax * NMaquinasDisponibles_;
  end
  else if sortear then
  begin
    ActualizarProbabilidadesReparacionYRotura(pa.disp, pa.tRepHoras);
    NMaquinasDisponibles_ := Sorteos_RepRotUnidades;
    PMaxDisponible := pa.PMax * NMaquinasDisponibles_;
{$IFDEF PROBANDO_OPTROT}
    if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
      Romperse := globs.sorteadorUniforme.rnd < self.Unidades_pRot;
{$ENDIF}
  end
  else
  begin
    NMaquinasDisponibles_ := paUnidades.nUnidades[0];
    PMaxDisponible := pa.PMax * pa.disp * NMaquinasDisponibles_;
  end;
end;


function TGTer_ArranqueParadaV2.NMaquinasDisponibles_x: integer;
begin
{$IFDEF PROBANDO_OPTROT}
  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) and
    (self.X_NMaquinasDespachadas > 0) then
    if Romperse then
      Result := 0
    else
      Result := 1
  else
{$ENDIF}
    Result := self.NMaquinasDisponibles_;
end;

class function TGTer_ArranqueParadaV2.CreateDataColumnList(
  xClaseDeCosa: TClaseDeCosa; xVersion: Integer): TDataColumnListOfCosa;
begin
  






end;

procedure TGTer_ArranqueParadaV2.AfterInstantiation;
begin
  inherited AfterInstantiation;
  pa := nil;
  nodo := nil;
end;


procedure TGTer_ArranqueParadaV2.PrepararPaso_ps;
var
  i: integer;
begin
  PMin := pa.PMIn;
  PxMax := pa.PMax - pa.PMin;

  for i := 1 to 3 do
  begin

    if pa.combustible[i] <> nil then
    begin
      cvMT[i] := (pa.combustible[i].pa.precio *
        pa.combustible[i].pa.PCS) / (pa.rendimientoMT[i] *
        pa.combustible[i].pa.PCI);

      cvPN[i] := (pa.combustible[i].pa.precio *
        pa.combustible[i].pa.PCS) / (pa.rendimientoMT[i] *
        pa.combustible[i].pa.PCI);
    end
    else
    begin
      cvMT[i] := Math.MaxDouble;
      cvPN[i] := Math.MaxDouble;
    end;
  end;

  c0 := Min(Min(cvMT[1], cvMT[1]), cvMT[3]);
  cv := Min(Min(cvPN[1], cvPN[1]), cvPN[3]);

  if X_NMaquinasDespachadas = 0 then // estaba apagada
  begin
    if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
      dCF := globs.CF.deltaCosto_vxd_estrella(ixd, globs.kPaso_ + 1, 1) * globs.fActPaso
    else
      dCF := globs.CF.deltaCosto_vxd_continuo(ixd, globs.kPaso_ + 1, 1) * globs.fActPaso;
  end
  else // estaba prendida
  begin
    if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
      dCF := globs.CF.deltaCosto_vxd_estrella(ixd, globs.kPaso_ + 1, -1) * globs.fActPaso
    else
      dCF := globs.CF.deltaCosto_vxd_continuo(ixd, globs.kPaso_ + 1, -1) *
        globs.fActPaso;
  end;

{$IFDEF HISTERESIS_AP}
  // si está habilitado el control de histéresis multiplico por 1000 el dCF para
  // que le cueste tomar la desición.
  if (globs.EstadoDeLaSala = CES_SIMULANDO) and (x_HorasHisteresisAP > 0) then
    dCF := dCF + pa.PenalidadONOFF;
{$ENDIF}

end;

procedure TGTer_ArranqueParadaV2.Sim_Paso_Fin;
var
  iposte: integer;
begin
  for iposte := 0 to high(P) do
    potMedia_despachada := potMedia_despachada + P[iposte] * globs.durpos[iposte];
  potMedia_despachada := potMedia_despachada * globs.invHorasDelPaso;
end;

procedure TGTer_ArranqueParadaV2.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
  f.wr('encendidoAlInicio', encendidoAlInicio);
  {$IFDEF HISTERESIS_AP}
  f.wr('FechaCambioEstado_ini', FechaCambioEstado_ini);
  {$ENDIF}
end;

procedure TGTer_ArranqueParadaV2.opt_nvers(var ivar, ivae, ires: integer);
begin
  if NMaquinasDisponibles_x = 0 then
    exit;
  Self.ivar := ivar;
  ivar := ivar + globs.NPostes + 1; //Potencias y A
  Self.ivae := ivae;
  ivae := ivae + 1;                 //A
  Self.ires := ires;
  ires := ires + globs.NPostes;     //Restricciones de minimos técnicos
  if pA.HayRestriccionEmaxPasoDeTiempo then
    Inc(ires);
end;

procedure TGTer_ArranqueParadaV2.optx_nvxs(var ixr, ixd, iauxNReal, iauxInt: integer);
begin
  Self.ixd := ixd;
  ixd := ixd + 1;
end;

procedure TGTer_ArranqueParadaV2.optx_RegistrarVariablesDeEstado(
  adminEstados: TAdminEstados);
begin
  adminEstados.Registrar_Discreta(ixd, 2, Self.Nombre + '_A', 'bool');
end;

procedure TGTer_ArranqueParadaV2.opt_cargue(s: TSimplex);
var
  inodores: integer;
  iposte: integer;
  jres: integer;
begin

  if NMaquinasDisponibles_x = 0 then
    exit; // si no hay máquinas no juego

{$IFDEF SPXCONLOG}
  spx_NombrarVariables(s);
{$ENDIF}
  inodores := nodo.ires;
  // CON MINIMOS TECNICOS
  // aporte a las restricciones de nodo

  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(inodores + iposte, ivar + iposte, 1); // coeficiente de la B[iposte]
    s.pon_e(inodores + iposte, ivar + globs.NPostes, Pmin); // coef A
  end;

  jres := ires;
  // restricciones adicionales impuestas por la variable de Acople
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(jres, ivar + iposte, -1); // coef B[iposte]
    s.pon_e(jres, ivar + globs.NPostes, PxMax);
    Inc(jres);
  end;

  //Restriccion a la energía máxima generable en un paso
  if pA.HayRestriccionEmaxPasoDeTiempo then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(jres, ivar + iposte, -globs.durpos[iposte]);
    s.pon_e(jres, ivar + globs.NPostes, -pa.PMin * globs.HorasDelPaso);
    s.pon_e(jres, s.nc, pa.EmaxPasoDeTiempo);
  end;

  // aportes a la función de utilidad
  for iposte := 0 to globs.NPostes - 1 do
    s.pon_e(s.nf, ivar + iposte, -cv * globs.DurPos[iposte]);
  s.pon_e(s.nf, ivar + globs.NPostes, -c0 * globs.HorasDelPaso);

  // controlamos el uso correcto del modelo.
  if NMaquinasDisponibles_ > 1 then
    raise Exception.Create(
      'Por ahora TGer_ArranqueParada soporta solamente centrales de una sóla máquina');

  // agregar costos de Arranque o Parda según corresponda
  if X_NMaquinasDespachadas = 0 then // estaba apagada
  begin
    s.acum_e(s.nf, ivar + globs.NPostes, -(pa.costo_Arranque + dCF));
  end
  else // estaba prendida
  begin
    s.acum_e(s.nf, ivar + globs.NPostes, (pa.costo_Parada + dCF));
    s.acum_e(s.nf, s.nc, -(pa.costo_Parada + dCF));
  end;
end;

procedure TGTer_ArranqueParadaV2.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  acoples: TListaAcoplesVEntera;
  iposte: integer;
  nmaquinas: integer;
begin
  nmaquinas := NMaquinasDisponibles_x;
  if nmaquinas = 0 then
    exit;
  (*
    // Restricciones de caja de las B (Esto no es necesario pues las restricciones adicionales
    // obligan que estas se cumplan. Por eso le pongo el 1.1 para dejarle la caja un poco floja
    for iposte:= 0 to globs.NPostes-1 do
      s.cota_sup_set( ivar+iposte, PxMax*NMaquinasDisponibles*1.1 );
  *)
  // Restricciones de caja de las A y las declaramos enteras
  setLength(acoples, globs.NPostes);
  for iposte := 0 to globs.NPostes - 1 do
  begin
    acoples[iposte].ivar := ivar + iposte;
    acoples[iposte].ires := ires + iposte;
  end;
  // Restricciones de caja de las A y las declaramos enteras
  TMIPSimplex(s).set_EnteraConAcoples(
    ivae, ivar + globs.NPostes, nmaquinas, acoples);
end;

procedure TGTer_ArranqueParadaV2.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
  EnergiaPorEncimaDelMinimo: NReal;
  m: NReal;

begin
  EnergiaPorEncimaDelMinimo := 0;
  CostoDirectoDelPaso := 0;
  if NMaquinasDisponibles_x = 0 then
  begin
    vclear(P);
    Xs_NMaquinasDespachadas := 0;
  end
  else
  begin
    Xs_NMaquinasDespachadas := trunc(s.xval(ivar + globs.NPostes) + 0.2);
    for iposte := 0 to globs.NPostes - 1 do
    begin
      m := s.xval(ivar + iposte);
      P[iposte] := m + Xs_NMaquinasDespachadas * Pmin;
      EnergiaPorEncimaDelMinimo := EnergiaPorEncimaDelMinimo + m * globs.DurPos[iposte];
    end;
    if Xs_NMaquinasDespachadas > 0 then
      CostoDirectoDelPaso := EnergiaPorEncimaDelMinimo * cv +
        Xs_NMaquinasDespachadas * c0 * globs.HorasDelPaso;
  end;

  if Xs_NMaquinasDespachadas > X_NMaquinasDespachadas then
  begin // prendió máquinas
    CostoDirectoDelPaso := CostoDirectoDelPaso +
      (Xs_NMaquinasDespachadas - X_NMaquinasDespachadas) * pa.costo_arranque;
    {$IFDEF HISTERESIS_AP}
    Xs_HorasHisterisisAP := pa.MinHorasON;
    {$ENDIF}
  end
  else if Xs_NMaquinasDespachadas < X_NMaquinasDespachadas then
  begin // apagó máquinas
    CostoDirectoDelPaso := CostoDirectoDelPaso +
      (X_NMaquinasDespachadas - Xs_NMaquinasDespachadas) * pa.costo_parada;
    {$IFDEF HISTERESIS_AP}
    Xs_HorasHisterisisAP := pa.MinHorasOFF;
    {$ENDIF}
  end
  else
  begin
  {$IFDEF HISTERESIS_AP}
    Xs_HorasHisterisisAP := max(X_HorasHisteresisAP - globs.HorasDelPaso, 0);
  {$ENDIF}
  end;

end;


procedure TGTer_ArranqueParadaV2.EvolucionarEstado;
begin
  X_NMaquinasDespachadas := Xs_NMaquinasDespachadas;

  {$IFDEF HISTERESIS_AP}
  X_HorasHisteresisAP := Xs_HorasHisterisisAP;
  {$ENDIF}
end;

{$IFDEF SPXCONLOG}
procedure TGTer_ArranqueParadaV2.spx_NombrarVariables(s: TSimplex);
var
  iposte: integer;
begin
  if NMaquinasDisponibles = 0 then
    exit;
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.set_NombreVar(ivar + iposte, Nombre + '_P[MW]' + IntToStr(iposte + 1));
    s.set_NombreRest(ires + iposte, Nombre + '_res-A' + IntToStr(iposte + 1));
  end;
  s.set_NombreVar(ivar + globs.NPostes, Nombre + '_A');
  if pA.HayRestriccionEmaxPasoDeTiempo then
    s.set_NombreRest(ires + globs.NPostes, Nombre + '_res-EMax');
end;

{$ENDIF}

function TGTer_ArranqueParadaV2.getNombreVar(ivar: integer;
  var nombre: string): boolean;
begin
  if NMaquinasDisponibles_x = 0 then
    Result := False
  else
  if (ivar >= self.ivar) and (ivar < self.ivar + globs.NPostes) then
  begin
    nombre := self.Nombre + '_P[MW]' + IntToStr(ivar - self.ivar + 1);
    Result := True;
  end
  else if (ivar = self.ivar + globs.NPostes) then
  begin
    nombre := self.Nombre + '_A[MW]';
    Result := True;
  end
  else
    Result := False;
end;

function TGTer_ArranqueParadaV2.getNombreRes(ires: integer;
  var nombre: string): boolean;
begin
  if NMaquinasDisponibles_x = 0 then
    Result := False
  else
  if (ires >= self.ires) and (ires < self.ires + globs.NPostes) then
  begin
    nombre := self.nombre + '_res-A' + IntToStr(ires - self.ires + 1);
    Result := True;
  end
  else if pa.HayRestriccionEmaxPasoDeTiempo and (ires = self.ires + globs.NPostes) then
  begin
    nombre := self.nombre + '_res-EMax';
    Result := True;
  end
  else
    Result := False;
end;

procedure TGTer_ArranqueParadaV2.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableNR('Costo', '[USD]', 6, 1, costoDirectoDelPaso, True);
  PublicarVariableNI('NMaqsDespachadas', '-', X_NMaquinasDespachadas, True);
  PublicarVariableNR('dCF', '[USD]', 6, 1, dCF, True);
  PublicarVariableNR('c0', '[USD/h]', 6, 1, c0, False);
  PublicarVariableNI('NMaqsDisponibles', '-', NMaquinasDisponibles_, False);
  PublicarVariableNR('PMaxDisponible', '[MW]', 6, 1, PMaxDisponible, False);
  PublicarVariableNR('PMediaDespachada', '[MW]', 6, 1, potMedia_despachada, False);
end;

procedure TGTer_ArranqueParadaV2.Free;
begin
  inherited Free;
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(TGTer_ArranqueParadaV2.ClassName, TGTer_ArranqueParadaV2);
  registrarClaseDeCosa(TFichaGTer_ArranqueParadaV2.ClassName,
    TFichaGTer_ArranqueParadaV2);
end;

procedure AlFinal;
begin

end;

end.
