unit udemandas01;

{$MODE Delphi}

interface

uses
  SysUtils,
  uauxiliares,
  xmatdefs,
  uDemandas, uFuentesAleatorias,
  uNodos, usimplex, ufichasLPD,
  ufechas,
  ucosa, uCosaConNombre,
  uconstantesSimSEE, math01;

resourcestring
  rs3CurvasHorararias = '3 Curvas Horarias';

type

  { TFichaDemanda01 }

  TFichaDemanda01 = class(TFichaLPD)
  public
    PotDiaHabil: TDAOfNreal;
    PotDiaMedioFeriado: TDAOfNreal;
    PotDiaFeriado: TDAOfNreal; // Potencia en MW

    constructor Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad;
      PotDiaHabil, PotDiaMedioFeriado, PotDiaFeriado: TDAOfNreal);

    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;


type

  { TDemanda01 }

  TDemanda01 = class(TDemanda)
  private
    CacheActivo: boolean;

  public
    pA, pB: TFichaDemanda01; // Fichas de parámetros dinámicos

    constructor Create(capa: integer; nombre: string; nacimiento, muerte: TFecha;
      lpdUnidades, lpd: TFichasLPD; nodo: TNodo; falla_profundidad,
  falla_costo: TDAOfNReal; fuente: TFuenteAleatoria; nombreBorne: string;
  SumarEnergiaHr, flg_SumarParaPostizado: boolean;
  icf_Fuente: TFuenteAleatoria; icf_NombreBorne: string;
  Prioridad_DemSpot: Integer; xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string
  );

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

    procedure RegistrarParametrosDinamicos(CatalogoReferencias: TCatalogoReferencias);
      override;

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

    function PotenciaFirme: NReal; override;

    //      procedure prepararSim; override;
    procedure prepararPaso_as; override;
    destructor destroy; override;

  end;


(* Deforma una curva de potencia horaria aplicando factores de crecimiento de
energía (fce) y del pico (fcp).
Por ejemplo, si el pico decrese 10% y la energía debe aumentar 5% los factores
serán fce= 1.05 y fcp= 0.9

El resultado es TRUE si todas las potencias resultantes son positivas y false
si alguna quedó negativa.
*)
function aplicarCrecimientos_CurvaHoraria(var PotHoraria: TDAOfNReal;
  fce, fcp: NReal): boolean;

procedure AlInicio;
procedure AlFinal;

implementation


//----------------------
// Métodos de TDemanda01
//======================

constructor TDemanda01.Create(capa: integer; nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  falla_profundidad, falla_costo: TDAOfNReal; fuente: TFuenteAleatoria;
  nombreBorne: string; SumarEnergiaHr, flg_SumarParaPostizado: boolean;
  icf_Fuente: TFuenteAleatoria; icf_NombreBorne: string; Prioridad_DemSpot: Integer;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string );
begin
  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades, nodo,
    falla_profundidad, falla_costo, fuente, nombreBorne,
    icf_fuente, icf_NombreBorne, SumarEnergiaHr, flg_SumarParaPostizado,
    Prioridad_DemSpot, xFuenteIdxP, xBorneIdxP );

  self.lpd := lpd;
  self.fuente := fuente;
  self.nombreBorne := nombreBorne;
  CacheActivo := False;
end;

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

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

procedure TDemanda01.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
  pa := nil;
  CacheActivo := False;
  lpd.Propietario := self;
end;



procedure TDemanda01.RegistrarParametrosDinamicos(
  CatalogoReferencias: TCatalogoReferencias);
begin
  inherited registrarParametrosDinamicos(CatalogoReferencias);
  lpd.expandirFichas(CatalogoReferencias, globs);
  lpd.RegistrarFichasAActualizar(Self, globs.ActualizadorLPD, @pA, @pB);
end;

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

class function TDemanda01.DescClase: string;
begin
  Result := rs3CurvasHorararias;
end;

function TDemanda01.PotenciaFirme: NReal;
begin
  Result := paUnidades.nUnidades_Operativas[0] * vmax(self.PPa);
end;

procedure TDemanda01.prepararPaso_as;
var
  alfa: NReal;

  hdd: integer;
  tipoDeDia: TTipoDia;
  iHoraDelPaso: integer;
  instante: TFecha;
begin
{  if CacheActivo then exit;
  CacheActivo:= true;}


  instante := globs.FechaInicioDelpaso;

  alfa := (instante.dt - pA.fecha.dt) / (pB.fecha.dt - pA.fecha.dt);
  hdd := instante.hora;

  for iHoraDelPaso := 0 to high( PHoraria_SinAfectar) do
  begin
    tipoDeDia := instante.TipoDeDia;
    case tipoDeDia of
      Habil: PHoraria_SinAfectar[iHoraDelPaso] :=
          ponder(pA.PotDiaHabil[hdd], pB.PotDiaHabil[hdd], alfa);
      SemiFeriado: PHoraria_SinAfectar[iHoraDelPaso] :=
          ponder(pA.PotDiaMedioFeriado[hdd], pB.PotDiaMedioFeriado[hdd], alfa);
      Feriado: PHoraria_SinAfectar[iHoraDelPaso] :=
          ponder(pA.PotDiaFeriado[hdd], pB.PotDiaFeriado[hdd], alfa);
    end; // del case
    hdd := (hdd + 1) mod 24;
  end;

  inherited prepararPaso_as;
end;


destructor TDemanda01.destroy;
begin
  self.lpd.Free;
  inherited destroy;
end;


//-------------------------
// Métodos de TFichaDemanda
//=========================

constructor TFichaDemanda01.Create(capa: integer; fecha: TFecha;
  periodicidad: TPeriodicidad;
  PotDiaHabil, PotDiaMedioFeriado, PotDiaFeriado: TDAOfNreal);
begin
  inherited Create(capa, fecha, periodicidad);
  self.PotDiaHabil := copy(PotDiaHabil, 0, MAXINT);
  self.PotDiaMedioFeriado := copy(PotDiaMedioFeriado, 0, MAXINT);
  self.PotDiaFeriado := copy(PotDiaFeriado, 0, MAXINT);
end;

function TFichaDemanda01.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('PotDiaHabil', PotDiaHabil);
  Result.addCampoDef('PotDiaMedioFeriado', PotDiaMedioFeriado);
  Result.addCampoDef('PotDiaFeriado', PotDiaFeriado);

end;

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

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




function aplicarCrecimientos_CurvaHoraria(var PotHoraria: TDAOfNReal;
  fce, fcp: NReal): boolean;
var
  k: integer;
  gamma: NReal;
  E, Pp, Pk, PpPrima: NReal;
  res: boolean;
  Pm: NReal;
  PMin: NReal;
  ro: TDAOfNReal; // ro_i = Pi/Pp

begin
  E := 0;
  Pp := PotHoraria[0];
  PMin := PotHoraria[0];
  for k := 0 to high(POtHOraria) do
  begin
    Pk := PotHoraria[k];
    E := E + Pk;
    if Pk > Pp then
      Pp := Pk
    else if Pk < PMin then
      PMin := Pk;
  end;
  Pm := E / length(PotHoraria);

  res := True;
  if (EsCero(Pp - Pm)) then
  begin
    // es una demanda plana, aplico solo factor de energía
    for k := 0 to high(PotHoraria) do
    begin
      PotHoraria[k] := PotHoraria[k] * fce;
    end;
  end
  else
  begin
    gamma := (fcp * Pp - fce * Pm) / (Pp - Pm);
    PpPrima := fcp * Pp;
    if (gamma >= 0) and ((PpPrima - gamma * (PP - Pmin)) >= 0) then
    begin
      for k := 0 to high(PotHoraria) do
      begin
        Pk := PpPrima - gamma * (PP - PotHoraria[k]);
        PotHoraria[k] := Pk;
      end;
    end
    else
      res := False;
  end;
  Result := res;
end;


function TFichaDemanda01.infoAd_: string;
begin
  Result := 'PotDíaHábil Media= ' + FloatToStrF(vprom(PotDiaHabil), ffGeneral, 10, 1) +
    ' MW, ' + 'PotDíaMedioFeriado Media= ' +
    FloatToStrF(vprom(PotDiaMedioFeriado), ffGeneral, 10, 1) + ' MW, ' +
    'PotDíaFeriado Media= ' + FloatToStrF(vprom(PotDiaFeriado),
    ffGeneral, 10, 1) + ' MW';
end;

destructor TFichaDemanda01.destroy;
begin
  setlength(PotDiaHabil, 0);
  setlength(PotDiaMedioFeriado, 0);
  setlength(PotDiaFeriado, 0);
  inherited destroy;
end;


procedure AlInicio;
begin
  registrarClaseDeCosa(TDemanda01.ClassName, TDemanda01);
  registrarClaseDeCosa(TFichaDemanda01.ClassName, TFichaDemanda01);
end;

procedure AlFinal;
begin
end;

end.
