unit uActorNodal;

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

interface

uses
  uCosa, uGlobs, uActores, uFechas, unodos, uCosaConNombre, uFichasLPD,
  xMatDefs, Classes, uauxiliares, uFuentesAleatorias;

type

  { TActorNodal }

  TActorNodal = class(TActor)
    // Como Gen. Nodo al que inyecta
    cv_Spot: TDAofNReal;
    // Costo variable del actor para cada poste = cmg - Multiplicador de lagrange de la restricción de caja de la potencia
    Lambda_P: TDAofNReal; // Multiplicador de Lagrange de la restricción de caja de P
    // Como demanda
    Prioridad_DemSpot: integer;
    procedure BeforeRead(version, id_hilo: integer); override;

    function ReferenciaAlNodo(nodo: TNodo): boolean; virtual; abstract;
    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;
    destructor Destroy; override;
  end;

  { TActorUniNodal }

  TActorUniNodal = class(TActorNodal)
  public
    P: TDAOfNReal; // Inyectada como generador al nodo
    ReservaRotante: TDAOfNReal; // Inyectada como generador al nodo
    P_horaria: TDAOfNReal; // Inyectada como generador al nodo horaria

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

    Nodo: TNodo;
    barras_flucar: TDAOfNint;
    codigos_flucar: TDAOfString;
    (**************************************************************************)

    // Participacion  por Servicio de Confiabilidad del Sistema
    ParticipacionSCS: nReal;
    // Participacion en Forzamiento  por Servicio de Confiabilidad del Sistema
    ForzamientoSCS: nReal;

    constructor Create(capa: integer; nombre: string;
      nacimiento, muerte: TFecha; lpdUnidades: TFichasLPD; Nodo: TNodo;
      xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);

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

    function ReferenciaAlNodo(nodo: TNodo): boolean; override;
    procedure PubliVars; override;
    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;

    procedure CalcularPagoServicioDeConfiabilidaddelSist; virtual;

    destructor Destroy; override;
    {$IFDEF BOSTA}
    procedure AfterInstantiation; override;
    {$ENDIF}
  end;

  { TActorBiNodal }

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

    NodoA, NodoB: TNodo;
    (**************************************************************************)

    // resultados del despacho
    P_NodoA, P_NodoB: TDAOfNReal; //[MW] Potencia inyectada como generador en cada Nodo.


    constructor Create(capa: integer; nombre: string;
      nacimiento, muerte: TFecha; lpdUnidades: TFichasLPD; NodoA, NodoB: TNodo;
      xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);

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

    function ReferenciaAlNodo(nodo: TNodo): boolean; override;
    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;
    destructor Destroy; override;

  end;

procedure AlInicio;
procedure ALFinal;

implementation

{ TActorNodal }

procedure TActorNodal.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  setlength(cv_Spot, 0);
  setlength(Lambda_P, 0);
  Prioridad_DemSpot := 0;
end;

procedure TActorNodal.PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs);
begin
  inherited PrepararMemoria(Catalogo, globs);
  setlength(cv_Spot, globs.NPostes);
  setlength(Lambda_P, globs.NPostes);
end;

destructor TActorNodal.Destroy;
begin
  if cv_spot <> nil then
    setlength(cv_Spot, 0);
  if lambda_P <> nil then
    setlength(Lambda_P, 0);
  inherited Destroy;
end;

//--------------------------
// Métodos de TActorUniNodal
//==========================

constructor TActorUniNodal.Create(capa: integer; nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades: TFichasLPD; Nodo: TNodo;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);
begin
  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades,
    xFuenteIdxP, xBorneIdxP);
  self.Nodo := Nodo;
  barras_flucar := nil;
  codigos_flucar := nil;
  cv_Spot := nil;
  Lambda_P := nil;
end;

function TActorUniNodal.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef_ref('nodo', TCosa(self.Nodo), Self);
  Result.addCampoDef('barras_flucar', barras_flucar, 49);
  Result.addCampoDef('codigos_flucar', codigos_flucar, 49);
  Result.addCampoDef('Prioridad_DemSpot', Prioridad_DemSpot, 160);
  Result.addCampoDef('ParticipacionSCS', ParticipacionSCS, 185);
  Result.addCampoDef('ForzamientoSCS', ForzamientoSCS, 185);
end;

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

procedure TActorUniNodal.AfterRead(f: TArchiTexto);
begin
  inherited AfterRead(f);
  if f.Version >= 49 then
    clear_vacias(codigos_flucar);
  if f.Version < 185 then
  begin
    ParticipacionSCS := 0;
    ForzamientoSCS := 0;
  end;
  self.Nodo := nil;
end;

function TActorUniNodal.ReferenciaAlNodo(nodo: TNodo): boolean;
begin
  Result := self.nodo = nodo;
end;

procedure TActorUniNodal.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableVR('P', 'MW', 6, 2, P, True, True);
  PublicarVariableVR('ReservaRotante', 'MW', 6, 2, ReservaRotante, True, True);
  //  PublicarVariableVR('P_horaria', 'MW', 6, 2, P_horaria, True, True);
  PublicarVariableVR('cv_Spot', 'USD/MWh', 12, 4, cv_Spot, True, True);
  PublicarVariableVR('Lambda_P', 'USD/MWh', 12, 4, Lambda_P, True, True);
  PublicarVariableNR('ParticipacionSCS', 'USD', 12, 2, ParticipacionSCS, True);
  PublicarVariableNR('ForzamientoSCS', 'USD', 12, 2, ForzamientoSCS, True);

end;

procedure TActorUniNodal.PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs);
begin
  inherited PrepararMemoria(Catalogo, globs);
  setlength(P, globs.NPostes);
  setlength(ReservaRotante, globs.NPostes);
  setlength(P_horaria, round(globs.HorasDelPaso));
end;

procedure TActorUniNodal.CalcularPagoServicioDeConfiabilidaddelSist;
var
  iPoste: integer;
  CmgMenosTecho, TechoMenosCV: NReal;
begin
  ParticipacionSCS := 0;
  ForzamientoSCS := 0;
  for iPoste := 0 to high(P) do
  begin
    CmgMenosTecho := nodo.cmarg[iposte] - globs.TechoDelSpot;
    if CmgMenosTecho > 0 then
    begin
      TechoMenosCV := globs.TechoDelSpot - CV_spot[iposte];
      if TechoMenosCV > 0 then
        ParticipacionSCS :=
          ParticipacionSCS + P[iposte] * globs.durpos[iposte] * CmgMenosTecho // al ltriangulito.
      else
      begin
        ParticipacionSCS :=
          ParticipacionSCS + P[iposte] * globs.durpos[iposte] *
          (nodo.cmarg[iposte] - CV_Spot[iposte]);  // al triangulito
        ForzamientoSCS :=
          ForzamientoSCS + P[iposte] * globs.durpos[iposte] * (-TechoMenosCV);
        // al rectángulito
      end;
    end;
  end;
end;


destructor TActorUniNodal.Destroy;
begin
  setlength(P, 0);
  setlength(ReservaRotante, 0);
  setlength(P_horaria, 0);

  setlength(barras_flucar, 0);
  setlength(codigos_flucar, 0);

  inherited Destroy;
end;


{$IFDEF BOSTA}
procedure TActorUniNodal.AfterInstantiation;
begin

  inherited AfterInstantiation;
  clear_vacias(codigos_flucar);
  self.Nodo := nil;

end;

{$ENDIF}

//-------------------------
// Métodos de TActorBiNodal
//=========================

constructor TActorBiNodal.Create(capa: integer; nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades: TFichasLPD; NodoA, NodoB: TNodo;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);
begin
  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades,
    xFuenteIdxP, xBorneIdxP);
  self.NodoA := NodoA;
  self.NodoB := NodoB;
  setlength(cv_Spot, 0);
  setlength(Lambda_P, 0);
  Prioridad_DemSpot := 1;
end;

function TActorBiNodal.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef_ref('nodoA', TCosa(NodoA), Self);
  Result.addCampoDef_ref('nodoB', TCosa(NodoB), Self);
end;

procedure TActorBiNodal.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  Prioridad_DemSpot := 1;
end;

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


function TActorBiNodal.ReferenciaAlNodo(nodo: TNodo): boolean;
begin
  Result := (nodoA = nodo) or (nodoB = nodo);
end;

procedure TActorBiNodal.PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs);

begin
  inherited prepararMemoria(Catalogo, globs);
  setlength(P_NodoA, globs.NPostes);
  setlength(P_NodoB, globs.NPostes);
  setlength(cv_Spot, globs.NPostes);
  setlength(Lambda_P, globs.NPostes);
end;

destructor TActorBiNodal.Destroy;
begin
  setlength(P_NodoA, 0);
  setlength(P_NodoB, 0);
  setlength(cv_Spot, 0);
  setlength(Lambda_P, 0);
  inherited Destroy;
end;

procedure AlInicio;
begin
  //  registrarClaseDeCosa(TActorUniNodal.ClassName, TActorUniNodal);
  //  registrarClaseDeCosa(TActorBiNodal.ClassName, TActorBiNodal);
end;

procedure AlFinal;
begin
end;

end.
