unit usolarpv;

interface

uses
  Math,
  SysUtils, Classes, xmatdefs, uGeneradores, uNodos,
  uglobs,
  usimplex,
  umipsimplex,
  ufichasLPD,
  ufechas,
  ucosa,
  ucosaConNombre,
  uconstantesSimSEE,
  uFuncionesReales,
  uFuentesAleatorias;

resourcestring
  mesFuenteAleatConPaso1h =
    'SolarPV, necesita una fuente aleatoria con paso de sorteo = 1h. ';
  mesElParque = 'El parque ';
  mesConectadoAFuente = ' está conectado a la fuente ';
  mesConPasoDeSorteo = ' con paso de sorteo = ';
  rsGeneradorSolarPV = 'Generador Solar PV';

{TSolarPV es un generador térmico simple cuya potencia se determina
mediante el cálculo de la irradiancia solar incidente y el área del panel.
La irradiancia de calcula como el producto del índice de claridad (que es una fuente de aleatoria) con la irradiación solar extraterrestre.}

type

  { TFichaSolarPV }

  TFichaSolarPV = 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_1000_W_m2: NReal; //[MW] Potencia Máxima de los módulos a 1000 W/m2.
    PMax_Inversor: NReal; // [MW] Potencia Máxima del inversor del módulo.

    PMax_OlD: NReal;

    disp: NReal; //Probabilidad de estar en el estado disponible
    tRepHoras: NReal;   //tiempo promedio de reparación en horas

    PagoPorDisponibilidad_USD_MWh: NReal; // [USD/u-h] Pago por Potencia disponible
    PagoPorEnergia_USD_MWh: NReal; // [USD/MWh] Pago por energia

    area_PorModulo_OLD: NReal;

    latitud: NReal;
    longitud: NReal;
    inclinacion: NReal;
    azimut: NReal;

    rendimiento_OLD_: NReal;
    fIradToPot: NReal; // [MW]/[W/m2] por módulo

    fPerdidas_pu: NReal; // Perdidas complexivas:
    // Inversor: 1 - 2%
    // Ohmicas(DC+AC): 0.2 - 0.5%
    // Trafo: 1 - 2%
    reflexion_suelo: NReal;
    (**************************************************************************)

    PMaxDisponiblePorModulo: NReal;

    constructor Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad;
      PMax_1000_W_m2, PMax_Inversor: NReal; disp: NReal; tRepHoras: NReal;
      PagoPorDisponibilidad_USD_MWh: NReal; PagoPorEnergia_USD_MWh: NReal;
      latitud: NReal; longitud: NReal; inclinacion: NReal; azimut: NReal;
      fperdidas_pu: NReal; reflexion_suelo: NReal);

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

    function infoAd_: string; override;
    procedure Free; override;
  end;



  TSolarPV = class(TGeneradorPostizador)
  public
    pa: TFichaSolarPV;
    NMaquinasDespachadas: TDAOfNInt;
    // cantidad de máquinas despachadas por poste o por paso ( Acople )

    //Cuanta potencia despacho en cada hora el generador en promedio
    potMedia_despachada: NReal;

    PMax_Central: NReal;  //PMax disponible
    flg_NoDisponible: boolean;

    fuente_IndiceClaridad: TFuenteAleatoria;
    borneIndiceClaridad: string;

    nroBorneIndiceClaridad: integer;
    {$IFDEF CALC_DEMANDA_NETA}
    kBornePotencia: integer;
    {$ELSE}
    kBornePPA: TDAofNInt; // Potencia del Poste Actual
    {$ENDIF}
    indice_kt: NReal;

    kt_to_P: TFRenR;   //se usa en prepararmemoria
    Irradiancia_plano_horizontal: NReal;
    Irradiancia_plano_inclinado: NReal;

    constructor Create(capa: integer; nombre: string; nacimiento, muerte: TFecha;
      lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  xflg_RestarParaPostizado: boolean; xflg_CacluarGradienteDeInversion: boolean;
  TonCO2xMWh: NReal; LowCostMustRun, CleanDevelopmentMechanism: boolean;
  indiceClaridad: TFuenteAleatoria; borneIndiceClaridad: string;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string); reintroduce;


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

    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;
    //crea la memoria, inicializa lo que se necesite para empezar.
    procedure RegistrarParametrosDinamicos(CatalogoReferencias: TCatalogoReferencias);
      override;
    //prepara todas las fichas de parametros dinámicos

    function PotenciaFirme: NReal; override;
    //se usa para calcular la potencia firme del sistema.

    function InfoAd_: string; override;
    class function DescClase: string; 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 Sim_Paso_Fin; 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 Free; override;

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

    class function TipoFichaLPD: TClaseDeFichaLPD; override;


    procedure CalcularPagoServicioDeConfiabilidaddelSist; override;

  end;




procedure AlInicio;
procedure AlFinal;

implementation

//----------------------------------
// Métodos de TFichaSolarPV
//==================================
constructor TFichaSolarPV.Create(capa: integer; fecha: TFecha;
  periodicidad: TPeriodicidad; PMax_1000_W_m2, PMax_Inversor: NReal;
  disp: NReal; tRepHoras: NReal; PagoPorDisponibilidad_USD_MWh: NReal;
  PagoPorEnergia_USD_MWh: NReal; latitud: NReal; longitud: NReal;
  inclinacion: NReal; azimut: NReal; fperdidas_pu: NReal; reflexion_suelo: NReal);
begin
  inherited Create(capa, fecha, periodicidad);
  self.PMax_1000_W_m2 := PMax_1000_W_m2;
  self.PMax_Inversor := PMax_Inversor;
  self.disp := disp;
  self.tRepHoras := tRepHoras;
  self.PagoPorDisponibilidad_USD_MWh := PagoPorDisponibilidad_USD_MWh;
  self.PagoPorEnergia_USD_MWh := PagoPorEnergia_USD_MWh;
  //  self.area_PorModulo := PMax_1000_W_m2 * 1000 / 0.2 ;
  self.latitud := latitud;
  self.longitud := longitud;
  self.inclinacion := inclinacion;
  self.azimut := azimut;
  self.fPerdidas_pu := fperdidas_pu;
  self.reflexion_suelo := reflexion_suelo;
end;

function TFichaSolarPV.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef('PMax', PMax_OLD, 0, 153);
  Result.addCampoDef('PMax_Inversor', PMax_Inversor, 153);
  Result.addCampoDef('PMax_1000_W_m2', PMax_1000_W_m2, 153, 0, '-1');
  Result.addCampoDef('disp', disp);
  Result.addCampoDef('tRepHoras', tRepHoras);
  Result.addCampoDef('PagoPorDisponibilidad_USD_uh',
    PagoPorDisponibilidad_USD_MWh, 0, 98);
  Result.addCampoDef('PagoPorEnergia', PagoPorEnergia_USD_MWh, 0, 98);
  Result.addCampoDef('PagoPorDisponibilidad_USD_MWh', PagoPorDisponibilidad_USD_MWh, 98);
  Result.addCampoDef('PagoPorEnergia_USD_MWh', PagoPorEnergia_USD_MWh, 98);
  Result.addCampoDef('area', area_PorModulo_OLD, 0, 153);
  Result.addCampoDef('latitud', latitud);
  Result.addCampoDef('longitud', longitud);
  Result.addCampoDef('inclinacion', inclinacion);
  Result.addCampoDef('azimut', azimut);
  Result.addCampoDef('rendimiento', rendimiento_OLD_, 0, 153);
  Result.addCampoDef('fPerdidas_pu', fPerdidas_pu, 153, 0, '0.0335');
  Result.addCampoDef('reflexion_suelo', reflexion_suelo);
end;

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

procedure TFichaSolarPV.AfterRead(f:TArchiTexto);
var
  NModulos: integer;
  PMaxTotal: NReal;

begin
  inherited AfterRead(f);
  if PMax_1000_W_m2 < 0 then
  begin     // Si la sala es vieja tenía como parámetro el área total
    // y la potencia máxima de un módulo
    fPerdidas_pu := 0.0335;
    PMaxTotal := area_PorModulo_OLD * (1000 / 1E6) * rendimiento_OLD_/ (1- fPerdidas_pu);
    NModulos := round(PMaxTotal / PMax_OLD);
    PMax_Inversor := PMax_OLD;
    PMax_1000_W_m2 := PMaxTotal / NModulos;
  end;
  fIradToPot:=  PMax_1000_W_m2 * (1 - fPerdidas_pu);
end;



function TFichaSolarPV.infoAd_: string;
begin
  Result := 'PMáx= ' + FloatToStrF(PMax_Inversor, ffGeneral, 10, 1) +
    ' MW, ' + 'fDisp= ' + FloatToStrF(disp, ffGeneral, 10, 2) + ' p.u., ' +
    'tRep= ' + FloatToStrF(tRepHoras, ffGeneral, 10, 1) + ' hs';
end;

procedure TFichaSolarPV.Free;
begin
  inherited Free;
end;




//-----------------------------
// Métodos de TSolarPV
//=============================
procedure TSolarPV.dump_Variables(var f: TextFile; charIndentacion: char);
begin
  inherited dump_Variables(f, charIndentacion);
  writeln(f, charIndentacion, 'PPico_Modulo[MW]= ',
    FloatToStrF(pa.PMax_1000_W_m2, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'PMax_Modulo[MW]= ',
    FloatToStrF(pa.PMax_Inversor, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'disp= ', pa.disp);
  writeln(f, charIndentacion, 'latitud[°]= ', pa.latitud);
  writeln(f, charIndentacion, 'longitud[°]= ', pa.longitud);
  writeln(f, charIndentacion, 'inclinacion[°]= ', pa.inclinacion);
  writeln(f, charIndentacion, 'azimut[°]= ', pa.azimut);
  writeln(f, charIndentacion, 'fPerdidas[p.u.]= ', pa.fPerdidas_pu);
  writeln(f, charIndentacion, 'reflexion del suelo= ', pa.reflexion_suelo);
  writeln(f);
end;

class function TSolarPV.TipoFichaLPD: TClaseDeFichaLPD;
begin
  Result := TFichaSolarPV;
end;

procedure TSolarPV.CalcularPagoServicioDeConfiabilidaddelSist;
var
   iPoste: integer;
   CmgMenosTecho: NReal;
begin
    ParticipacionSCS:= 0;
    ForzamientoSCS:=0;
    for iPoste:= 0 to high( P )  do
    begin
       CmgMenosTecho:= nodo.cmarg[iposte] - globs.TechoDelSpot;
       if  CmgMenosTecho > 0  then
           ParticipacionSCS:= ParticipacionSCS + P[iposte]* globs.durpos[iposte] * CmgMenosTecho // al ltriangulito.
    end
end;



constructor TSolarPV.Create(capa: integer; nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  xflg_RestarParaPostizado: boolean; xflg_CacluarGradienteDeInversion: boolean;
  TonCO2xMWh: NReal; LowCostMustRun, CleanDevelopmentMechanism: boolean;
  indiceClaridad: TFuenteAleatoria; borneIndiceClaridad: string;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string );
begin

  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades,
    nodo, TonCO2xMWh, LowCostMustRun, CleanDevelopmentMechanism,
    xflg_RestarParaPostizado, xflg_CacluarGradienteDeInversion, xFuenteIdxP, xBorneIdxP );

  self.lpd := lpd;
  self.fuente_indiceClaridad := indiceClaridad;
  self.borneIndiceClaridad := borneIndiceClaridad;
  nroBorneIndiceClaridad := -1;
  P := nil;
  NMaquinasDespachadas := nil;
end;

function TSolarPV.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef_ref('indiceClaridad', TCosa(fuente_IndiceClaridad), self);
  Result.addCampoDef('borneIndiceClaridad', borneIndiceClaridad);
  Result.addCampoDef('lpd', TCosa(lpd));
end;

procedure TSolarPV.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  P := nil;
  NMaquinasDespachadas := nil;
  pa := nil;
  nodo := nil;
  nroBorneIndiceClaridad := -1;
end;

procedure TSolarPV.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
  if lpd = nil then
    // esto es solo para que funcione si no salvó la lista por error
    lpd := TFichasLPD.Create(capa, 'fichasLPD', self, TFichaSolarPV)
  else
    lpd.Propietario := self;
end;



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

var
{$IFNDEF CALC_DEMANDA_NETA}
  iposte: integer;
{$ENDIF}
  auxf: TFRenR;
  //vector auxiliar que representa un factor multilicativo segun el mes, en este caso siempre es 1.
  vector_aux: TDAOfNreal;
  j: integer;

  //  fuente: TFuenteAleatoria;
  //  pot_hora: NReal;

begin
  inherited prepararMemoria(Catalogo, globs);
  setlength(P, globs.NPostes);
  SetLength(NMaquinasDespachadas, globs.NPostes);
  SetLength(vector_aux, 12);

  for j := 0 to (length(vector_aux) - 1) do
    vector_aux[j] := 1;

  if not ((fuente_IndiceClaridad.durPasoDeSorteoEnHoras = 1)) then
    raise Exception.Create(mesFuenteAleatConPaso1h + mesElParque +
      nombre + mesConectadoAFuente + fuente_IndiceClaridad.nombre +
      mesConPasoDeSorteo + IntToStr(fuente_IndiceClaridad.durPasoDeSorteoEnHoras));

  if nroBorneIndiceClaridad = -1 then // la primera vez definimos los bornes
  begin
    nroBorneIndiceClaridad := fuente_IndiceClaridad.IdBorne(borneIndiceClaridad);

    SetLength(PPA, globs.NPostes);

    {$IFDEF CALC_DEMANDA_NETA}

    kt_to_P := TFRenR_GranjaSolar.Create(capa, @pa, borneIndiceClaridad, globs);

    auxf := TFf_xmult_conselectorYBuffer.Create(capa, kt_to_P,
      vector_aux, 1, @globs.MesInicioDelPaso, @PHoraria_PreSorteosPorUnidad,
      @globs.kSubPaso_);

    kBornePotencia := fuente_IndiceClaridad.registrarFuncion(auxf,
      borneIndiceClaridad, -1);

    if fuente_IndiceClaridad.ResumirMaxVar(globs) <> nil then
    begin
      fuente_IndiceClaridad.flg_ResumirBorneras := False;
      flg_ResumirPromediando := False;
    end
    else
      flg_ResumirPromediando := True;


    {$ELSE}
    SetLength(kBornePPA, globs.NPostes);

    kt_to_P := TFRenR_GranjaSolar.Create(capa, @pa, borneIndiceClaridad, globs);

    for iposte := 0 to high(kBornePPA) do
    begin
       (*
       Para cada poste definimos un borne auxiliar que llevará la cuenta
       de la energía generada por el parque en ese poste y así puede calcular
       la potencia media equivalente del parque para ese poste.
       Se supone que la fuente de indice de claridad tiene paso de sorteo HORARIO.
       *)
      auxf := TFf_xmult_conselector.Create(capa, kt_to_P, vector_aux,
        1, @globs.MesInicioDelPaso, iposte, @globs.kPosteHorasDelPaso,
        @globs.kSubPaso_);

      kBornePPA[iposte] := fuente_IndiceClaridad.registrarFuncion(auxf,
        borneIndiceClaridad, iposte);
    end;
    {$ENDIF}
  end;
end;

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


function TSolarPV.PotenciaFirme: NReal;
begin
  Result := 0; // ojo, esto es una convensión.
  // Si este actor lo usamos para Generación Distribuída o Importación
  // devolvemos CERO pues la potencia firme debe ser calculada por algún otro
  // método.

end;

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

class function TSolarPV.DescClase: string;
begin
  Result := rsGeneradorSolarPV;
end;

procedure TSolarPV.Sim_Cronica_Inicio;
begin
  inherited Sim_Cronica_Inicio;
end;

function TSolarPV.get_pa_FD(kTipoUnidad: integer): NReal;
begin
  Result := pa.disp;
end;

function TSolarPV.get_pa_TMR(kTipoUnidad: integer): NReal;
begin
  Result := pa.tRepHoras;
end;


procedure TSolarPV.SorteosDelPaso(sortear: boolean);
begin
  if hayForzamientos or globs.ObligarDisponibilidad_1_ then
  begin
    NMaquinasDisponibles := paUnidades.nUnidades_Operativas[0];
    PMax_Central := pa.PMax_Inversor * NMaquinasDisponibles;
  end
  else if sortear then
  begin
    ActualizarProbabilidadesReparacionYRotura_(pa.disp, pa.tRepHoras);
    NMaquinasDisponibles := Sorteos_RepRotUnidades;
    PMax_Central := pa.PMax_Inversor * NMaquinasDisponibles;
  end
  else
  begin
    NMaquinasDisponibles := paUnidades.nUnidades_Operativas[0];
    PMax_Central := pa.PMax_Inversor * pa.disp * NMaquinasDisponibles;
  end;
  flg_NoDisponible := EsCero(PMax_Central);
  inherited SorteosDelPaso(sortear);
end;

procedure TSolarPV.PrepararPaso_ps;
{$IFNDEF CALC_DEMANDA_NETA}
var
  iPoste: integer;
{$ENDIF}

begin
  inherited PrepararPaso_ps;

  indice_kt := (kt_to_P as TFRenR_GranjaSolar).indice_kt;//solo sirve para el horario
  Irradiancia_plano_horizontal := (kt_to_P as TFRenR_GranjaSolar).Ih;
  //solo sirve para el horario
  Irradiancia_plano_inclinado := (kt_to_P as TFRenR_GranjaSolar).Ii;
  //solo sirve para el horario

  if flg_NoDisponible then
  begin
    vclear(PPA);
    exit;
  end;

  {$IFNDEF CALC_DEMANDA_NETA}
  EnergiaDisponibleDelPaso := 0;
  for iposte := 0 to high(PPA) do
  begin
    PPA[iposte] := Self.fuente_IndiceClaridad.bornera[Self.kBornePPA[iposte]] *
      NMaquinasDisponibles;
    EnergiaDisponibleDelPaso :=
      EnergiaDisponibleDelPaso + PPA[iposte] * globs.DurPos[iposte];
  end;
  {$ENDIF}
end;




//procedure TSolarPV.Sim_Paso_Fin; //lee la solución al fin de cada paso
//var
//iposte: integer;
//begin
//potMedia_despachada := 0;
//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 TSolarPV.opt_nvers(var ivar, ivae, ires: integer);
//cantidad de variables de control que usa (cant postes, potencia y potencias acoples)
begin
  if flg_NoDisponible then
    exit;

  Self.ivar := ivar;
  Self.ivae := ivae;
  Self.ires := ires;
  ivar := ivar + globs.NPostes;
end;

procedure TSolarPV.opt_cargue(s: TSimplex);   //carga el modelo en el simplex
var
  inodores: integer;
  iposte: integer;

begin
  if flg_NoDisponible then
    exit; // si no hay máquinas no juego

  inodores := nodo.ires; //restricciones de nodo
  // aporte a las restricciones del nodo
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(inodores + iposte, ivar + iposte, 1);
  end;
end;

procedure TSolarPV.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
begin
  if flg_NoDisponible then
    exit; // si no hay máquinas no juego

  // Le fijamos como cota superior PMax a la potencia en todos los postes

  for iposte := 0 to globs.NPostes - 1 do
    if PPA[iposte] > AsumaCero then
      s.cota_sup_set(ivar + iposte, min(PMax_Central, PPA[iposte]))
    else
      s.FijarVariable(ivar + iposte, 0);
end;

procedure TSolarPV.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
  e, eacum, disp: NReal;

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

  // recuperamos los valores de Potencia despachada
  eacum := 0;
  disp := 0;
  for iposte := 0 to globs.NPostes - 1 do
  begin
    e := s.xval(ivar + iposte);
    P[iposte] := e;
    Lambda_P[iPoste]:= s.xmult( ivar + iposte ) / globs.DurPos[iposte];
    cv_Spot[iPoste]:= Nodo.cmarg[iposte] - Lambda_P[iPoste];
    eacum := eacum + e * globs.DurPos[iposte];
    disp := disp + PPA[iposte] * globs.DurPos[iposte];
  end;

  Ingreso_PorDisponibilidad_ := disp * pa.PagoPorDisponibilidad_USD_MWh;
  Ingreso_PorEnergia_ := eacum * pa.PagoPorEnergia_USD_MWh;

end;

function TSolarPV.getNombreVar(ivar: integer; var nombre: string): boolean;
begin
  if NMaquinasDisponibles = 0 then
    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
    Result := False;
end;

procedure TSolarPV.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableNI('NMaquinasDisponibles', '-', NMaquinasDisponibles, True);
  PublicarVariableVR('PotenciaGenerable', '[MW]', 6, 2, PPA, True, True);
  PublicarVariableNR('IndiceClaridad', '-', 6, 2, indice_kt, True);
  PublicarVariableNR('Irradiancia_p_inclinado', 'kWh/m2', 6, 2,
    Irradiancia_plano_inclinado, True);
  PublicarVariableNR('Irradiancia_p_horizontal', 'kWh/m2', 6, 2,
    Irradiancia_plano_horizontal, True);
  PublicarVariableNR('CostoDirectoDelPaso', '[USD]', 12, 2,
    self.costoDirectoDelPaso, True);

  {$IFDEF DECLARAR_VARIABLES_SIMRES_DEF}
  declararVarsPSimResPorDefectoIntercalandoPostes(['P', 'Costo',
    'NMaqsDespachadas', 'PMax'], globs.NPostes);
  {$ENDIF}
end;

procedure TSolarPV.Free;
begin
  setlength(self.PPA, 0);
  {$IFNDEF CALC_DEMANDA_NETA}
  setlength(self.kBornePPA, 0);
  {$ENDIF}
  inherited Free;
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(TSolarPV.ClassName, TSolarPV);
  registrarClaseDeCosa(TFichaSolarPV.ClassName,
    TFichaSolarPV);
end;

procedure AlFinal;
begin
  //  CloseFile(fdbg);
end;

end.
