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

interface

uses
  Math,
  SysUtils, Classes, xmatdefs, uGTer, unodos,
  uglobs,
  umipsimplex,
  usimplex,
  ufichasLPD,
  ufechas,
  ucosa, uranddispos,
  uconstantesSimSEE, uFuentesAleatorias;

type

  { TFichaGTer_OnOffPorPaso }

  TFichaGTer_OnOffPorPaso = class(TFichaLPD)

  public

    (**************************************************************************)
    (*               A T R I B U T O S   P E R S I S T E N T E S              *)
    (**************************************************************************)

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

    (**************************************************************************)

    nroBornePreciosPorCombustible: integer;

    constructor Create(fecha: TFecha; periodicidad: TPeriodicidad;
      PMin, PMax: NReal; cv_min, cv: NReal;
      indicePreciosPorCombustible: TFuenteAleatoria;
      bornePreciosPorCombustible: string; disp: NReal; tRepHoras: NReal;
      HayRestriccionEmaxPasoDeTiempo: boolean; EmaxPasoDeTiempo: NReal);

     
    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;
    procedure AfterInstantiation; 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_OnOffPorPaso = class(TGTer)
  public
    pa: TFichaGTer_OnOffPorPaso;

    NMaquinasDespachadas: integer;
    // cantidad de máquinas despachadas ( variable de Acople )

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

    constructor Create(nombre: string; nacimiento, muerte: TFecha;
      nodo: TNodo; fichaIni: TFichaLPD); override;

     
    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 SorteosDelPaso(sortear: boolean); override;

    procedure PrepararPaso_ps; override;
    procedure opt_nvers(var ivar, ivae, ires: integer); override;
    procedure opt_cargue(s: TSimplex); override;
    procedure opt_fijarRestriccionesDeCaja(s: TSimplex); override;
    procedure opt_leerSolucion(s: TSimplex); override;

    procedure Sim_Paso_Fin; 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;

    function CostoDirectoDelPaso: NReal; override;
    procedure PubliVars; override;

    // Retorna la potencia despachada en el poste
    procedure sim_PrintResultados_Encab(var fsal: textfile; kencab: integer); override;
    procedure sim_PrintResultados(var fsal: textfile); override;

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

    function TipoFichaLPD: TClaseDeFichaLPD; override;
    class function CreateDataColumnList(xClaseDeCosa:TClaseDeCosa; xVersion: Integer=-2): TDataColumnListOfCosa; override;
    procedure AfterInstantiation; override;
  end;

procedure AlInicio;
procedure AlFinal;

implementation

//-----------------------------------
// Métodos de TFichaGTer_OnOffPorPaso
//===================================
constructor TFichaGTer_OnOffPorPaso.Create(fecha: TFecha;
  periodicidad: TPeriodicidad; PMin, PMax: NReal; cv_min, cv: NReal;
  indicePreciosPorCombustible: TFuenteAleatoria; bornePreciosPorCombustible: string;
  disp: NReal; tRepHoras: NReal; HayRestriccionEmaxPasoDeTiempo: boolean;
  EmaxPasoDeTiempo: NReal);
begin
  inherited Create(fecha, periodicidad);
  self.PMin := PMin;
  self.PMax := PMax;
  self.cv_min := cv_min;
  self.cv := cv;
  self.indicePreciosPorCombustible := indicePreciosPorCombustible;
  self.bornePreciosPorCombustible := bornePreciosPorCombustible;
  self.disp := disp;
  self.tRepHoras := tRepHoras;
  self.HayRestriccionEmaxPasoDeTiempo := HayRestriccionEmaxPasoDeTiempo;
  self.EmaxPasoDeTiempo := EmaxPasoDeTiempo;
end;

 
constructor TFichaGTer_OnOffPorPaso.Create_ReadFromText(f: TArchiTexto);
begin
  if f.Version < 6 then
  begin
    inherited Create_ReadFromText(f);
    f.IniciarLecturaRetrasada;
    f.rd('PMin', PMin);
    f.rd('PMax', PMax);
    f.rd('cv_min', cv_min);
    f.rd('cv', cv);
    f.rdReferencia('indicePreciosPorCombustible',
      TCosa(indicePreciosPorCombustible), Self);
    f.rd('disp', disp);
    f.rd('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
    f.rd('EmaxPasoDeTiempo', EmaxPasoDeTiempo);
    f.EjecutarLectura;

    self.indicePreciosPorCombustible := nil;
    self.bornePreciosPorCombustible := '';
    self.tRepHoras := 15 * 24;
  end
  else if f.Version < 14 then
  begin
    inherited Create_ReadFromText(f);
    f.IniciarLecturaRetrasada;
    f.rd('PMin', PMin);
    f.rd('PMax', PMax);
    f.rd('cv_min', cv_min);
    f.rd('cv', cv);
    f.rdReferencia('indicePreciosPorCombustible',
      TCosa(indicePreciosPorCombustible), Self);
    f.rd('bornePreciosPorCombustible', bornePreciosPorCombustible);
    f.rd('disp', disp);
    f.rd('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
    f.rd('EmaxPasoDeTiempo', EmaxPasoDeTiempo);
    f.EjecutarLectura;

    self.tRepHoras := 15 * 24;
  end
  else
  begin
    inherited Create_ReadFromText(f);
    f.IniciarLecturaRetrasada;
    f.rd('PMin', PMin);
    f.rd('PMax', PMax);
    f.rd('cv_min', cv_min);
    f.rd('cv', cv);
    f.rdReferencia('indicePreciosPorCombustible',
      TCosa(indicePreciosPorCombustible), Self);
    f.rd('bornePreciosPorCombustible', bornePreciosPorCombustible);
    f.rd('disp', disp);
    f.rd('tRepHoras', tRepHoras);
    f.rd('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
    f.rd('EmaxPasoDeTiempo', EmaxPasoDeTiempo);
    f.EjecutarLectura;
  end;
end;

procedure TFichaGTer_OnOffPorPaso.WriteToText(f: TArchiTexto);
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.wr('cv_min', cv_min, uconstantesSimSEE.CF_PRECISION, uconstantesSimSEE.CF_DECIMALES);
  f.wr('cv', cv, 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('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
  f.wr('EmaxPasoDeTiempo', EmaxPasoDeTiempo);
end;


procedure TFichaGTer_OnOffPorPaso.generarLineaResumen(var archi: TextFile);
begin
  Write(archi, PMin: 8: 1, #9,                                             //PMín
    PMax: 8: 1, #9,                                             //PMáx
    cv_min: 8: 2, #9,                                           //CV_Mín
    ((cv_min * PMin + cv * (PMax - PMin)) / PMax): 8: 2, #9,    //CV_Medio
    cv: 8: 2, #9,                                               //CV_Incremental
    disp: 8: 2, #9,                                             //FDisp
    '-', #9,                                              //Costo Arranque
    '-', #9);                                             //Costo Parada
end;

function TFichaGTer_OnOffPorPaso.infoAd: string;
begin
  Result := 'PMín= ' + FloatToStrF(PMin, ffGeneral, 10, 1) + ' MW, ' +
    'PMáx= ' + FloatToStrF(PMax, ffGeneral, 10, 1) + ' MW, ' +
    'cv_min= ' + FloatToStrF(cv_min, ffGeneral, 10, 1) + ' USD/MWh, ' +
    'cv= ' + FloatToStrF(cv, ffGeneral, 10, 1) + ' USD/MWh, ' + 'fDisp= ' +
    FloatToStrF(disp, ffGeneral, 10, 2) + ' p.u., ' + 'tRep= ' +
    FloatToStrF(tRepHoras, ffGeneral, 10, 1) + 'h';
end;

procedure TFichaGTer_OnOffPorPaso.Free;
begin
  inherited Free;
end;

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













end;

procedure TFichaGTer_OnOffPorPaso.AfterInstantiation;
begin
  inherited AfterInstantiation;
end;

//------------------------------
// Métodos de TGTer_OnOffPorPaso
//==============================

procedure TGTer_OnOffPorPaso.sim_PrintResultados_Encab(var fsal: textfile;
  kencab: integer);
var
  iposte: integer;
  ts: string;
begin
  if kencab = 0 then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      Write(fsal, #9, Nombre, #9, Nombre); //Potencias y costos del poste
    Write(fsal, #9, nombre);               //NMaqsDespachadas
  end
  else if kencab = 1 then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      Write(fsal, #9, '[MW]', #9, '[USD]'); //Potencias y costos del poste
    Write(fsal, #9, '-');                   //NMaqsDespachadas
  end
  else if kencab = 2 then
  begin
    for iposte := 1 to globs.NPostes do
    begin
      ts := IntToStr(iposte);
      Write(fsal, #9, 'P_P' + ts, #9, 'Costo_P' + ts); //Potencias y costos del poste
    end;
    Write(fsal, #9, 'NMaqsDespachadas');               //NMaqsDespachadas
  end
  else
  begin
    for iposte := 1 to globs.NPostes do
    begin
      ts := IntToStr(iposte);
      Write(fsal, #9, ts, #9, ts); //Potencias y costos del poste
    end;
    Write(fsal, #9, '0');               //NMaqsDespachadas
  end;
end;

procedure TGTer_OnOffPorPaso.sim_PrintResultados(var fsal: textfile);
var
  iPoste: integer;
  costodelposte: NReal;
begin
  for iposte := 0 to globs.NPostes - 1 do
  begin
    if NMaquinasDespachadas > 0 then
      costodelposte := ((P[iposte] - PMin) * cv + NMaquinasDespachadas * c0) *
        globs.durpos[iposte]
    else
      costodelposte := 0;

    Write(fsal, #9, P[iPoste]: 6: 1, #9, costodelposte: 6: 1);
    //Potencias y costos del poste
  end;
  Write(fsal, #9, NMaquinasDespachadas);                 //NMaqsDespachadas
end;

procedure TGTer_OnOffPorPaso.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, '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, 'HayRestrEMaxPasoDeTiempo= ',
    pa.hayRestriccionEmaxPasoDeTiempo);
  writeln(f, charIndentacion, 'EMaxPasoDeTiempo[MW/h]= ',
    FloatToStrF(pa.EmaxPasoDeTiempo, ffFixed, 10, 3));

  writeln(f);
end;

function TGTer_OnOffPorPaso.TipoFichaLPD: TClaseDeFichaLPD;
begin
  Result := TFichaGTer_OnOffPorPaso;
end;

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


end;

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

constructor TGTer_OnOffPorPaso.Create(nombre: string; nacimiento, muerte: TFecha;
  nodo: TNodo; fichaIni: TFichaLPD);
begin
  inherited Create(nombre, nacimiento, muerte, nodo, fichaIni);
  if fichaIni <> nil then
    self.lpd.Add(fichaIni);
end;

 
constructor TGTer_OnOffPorPaso.Create_ReadFromText(f: TArchiTexto);
begin
  inherited Create_ReadFromText(f);
  pa := nil;
  nodo := nil;
end;

procedure TGTer_OnOffPorPaso.WriteToText(f: TArchiTexto);
begin
  inherited WriteToText(f);
end;


procedure TGTer_OnOffPorPaso.PrepararMemoria(globs: TGlobs);
begin
  inherited prepararMemoria(globs);
  NMaquinasDespachadas := 0;
end;

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

function TGTer_OnOffPorPaso.PotenciaFirme: NReal;
begin
  Result := (paUnidades.nUnidades) * pa.PMax * pa.disp;
end;

function TGTer_OnOffPorPaso.InfoAd: string;
begin
  Result := '';
end;

class function TGTer_OnOffPorPaso.DescClase: string;
begin
  Result := 'Generador Térmico con Encendido y Apagado por Paso de Tiempo';
end;


procedure TGTer_OnOffPorPaso.SorteosDelPaso(sortear: boolean);
begin
  if globs.ObligarDisponibilidad_1_ then
  begin
    NMaquinasDisponibles := paUnidades.nUnidades;
    PMaxDisponible := pa.PMax * NMaquinasDisponibles;
  end
  else
  if sortear then
  begin
    ActualizarProbabilidadesReparacionYRotura(pa.disp, pa.tRepHoras);
    NMaquinasDisponibles := Sorteos_RepRotUnidades;
    PMaxDisponible := pa.PMax * NMaquinasDisponibles;
  end
  else
  begin
    NMaquinasDisponibles := paUnidades.nUnidades;
    PMaxDisponible := pa.PMax * pa.disp * NMaquinasDisponibles;
  end;
end;

procedure TGTer_OnOffPorPaso.PrepararPaso_ps;
var
  indice: NReal;
begin
  PMin := pa.PMIn;
  PxMax := pa.PMax - pa.PMin;
  if pa.indicePreciosPorCombustible <> nil then
  begin
    indice := pa.indicePreciosPorCombustible.bornera[pa.nroBornePreciosPorCombustible];
    c0 := pa.PMin * pa.cv_min * indice;
    cv := pa.cv * indice;
  end
  else
  begin
    c0 := pa.PMin * pa.cv_min;
    cv := pa.cv;
  end;
end;

procedure TGTer_OnOffPorPaso.Sim_Paso_Fin;
var
  iposte: integer;
begin
  if NMaquinasDisponibles > 0 then
  begin
    for iposte := 0 to high(P) do
      potMedia_despachada := potMedia_despachada + P[iposte] * globs.durpos[iposte];
    potMedia_despachada := potMedia_despachada * globs.invHorasDelPaso;
  end
  else
  begin
    potMedia_despachada := 0;
  end;
end;

procedure TGTer_OnOffPorPaso.opt_nvers(var ivar, ivae, ires: integer);
begin

  if SoyLibre then
  begin
    Self.ivar := ivar;
    ivar := ivar + globs.NPostes + 1;
    Self.ivae := ivae;
    ivae := ivae + 1;
    Self.ires := ires;
    ires := ires + globs.NPostes;
  end
  else
  if HorasOnOff > 0 then // prendido forzado.
  begin
    Self.ivar := ivar;
    ivar := ivar + globs.NPostes;
    Self.ires := ires;
    ires := ires + globs.NPostes;
  end
  else
    exit; // apagado forzado


  if pA.HayRestriccionEmaxPasoDeTiempo then
    Inc(ires);
end;

procedure TGTer_OnOffPorPaso.opt_cargue(s: TSimplex);
var
  inodores: integer;
  iposte: integer;
  jres: integer;
begin
  if NMaquinasDisponibles = 0 then
    exit; // si no hay máquinas no juego

{$IFDEF SPXCONLOG}
  spx_NombrarVariables(s);
{$ENDIF}

  inodores := nodo.ires;

  // aporte a las restricciones del 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;
  // restricciones adicionales impuestas por la variable de Acople
  jres := ires;
  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);
end;

procedure TGTer_OnOffPorPaso.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
  acoples: TListaAcoplesVEntera;
begin
  if NMaquinasDisponibles = 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);

  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, NMaquinasDisponibles, acoples);
end;

procedure TGTer_OnOffPorPaso.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
begin
  if NMaquinasDisponibles = 0 then
  begin
    vclear(P);
    NMaquinasDespachadas := 0;
    exit;
  end;

  NMaquinasDespachadas := trunc(s.xval(ivar + globs.NPostes) + 0.2);

  for iposte := 0 to globs.NPostes - 1 do
    P[iposte] := s.xval(ivar + iposte) + NMaquinasDespachadas * Pmin;
end;

{$IFDEF SPXCONLOG}
procedure TGTer_OnOffPorPaso.spx_NombrarVariables(s: TSimplex);
var
  iposte: integer;
begin
  if NMaquinasDisponibles = 0 then
    exit; // si no hay máquinas no juego
  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_OnOffPorPaso.getNombreVar(ivar: integer; var nombre: string): boolean;
begin
  if NMaquinasDisponibles = 0 then // si no hay máquinas no juego
    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_OnOffPorPaso.getNombreRes(ires: integer; var nombre: string): boolean;
begin
  if NMaquinasDisponibles = 0 then // si no hay máquinas no juego
    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;

function TGTer_OnOffPorPaso.CostoDirectoDelPaso: NReal;
var
  costo, EnergiaPorEncimaDelMinimo: NReal;
  iposte: integer;
begin
  costo := 0;

  if NMaquinasDespachadas > 0 then
  begin
    EnergiaPorEncimaDelMinimo := 0;
    for iposte := 0 to globs.NPostes - 1 do
      EnergiaPorEncimaDelMinimo :=
        EnergiaPorEncimaDelMinimo + (P[iposte] - PMin) * globs.DurPos[iposte];
    costo := EnergiaPorEncimaDelMinimo * cv + NMaquinasDespachadas *
      c0 * globs.HorasDelPaso;
  end;

  Result := costo;
end;

procedure TGTer_OnOffPorPaso.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableNI('NMaqsDespachadas', NMaquinasDespachadas);
  PublicarVariableNR('c0[USD/h]', c0);
  PublicarVariableNI('NMaqsDisponibles', NMaquinasDisponibles);
  PublicarVariableNR('PMaxDisponible[MW]', PMaxDisponible);
  PublicarVariableNR('PMediaDespachada[MW]', potMedia_despachada);

  //Hay que crear una ficha para poder calcular los offsets de las variables dentro de
  //las fichas
 {  self.pa := TFichaGTer_OnOffPorPaso.Create(NIL, 0, 1, 2, 3, 4, 5, 20, 20, false);
  PublicarVariablePNI('Número de Maquinas', pa, pa.NMAquinas);
  PublicarVariablePNR('Potencia Mínima[MWh]', pa, pa.Pmin);
  PublicarVariablePNR('Potencia Máxima[MWh]', pa, pa.Pmax);
  PublicarVariablePNR('Costo Variable Mínimo[USD/h]', pa, pa.cv_min);
  PublicarVariablePNR('Costo Variable[USD/h]', pa, pa.cv);
  PublicarVariablePNR('Coeficiente de Disponibilidad Fortuita[p.u.]', pa, pa.disp);
  PublicarVariablePB('Se Puede Prender y Apagar por Poste', pa, pa.ONOFF_porposte);
  self.pa.free;
  pa := NIL;  }
end;


procedure TGTer_OnOffPorPaso.Free;
begin
  inherited Free;
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(TGTer_OnOffPorPaso.ClassName, TGTer_OnOffPorPaso);
  registrarClaseDeCosa(TFichaGTer_OnOffPorPaso.ClassName, TFichaGTer_OnOffPorPaso);
end;

procedure AlFinal;
begin
end;

end.
