unit uArcoCombustible;

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

interface

uses
  Classes,
  SysUtils, xmatdefs, usimplex, uglobs,
  uNodoCombustible,
  uActorNodalCombustible,
  ucosa,
  uCosaConNombre,
  ufechas, uconstantesSimSEE, uranddispos,
  uFuentesAleatorias,
  uFichasLPD;

resourcestring
  rsArcoSimpleCombustible = 'Arco Combustible';

type

  { TFichaArcoCombustible }

  TFichaArcoCombustible = class(TFichaLPD)
  public

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

    ren: TDAofNReal;
    peaje_USD_por_MWh: TDAofNReal;
    QMax: TDAofNreal;
    fd: NReal; // factor de disponibilidad
    TMR: NReal;
    flg_ConsiderarPeajeEnElDespacho: boolean;
    flg_SumarPeajeAlCDP: boolean;
    factorPeajeCDP: NReal;
    PagoPorCapacidad_USD_por_MWh: NReal;
    (**************************************************************************)



    constructor Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad;
      rendimiento, peaje, QMax: TDAofNReal; fd: NReal; TMR: NReal;
      ConsidearrPeajeEnElDespacho, SumarPeajeAlCDP: boolean;
      FactorPeajeCDP: NReal; PagoPorCapacidad_USD_por_MWh: NReal);

    function Rec: TCosa_RecLnk; override;
    procedure BeforeRead(version, id_hilo: integer); override;
    procedure AfterRead(f:TArchiTexto); override;

    function InfoAd_: string; override;
    destructor destroy; override;

  end;



  { TArcoCombustible }

  TArcoCombustible = class(TActorBiNodalCombustible)
  public
    NLineasDisponibles: integer;
    QMaxDisponible_: TDAofNReal;
    Q_Entrante: TDAOfNReal; // caudal entrante
    //Costo por poste del transporte de Gas
    //costo[iposte]:= Q[iposte] * pa.peaje * globs.durpos[iposte];
    costo: TDAofNReal;
    // valor por poste del multiplicador de Lagrange de la restrición de QMax
    costo_congestion: TDAOfNReal;
    pa: TFichaArcoCombustible;

    constructor Create(capa: integer; nombre: string;
      lpdUnidades, lpd: TFichasLPD; Entrada, Salida: TNodoCombustible;
      xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);

    function Rec: TCosa_RecLnk; override;
    procedure BeforeRead(version, id_hilo: integer); override;
    procedure AfterRead(f:TArchiTexto); override;

    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;
    procedure RegistrarParametrosDinamicos(Catalogo: TCatalogoReferencias); override;
    function InfoAd_: string; override;
    class function DescClase: string; override;

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

    function getNombreVar(ivar: integer; var nombre: string): boolean; override;
    function getNombreRes(ires: integer; var nombre: string): boolean; override;

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

    procedure PubliVars; override;
    destructor destroy; override;

    function get_pa_FD(kTipoUnidad: integer): NReal; override;
    function get_pa_TMR(kTipoUnidad: integer): NReal; override;

  end;



procedure AlInicio;
procedure AlFinal;

implementation

uses uActores;


//-------------------
// Métodos de TArcoCombustible
//===================

constructor TArcoCombustible.Create(capa: integer; nombre: string;
   lpdUnidades, lpd: TFichasLPD;
  Entrada, Salida: TNodoCombustible;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);
begin
  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades, Entrada, Salida,
  xFuenteIdxP, xBorneIdxP );
  self.lpd := lpd;
end;

function TArcoCombustible.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('lpd', TCosa(lpd));
end;

procedure TArcoCombustible.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
end;

procedure TArcoCombustible.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
  lpd.Propietario := self;
end;


procedure TArcoCombustible.PrepararMemoria(Catalogo: TCatalogoReferencias;
  globs: TGlobs);
var
  n, k, j: integer;
  af: TFichaArcoCombustible;

begin
  inherited prepararMemoria(Catalogo, globs);
  setlength(Q_Entrante, globs.NPostes);
  SetLength(costo, globs.NPostes);
  setlength(costo_congestion, globs.NPostes);
  setlength(QMaxDisponible_, globs.NPostes);


  for j := 0 to self.lpd.Count - 1 do
  begin
    af := self.lpd.items[j] as TFichaArcoCombustible;
    if (length(af.ren) <> globs.NPostes) then
    begin
      n := length(af.ren);
      setlength(af.ren, globs.NPostes);
      setlength(af.peaje_USD_por_MWh, globs.NPostes);
      setlength(af.QMax, globs.NPostes);
      for k := n to high(af.ren) do
        af.ren[k] := af.ren[n - 1];
      for k := n to high(af.peaje_USD_por_MWh) do
        af.peaje_USD_por_MWh[k] := af.peaje_USD_por_MWh[n - 1];
      for k := n to high(af.QMax) do
        af.QMax[k] := af.QMax[n - 1];
    end;
  end;

end;

procedure TArcoCombustible.RegistrarParametrosDinamicos(
  Catalogo: TCatalogoReferencias);
begin
  inherited registrarParametrosDinamicos(Catalogo);
  lpd.expandirFichas(Catalogo, globs);
  lpd.RegistrarFichasAActualizar(Self, globs.ActualizadorLPD, @pA, nil);
end;

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

class function TArcoCombustible.DescClase: string;
begin
  Result := rsArcoSimpleCombustible;
end;


function TArcoCombustible.get_pa_FD(kTipoUnidad: integer): NReal;
begin
  Result := pa.fd;
end;

function TArcoCombustible.get_pa_TMR(kTipoUnidad: integer): NReal;
begin
  Result := pa.TMR;
end;

procedure TArcoCombustible.SorteosDelPaso(sortear: boolean);
var
  kPoste: integer;

begin
  if globs.ObligarDisponibilidad_1_ then
  begin
    NLineasDisponibles := paUnidades.nUnidades_Operativas[0];
    for kPoste := 0 to globs.NPostes - 1 do
      QMaxDisponible_[kPoste] := pa.QMax[kPoste] * NLineasDisponibles;
  end
  else
  if sortear then
  begin
    ActualizarProbabilidadesReparacionYRotura_(pa.fd, pa.TMR);
    NLineasDisponibles := Sorteos_RepRotUnidades;
    for kPoste := 0 to globs.NPostes - 1 do
      QMaxDisponible_[kPoste] := pa.QMax[kPoste] * NLineasDisponibles;
  end
  else
  begin
    NLineasDisponibles := paUnidades.nUnidades_Operativas[0];
    for kPoste := 0 to globs.NPostes - 1 do
      QMaxDisponible_[kPoste] := pa.QMax[kPoste] * pa.fd * NLineasDisponibles;
  end;
end;

procedure TArcoCombustible.opt_nvers(var ivar, ivae, ires: integer);
begin
  Self.ivar := ivar;
  if NLineasDisponibles > 0 then
    ivar := ivar + globs.NPostes;
end;

procedure TArcoCombustible.opt_cargue(s: TSimplex);
var
  ibaseResSal, ibaseResEnt: integer;
  iposte: integer;
begin
  if NLineasDisponibles > 0 then
  begin
    // Restricciones de los nodos combustible
    ibaseResEnt := NodoCombA.ires;
    ibaseResSal := NodoCombB.ires;
    for iposte := 0 to globs.NPostes - 1 do
    begin
      s.pon_e(ibaseResEnt + iposte, ivar + iposte, -1);
      s.pon_e(ibaseResSal + iposte, ivar + iposte, pa.ren[iposte]);

      // Ahora agregamos a la función de UTILIDAD (-costo)
      if pa.flg_ConsiderarPeajeEnElDespacho then
        s.pon_e(s.nf, ivar + iposte, -pa.peaje_USD_por_MWh[iposte] *
          NodoCombA.combustible.MWh_por_Q1h_ * globs.durpos[iposte]);
    end;
  end;
end;

procedure TArcoCombustible.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
begin
  if NLineasDisponibles > 0 then
    // Le fijamos como cota máxima QMax al caudal en todos los postes
    for iposte := 0 to globs.NPostes - 1 do
      s.cota_sup_set(ivar + iposte, QMaxDisponible_[iposte]);
end;

procedure TArcoCombustible.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
  m: NReal;
  Q: NReal;
begin
  CostoDirectoDelPaso := 0;
  Ingreso_PorDisponibilidad_ := 0;
  Ingreso_PorEnergia_ := 0;
  vclear(Q_Entrante);
  vclear(Q_NodoCombA);
  vclear(Q_NodoCombB);
  vclear(costo_congestion);

  if NLineasDisponibles > 0 then
  begin
    if pa.PagoPorCapacidad_USD_por_MWh <> 0 then
      for iposte := 0 to globs.NPostes - 1 do
        Ingreso_PorDisponibilidad_ :=
          Ingreso_PorDisponibilidad_ + pa.PagoPorCapacidad_USD_por_MWh *
          QMaxDisponible_[iposte] * NodoCombA.combustible.MWh_por_Q1h_ *
          globs.DurPos[iposte];

    for iposte := 0 to globs.NPostes - 1 do
    begin
      Q := s.xval(ivar + iposte);
      Q_Entrante[iposte] := Q;
      if pa.flg_SumarPeajeAlCDP then
      begin
        m := Q * globs.DurPos[iposte] * NodoCombA.combustible.MWh_por_Q1h_ *
          pa.peaje_USD_por_MWh[iposte];
        costo[iposte] := m;
        Ingreso_PorEnergia_ := Ingreso_PorEnergia_ + m;
      end;
      costo_congestion[iposte] := -s.xmult(ivar + iposte);
      Q_NodoCombA[iposte] := -Q;
      Q_NodoCombB[iposte] := Q * pa.ren[iposte];
    end;

    if pa.flg_SumarPeajeAlCDP then
    begin
      costoDirectoDelPaso := costoDirectoDelPaso + Ingreso_PorEnergia_ *
        pa.factorPeajeCDP;
      Ingreso_PorEnergia_ := (1 - pa.factorPeajeCDP) * Ingreso_PorEnergia_;
    end;
  end;
end;


function TArcoCombustible.getNombreVar(ivar: integer; var nombre: string): boolean;
begin
  if (ivar >= self.ivar) and (ivar < self.ivar + globs.NPostes) then
  begin
    nombre := self.Nombre + '_Q[m3/s]' + IntToStr(ivar - self.ivar + 1);
    Result := True;
  end
  else
    Result := False;
end;

function TArcoCombustible.getNombreRes(ires: integer; var nombre: string): boolean;
begin
  Result := False;
end;

procedure TArcoCombustible.dump_Variables(var f: TextFile; charIndentacion: char);
var
  iposte: integer;

begin
  inherited dump_Variables(f, charIndentacion);

  Write(f, charIndentacion, 'peaje=');
  for iposte := 0 to high(pa.peaje_USD_por_MWh) do
  begin
    if iposte > 0 then
      Write(f, ',');
    Write(f, ' ' + FloatToStrF(pa.peaje_USD_por_MWh[iposte], ffFixed, 10, 3));
  end;
  writeln(f);

  Write(f, charIndentacion, 'QMax=');
  for iposte := 0 to high(pa.QMax) do
  begin
    if iposte > 0 then
      Write(f, ',');
    Write(f, ' ', FloatToStrF(pa.QMax[iposte], ffFixed, 10, 3));
  end;
  writeln(f);

  writeln(f);
end;

procedure TArcoCombustible.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableVR('Q', '[m3/s]', 6, 1, Q_Entrante, True, True);
  PublicarVariableVR('Costo', '[USD]', 6, 1, costo, True, True);
  PublicarVariableVR('CostoCongestion', '[USD/(m3/s)]', 6, 1,
    costo_congestion, True, True);
  PublicarVariableNI('NLineasDisponibles', '[u]', NLineasDisponibles, True);
end;

destructor TArcoCombustible.destroy;
begin
  if lpd <> nil then
    lpd.Free;
  setlength(Q_Entrante, 0);
  SetLength(costo, 0);
  //SetLength(costo_congestion, 0);
  setlength(QMaxDisponible_, 0);
  inherited destroy;
end;

//---------------------
//Metodos de TFichaArcoCombustible
//=====================

constructor TFichaArcoCombustible.Create(capa: integer; fecha: TFecha;
  periodicidad: TPeriodicidad; rendimiento, peaje, QMax: TDAofNReal;
  fd: NReal; TMR: NReal; ConsidearrPeajeEnElDespacho, SumarPeajeAlCDP: boolean;
  FactorPeajeCDP: NReal; PagoPorCapacidad_USD_por_MWh: NReal);
begin
  inherited Create(capa, fecha, periodicidad);
  self.ren := rendimiento;
  self.peaje_USD_por_MWh := peaje;
  self.QMax := QMax;
  self.fd := fd;
  self.TMR := TMR;
  self.flg_ConsiderarPeajeEnElDespacho := ConsidearrPeajeEnElDespacho;
  self.flg_SumarPeajeAlCDP := SumarPeajeAlCDP;
  self.factorPeajeCDP := FactorPeajeCDP;
  self.PagoPorCapacidad_USD_por_MWh := PagoPorCapacidad_USD_por_MWh;
end;

function TFichaArcoCombustible.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('rendimiento', ren);
  Result.addCampoDef('peaje', peaje_USD_por_MWh);
  Result.addCampoDef('QMax', QMax);
  Result.addCampoDef('fd', fd);
  Result.addCampoDef('TMR', TMR);
  Result.addCampoDef('ConsiderarPeajeEnElDespacho', flg_ConsiderarPeajeEnElDespacho);
  Result.addCampoDef('SumarPeajeAlCDP', flg_SumarPeajeAlCDP);
  Result.addCampoDef('factorPeajeCDP', factorPeajeCDP);
  Result.addCampoDef('PagoPorCapacidad_USD_por_MWh', PagoPorCapacidad_USD_por_MWh);
end;

procedure TFichaArcoCombustible.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  flg_ConsiderarPeajeEnElDespacho := True;
  flg_SumarPeajeAlCDP := True;
  factorPeajeCDP := 1.0;
end;

procedure TFichaArcoCombustible.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
end;



function TFichaArcoCombustible.InfoAd_: string;
begin
  Result := 'QMáx[m3/s]= ' + DAOfNRealToStr_(QMax, 10, 1, ';') +
    ', fD= ' + FloatToStrF(fd, ffGeneral, 10, 2) + ', TMR[h]= ' +
    FloatToStrF(TMR, ffGeneral, 10, 1) + ', ren= ' + DAOfNRealToStr_(ren, 10, 2, ';') +
    ', peaje[USD/MWh]= ' + DAOfNRealToStr_(peaje_USD_por_MWh, 10, 1, ';');
end;

destructor TFichaArcoCombustible.destroy;
begin
  setlength(ren, 0);
  setlength(peaje_USD_por_MWh, 0);
  setlength(QMax, 0);

  inherited destroy;
end;


procedure AlInicio;
begin
  registrarClaseDeCosa(TArcoCombustible.ClassName, TArcoCombustible);
  registrarClaseDeCosa(TFichaArcoCombustible.ClassName, TFichaArcoCombustible);
end;

procedure AlFinal;
begin
end;

end.
