unit ubancodebaterias01;

interface

uses
  Classes,
  xMatDefs, uSimplex,
  ucosa, uCosaConNombre,
  uGlobs, uFechas,
  ugeneradores,
  uNodos,
  SysUtils,
  uEstados,
  uFichasLPD,
  uFuentesAleatorias,
  uconstantesSimSEE,
  uevapUruguay;

resourcestring
  rsBancoDeBaterias01 = 'Banco de Baterías';

type
  TBancoDeBaterias01 = class; // forward declaration



  { TFichaBancoDeBaterias01 }

  TFichaBancoDeBaterias01 = class(TFichaLPD)
  public

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

    PMax_Gen: NReal;
    PMax_Dem: NReal;
    ren_Gen: NReal;
    ren_Dem: NReal;
    CapacidadMaxima_MWh: NReal;
    fd: NReal;
    tmr: NReal;

    cv_MWh_ValorizadoManual: NReal;
    pagoPorDisponibilidad_USDxMWhh: NReal;
    (**************************************************************************)


    constructor Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad;
      PMax_Gen, PMax_Dem: NReal; ren_Gen, ren_Dem: NReal;
      CapacidadMaxima_MWh: NReal; fd, TMR, cv_MWh_ValorizadoManual, pagoPorDisponibilidad_USDxMWhh: NReal);

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

  end;




  { TBancoDeBaterias01 }

  TBancoDeBaterias01 = class(TGenerador)
  public
    (**************************************************************************)
    (*               A T R I B U T O S   P E R S I S T E N T E S              *)
    (**************************************************************************)

    //Variable de Estado
    NDisc: integer; // discretizacion del estad
    Carga_ini: NReal; // valor inicial
    flg_ValorizadoManual: boolean;
    (**************************************************************************)


    pa: TFichaBancoDeBaterias01;

    X_Carga: NReal;
    Xs_Carga: NReal;

    cv_MWh: NReal; // valor de la energía almacenada

    // derivada del costo futuro respecto a la carga de la bateria
    dCFdC: NReal;

    NMaquinasDisponibles: integer;


    CapacidadInstalada_MWh: NReal;
    PMax_Gen, PMax_Dem: NReal;
    PGen, PDem: TDAOfNReal;

    constructor Create(capa: integer; nombre: string; nacimiento, muerte: TFecha;
      lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  flg_CalcularGradienteDeInversion: boolean; Carga_ini: NReal; NDisc_: integer;
  flg_ValorizadoManual: boolean; TonCO2xMWh: NReal; LowCostMustRun,
  CleanDevelopmentMechanism: boolean;
      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 PotenciaFirme: NReal; override;

    function InfoAd_: string; override;

    class function DescClase: string; override;


    //      procedure Sim_Inicio; override;
    procedure Sim_Cronica_Inicio; override;

    function get_pa_FD(kTipoUnidad: integer): NReal; override;
    function get_pa_TMR(kTipoUnidad: integer): NReal; 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 EvolucionarEstado; override;


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

    procedure PosicionarseEnEstrellita; override;

    procedure ActualizarEstadoGlobal(flg_Xs: boolean); override;

    procedure optx_nvxs(var ixr, ixd, iauxr, iauxd: integer); override;
    procedure optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados);
      override;

    procedure Free; override;
    procedure PubliVars; override;

    // imprime tabla de valores del agua en USD/Hm3
    procedure opt_PrintResultados_Encab(var fsal: textfile); override;
    procedure opt_PrintResultados(var fsal: textfile); override;
    procedure dump_Variables(var f: TextFile; charIndentacion: char); override;
    {$IFDEF BOSTA}
    procedure AfterInstantiation; override;
    {$ENDIF}
  end;

procedure AlInicio;
procedure AlFinal;

implementation


constructor TBancoDeBaterias01.Create(capa: integer; nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  flg_CalcularGradienteDeInversion: boolean; Carga_ini: NReal; NDisc_: integer;
  flg_ValorizadoManual: boolean; TonCO2xMWh: NReal; LowCostMustRun,
  CleanDevelopmentMechanism: boolean; xFuenteIdxP: TFuenteAleatoria;
  xBorneIdxP: string );

begin
  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades, nodo,
    TonCO2xMWh, LowCostMustRun, CleanDevelopmentMechanism,
    flg_CalcularGradienteDeInversion, xFuenteIdxP, xBorneIdxP );
  Self.lpd := lpd;

  self.Carga_ini := Carga_ini;
  self.NDisc := NDisc_;
  self.flg_ValorizadoManual := flg_ValorizadoManual;
end;

function TBancoDeBaterias01.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('Carga_ini', Carga_Ini);
  Result.addCampoDef('NDisc', NDisc);
  Result.addCampoDef('flg_ValorizadoManual', flg_ValorizadoManual, 121 );
  Result.addCampoDef('lpd', TCosa(lpd));
end;

procedure TBancoDeBaterias01.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  lpd := nil;
end;

procedure TBancoDeBaterias01.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
  pa := nil;
  nodo := nil;
  if lpd <> nil then
    lpd.Propietario := self;
end;


procedure TBancoDeBaterias01.PrepararMemoria(Catalogo: TCatalogoReferencias;
  globs: TGlobs);
begin
  inherited prepararMemoria(Catalogo, globs);
  setlength(PGen, globs.NPostes);
  setlength(PDem, globs.NPostes);
end;

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

end;

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

function TBancoDeBaterias01.PotenciaFirme: NReal;
begin
  Result := 0;
end;

class function TBancoDeBaterias01.DescClase: string;
begin
  Result := rsBancoDeBaterias01;
end;

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

function TBancoDeBaterias01.get_pa_TMR(kTipoUnidad: integer): NReal;
begin
  Result := pa.tmr;
end;



procedure TBancoDeBaterias01.SorteosDelPaso(sortear: boolean);
begin
  CapacidadInstalada_MWh:= paUnidades.nUnidades_Instaladas[0]* pa.CapacidadMaxima_MWh;

  if globs.ObligarDisponibilidad_1_ or ( not sortear ) then
    NMaquinasDisponibles :=   paUnidades.nUnidades_Operativas[0]
  else
  begin
    ActualizarProbabilidadesReparacionYRotura_(pa.fd, pa.tmr);
    NMaquinasDisponibles := Sorteos_RepRotUnidades;
  end;
  PMax_Gen := pa.PMax_Gen * NMaquinasDisponibles;
  PMax_Dem := pa.PMax_Dem * NMaquinasDisponibles;

end;

procedure TBancoDeBaterias01.opt_PrintResultados_Encab(var fsal: textfile);
begin
  Write(fsal, #9, FloatToStrF(X_Carga, ffgeneral, 6, 3));
end;

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

procedure TBancoDeBaterias01.dump_Variables(var f: TextFile; charIndentacion: char);
begin
  inherited dump_Variables(f, charIndentacion);
  writeln(f, charIndentacion, 'Carga[MWh]= ', FloatToStrF(X_Carga, ffFixed, 10, 3));
  writeln(f);
end;

{$IFDEF BOSTA}
procedure TBancoDeBaterias01.AfterInstantiation;
begin
  inherited AfterInstantiation;
  pa := nil;
  nodo := nil;
  if lpd <> nil then
    lpd.Propietario := self;
end;
{$ENDIF}
procedure TBancoDeBaterias01.PrepararPaso_ps;
var
  res: integer;
  xrpos: NREal;
  cv_Dem, cv_Gen: NReal;
begin

  if flg_ValorizadoManual then
    cv_MWh := pa.cv_MWh_ValorizadoManual
  else
  begin
    globs.CF.devxr_continuo(
      ixr, globs.kPaso_Opt + 1, cv_Dem, cv_Gen, res, xrpos);

    case res of
      -1: cv_MWh := cv_Dem;
      0: cv_MWh := (cv_Dem + cv_Gen) / 2.0;
      1: cv_MWh := cv_Gen;
    end;

    if CapacidadInstalada_MWh > 0.00001 then
       cv_MWh := -cv_MWh / CapacidadInstalada_MWh;
  end;

end;

procedure TBancoDeBaterias01.opt_nvers(var ivar, ivae, ires: integer);
begin
  self.ivar := ivar;
  self.ires := ires;
  if NMaquinasDisponibles > 0 then
  begin
    ivar := ivar + 2 * globs.NPostes + 1; // PGen_i ;  PDem_i ; Xs_Carga
    ires := ires + 1; // Restricción dinámica
    // X_Carga - PGen_i*dupos_i * renGen + PDem_i * dupos_i / renDem  - Xs_Carga = 0
  end;
end;

procedure TBancoDeBaterias01.opt_cargue(s: TSimplex);
var
  ibaseres: integer;
  iposte: integer;
  jres: integer;
  maux: NReal;
begin

  if NMaquinasDisponibles <= 0 then   exit;

  ibaseres := nodo.ires;

  // Tenemos que aportar a las restricciones de demanda del nodo al que está
  // conectado el generador
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(ibaseres + iposte, ivar + iposte, 1);
    s.pon_e(ibaseres + iposte, ivar + globs.NPostes + iposte, -1);
  end;


  // Xs_Carga = X_Carga -  PGen_i * durpos_i / renGen +  PDem_i * durpos_i * renDem
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(ires, ivar + iposte, -globs.durpos[iposte] / pa.ren_Gen);
    s.pon_e(ires, ivar + globs.NPostes + iposte, globs.durpos[iposte] * pa.ren_Dem);
  end;

  s.pon_e(ires, ivar + 2 * globs.NPostes, -1); // -Xs_Carga
  s.pon_e(ires, s.nc, X_Carga);


  // Aportes a la función de -costo.
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(s.nf, ivar + iposte, s.e(ires, ivar + iposte) * cv_MWh);
    s.pon_e(s.nf, ivar + globs.NPostes + iposte, s.e(
      ires, ivar + globs.NPostes + iposte) * cv_MWh);
  end;

end;

procedure TBancoDeBaterias01.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
begin
  // Le fijamos como cota máxima PMax a la potencia en todos los postes
  if NMaquinasDisponibles > 0 then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      s.cota_sup_set(ivar + iposte, PMax_Gen);

    for iposte := 0 to globs.NPostes - 1 do
      s.cota_sup_set(ivar + globs.NPostes + iposte, PMax_Dem);

    s.cota_sup_set(ivar + 2 * globs.NPostes, pa.CapacidadMaxima_MWh);
    s.FijarRestriccionIgualdad(ires);
  end;
end;

procedure TBancoDeBaterias01.Sim_Cronica_Inicio;
begin
  inherited Sim_Cronica_Inicio;

  X_Carga := Carga_ini;

end;

procedure TBancoDeBaterias01.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;

begin
  CostoDirectoDelPaso := 0;

  if NMaquinasDisponibles <= 0 then
  begin
    vclear(PGen);
    vclear(PDem);
    vclear(P);
    //vclear( cv_Spot );
    for iposte := 0 to globs.NPostes - 1 do
    begin
      Lambda_P[iPoste]:= 0;
      cv_Spot[iPoste]:=get_cv_falla; // para que en el ordenamiento quede último, con costo variable igual a la falla;
    end;
    Ingreso_PorDisponibilidad_:= 0;
    Xs_Carga := X_Carga;
    exit;
  end;

  for iposte := 0 to globs.NPostes - 1 do
  begin
    PGen[iposte] := s.xval(ivar + iposte);
    PDem[iposte] := s.xval(ivar + globs.npostes + iposte);
    P[iposte] := PGen[iposte] - PDem[iposte];
    Lambda_P[iPoste]:= s.xmult( ivar + iposte ) / globs.DurPos[iPoste];
    cv_Spot[iPoste]:= Nodo.cmarg[iposte] - Lambda_P[iPoste];
   end;

  Ingreso_PorDisponibilidad_:= pa.CapacidadMaxima_MWh * NMaquinasDisponibles * pa.pagoPorDisponibilidad_USDxMWhh * globs.HorasDelPaso;
  Xs_Carga := s.xval(ivar + 2 * globs.NPostes);

end;


procedure TBancoDeBaterias01.EvolucionarEstado;
begin
  X_Carga := Xs_Carga;
end;


function TBancoDeBaterias01.getNombreVar(ivar: integer; var nombre: string): boolean;
begin
  if (ivar >= self.ivar) and (ivar < self.ivar + 2 * globs.NPostes) then
  begin
    Result := True;
    if (ivar < self.ivar + globs.NPostes) then
      nombre := self.Nombre + '_PGen[MW]' + IntToStr(ivar - self.ivar + 1)
    else
      nombre := self.Nombre + '_PDem[MW]' + IntToStr(ivar - self.ivar -
        globs.NPostes + 1);
  end
  else
    Result := False;
end;

function TBancoDeBaterias01.getNombreRes(ires: integer; var nombre: string): boolean;
var
  k: integer;
begin
  if (ires = self.ires) then
  begin
    nombre := self.nombre + 'f(x,u,r)-Xs=0';
    Result := True;
  end
  else
    Result := False;
end;

procedure TBancoDeBaterias01.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableVR('PGen', '[MW]', 6, 2, PGen, True, True);
  PublicarVariableVR('PDem', '[MW]', 6, 2, PDem, True, True);
  PublicarVariableNR('cv_MWh', '[USD/MWh]', 6, 1, cv_MWh, True);
  PublicarVariableNR('X_Carga', '[MWh]', 6, 1, X_Carga, True);
  PublicarVariableNI('NMaquinasDisponibles', '-', NMaquinasDisponibles, False);
end;

procedure TBancoDeBaterias01.optx_nvxs(var ixr, ixd, iauxr, iauxd: integer);
begin
  if not flg_ValorizadoManual then
  begin
    self.ixr := ixr;
    ixr := ixr + 1;
  end;
end;

procedure TBancoDeBaterias01.PosicionarseEnEstrellita;
begin
  if not flg_ValorizadoManual then
    X_Carga := globs.CF.xr[ixr]* CapacidadInstalada_MWh ;
end;

procedure TBancoDeBaterias01.ActualizarEstadoGlobal(flg_Xs: boolean);
begin
  if not flg_ValorizadoManual then
    globs.CF.xr[ixr] := X_Carga / CapacidadInstalada_MWh;
end;

procedure TBancoDeBaterias01.optx_RegistrarVariablesDeEstado(
  adminEstados: TAdminEstados);
begin
  if not flg_ValorizadoManual then
    adminEstados.Registrar_Continua(
      ixr,
      0.0,
      1.0,
      ndisc,
      nombre + '_Carga', // nombre de la variable
      'p.u.' // unidades
      );
end;

procedure TBancoDeBaterias01.Free;
begin
  if lpd <> nil then
    lpd.Free;
  setlength(PGen, 0);
  setlength(PDem, 0);
  inherited Free;
end;



{*********************************
*Métodos de TFichaBancoBaterias *
*********************************}

constructor TFichaBancoDeBaterias01.Create(capa: integer; fecha: TFecha;
  periodicidad: TPeriodicidad; PMax_Gen, PMax_Dem: NReal; ren_Gen,
  ren_Dem: NReal; CapacidadMaxima_MWh: NReal; fd, TMR, cv_MWh_ValorizadoManual,
  pagoPorDisponibilidad_USDxMWhh: NReal);
begin
  inherited Create(capa, fecha, periodicidad);
  Self.PMax_Gen := PMax_Gen;
  self.PMax_Dem := PMax_Dem;
  self.ren_Gen := ren_Gen;
  self.ren_Dem := ren_Dem;
  self.CapacidadMaxima_MWh := CapacidadMaxima_MWh;
  self.fd := fd;
  self.TMR := TMR;
  self.cv_MWh_ValorizadoManual := cv_MWh_ValorizadoManual;
  self.pagoPorDisponibilidad_USDxMWhh:= pagoPorDisponibilidad_USDxMWhh;
end;

function TFichaBancoDeBaterias01.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('PMax_Gen', PMax_Gen);
  Result.addCampoDef('PMax_Dem', PMax_Dem);
  Result.addCampoDef('ren_Gen', ren_Gen);
  Result.addCampoDef('ren_Dem', ren_Dem);
  Result.addCampoDef('CapacidadMaxima_MWh', CapacidadMaxima_MWh);
  Result.addCampoDef('fd', fd);
  Result.addCampoDef('TMR', TMR);
  Result.addCampoDef('cv_MWh_ValorizadoManual', cv_MWh_ValorizadoManual, 121 );
  result.addCampoDef('pagoPorDisponibilidad_USDxMWhh', pagoPorDisponibilidad_USDxMWhh, 149 );
end;

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

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



procedure TFichaBancoDeBaterias01.Free;
begin
  inherited Free;
end;


procedure AlInicio;
begin
  registrarClaseDeCosa(TBancoDeBaterias01.ClassName, TBancoDeBaterias01);
  registrarClaseDeCosa(TFichaBancoDeBaterias01.ClassName, TFichaBancoDeBaterias01);
end;

procedure AlFinal;
begin
end;

end.
