{+doc
+NOMBRE:
+CREACION:21.09.92
+AUTORES: rch, rz
+REGISTRO:
+TIPO: Unidad Pascal.
+PROPOSITO:  Definici¢n del objeto FuenteDeSol. Cuando Se Inicializa se
  indica la latitud y la longitud donde se ubicar  la fuente para
  tener en cuenta seg£n el mes del a¤o el micro-clima de las distintas
  zonas del pa¡s.
    La fuente de sol es un objeto ANIMADO que se activa todos los
  d¡as para generar el valor de la energ¡a acumulada que se le
  asignar  al d¡a y una vez por mes para cambiar el factor de posici¢n
  geogr fico que tiene en cuenta el micro-clima.

+PROYECTO: SOLAR.

+REVISION:
+AUTOR:
+DESCRIPCION:
-doc}

unit fdsol_ktcegh;

interface

uses
  xMatDefs,
  FDR01, FacPos, VGlbs02, NucleoT, FDSol,
  IT4, uDTSintetizador, fddp, uDisNormCan;

const
  LatitudDeLaEstanzuela = 34.25; {??? Conseguir los valores reales}
  LongitudDeLaEstanzuela = 57.75;

  HoraSalidaDelSol = 8;
  HoraPuestaDelSol = 18;
  HorasDeSol = HoraPuestaDelSol - HoraSalidaDelSol;

var
  modelo: string;
{ 'Liu-Jordan', 'Perez' y 'HDKR'}

type

  TFDSol_ktcegh = class(TFuenteDeSol)
    Xk: NReal;  //El estado gaussiano del sintetizador
    KTk: NReal; //El ultimo KT sintetizado

    xEnergiaDelDia: NReal;
    FDPG: NReal; { Factor de posicion geografica para el mes en
                  curso }

    sintetizador: TDTSintetizador;
    fuenteGaussiana: Tf_ddp_GaussianaNormal;
    w: NReal;

    constructor Create(xNombre: string; Latitud, Longitud: NReal;
      archSintetizador: string);
    function Valor: NReal; override;
    procedure Free; override;

    function EnergiaDeLaHoraEnCurso: NReal; override;
    function EnergiaDelDia: NReal; override;
    procedure CadaDia; override;{ latente }
    procedure CadaMes; override;{ latente }
    function Gaussianar(xNoGaussiana: NReal; kBorne: integer): NReal;
    //Genera un valor aleatorio con distribución gaussiana (rk). Avanza el estado
    //Xk según la ecuación Xk+1:= A * Xk + B * rk
    //Pasa el estado por la función deformante para obtener el nuevo KT
    procedure sintetizarNuevoKT;
  end;

procedure test;

implementation

const  {???}

  h0 = 727.0380584;    //cal/cm2
  hA = 346.7540654;    //cal/cm2
  DesplazamientoEnDias = 81.3907235;

  NumerDia_1del10 = 274; { N£mero del d¡a del a¤o ( a¤o de 365 d¡as)
    que corresponde al 1§ de Octubre }

function RadGlobAntesDeKT(k: integer): NReal;  //Retorna en cal/cm2
var
  alfa: NReal;
const
  w = 2 * 3.1416 / 365;
begin
  alfa := (k - NumerDia_1del10 - DesplazamientoEnDias) * w;
  Result := h0 + hA * cos(alfa);
end;

constructor TFDSol_ktcegh.Create(xNombre: string; Latitud, Longitud: NReal;
  archSintetizador: string);
begin
  inherited Create(xNombre);
  fuenteGaussiana := Tf_ddp_GaussianaNormal.Create(nil, 0);
  sintetizador := TDTSintetizador.Create(archSintetizador);
  Xk := gaussianar(sintetizador.EstadoInicial_Real[0], 0);
  CalcularFactores(
    Latitud,
    Longitud,
    LatitudDeLaEstanzuela,
    LongitudDeLaEstanzuela);

  Lat := Latitud;
  Long := Longitud;
  CadaMes; { Actualiza el micro-clima para el mes de comienzo }
  CadaDia; { Actualiza el valor de energ¡a para el d¡a actual }
end;

procedure TFDSol_ktcegh.CadaMes;
begin
  FDPG := FactorDePosicionGeografica(Ord(Mes) + 1);
end;

procedure TFDSol_ktcegh.CadaDia;
//  Pot6HorasP48Wp: NReal;
begin
  sintetizarNuevoKT;

  xEnergiaDelDia := KTk * RadGlobAntesDeKT(DiaDelAnio) * FDPG;
  //  Pot6HorasP48Wp:= It4.Cal_A_KWH( xEnergiaDelDia )*1000/24*6*100*100 * 0.34 *0.12;

  xEnergiaDelDia := it4.NuevoDia_HgCalcm2(DiaDelAnio,
    beta,
    modelo,
    xEnergiaDelDia  ); { [WH/m2], energía diaria en el plano inclinado }

  xEnergiaDelDia := xEnergiaDelDia * 3600;
end;

function TFDSol_ktcegh.EnergiaDelDia: NReal;
begin
  EnergiaDelDia := xEnergiaDelDia;
end;

function TFDSol_ktcegh.EnergiaDeLaHoraEnCurso: NReal;
begin
  EnergiaDeLaHoraEnCurso := EnergiaHoraPtr^[hora] * 3600;
end;

function TFDSol_ktcegh.Valor;
begin
  Valor := xEnergiaDelDia;
end;

procedure TFDSol_ktcegh.Free;
begin
  sintetizador.Free;
  inherited Free;
end;

function TFDSol_ktcegh.Gaussianar(xNoGaussiana: NReal; kBorne: integer): NReal;
var
  buscando: boolean;
  k: integer;
  fdef: TDAOfNReal;
  res: NReal;
begin
  fdef := sintetizador.funcionesDeformantes[0][0];
  buscando := True;
  k := 0;
  while buscando and (k < high(fdef)) do
  begin
    if fdef[k + 1] >= xNoGaussiana then
      buscando := False
    else
      Inc(k);
  end;
  if buscando then
    res := 1
  else
    res := k / high(fdef);

  Result := Inv_DistribucionNormalCanonica(res);
end;

procedure TFDSol_ktcegh.sintetizarNuevoKT;
var
  ruidoBlancoGaussiano, rn: NReal;
  indiceFuncDeformante: integer;
begin
  repeat
    ruidoBlancoGaussiano := fuenteGaussiana.rnd;
  until (ruidoBlancoGaussiano > -3.69) and (ruidoBlancoGaussiano < 3.69);
  Xk := Xk * sintetizador.A.e(1, 1) + sintetizador.B.e(1, 1) * ruidoBlancoGaussiano;
  rn := DistribucionNormalCanonica(Xk);
  indiceFuncDeformante := Round(rn * high(sintetizador.funcionesDeformantes[0][0]));
  KTk := sintetizador.funcionesDeformantes[0][0][indiceFuncDeformante];
end;

procedure test;
var
  i, dia: integer;
  f: TFDSol_ktcegh;
  energiaDelDia: NReal;
  fsal: TextFile;
begin
  AssignFile(fsal, 'test.txt');
  Rewrite(fsal);
  Writeln(fsal, 'Día', #9, 'KT', #9, 'energíaDelDía');

  f := TFDSol_ktcegh.Create('Sol', LatitudDeLaEstanzuela, LongitudDeLaEstanzuela,
    'ModeloKT.txt');
  for i := 1 to 2971 do
  begin
    dia := (i + NumerDia_1del10 - 1) mod 365;
    f.sintetizarNuevoKT;
    energiaDelDia := f.KTk * RadGlobAntesDeKT(dia);
    Writeln(fsal, i, #9, f.KTk, #9, energiaDelDia);
  end;

  CloseFile(fsal);
  f.Free;
end;

begin
  modelo := 'Liu-Jordan';{, 'Perez' y 'HDKR'}
end.
