{$DEFINE _OPT_kselectordeformador_}
{$DEFINE APLICAR_FACTOR_EN_OPT}

{$IFNDEF FORZAR_NO_RDIN}
  {$DEFINE RDIN}//
{$ENDIF}
(*+doc

Fuente CEGH - Correlaciones en Espacio Gaussiano con Histograma.
El modelo incluye un núcleo lineal, que sintetiza series temporales
gaussianas. El núcleo lineal capta las correlaciones temporales y espaciales
de las diferentes series.
Estas series gaussianas son luego llevadas a un espacio real mediante un conjunto
de trasformaciones no lineales de forma que el histograma de amplitudes de las
series es el deseado.
Las trasformaciones no lineales pueden variar con el tiempo lo que permite
ir variando el histograma esperado de los valores sintéticos con el tiempo.
El ejemplo de aplicación para el que fue desarrollado el modelo es para sintetizar
series de posibles aportes hidráulicos a las represas y en dicha aplicación
resulta natural hacer variar las transformaciones no lineales según la estación
del año para lograr histogramas diferentes en Primavera que en Verano.

-doc*)
unit uFuenteSintetizador;

interface

uses
  uFuentesAleatorias, MatReal, uCosa,
  uCosaConNombre,
  xMatDefs, fddp,
  uAuxiliares, uEstados,
  uGlobs, uconstantesSimSEE,usalasdejuego,
  Classes, umodelosintcegh, uDatosHistoricos,
  uFechas, Math, upronostico, ucosanubeseable,
  ufichasdeterminismos_obsoleta,
  uvatespronosticos, umatriz_ruida,
  ugeturlinfo, uintermediariocostofuturo,
  uconsultapronosticoscli, usimplex,
  ufichasLPD;

resourcestring
  rsSintetizadorCEGH = 'Sintetizador CEGH';

  exFaltaEspValorDeterministicoBornes =
    'Falta especificar el valor inicial de alguno de los Bornes en';

    exErrorDiferenteLargoReducirEstado =
    'ERROR, R=NIL AND length(X) <> length(y) en TFuenteSintetizadorCEGH.ReducirEstado';

    exNoSuficientesValoresDeterministicosInicializar =
      'No hay suficiente valores determinísticos como para inicial la memoria del filtro.';

    rsFichaDe = 'Ficha de';

  exFuenteCEGHFichaFuente_ = 'TFuenteSintetizadorCEGH.getFichaPD: la fuente';
  exFechaInvalida_ = 'no tiene válidas para la fecha';
  exFuenteCEGHPrepararMemoria_ = 'TFuenteSintetizadorCEGH.PrepararMemoria: la fuente';
  exNoTieneMultiplicadorVE_ =
    'no tiene especificados suficientes multiplicadores de valores esperados o';
  exVarianzaEnFicha_ = 'varianzas en su ficha nro';
  exFichaEspecificarTantosVEcomoBornes_ =
    'Cada ficha debe especificar tantos ' +
    'valores esperados y varianzas como bornes de salida tenga la fuente.';


  exErrorDiferenteLargoExpandirEstado =
    'ERROR, RT=NIL y length(X) <> length(' +
    'Y) en TFuenteSintetizadorCEGH.ExpandirEstado';

  exVarianzaDemasiadoGrande_ =
    'La varianza es demasiado grande. El máximo alcanzable es:';
  exValorMedioDemasiadoAlto = 'El valor medio es demasiado alto';
  exValorMedioBajo = 'El valor medio es muy bajo';
  exMaximoNumeroIteraciones = 'Salí por número máximo de iteraciones.';
  exNoSeLogroDeformarHistorgramaSerie_ =
    'CalcularNuevosDeformadores: No se logró ' +
    'deformar el histograma para lograr los valores indicados en la serie';
  exAcercarVarianzaPromedio =
    'Intente acercar los valores de promedio y ' +
    'varianza objetivo a los originales (multiplicadores a 1).';
  exFaltaValorDeterministicoBorne_ =
    'Falta especificar el valor deterministico de alguno de los bornes en';
  exCreandoLaFuente = 'Creando la fuente';
  exArchivoDatosDuracionDistinta =
    'Especificó un archivo de datos ' +
    'historicos con distinta duración de paso de sorteo que la del archivo del modelo.';
  exBornesArchivoDiferente =
    'Los bornes en el archivo del modelo difieren de ' +
    'los bornes en el archivo de datos historicos.';
  exCEGHInitDatosHistoricosFromFile =
    'TFuenteSintetizadorCEGH.InitDatosHistoricosFromFile:';

  exLeyendoLaFuente = 'Leyendo la fuente';


const
  exFuenteSintetizador_ = 'FuenteSintetizadorCEGH:';

  (*
      Xs = A1 X[k-1] + A2 X[k-2] + .. An X[k-n]  + B rbg

      Donde A = [ A1; A2;  .. An ]  y B  son las matrices del filtro.

      La dimensión del estado es A.nc                                         paso:   1    -2.297    -2.065    -2.031    -1.993    -1.952    -1.898    -1.895    -1.895    -1.745    -1.638    -1.584    -1.516    -1.512    -1.478    -1.410    -1.373    -1.291    -1.254    -1.243    -1.229    -1.220    -1.187    -1.175    -1.159    -1.148    -1.137    -1.108    -1.095    -1.090    -1.072    -1.059    -1.057    -1.040    -1.032    -1.004    -0.991    -0.958    -0.944    -0.911    -0.902    -0.885    -0.873    -0.853    -0.843    -0.827    -0.820    -0.794    -0.780    -0.770    -0.753    -0.739    -0.722    -0.694    -0.681    -0.660    -0.653    -0.647    -0.632    -0.630    -0.627    -0.620    -0.594    -0.564    -0.544    -0.503    -0.478    -0.445    -0.441    -0.427    -0.419    -0.419    -0.384    -0.342    -0.338    -0.335    -0.328    -0.304    -0.294    -0.286    -0.276    -0.261    -0.248    -0.244    -0.240    -0.215    -0.197    -0.180    -0.170    -0.163    -0.148    -0.146    -0.134    -0.110    -0.093    -0.079    -0.063    -0.055    -0.050    -0.022    -0.014    -0.001     0.027     0.042     0.050     0.062     0.079     0.106     0.128     0.134     0.141     0.160     0.164     0.169     0.181     0.192     0.197     0.209     0.215     0.226     0.234     0.258     0.264     0.288     0.310     0.316     0.319     0.322     0.354     0.358     0.369     0.383     0.408     0.420     0.434     0.447     0.462     0.469     0.478     0.485     0.505     0.532     0.559     0.574     0.594     0.616     0.629     0.638     0.641     0.650     0.663     0.688     0.705     0.715     0.731     0.784     0.794     0.804     0.814     0.824     0.840     0.850     0.870     0.885     0.894     0.905     0.919     0.947     0.950     0.980     0.992     1.005     1.020     1.046     1.062     1.104     1.133     1.195     1.222     1.300     1.320     1.401     1.427     1.440     1.465     1.484     1.494     1.500     1.510     1.537     1.557     1.636     1.645     1.668     1.781     1.893     1.906     1.953     2.184     2.470     3.330
paso:   2    -2.575    -2.064    -2.031    -2.004    -1.965    -1.923    -1.895    -1.895    -1.763    -1.743    -1.642    -1.588    -1.519    -1.512    -1.467    -1.411    -1.365    -1.262    -1.237    -1.220    -1.179    -1.158    -1.133    -1.110    -1.092    -1.077    -1.066    -1.057    -1.035    -1.024    -1.003    -0.991    -0.967    -0.947    -0.922    -0.913    -0.897    -0.888    -0.880    -0.860    -0.844    -0.828    -0.818    -0.780    -0.755    -0.739    -0.699    -0.692    -0.679    -0.658    -0.650    -0.631    -0.629    -0.627    -0.620    -0.604    -0.586    -0.557    -0.544    -0.526    -0.495    -0.478    -0.462    -0.446    -0.444    -0.442    -0.425    -0.420    -0.398    -0.361    -0.339    -0.333    -0.327    -0.320    -0.311    -0.307    -0.299    -0.289    -0.286    -0.281    -0.265    -0.263    -0.258    -0.220    -0.197    -0.182    -0.164    -0.158    -0.148    -0.139    -0.130    -0.108    -0.093    -0.085    -0.062    -0.048    -0.026    -0.016    -0.014     0.007     0.037     0.058     0.068     0.073     0.087     0.098     0.113     0.130     0.138     0.156     0.164     0.186     0.197     0.205     0.212     0.226     0.231     0.243     0.258     0.285     0.310     0.319     0.322     0.350     0.360     0.370     0.377     0.385     0.420     0.429     0.447     0.462     0.470     0.478     0.495     0.509     0.530     0.537     0.548     0.559     0.590     0.605     0.612     0.628     0.638     0.648     0.661     0.684     0.696     0.724     0.745     0.792     0.799     0.810     0.815     0.840     0.851     0.857     0.878     0.890     0.899     0.907     0.914     0.927     0.948     0.952     0.981     0.996     1.005     1.028     1.053     1.077     1.129     1.134     1.164     1.183     1.230     1.298     1.309     1.327     1.406     1.424     1.472     1.485     1.495     1.501     1.516     1.550     1.629     1.645     1.691     1.812     1.899     1.910     1.920     1.960     2.066     2.276     2.370     3.330
paso:   3    -2.652    -2.107    -2.004    -1.993    -1.896    -1.867    -1.756    -1.732    -1.712    -1.628    -1.579    -1.521    -1.512    -1.453    -1.415    -1.377    -1.351    -1.274    -1.241    -1.186    -1.155    -1.136    -1.107    -1.081    -1.066    -1.051    -1.034    -1.013    -1.006    -0.992    -0.981    -0.969    -0.956    -0.926    -0.917    -0.894    -0.885    -0.872    -0.856    -0.846    -0.829    -0.809    -0.754    -0.745    -0.704    -0.690    -0.678    -0.653    -0.644    -0.627    -0.617    -0.603    -0.585    -0.562    -0.534    -0.527    -0.494    -0.469    -0.450    -0.444    -0.444    -0.439    -0.422    -0.396    -0.390    -0.368    -0.339    -0.327    -0.323    -0.318    -0.311    -0.307    -0.288    -0.285    -0.265    -0.263    -0.257    -0.248    -0.215    -0.198    -0.192    -0.169    -0.157    -0.148    -0.143    -0.130    -0.111    -0.106    -0.096    -0.085    -0.085    -0.052    -0.043    -0.034    -0.020    -0.014    -0.012     0.005     0.019     0.050     0.066     0.071     0.075     0.087     0.089     0.098     0.129     0.135     0.151     0.156     0.178     0.192     0.197     0.205     0.211     0.225     0.226     0.230     0.244     0.259     0.282     0.301     0.316     0.321     0.347     0.354     0.369     0.377     0.411     0.421     0.434     0.446     0.469     0.476     0.487     0.509     0.524     0.537     0.548     0.562     0.581     0.591     0.603     0.610     0.640     0.683     0.693     0.725     0.742     0.768     0.794     0.805     0.811     0.815     0.845     0.856     0.885     0.892     0.905     0.912     0.931     0.948     0.977     0.986     0.996     1.019     1.043     1.064     1.082     1.115     1.132     1.136     1.166     1.187     1.240     1.299     1.315     1.367     1.406     1.419     1.456     1.483     1.491     1.497     1.511     1.539     1.610     1.645     1.794     1.854     1.893     1.904     1.915     1.941     2.042     2.154     2.238     2.407     2.613     3.330
paso:   4    -2.614    -2.096    -2.004    -1.952    -1.868    -1.811    -1.752    -1.716    -1.699    -1.572    -1.520    -1.490    -1.463    -1.409    -1.374    -1.356    -1.306    -1.280    -1.241    -1.191    -1.147    -1.118    -1.091    -1.080    -1.049    -1.031    -1.015    -1.013    -0.985    -0.977    -0.955    -0.925    -0.920    -0.899    -0.893    -0.881    -0.863    -0.852    -0.833    -0.785    -0.754    -0.745    -0.745    -0.718    -0.678    -0.673    -0.655    -0.633    -0.615    -0.597    -0.575    -0.554    -0.529    -0.522    -0.503    -0.449    -0.444    -0.444    -0.443    -0.422    -0.393    -0.389    -0.382    -0.352    -0.329    -0.324    -0.319    -0.311    -0.307    -0.289    -0.279    -0.264    -0.257    -0.254    -0.250    -0.215    -0.199    -0.194    -0.189    -0.163    -0.154    -0.150    -0.129    -0.111    -0.106    -0.098    -0.085    -0.084    -0.074    -0.060    -0.050    -0.037    -0.034    -0.026    -0.012    -0.008     0.005     0.016     0.028     0.041     0.051     0.068     0.072     0.076     0.087     0.088     0.095     0.116     0.155     0.156     0.189     0.197     0.208     0.226     0.233     0.246     0.261     0.273     0.301     0.306     0.323     0.333     0.347     0.365     0.377     0.394     0.413     0.433     0.455     0.471     0.481     0.490     0.511     0.523     0.537     0.538     0.547     0.567     0.576     0.591     0.606     0.611     0.622     0.630     0.658     0.671     0.684     0.691     0.710     0.717     0.725     0.735     0.766     0.782     0.803     0.839     0.853     0.867     0.891     0.911     0.930     0.936     0.952     0.966     0.974     1.012     1.022     1.059     1.075     1.119     1.124     1.136     1.148     1.168     1.194     1.206     1.272     1.305     1.324     1.348     1.364     1.384     1.421     1.462     1.485     1.491     1.511     1.545     1.612     1.778     1.844     1.902     1.941     2.109     2.155     2.216     2.334     2.497     2.657     3.255


      El estado completo lo podemos poner como la concatenación de los vectores
      X[k-1] ... X[k-n]

      Los bornes de salida tienen la dimensión de Xs que es A.nf
      Los bornes en el mundo real tienen por consiguiente la misma dimensión A.nf

      La entrada RB:
      En la bornera ponemos el vector primero r[0], (los ruidos blancos)

      El estado; dim_X = A.nc + A.nc (pongo todos los estados en el mundo real por comodidad)
      luego el vector X[k-1] ... X[k-n].
      Luego de eso ponemos las salidas en el mundo real Y[k-1]

      Luego de eso repetimos el estado para X_s

  *)

//La bornera del sintetizador es:
//0                      .. dimRB-1                    -> ruidos blancos de entrada
//jPrimer_X              .. jPrimer_X + (dim_X/2)-1    -> estado gaussiano de este paso
//jPrimer_X + (dim_X/2)  .. jPrimer_X + dim_X -1       -> estado real de este paso
//jPrimer_Xs             .. jPrimer_Xs + (dim_Xs/2)-1  -> estado gaussiano del próximo paso
//jPrimer_Xs + (dim_Xs/2).. jPrimer_Xs + dim_Xs -1     -> estado real del próximo paso
//jPrimer_BC             .. jPrimer_BC + dim_BC-1      -> bornes calculados

//Primero vienen los ruidos blancos hasta dim_RB, luego hasta la mitad de dim_X
//vienen el estado de la fuente en el espacio gaussiano, en la segunda mitad de
//dim_X viene el estado en el espacio normal (los valores que tomaran los bornes),
//luego viene el estado gaussiano y normal del paso siguiente y al final del todo
// los bornes calculados.
type
  TTipoValorEsperadoCEGH = (TTVE_real, TTVE_Gaussiano);
  TDAOfTTipoValorEsperadoCEGH = array of TTipoValorEsperadoCEGH;


  { TFuenteSintetizadorCEGH_auxRec }
  TFuenteSintetizadorCEGH_auxRec = class
    corridaDeterminista: boolean;
    _EstadoInicial_Real: TDAofNReal;
    i: integer;
    _valoresBorne: TDAofNReal;
    k, j: integer;

    //  cantSesgos: integer;

    // auxiliares para pasar de versión 45,46 a >47
    x_cantsesgo_ruido: integer;
    _x_sesgo_ruido: TDAOfDAOfNReal;
    _x_factor_ruido: TDAOfNReal;
    _x_fechaIniSesgo: TFecha;

    x_rangoFechaSesgo: NReal;
    x_NPCC, x_NPLC, x_NPSA, x_NPAC: integer;
    _x_aPronostico: TPronostico;
    _lDeterminismos: TListaDeCosas;
    _xlpd: TListaDeCosas;
    _aDeterminismo: TFichaDeterminismo;

    x_arranqueConico, x_determinismoSoloEstadoInicial: boolean;
    x_aPronostico_rangoFechaSesgo: NReal;

    // variables obsoletas de la época de los f
    valorRbVeSeleccionado: boolean;
    valorProbExcedencia: NReal;
    valorCalibControlCono: integer;
    valorCalibIncDesviacion: integer;
    valorCalibMultNormaUno: integer;
    valorCalibCantIteraciones: integer;
    kBornePublicado: integer;
    _pronosticos: TPronosticos;

    constructor Create;
    destructor destroy; override;

  end;

  { TFuenteSintetizadorCEGH }

  TFuenteSintetizadorCEGH = class(TFuenteAleatoria)

  private
    ixr: integer;       //Indice de la variable de estado en el conjunto global

    ivar, ires, ivae: integer;

    fuenteGaussiana: Tf_ddp_GaussianaNormal;

    //Si simularConDatosHistoricos estos valores apuntan a los indices y pesos
    // necesarios para calcular el proximo valor a apartir de las series histócas
    //    indiceDatosHistoricos: integer;
    //    indiceDatosHistoricos_s: integer;
    indicesDatosHistoricos, indicesDatosHistoricos_s: TDAOfNInt;
    pesosDatosHistoricos, pesosDatosHistoricos_s: TDAOfNReal;
    DespAnios_IniSim_IniDatosHistoricos: integer;

    //para no crearlos en cada paso
    calcularSalidaBorne: TDAOfBoolean;
    todosLosBornesEnTrue: TDAOfBoolean;


(*
    //Busca en los datos historicos el primer valor cuyo período de validez
    //contenga a fecha sin considerar el anio.
    //fechaIniSorteo <= fecha < fechaFinSorteo comparando solo mes y dia
    //offsetDatos es el desplazamiento en anios desde la fecha de inicio de los
    //valores historicos. El indice se calculara desde
    //datosHistoricos.fechaIni + offsetDatos anios
    // retorna en indiceDatos, el valor del índice que apunta al dato
    //???? no se si se usa
    function getIndiceDato__(fecha: TFecha; nAnios_offsetDatos: integer): integer;
  *)

    procedure InitDatosHistoricosFromFile;
    procedure InitFuenteEntrada;
    function referenciaFuente(fuente: TFuenteAleatoria): boolean; override;

    procedure Sim_Cronica_Inicio_SINTETICAS;
    procedure Sim_Cronica_Inicio_HISTORICAS;

  protected
    procedure GaussianarRafaga(var destino: TDAOfNReal; kBaseDestino: integer;
      const origen: TDAOfNReal; kBaseOrigen: integer;
      NBornesDestino, NRetardosXDestino: integer; NBornesOrigen: integer;
      datosModelo: TModeloCEGH; fecha: TFecha);

    procedure SortearEntradaRB(var aRB: NReal); override;
    procedure ValorEsperadoEntradaRB(var aRB: Nreal); override;
    procedure calcular_jsInicioFinal; override;

  public
    (**************************************************************************)
    (* A T R I B U T O S   P E R S I S T E N T E S                            *)
    (**************************************************************************)
    nombreArchivoModelo: TArchiRef_Nubeseable;
    dummy_nombreArchivoModelo: TArchiRef_;
    simularConDatosHistoricos: boolean;
    sincronizarConHistoricos: boolean;
    SincronizarConSemillaAleatoria: boolean;
    nombreArchivoDatosHistoricos: TArchiRef_Nubeseable;
    dummy_nombreArchivoDatosHistoricos: TArchiRef_;
    usarModeloAuxiliar: boolean;
    nombreArchivoModeloAuxiliar: TArchiRef_Nubeseable;
    dummy_nombreArchivoModeloAuxiliar: TArchiRef_;

    //Información para introducción de pronósticos mediante sesgos.
    escenariosDePronosticos: TEscenarioDePronosticos;


    //Dirección web para extracción de pronósticos.
    url_get: string;



    fuentesEntrada: TListaDeCosas;
    flg_MODELO_ENTRADA_SALIDA: boolean;

    flg_modo_cono : integer;  //  GFlieller@20190711  Flag que determina si el cono se
                              //               se carga desde un archivo de
                              //               calibracion.

    (**************************************************************************)


    escenarioSorteados: TPronosticos;
    sorteadorDePronosticos_: TMadreUniforme;

    datosModelo_Sim: TModeloCEGH;
    datosHistoricos: TDatosHistoricos;

    // esto es si queremos que al Optimizar utilice otro modelo
    // diferente al de Simular y además cuando simula
    // usa el modelo auxiliar para establecer el estado global
    // del sistema.
    modeloAuxiliar: TModeloCEGH;
    modeloAuxiliarActivo: boolean;

    // apunta al modelo a usar en la optimización.
    // puede ser datosModelo o modeloAuxiliar según el caso.
    datosModelo_Opt: TModeloCEGH;

    // variables auxiliares
    XRed, XsRed: TDAOfNReal; // estados reducidos de X y Xs
    XRed_aux: TDAOfNReal;

    // Estimación lineal de la diferencia en el costo futuro que ocasiona la evolución
    // del estado de EstadoK_Actual a EstadoK_Aux
    DeltaCosto: NReal;

    //    jPrimer_RBamp, jUltimo_RBamp: integer;
    jPrimer_X_x, jUltimo_X_x: integer;
    // primer X en el vector  de estado Xs (dim A.nc)
    jPrimer_X_y, jUltimo_X_y: integer; // primer y (mundo real ) ( dim A.nf )

    jPrimer_Xs_x, jUltimo_Xs_x: integer;
    // primer X en el vector  de estado Xs (dim A.nc)
    jPrimer_Xs_y, jUltimo_Xs_y: integer; // primer y (mundo real ) ( dim A.nf )


    //******* VARIABLES AUXILIARES PARA OPTIMIZAR TIEMPOS DE CALCULO *****

    // M_amp * M_red
    MaMr_cte: TMatR;
    MaMr_mc: TDAOfMatR;

    {$IFDEF RESUMEN_POSTIZADO}
    fdebug: textfile;
    {$ENDIF}

    constructor Create(capa: integer; nombre, nombreArchivoModelo,
      nombreArchivoDatosHistoricos: string; simularConDatosHistoricos: boolean;
  SincronizarConHistoricos, sincronizarConSemillaAleatoria: boolean;
  nombreArchivoModeloAuxiliar: string; usarModeloAuxiliar: boolean;
  EscenariosDePronosticos: TEscenarioDePronosticos;
  resumirPromediando: boolean; url_get: string; flg_MODELO_ENTRADA_SALIDA: boolean = false;
      listaFuentesEntrada: TListaDeCosas = nil; flg_modo_cono_ : integer = 0);

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

    class function DescClase: string; override;

    //Luego de asignado el nombre de archivo se carga desde el
    procedure InitModeloFromFile;

    procedure PrepararMemoria_pre( Catalogo: TCatalogoReferencias; globs: TGlobs); override;

    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;
    procedure InicioSim; override;
    procedure InicioOpt; override;
    procedure SorteosDelPaso(xsortear: boolean); override;
    function cronicaIdInicio: string; override;
    procedure Sim_Cronica_Inicio; override;
    procedure fijarEstadoInterno; override;

    // Calcula el estado siguiente. Solo calcula Xs, no lo aplica.
    procedure calcular_Xs; override;
    procedure PosicionarseEnEstrellita; override;
    procedure EvolucionarEstado; override;

    procedure ActualizarEstadoGlobal(flg_Xs: boolean); override;

    procedure Optx_nvxs(var ixr, ixd, iauxNReal, iauxInt: integer); override;
    procedure Optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados); override;


    {$IFDEF INTERMEDIARIO_DE_COSTO_FUTURO}
    procedure opt_nvers(var ivar, ivae, ires: integer); override;
    procedure opt_cargue(s: TSimplex); override;

    procedure registrarVarYResEnIntermediario(intermediario: TIntermediarioCostoFuturo);
      override;
    procedure opt_fijarRestriccionesDeCaja(s: TSimplex); override;

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

    {$ENDIF}

    // carga el deltacosto para el término indep del simplex
    function calc_DeltaCosto: NReal; override;

    // las fuentes con estado tienen que calcular el delta costo
    // por el delta_X resultante del sorteo
    procedure PrepararPaso_ps; override;

    function dim_RB: integer; override;
    function dim_X: integer; override;
    function dim_Wa: integer; override;


    //Retorna el indice del array donde ira el valor de ese borne
    function IdBorne(nombre: string): integer; override;

    // Retorna el nombre del Borne a partir del índice
    function NombreBorne(idBorne: integer): string; override;

    // Calcula el estado reducido a partir del estado X.
    // y= R* X.  Si R=NIL y length(x)=length(y) hace y= x;
    // X forma parte de la bornera a partir de jIniX
    procedure ReducirEstado(var y: TDAofNReal; jIniX: integer;
      const datosModelo: TModeloCEGH; const R: TMatR; const Bornera: TDAOfNReal);

    // Calcula el estado sin reducir X a partir del estado reducido y
    // mediante la estimación X= RT* y
    // Si RT= NIL y length(y)=length(x) hace X= y
    //El X esta en la bornera a partir de jIniX
    procedure ExpandirEstado(datosModelo: TModeloCEGH; jIniX: integer;
      var bornera: TDAofNReal; const y: TDAOfNReal);

    //Aplica las funciones deformantes a los valores del estado X en los bornes
    //indicados en calcularBorne
    procedure calcularSalidasDeX(Xs: boolean); overload;
    procedure calcularSalidasDeX(datosModelo: TModeloCEGH; Xs: boolean;
      calcularBorne: TDAOfBoolean); overload;


    destructor destroy; override;

    procedure PubliVars; override;

    // retorna indice selector de la función desformante
    // que corresponde al paso de tiempo si fecha es nil y al de la fecha
    //sino.
    function kSelectorDesformador(datosModelo: TModeloCEGH; fecha: TFecha): integer;

    function Gaussianar_(datosModelo: TModeloCEGH; xNoGaussiana: NReal;
      kBorne: integer; fecha: TFecha): NReal;

    //Solo para debug
    function descBornera: string; override;
    procedure Dump_Variables(var f: TextFile; charIndentacion: char); override;


    procedure sim_FinCronicaPrintEstadoFinal(var fsal: textfile); override;

    // recalibra los sesgos y atenuadores de acuerdo con los parámetros de los
    // pronósticos.
    procedure ReCalibrarPronosticos(datosModelo: TModeloCEGH; fechaIniSim: TFecha);

    // intenta obtener de la dirección url_get los pronósticos
    // de acuerdo a la descripción de los mismos.
    function GetPronosticos(fechaIniSim: TFecha): boolean;

    function getArchiRefLst: TListaDeArchiRef_Nubeseable; override;


  private
    px_: TFuenteSintetizadorCEGH_auxRec;
  end;


procedure cambioFichaPDFuenteSintetizadorCEGH(fuente: TCosa);
procedure AlInicio;
procedure AlFinal;



implementation

uses
  ucalibrarconopronosticos,
  SysUtils;

{$IFDEF LOG_APLICAR_FACTOR_EN_OPT}
var
  flog_aplicar_factor_en_opt: textfile;
{$ENDIF}

{$IFDEF LOG_RUIDA_PRONOS}
 var
  flog_ruida_pronos: textfile;
{$ENDIF}

{ TFuenteSintetizadorCEGH_auxRec }

constructor TFuenteSintetizadorCEGH_auxRec.Create;
begin
  setlength(_EstadoInicial_Real, 0);
  setlength(_valoresBorne, 0);
  setlength(_x_sesgo_ruido, 0);
  setlength(_x_factor_ruido, 0);
  _x_fechaInisesgo := nil;
  _x_aPronostico := nil;
  _lDeterminismos := nil;
  _xlpd := nil;
  _aDeterminismo := nil;
  _pronosticos := nil;
end;

destructor TFuenteSintetizadorCEGH_auxRec.destroy;
begin
  setlength(_EstadoInicial_Real, 0);
  setlength(_valoresBorne, 0);
  setlength(_x_sesgo_ruido, 0);
  setlength(_x_factor_ruido, 0);
  if _x_fechaInisesgo <> nil then _x_fechaInisesgo.Free;
  if _x_aPronostico <> nil then _x_aPronostico.Free;
  if _lDeterminismos <> nil then _lDeterminismos.Free;
  if _xlpd <> nil then _xlpd.Free;
  if _aDeterminismo <> nil then _aDeterminismo.Free;
  if _pronosticos <> nil then _pronosticos.Free;
  inherited destroy;
end;

{$IFDEF DEBUG_SORTEOS}
var
  fdebug_sorteos: TextFile;

{$ENDIF}



constructor TFuenteSintetizadorCEGH.Create(capa: integer; nombre,
  nombreArchivoModelo, nombreArchivoDatosHistoricos: string;
  simularConDatosHistoricos: boolean; SincronizarConHistoricos,
  sincronizarConSemillaAleatoria: boolean; nombreArchivoModeloAuxiliar: string;
  usarModeloAuxiliar: boolean;
  EscenariosDePronosticos: TEscenarioDePronosticos;
  resumirPromediando: boolean; url_get: string;
  flg_MODELO_ENTRADA_SALIDA: boolean; listaFuentesEntrada: TListaDeCosas;
  flg_modo_cono_ : integer = 0);
var
  i: integer;
begin
  inherited Create(capa, nombre, 0, resumirPromediando);
  sorteadorDePronosticos_ := nil;
  self.nombreArchivoModelo := TArchiRef_Nubeseable.Create(capa, 0,
    0, False, TArchiRef_.Create(nombreArchivoModelo));
  self.simularConDatosHistoricos := simularConDatosHistoricos;
  self.SincronizarConHistoricos := SincronizarConHistoricos;
  self.sincronizarConSemillaAleatoria := sincronizarConSemillaAleatoria;
  self.nombreArchivoDatosHistoricos :=
    TArchiRef_Nubeseable.Create(capa, 0, 0, False, TArchiRef_.Create(
    nombreArchivoDatosHistoricos));
  self.nombreARchivoModeloAuxiliar :=
    TArchiRef_Nubeseable.Create(capa, 0, 0, False,
    TArchiRef_.Create(nombreArchivoModeloAuxiliar));
  self.usarModeloAuxiliar := usarModeloAuxiliar;
  self.escenariosDePronosticos := escenariosDePronosticos;
  self.url_get := url_get;
  self.flg_modo_cono := flg_modo_cono_;
  fuenteGaussiana := nil;

  self.datosModelo_Sim := nil;
  InitModeloFromFile;

  self.fuentesEntrada := listafuentesEntrada;
  self.flg_MODELO_ENTRADA_SALIDA := flg_MODELO_ENTRADA_SALIDA;


  if simularConDatosHistoricos then
    InitDatosHistoricosFromFile;

  modeloAuxiliar := nil;
  modeloAuxiliarActivo := False;
  self.usarModeloAuxiliar := False;

end;

function TFuenteSintetizadorCEGH.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;

  Result.addCampoDef_archRef('nombreArchivo', dummy_nombreArchivoModelo, 0, 10);
  Result.addCampoDef('EstadoInicial_Real', px_._EstadoInicial_Real, 0, 10);
  Result.addCampoDef('corridaDeterminista', px_.corridaDeterminista, 0, 10);
  Result.addCampoDef_archRef('nombreArchivo', dummy_nombreArchivoModelo, 10, 11);
  Result.addCampoDef('lDeterminismos', TCosa(px_._lDeterminismos), 10, 11);
  Result.addCampoDef_archRef('nombreArchivo', dummy_nombreArchivoModelo, 11,181);
  Result.addCampoDef('nb_nombreArchivo', Tcosa(nombreArchivoModelo), 179,182);
  Result.addCampoDef_ref( 'nb_nombreArchivo_ref', TCosa(nombreArchivoModelo),self, 182 );
 // Result.addCampoDef('lpd', TCosa(px.xlpd), 11, 56);
  Result.addCampoDef('lDeterminismos', TCosa(px_._lDeterminismos), 11, 56);
  Result.addCampoDef('sincronizarConHistoricos', sincronizarConHistoricos, 60);
  Result.addCampoDef('sincronizarConSemillaAleatoria',
    sincronizarConSemillaAleatoria, 96);
  Result.addCampoDef('simularConDatosHistoricos', simularConDatosHistoricos, 11);
  Result.addCampoDef_archRef('nombreArchivoDatosHistoricos',
    dummy_nombreArchivoDatosHistoricos, 11,181);
  Result.addCampoDef('nb_nombreArchivoDatosHistoricos',
    Tcosa(nombreArchivoDatosHistoricos), 179,182);
  Result.addCampoDef_ref( 'nb_nombreArchivoDatosHistoricos_ref',
    TCosa(nombreArchivoDatosHistoricos),self, 182 );
  Result.addCampoDef('usarModeloAuxiliar', usarModeloAuxiliar, 32);
  Result.addCampoDef_archRef('nombreArchivoModeloAuxiliar',
    dummy_nombreArchivoModeloAuxiliar, 32,181);
  Result.addCampoDef('nb_nombreArchivoModeloAuxiliar',
    Tcosa(nombreArchivoModeloAuxiliar), 179,182);
  Result.addCampoDef_ref( 'nb_nombreArchivoModeloAuxiliar_ref',
    TCosa(nombreArchivoModeloAuxiliar),self, 182 );
  Result.addCampoDef('arranqueConico', px_.x_arranqueConico, 37, 56);
  Result.addCampoDef('determinismoSoloEstadoInicial',
    px_.x_determinismoSoloEstadoInicial, 44, 56);

  // Lee un campo cantidad NombreCantidad y luego la misma cantidad de vectores de reales
  // todos con el mismo NombreItem
  // Esta función es por compatibilidad con una versión antigua de escritura
  Result.addCampoDef_Array_OLD1_(
    'cantsesgo_ruido', // NombreCantidad
    'sesgo_ruido', // NombreItem
    px_._x_sesgo_ruido, //  TDAOfDAOfNReal Vector de Vectores items.
    45, 55);

  Result.addCampoDef('factor_ruido', px_._x_factor_ruido, 45, 55);
  Result.addCampoDef('fechaInisesgo', px_._x_fechaInisesgo, 45, 55);
  Result.addCampoDef('rangoFechaSesgo', px_.x_rangoFechaSesgo, 45, 55);
  Result.addCampoDef('valorRbVeSeleccionado', px_.valorRbVeSeleccionado, 47, 55);
  Result.addCampoDef('valorProbExcedencia', px_.valorProbExcedencia, 47, 55);
  Result.addCampoDef('valorCalibControlCono', px_.valorCalibControlCono, 47, 55);
  Result.addCampoDef('valorCalibIncDesviacion', px_.valorCalibIncDesviacion, 47, 55);
  Result.addCampoDef('valorCalibMultNormaUno', px_.valorCalibMultNormaUno, 47, 55);
  Result.addCampoDef('valorCalibCantIteraciones',
    px_.valorCalibCantIteraciones, 47, 55);
  Result.addCampoDef('valorSesgoControlCono', px_.x_NPCC, 47, 55);
  Result.addCampoDef('valorSesgoIncDesviacion', px_.x_NPAC, 47, 55);
  Result.addCampoDef('valorSesgoMultNormaUno', px_.x_NPLC, 47, 55);
  Result.addCampoDef('pronosticos', TCosa(px_._pronosticos), 55, 143);
  Result.addCampoDef('url_get', url_get, 127);
  Result.addCampoDef('escenariosDePronosticos', TCosa(escenariosDePronosticos), 143);


//VC CAMBIAR ESTO
  Result.addCampoDef('fuentesEntrada', TCosa(fuentesEntrada), 188);//, self, 186);
  Result.addCampoDef('flg_MODELO_ENTRADA_SALIDA', flg_MODELO_ENTRADA_SALIDA, 188);

// GFlieller@20190711
  Result.addCampoDef('flg_modo_cono', flg_modo_cono, 194, 0);


end;

procedure TFuenteSintetizadorCEGH.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  px_ := TFuenteSintetizadorCEGH_auxRec.Create;
  datosModelo_Sim := nil;
  modeloAuxiliar := nil;
  dummy_nombreArchivoModeloAuxiliar := nil;
  nombreArchivoModeloAuxiliar := nil;
  modeloAuxiliarActivo := False;
  usarModeloAuxiliar := False;
  px_._lDeterminismos := nil;
  px_._xlpd := nil;
  escenariosDePronosticos := nil;
  px_._x_fechaInisesgo := nil;
  SincronizarConHistoricos := False;
  SincronizarConSemillaAleatoria := False;
  sorteadorDePronosticos_ := nil;
end;

procedure TFuenteSintetizadorCEGH.AfterRead(f: TArchiTexto);
var
  i: integer;
  k, j: integer;
begin
  inherited AfterRead(f);

  if f.Version < 10 then
  begin
    px_._lDeterminismos := TListaDeCosas.Create(capa, 'lDeterminismos');
    for i := 0 to high(px_._EstadoInicial_Real) do
    begin
      px_._valoresBorne := copy(px_._EstadoInicial_Real, i, 1);
      px_._lDeterminismos.Add(TFichaDeterminismo.Create(capa, px_._valoresBorne));
    end;
    fuenteGaussiana := nil;
    InitModeloFromFile;
    simularConDatosHistoricos := False;
    nombreArchivoDatosHistoricos := nil;
    datosHistoricos := nil;
  end
  else if f.Version < 11 then
  begin
    fuenteGaussiana := nil;
    InitModeloFromFile;
    simularConDatosHistoricos := False;
    nombreArchivoDatosHistoricos := nil;
    datosHistoricos := nil;
  end
  else
  begin
    fuenteGaussiana := nil;
    modeloAuxiliar := nil;
    px_._x_sesgo_ruido := nil;
    // lo asigno a nil para chequear si es asignado más adelante

    if f.Version < 47 then
    begin
      // información de deformadores
      px_.valorRbVeSeleccionado := True;
      px_.valorProbExcedencia := 95;
      px_.valorCalibControlCono := 10;
      px_.valorCalibIncDesviacion := 10;
      px_.valorCalibMultNormaUno := 7;
      px_.valorCalibCantIteraciones := 20;
      px_.x_NPCC := 10;
      px_.x_NPLC := 7;
      px_.x_NPAC := 17;
    end ;

    if f.Version <= 54 then
    begin
      if (px_.x_determinismoSoloEstadoInicial) then
        px_.x_NPSA := 0
      else
        px_.x_NPSA := px_.x_NPCC;
      if px_._x_sesgo_ruido <> nil then
      begin
        px_._pronosticos := TPronosticos.Create(capa, '');
        for k := 0 to high(px_._x_sesgo_ruido) do
        begin

          // ojo la cantidad de retardos no la conozco todavía.
          // le pongo CERO y se ajusta más adelante
          px_._x_aPronostico :=
            TPronostico.Create(capa, px_.x_NPCC, px_.x_NPLC, px_.x_NPSA,
            px_.x_NPAC, '', '');
          for j := 0 to high(px_._x_aPronostico.sesgo) do
          begin
            if j < length(px_._x_sesgo_ruido[k]) then
              px_._x_aPronostico.sesgo[j] := px_._x_sesgo_ruido[k][j]
            else
              px_._x_aPronostico.sesgo[j] := 0.0;

            if (j < length(px_._x_aPronostico.factor)) then
              if j < length(px_._x_factor_ruido) then
                px_._x_aPronostico.factor[j] := px_._x_factor_ruido[j]
              else
                px_._x_aPronostico.factor[j] := 1.0;

          end;
          px_._x_aPronostico.escenario.fechaIniCono.dt := px_._x_fechaInisesgo.dt;
          px_.x_aPronostico_rangoFechaSesgo := px_.x_rangoFechaSesgo;
          px_._Pronosticos.Add(px_._x_aPronostico);
          setlength(px_._x_sesgo_ruido[k], 0);
        end;
        setlength(px_._x_sesgo_ruido, 0);
        setlength(px_._x_factor_ruido, 0);
        px_._x_fechaInisesgo.Free;
      end;
    end;

    if f.version < 179 then
    begin
      nombreArchivoDatosHistoricos :=
        f.Create_add_ArchiRefNubeseable_( self.capa, dummy_nombreArchivoDatosHistoricos) as TArchiRef_Nubeseable;
      nombreArchivoModelo :=
        f.Create_add_ArchiRefNubeseable_( self.capa, dummy_nombreArchivoModelo) as TArchiRef_Nubeseable;
      nombreArchivoModeloAuxiliar :=
        f.Create_add_ArchiRefNubeseable_( self.capa, dummy_nombreArchivoModeloAuxiliar) as TArchiRef_Nubeseable;
   end ;


    if f.version < 182 then
  //registrar el archivo en las referencias
    begin
      if (nombreArchivoModelo <> nil) then // and (nombreArchivoModelo.ArchiRef.archi <> '') then
            TCatalogoReferencias(f.evaluador.Catalogo).registrar_referencia(self,
                self.nombreArchivoModelo.ClassName,
                self.nombreArchivoModelo.ArchiRef.get_archi, nombreArchivoModelo);
       if (nombreArchivoDatosHistoricos <> nil) then // and (nombreArchivoDatosHistoricos.ArchiRef.archi <> '') then
           TCatalogoReferencias(f.evaluador.Catalogo).registrar_referencia(self,
                self.nombreArchivoDatosHistoricos.ClassName,
                self.nombreArchivoDatosHistoricos.ArchiRef.get_archi, nombreArchivoDatosHistoricos) ;
       if (nombreArchivoModeloAuxiliar <> nil) then // and (nombreArchivoModeloAuxiliar.ArchiRef.archi <> '')  then
           TCatalogoReferencias(f.evaluador.Catalogo).registrar_referencia(self,
                self.nombreArchivoModeloAuxiliar.ClassName,
                self.nombreArchivoModeloAuxiliar.ArchiRef.get_archi, nombreArchivoModeloAuxiliar)  ;
    end;

   // InitModeloFromFile;    SE MUEVE A prepararmemoria @xc

    if (px_._lDeterminismos <> nil) then
    begin
      // si llego por aca quiere decir que la sala es un aversión < 56 y
      // el pronóstico si fue creado por existencia de sesgos no está completo
      // pues le faltan los datos guía.
      if (px_._pronosticos = nil) then
      begin
        // no hay sesgos, solo determinismos esto
        // lo iterpreto como determinismos PUROS.
        if px_._lDeterminismos.Count > 0 then
        begin
          px_._pronosticos := TPronosticos.Create(capa, '');
          for k := 0 to px_._lDeterminismos.Count - 1 do
          begin
            px_._aDeterminismo := TFichaDeterminismo(px_._lDeterminismos[k]);
            px_.x_NPCC := length(px_._aDeterminismo.valores);
            px_.x_NPLC := 0;
            px_.x_NPSA := px_.x_NPCC;
            px_.x_NPAC := 0;
            px_._x_aPronostico :=
              TPronostico.Create(capa, px_.x_NPCC, px_.x_NPLC, px_.x_NPSA,
              px_.x_NPAC, '', '');
            px_._pronosticos.add(px_._x_aPronostico);
          end;
        end;
      end;

      // bueno ahora copio los determinismos a la guía del pronóstico
      // OJO puede pasar que la guia no tenga el mismo largo que los
      // determinismos por lo que chequeo los largos
      for j := 0 to px_._lDeterminismos.Count - 1 do
      begin
        px_._aDeterminismo := px_._lDeterminismos[j] as TFichaDeterminismo;
        px_._x_aPronostico := px_._pronosticos[j] as TPronostico;

        if length(px_._x_aPronostico.guia) <> length(px_._aDeterminismo.valores) then
          setlength(px_._x_aPronostico.guia, length(px_._aDeterminismo.valores));

        for k := 0 to high(px_._aDeterminismo.valores) do
        begin
          px_._x_aPronostico.guia[k] := px_._aDeterminismo.valores[k];
        end;
      end;

      px_._lDeterminismos.Free;
      px_._lDeterminismos := nil;
    end;
    {if simularConDatosHistoricos then
      InitDatosHistoricosFromFile;}
  end;
  if px_._xlpd <> nil then
  begin
    px_._xlpd.Free;
    px_._xlpd:= nil;
  end;


  if f.Version < 143 then
  begin
    self.escenariosDePronosticos := TEscenarioDePronosticos.Create(0);
    self.escenariosDePronosticos.Add(px_._pronosticos, 100);
    px_._pronosticos:= nil;
  end;



  if f.version < 188 then
//registrar el atributo fuentesEntrada
  begin
    self.fuentesEntrada := TListaDeCosas.Create(capa, 'FuentesDeEntrada');
    self.flg_MODELO_ENTRADA_SALIDA := false;
  end;
  px_.Free;
end;


class function TFuenteSintetizadorCEGH.DescClase: string;
begin
  Result := rsSintetizadorCEGH;
end;

function TFuenteSintetizadorCEGH.kSelectorDesformador(datosModelo: TModeloCEGH;
  fecha: TFecha): integer;
var
  res: integer;
begin
  // esta función hace lo mismo que la de igual nombre de TModeloSintetizadorCEGH, pero
  // por eficiencia aquí se puede utilizar aprovechando lo ya calculado en las variables de
  // globs para inicio del paso.
  if fecha = nil then
  begin
  {$IFDEF _OPT_kselectordeformador_}
    case datosModelo.durPasoDeSorteoEnHoras of
      730: res := globs.MesInicioDelPaso - 1; // mensual
      672: res := (globs.SemanaInicioDelPaso - 1) div 4; // 4-semanas
      336: res := (globs.SemanaInicioDelPaso - 1) div 2;  // bi-semanal
      168: res := globs.SemanaInicioDelPaso - 1; // semanal
      24: if datosModelo.nPuntosPorPeriodo = 7 then
          res := globs.DiaDeLaSemanaInicioDelPaso - 1 // 0 Domingo
        else
          res := min(globs.DiaDelAnioInicioDelPaso - 1, 364); // Diario,
      1: res := globs.HoraDelAnioInicioDelPaso; // Horario
      else
        raise Exception.Create(rs_kSelectorDeformador + ' ' +
          IntToStr(durPasoDeSorteoEnHoras));
    end;
    res := res mod datosModelo.nPuntosPorPeriodo;
  {$ELSE}
    res := datosModelo.kSelectorDeformador(globs.FechaInicioDelPaso);
  {$ENDIF}
  end
  else
    res := datosModelo.kSelectorDeformador(fecha);
  Result := res;
end;


function TFuenteSintetizadorCEGH.descBornera: string;
begin
  Result :=
    'RB: ' + IntToStr(jPrimer_RB_) + '..' + IntToStr(jUltimo_RB_) +
    #10 + 'Wa: ' + IntToStr(jPrimer_Wa__) + '..' + IntToStr(jUltimo_Wa_) +
    #10 + 'X: ' + IntToStr(jPrimer_X_x) + '..' + IntToStr(jUltimo_X_x) +
    #10 + 'Y: ' + IntToStr(jPrimer_X_y) + '..' + IntToStr(jUltimo_X_y) +
    #10 + 'Xs: ' + IntToStr(jPrimer_Xs_x) + '..' + IntToStr(jUltimo_Xs_x) +
    #10 + 'Ys: ' + IntToStr(jPrimer_Xs_y) + '..' + IntToStr(jUltimo_Xs_y) +
    #10 + 'BC: ' + IntToStr(jPrimer_BC) + '..' + IntToStr(jUltimo_BC);
end;

procedure TFuenteSintetizadorCEGH.Dump_Variables(var f: TextFile;
  charIndentacion: char);
begin
  inherited Dump_Variables(f, charIndentacion);
  Writeln(f, charIndentacion, descBornera);
end;

procedure TFuenteSintetizadorCEGH.sim_FinCronicaPrintEstadoFinal(var fsal: textfile);
var
  k: integer;
  val: NReal;
begin
  for k := 0 to NombresDeBornes_Publicados.Count - 1 do
  begin
    val := Bornera[jPrimer_X_y + k];
    writeln(fsal, Nombre + '.' + NombresDebornes_Publicados[k] +
      ' = ' + FloatToStr(val));
  end;
end;

function TFuenteSintetizadorCEGH.cronicaIdInicio: string;
begin
  if simularConDatosHistoricos then
    if SincronizarConHistoricos then
      Result := Self.ClaseNombre + #9 + IntToStr(globs.AnioInicioDelPaso)
    else
      Result := Self.ClaseNombre + #9 + IntToStr(datosHistoricos.anioIni +
        ((globs.kCronica_ - 1) mod datosHistoricos.nAniosDatos_365d)) +
        ', ' + IntToStr(indicesDatosHistoricos[0])
  else
    Result := '';
end;


procedure TFuenteSintetizadorCEGH.Sim_Cronica_Inicio_SINTETICAS;
var
  kBorne, jRetardo: integer;
  aPronostico: TPronostico;
  j_x, j_y, j_rb, sel, jCol: integer;
  fechaDelDato: TFecha;
  Prob: NReal;
  dm: TModeloCEGH;
  usarCono: TDAOfBoolean;
  kSesgo: TDAOfNInt;
  kFactor: TDAofNInt;
  ax: NReal;
  fila: TVectR;
  BampIniSim: TMatR;
begin // simulando con series Sintéticas
  fechaDelDato := TFecha.Create_Dt(globs.fechaIniSim.dt);
  dm := datosModelo_Sim;
  if escenariosDePronosticos.Count > 1 then
    Prob := sorteadorDePronosticos_.rnd
  else
    Prob := 1;

  escenarioSorteados := escenariosDePronosticos.GetEscenarioPorP_(Prob);
  setlength(usarCono, escenarioSorteados.Count);
  setlength(kSesgo, escenarioSorteados.Count);
  setlength(kFactor, escenarioSorteados.Count);

  if escenarioSorteados.Count <> (datosModelo_Sim.nBornesSalida + datosModelo_Sim.nBornesEntrada) then
    raise Exception.Create( exFaltaEspValorDeterministicoBornes+' ' + Self.nombre);

  for kBorne := 0 to datosModelo_Sim.nBornesSalida - 1 do
  begin

    aPronostico := escenarioSorteados[kBorne];

    j_rb := jPrimer_RB_;

    for jRetardo := 0 to datosModelo_Sim.nRetardos - 1 do
    begin
      fechaDelDato.PonerIgualA(globs.fechaIniSim);
      fechaDelDato.addHoras(-jRetardo * durPasoDeSorteoEnHoras);

      j_x := jPrimer_X_x + jRetardo * datosModelo_Sim.nBornesSalida;
      j_y := jPrimer_X_y + jRetardo * datosModelo_Sim.nBornesSalida;
      usarCono[kBorne] := aPronostico.fechaEnRango(globs.fechaIniSim,
        kSesgo[kBorne], kFactor[kBorne]);

      ax := 0;
      if (kSesgo[kBorne] >= 0) then
        ax := ax + aPronostico.guia_eg[kSesgo[kBorne]]
      else
      begin
        if abs(globs.fechaIniSim.dt - escenarioSorteados.fechaIniCono.dt) <
          dt_PasoDeSorteo then
          ax := aPronostico.guia_eg[datosModelo_Sim.nRetardos - 1];
      end;

      sel := kSelectorDesformador(datosModelo_Sim, fechaDelDato);

      if dm.BAmpIniSim_cte <> nil then
        BAmpIniSim := dm.BampIniSim_cte
      else
      if dm.BAmpIniSim_mc <> nil then
        BAmpIniSim := dm.BAmpIniSim_mc[sel]
      else
        BampIniSim := nil;


      if BampIniSim <> nil then
      begin
        fila := BAmpIniSim.fila(kBorne + 1);
        for jCol := 1 to BAmpIniSim.nc do
        begin
          if kFactor[kBorne] >= 0 then
            ax := ax + fila.e(jCol) * bornera[j_rb + jCol - 1] *
              aPronostico.factor[kFactor[kBorne]]
          else
          if abs(globs.fechaIniSim.dt - escenarioSorteados.fechaIniCono.dt) <
            dt_PasoDeSorteo then
            ax := ax + fila.e(jCol) * bornera[j_rb + jCol - 1] *
              aPronostico.AperturaInicial_pu
          else
            ax := ax + fila.e(jCol) * bornera[j_rb + jCol - 1];
        end;
      end;


      Bornera[j_x + kBorne] := ax;
      Bornera[j_y + kBorne] := dm.gTox(ax, kBorne + 1, sel + 1);
    end;
  end;
  fechaDelDato.Free;
end;


procedure TFuenteSintetizadorCEGH.Sim_Cronica_Inicio_HISTORICAS;
var
  kBorne, jRetardo: integer;
  j_x, j_y: integer;
  mval: NReal;
  dt_dato: double;
  fechaDelDato: TFecha;
  Prob: NReal;
begin

  fechaDelDato := TFecha.Create_Clone(globs.fechaIniSim);

  if escenariosDePronosticos.Count > 1 then
    Prob := sorteadorDePronosticos_.rnd
  else
    Prob := 1;

  escenarioSorteados := escenariosDePronosticos.GetEscenarioPorP_(Prob);

  for jRetardo := 0 to datosModelo_Sim.nRetardos - 1 do
  begin
    dt_dato := globs.fechaIniSim.dt - jRetardo * dt_PasoDeSorteo;

    if sincronizarConSemillaAleatoria then
      datosHistoricos.calc_indices_y_pesos_dt(
        DespAnios_IniSim_IniDatosHistoricos - globs.ultimaSemillaFijada,
        dt_dato,
        indicesDatosHistoricos, pesosDatosHistoricos)
    else
    if sincronizarConHistoricos then
      datosHistoricos.calc_indices_y_pesos_dt(
        DespAnios_IniSim_IniDatosHistoricos,
        dt_dato,
        indicesDatosHistoricos, pesosDatosHistoricos)
    else
      datosHistoricos.calc_indices_y_pesos_dt(
        DespAnios_IniSim_IniDatosHistoricos - globs.kCronica_,
        dt_dato,
        indicesDatosHistoricos, pesosDatosHistoricos);


    j_x := jPrimer_X_x + jRetardo * datosModelo_Sim.nBornesSalida;
    j_y := jPrimer_X_y + jRetardo * datosModelo_Sim.nBornesSalida;

    fechaDelDato.dt := dt_dato;
    for kBorne := 0 to datosModelo_Sim.nBornesSalida - 1 do
    begin
      mval := datosHistoricos.get_mval_(kBorne, IndicesDatosHistoricos,
        PesosDatosHistoricos);
      Bornera[j_x + kBorne] :=
        gaussianar_(datosModelo_Sim, mval, kBorne, fechaDelDato);
      Bornera[j_y + kBorne] := mval;
    end;
  end;
  fechaDelDato.Free;

end;

procedure TFuenteSintetizadorCEGH.Sim_Cronica_Inicio;
begin
  inherited Sim_Cronica_Inicio;
  if not simularConDatosHistoricos then
    Sim_Cronica_inicio_SINTETICAS
  else // simulando con series Históricas
    Sim_Cronica_Inicio_HISTORICAS;
end;

procedure TFuenteSintetizadorCEGH.fijarEstadoInterno;
var
  i: integer;
  dm: TModeloCEGH;
begin
  if globs.EstadoDeLaSala = CES_SIMULANDO then
  begin
    assert(datosModelo_Sim.nVE = 0,
      'TFuenteSintetizadorCEGH.setEstadoInterno con nVE= ' +
      IntToStr(datosModelo_Sim.nVE) + ' debe ser 0');
    dm := datosModelo_Sim;
  end
  else
  begin
    assert(datosModelo_Opt.nVE = 0,
      'TFuenteSintetizadorCEGH.setEstadoInterno con nVE= ' +
      IntToStr(datosModelo_Opt.nVE) + ' debe ser 0');
    dm := datosModelo_Opt;
  end;
  for i := jPrimer_X_x to jUltimo_X_x do
    Bornera[i] := 0; // Pongo el valor de Probabilidad 50%
  calcularSalidasDeX(dm, False, todosLosBornesEnTrue);
end;

procedure TFuenteSintetizadorCEGH.PosicionarseEnEstrellita;
var
  i: integer;

  ax, bw: NReal;
  j: integer;
  fila: TVectR;

  aPronostico: TPronostico;
  usarCono: TDAOfBoolean;
  kSesgo: TDAOfNInt;
  kFactor: TDAofNInt;
  kSerie: integer;

  BAmp: TMatR;
  kSel: Integer;

  {$IFDEF LOG_RUIDA_PRONOS}
    k: integer;
  {$ENDIF}

begin

  setlength(usarCono, escenarioSorteados.Count);
  setlength(kSesgo, escenarioSorteados.Count);
  setlength(kFactor, escenarioSorteados.Count);

  for kSerie := 0 to escenarioSorteados.Count - 1 do
  begin
    aPronostico := TPronostico(escenarioSorteados.items[kSerie]);
    usarCono[kSerie] := aPronostico.fechaEnRango(globs.FechaInicioDelpaso,
      kSesgo[kSerie], kFactor[kSerie]);
  end;

  if datosModelo_Opt.nVE = 0 then
  begin
    // Caso expansión total
    kSel := kSelectorDesformador(datosModelo_opt, nil);
    if datosModelo_Opt.A_cte <> nil then
      BAmp := escenarioSorteados.GetBamp(globs.kPaso_Opt)
    else
        {$IFDEF dbg_VC}
        BAmp := TMatR.Create_identidad(datosModelo_Opt.A_nf);
//        BAmp.PorReal(0.9998);
        {$ELSE}
        BAmp := DatosModelo_Opt.BAmp_mc[kSel];
        {$ENDIF}


    //{$IFDEF dbg_VC}
    //BAmp.WriteArchiXLT('BAmp.xlt');
    //{$ENDIF}

    {$IFDEF LOG_RUIDA_PRONOS}
   { if (globs.CF.ordinalEstrellaActual = 0) and (nombre = 'Aportes') then
    begin
     Bamp.WriteArchiXLT('Bamp_'+IntToStr(globs.kPaso_Opt)+'.xlt');
      datosModelo_Opt.BAmp_cte.WriteArchiXLT('Bamp_cte.xlt');
    end;   }
    {$ENDIF}

    for i := jPrimer_X_x to jUltimo_X_x do
    begin
      //esto esta mal para el multiretardo
      kSerie := (i - jPrimer_X_x);
      {$IFDEF dbg_VC}
      if DatosModelo_Opt.A_nc <> DatosModelo_Opt.A_nf then
         kSerie := 0;
   //   BAmp.WriteArchiXLT('BAmp.xlt');
      {$ENDIF}
      fila := BAmp.fila(kserie + 1);
      aPronostico := escenarioSorteados.items[kSerie];

      // hay informacion de pronosticos
      ax:=aPronostico.fguia_extendida_(aPronostico.guia_eg, kSesgo[kSerie], 0);

      // Calculamos el estado expandido X= BAmp * R
      bw := 0;
      for j := 1 to fila.n do
        bw := bw + fila.e(j) * bornera[jPrimer_Wa__ + j - 1];
      {$IFDEF APLICAR_FACTOR_EN_OPT}

      {$IFDEF LOG_APLICAR_FACTOR_EN_OPT}
      if (globs.CF.ordinalEstrellaActual = 0) and (kSerie = 2) and
        (nombre = 'Aportes') then
        writeln(flog_aplicar_factor_en_opt, self.nombre, #9,
          globs.kPaso_Opt, #9, kSesgo[kSerie], #9, aPronostico.guia_eg[kSesgo[kSerie]],
          #9, kFactor[kSerie], #9, aPronostico.factor[kFactor[kSerie]]);
      {$ENDIF}

      {$IFNDEF RUIDA_PRONOS}
      if (kFactor[kSerie] >= 0) and (kFactor[kSerie] <= High(aPronostico.factor)) then
        Bornera[i] := ax + bw * aPronostico.factor[kFactor[kSerie]]
      else
      {$ENDIF}
        Bornera[i] := ax + bw;

      {$ELSE}

      Bornera[i] := ax + bw;
      {$ENDIF}


    end;
  end
  else
  begin
    // copiamos el estado reducido
    for i := 0 to high(XRed) do
      XRed[i] := globs.CF.xr[self.ixr + i];

    // expandimos el reducido para posicionar el no reducido
    ExpandirEstado(datosModelo_Opt, jPrimer_X_x, Bornera, XRed);
  end;

  calcularSalidasDeX(datosModelo_Opt, False, todosLosBornesEnTrue);

  setlength(usarCono, 0);
  setlength(kSesgo, 0);
  setlength(kFactor, 0);

  {$IFDEF LOG_RUIDA_PRONOS}
    if (globs.CF.ordinalEstrellaActual = 0) and (nombre = 'BPS50yCMOBR') then
      for k:=0 to NombresDeBornes_Publicados.Count-1 do
        writeln(flog_ruida_pronos, NombresDeBornes_Publicados[k], #9, globs.kPaso_Opt, #9,
          Bornera[jPrimer_X_y+k], #9, datosModelo_Opt.gTox(escenarioSorteados.Guia_eg(globs.kPaso_Opt).e(1+k), k + 1, kSelectorDesformador(datosModelo_Opt, nil) + 1));
  {$ENDIF}

end;

procedure TFuenteSintetizadorCEGH.calcular_jsInicioFinal;
begin
  inherited calcular_jsInicioFinal;

  {$IFDEF MODELO_ENTRADA_SALIDA}
  if flg_MODELO_ENTRADA_SALIDA then
  //no esta para retardo mayor que 1 todavia
  begin
    jPrimer_X_x := jPrimer_x; // primer X en el vector  de estado Xs (dim A.nc)
    if datosModelo_Sim.A_cte <> nil then
      jUltimo_X_x := jPrimer_X_x + datosModelo_Sim.A_cte.nf - 1
    else
      jUltimo_X_x := jPrimer_X_x + datosModelo_Sim.mcA[0].nf - 1;

    jPrimer_X_y := jUltimo_X_x + 1; // primer y (mundo real ) ( dim A.nf )
  end
  else
  begin
    // calculamos los indices auxiliares en las borneras
    jPrimer_X_x := jPrimer_x; // primer X en el vector  de estado Xs (dim A.nc)
    if datosModelo_Sim.A_cte <> nil then
      jUltimo_X_x := jPrimer_X_x + datosModelo_Sim.A_cte.nc - 1
    else
      jUltimo_X_x := jPrimer_X_x + datosModelo_Sim.mcA[0].nc - 1;

    jPrimer_X_y := jUltimo_X_x + 1; // primer y (mundo real ) ( dim A.nf )
  end;
  {$ELSE}
    // calculamos los indices auxiliares en las borneras
  jPrimer_X_x := jPrimer_x; // primer X en el vector  de estado Xs (dim A.nc)
  if datosModelo_Sim.A_cte <> nil then
    jUltimo_X_x := jPrimer_X_x + datosModelo_Sim.A_cte.nc - 1
  else
    jUltimo_X_x := jPrimer_X_x + datosModelo_Sim.mcA[0].nc - 1;

  jPrimer_X_y := jUltimo_X_x + 1; // primer y (mundo real ) ( dim A.nf )
  {$ENDIF}

  {$IFDEF MODELO_ENTRADA_SALIDA}
   if flg_MODELO_ENTRADA_SALIDA then
  begin
    if datosModelo_Sim.A_cte <> nil then
      jUltimo_X_y := jPrimer_X_y + datosModelo_Sim.A_cte.nf - 1
    else
      jUltimo_X_y := jPrimer_X_y + datosModelo_Sim.mcA[0].nf - 1;
  end
  else
  begin
    if datosModelo_Sim.A_cte <> nil then
      jUltimo_X_y := jPrimer_X_y + datosModelo_Sim.A_cte.nc - 1
    else
      jUltimo_X_y := jPrimer_X_y + datosModelo_Sim.mcA[0].nc - 1;
  end;
  {$ELSE}
  if datosModelo_Sim.A_cte <> nil then
    jUltimo_X_y := jPrimer_X_y + datosModelo_Sim.A_cte.nc - 1
  else
    jUltimo_X_y := jPrimer_X_y + datosModelo_Sim.mcA[0].nc - 1;
  {$ENDIF}

  jPrimer_Xs_x := jPrimer_X_x + dim_x; // primer X en el vector  de estado Xs (dim A.nc)
  jUltimo_Xs_x := jUltimo_X_x + dim_x;
  jPrimer_Xs_y := jPrimer_X_y + dim_x; // primer y (mundo real ) ( dim A.nf )
  jUltimo_Xs_y := jUltimo_X_y + dim_x;
end;


procedure TFuenteSintetizadorCEGH.PrepararMemoria(Catalogo: TCatalogoReferencias;
  globs: TGlobs);
var
  i: integer;
begin

  inherited PrepararMemoria(Catalogo, globs);
  fuenteGaussiana := Tf_ddp_GaussianaNormal.Create(sorteadorUniforme, 0);

  // Creo el sorteador de escenarios independiente del sorteadorUniforme
  // para no alterar el orden los sorteos

  if sorteadorDePronosticos_ = nil then
    sorteadorDePronosticos_ :=
      globs.madresUniformes.Get_NuevaMadreUniforme(get_hash_nombre + 1543);

  escenariosDePronosticos.prepararse(durPasoDeSorteoEnHoras);

  SetLength(calcularSalidaBorne, datosModelo_Sim.nBornesSalida);
  SetLength(todosLosBornesEnTrue, datosModelo_Sim.nBornesSalida);
  for i := 0 to datosModelo_Sim.nBornesSalida - 1 do
    todosLosBornesEnTrue[i] := True;

  if simularConDatosHistoricos then
  begin
    datosHistoricos.setLength_indices_y_pesos(indicesDatosHistoricos,
      pesosDatosHistoricos);
    datosHistoricos.setLength_indices_y_pesos(
      indicesDatosHistoricos_s, pesosDatosHistoricos_s);
    if sincronizarConHistoricos then
      DespAnios_IniSim_IniDatosHistoricos := 0
    else
      DespAnios_IniSim_IniDatosHistoricos :=
        (globs.fechaIniSim.anio - datosHistoricos.fechaIni.anio) + 1;
  end;

end;

procedure TFuenteSintetizadorCEGH.InicioSim;
begin
  inherited InicioSim;
  self.ReCalibrarPronosticos(datosModelo_Sim, self.globs.fechaIniSim);
end;

procedure TFuenteSintetizadorCEGH.InicioOpt;
var
  k: integer;
  Prob: NReal;
begin
  inherited InicioOpt;

   // solo para que tenga algo definido

  if escenariosDePronosticos.Count > 1 then
    Prob := sorteadorDePronosticos_.rnd
  else
    Prob := 1;
  escenarioSorteados := escenariosDePronosticos.GetEscenarioPorP_(Prob);


  ReCalibrarPronosticos(datosModelo_Opt, self.globs.fechaIniSim);

  MaMr_cte := nil;
  MaMr_mc := nil;

  if datosModelo_Opt.A_cte <> nil then
  begin
    if datosModelo_Opt.MRed_cte <> nil then
    begin
      MaMr_cte := TMatR.Create_Init(datosModelo_Opt.MAmp_cte.nf,
        datosModelo_Opt.MRed_cte.nc);
      MaMr_cte.Mult(datosModelo_Opt.MAmp_cte, datosModelo_Opt.MRed_cte);
    end;
  end
  else
  begin
    if datosModelo_Opt.MRed_mc <> nil then
    begin
      setlength(MaMr_mc, datosModelo_Opt.nPuntosPorPeriodo);
      for k := 0 to datosModelo_Opt.nPuntosPorPeriodo - 1 do
      begin
        MaMr_mc[k] := TMatR.Create_Init(datosModelo_Opt.MAmp_mc[k].nf,
          datosModelo_Opt.MRed_mc[k].nc);
        MaMr_mc[k].Mult(datosModelo_Opt.MAmp_mc[k], datosModelo_Opt.MRed_mc[k]);
      end;
    end;
  end;
end;

procedure TFuenteSintetizadorCEGH.SorteosDelPaso(xsortear: boolean);
var
  Prob: NReal;
begin
  inherited SorteosDelPaso(xsortear);

  // En este procedimiento el sorteo de escenarios se debe ralizar solo para la
  // optimizacion, ya que en cada cronica se elige un escenario.
  // Para la simulacion el sorteo se realiza una unica vez por cronica en Sim_Cronica_Inicio
  if self.globs.EstadoDeLaSala = CES_OPTIMIZANDO then
  begin
    if escenariosDePronosticos.Count > 1 then
      Prob := sorteadorDePronosticos_.rnd
    else
      Prob := 1;
    escenarioSorteados := escenariosDePronosticos.GetEscenarioPorP_(Prob);
  end;

end;



function TFuenteSintetizadorCEGH.IdBorne(nombre: string): integer;
begin
  if flg_MODELO_ENTRADA_SALIDA then
  begin
    Result :=
      Dim_Rb + // salto los rb
      Dim_Wa + datosModelo_Sim.A_nf + // salto las x
      NombresDeBornes_Publicados.IndexOf(nombre);
  end
  else
  begin
    Result :=
      Dim_Rb + // salto los rb
      Dim_Wa + datosModelo_Sim.A_nc + // salto las x
      NombresDeBornes_Publicados.IndexOf(nombre);
  end;

end;

function TFuenteSintetizadorCEGH.NombreBorne(idBorne: integer): string;
var
  k: integer;
begin
  if flg_MODELO_ENTRADA_SALIDA then
     k := idBorne - Dim_Rb - Dim_Wa - datosModelo_Sim.A_nf
  else
     k := idBorne - Dim_Rb - Dim_Wa - datosModelo_Sim.A_nc;
  if (k < 0) or (k >= NombresDeBornes_Publicados.Count) then
    Result := '?'
  else
    Result := NombresDeBornes_Publicados[k];
end;

procedure TFuenteSintetizadorCEGH.ReducirEstado(var y: TDAofNReal;
  jIniX: integer; const datosModelo: TModeloCEGH; const R: TMatR;
  const Bornera: TDAOfNReal);
var
  i, j: integer;
  fila: TVectR;
  ay: NReal;
begin
  if R <> nil then
  begin
    // Calculamos el estado reducido y= R*x
    for i := 1 to R.nf do
    begin
      ay := 0;
      fila := R.Fila(i);
      for j := 1 to R.nc do
        ay := ay + fila.e(j) * bornera[jIniX + j - 1];
      y[i - 1] := ay;
    end;
  end
  else if length(y) = datosModelo.nVE then
  begin
    for i := 0 to datosModelo.nVE - 1 do
      y[i] := bornera[i];
  end
  else
    raise Exception.Create(exErrorDiferenteLargoReducirEstado);
end;

procedure TFuenteSintetizadorCEGH.ExpandirEstado(datosModelo: TModeloCEGH;
  jIniX: integer; var bornera: TDAofNReal; const y: TDAOfNReal);
var
  i, j: integer;
  fila: TVectR;
  ax: NReal;
  aPronostico: TPronostico;
  usarCono: TDAOfBoolean;
  kSesgo: TDAOfNInt;
  kFactor: TDAofNInt;
  kSerie: integer;

  guia_eg_aux, guia_eg: TVectR;
  Id: TMatR;
  flg_Aplicar_MAmp: boolean;
  MAmp, BAmp: TMatR;
  MaMr: TMatR;
  kSel: integer;
  bw: NReal;

begin

  if (datosModelo.MAmp_cte <> nil) or (datosModelo.MAmp_mc <> nil) then
  begin
    setlength(usarCono, escenarioSorteados.Count);
    setlength(kSesgo, escenarioSorteados.Count);
    setlength(kFactor, escenarioSorteados.Count);

    if datosModelo.A_cte <> nil then
    begin
      MAmp := datosModelo.MAmp_cte;
      BAmp := escenarioSorteados.GetBamp(globs.kPaso_Opt);
      MaMr := MaMr_cte;
    end
    else
    begin
      kSel := kSelectorDesformador(datosModelo, nil);
      MAmp := datosModelo.MAmp_mc[kSel];
      {$IFDEF dbg_VC}
      BAmp := nil;
      {$ELSE}
      BAmp := datosModelo.BAmp_mc[kSel];
      {$ENDIF}
      MaMr := MaMr_mc[kSel];
    end;

    guia_eg := escenarioSorteados.Guia_eg(globs.kPaso_Opt);
    //guia_eg := TVectR.Create_Init(escenarioSorteados.Count);
    //
    //for kSerie := 0 to escenarioSorteados.Count - 1 do
    //begin
    //  aPronostico := TPronostico(escenarioSorteados.items[kSerie]);
    //  usarCono[kSerie] := aPronostico.fechaEnRango(globs.FechaInicioDelpaso,
    //    kSesgo[kSerie], kFactor[kSerie]);
    //
    //  if (kSesgo[kSerie] >= 0) and (kSesgo[kSerie] < length(aPronostico.guia_eg)) then
    //    guia_eg.pon_e(kSerie, aPronostico.guia_eg[kSesgo[kSerie]])
    //  else
    //    guia_eg.pon_e(kSerie, 0.0);
    //end;

    flg_Aplicar_MAmp := MAmp.nf = escenarioSorteados.Count;

    // Calculamos el estado expandido x= MAmp * y
  //  for i := 1 to escenarioSorteados_.Count - 1 do
  // rch@201905181901 comento la de arriba y la cambio por la de abajo
    for i := 1 to escenarioSorteados.Count do
    begin

      kSerie := i-1;

      aPronostico := TPronostico(escenarioSorteados.items[kSerie]);
      ax := 0;

      if flg_Aplicar_MAmp then
      begin
        fila := MAmp.Fila(i);
        for j := 1 to MAmp.nc do
          ax := ax + fila.e(j) * y[j - 1];
      end;

      // Calculamos el estado expandido x= MAmp * y + BAmp * R
      if BAmp <> nil then
      begin
        fila := Bamp.fila(i);
        bw := 0;
        for j := 1 to Bamp.nc do
          bw := bw + fila.e(j) * bornera[jPrimer_Wa__ + j - 1];
        // se supone que los ruidos están al arranque

        {$IFDEF APLICAR_FACTOR_EN_OPT}

        {$IFNDEF RUIDA_PRONOS}
        if (kFactor[kSerie] >= 0) and (kFactor[kSerie] <
          length(aPronostico.factor)) then
          ax := ax + bw * aPronostico.factor[kFactor[kSerie]]
        else
        {$ENDIF}
          ax := ax + bw;
        {$ELSE}
        ax := ax + bw;
        {$ENDIF}

      end;

    //VC esta mal esto!!!
    {$IFDEF dbg_VC}
      guia_eg.resize(MaMr.nf);
    {$ENDIF}
      Id := TMatR.Create_identidad(MaMr.nf);
      if (MaMr <> nil) then
      begin
        Id.Fila(i).res(MaMr.Fila(i));
        ax := ax + Id.Fila(i).PEV(guia_eg);
      end;
      Id.Free;
      bornera[jIniX + i - 1] := ax;
    end;

    guia_eg.Free;
  end
  else
  if datosModelo.nVE = length(y) then
  begin
    for i := 0 to datosModelo.nVE - 1 do
      bornera[jIniX + i] := y[i];
  end
  else
    raise Exception.Create(exErrorDiferenteLargoExpandirEstado);
end;

procedure TFuenteSintetizadorCEGH.ActualizarEstadoGlobal(flg_Xs: boolean);
var
  i: integer;
  tBornera: TDAOfNreal;
  kSel: integer;

begin
  //rch@20140826  OJO , por ahora ingnoro flg_Xs

  if (globs.EstadoDeLaSala = CES_SIMULANDO) and (datosModelo_Opt <>
    datosModelo_Sim) then
  begin
    setlength(tBornera, length(bornera));
    // convertir estados del modelo simulador al optimizador
    if globs.CFauxActivo then
      // atención estoy suponiendo que el CFAux es manejable con el modelo usado en Sim.
      gaussianarRafaga(
        tBornera, jPrimer_X_x,  // destino
        Bornera, jPrimer_X_y,   // origen
        datosModelo_Sim.A_nc, datosModelo_Sim.nRetardos,
        datosModelo_Sim.A_nc, // nBornes del Origen.
        datosModelo_Sim, globs.FechaInicioDelpaso)
    else
      gaussianarRafaga(
        tBornera, jPrimer_X_x,  // destino
        Bornera, jPrimer_X_y,   // origen
        datosModelo_Opt.A_nc, datosModelo_Opt.nRetardos,
        datosModelo_Sim.A_nc, // nBornes del Origen.
        datosModelo_Opt, globs.FechaInicioDelpaso);

  end
  else
    tBornera := Bornera;

  if not globs.CFauxActivo or (datosModelo_Opt.MRed_aux = nil)
  // si no hay un reductor especial uso el mismo del principal
  then
  begin
    if datosModelo_Opt.MRed_cte <> nil then
    begin
      // Calculamos el estado reducido y= R*x
      if datosModelo_Opt.A_cte <> nil then
        ReducirEstado(XRed, jPrimer_X_x, datosModelo_Opt,
          datosModelo_Opt.MRed_cte, tBornera)
      else
      begin
        kSel := kSelectorDesformador(datosModelo_Opt, nil);
        ReducirEstado(XRed, jPrimer_X_x, datosModelo_Opt,
          datosModelo_Opt.MRed_mc[kSel], tBornera);
      end;
      for i := 0 to high(XRed) do
        globs.CF.xr[self.ixr + i] := XRed[i];
    end
    else if datosModelo_Opt.nVE > 0 then
    begin
      //Los estados estan sin reducir. Son los que estan en el administrador de
      //estados
      for i := 0 to datosModelo_Opt.nVe - 1 do
        globs.CF.xr[self.ixr + i] := tBornera[jPrimer_X_x + i];
      //  aplicarFunciones;
    end;
  end
  else
  begin
    if datosModelo_Opt.MRed_aux <> nil then
    begin
      // Calculamos el estado reducido y= R*x
      ReducirEstado(XRed_aux, jPrimer_X, datosModelo_Opt,
        datosModelo_Opt.MRed_aux, tBornera);

      for i := 0 to high(XRed_aux) do
        globs.CF.xr[self.ixr + i] := XRed_aux[i];
    end
    else if datosModelo_Opt.nVE_aux > 0 then
    begin
      //Los estados estan sin reducir. Son los que estan en el administrador de
      //estados
      for i := 0 to datosModelo_Opt.nVE_aux do
        globs.CF.xr[self.ixr + i] := tBornera[jPrimer_X + i];
      //  aplicarFunciones;
    end;
  end;
  if tBornera <> Bornera then
    setlength(tBornera, 0);
end;

procedure TFuenteSintetizadorCEGH.Optx_nvxs(var ixr, ixd, iauxNReal, iauxInt: integer);
begin
  self.ixr := ixr;
  ixr := ixr + datosModelo_Opt.nVE;
end;

procedure TFuenteSintetizadorCEGH.Optx_RegistrarVariablesDeEstado(
  adminEstados: TAdminEstados);
var
  i: integer;
  xmin, xmax: double;
  area, deltaArea: double;
  j: integer;
  xt: double;
  dn: Tf_ddp_GaussianaNormal;
  probs: TDAOfNReal;

  dx_pcd, min_dx_pcd: NReal;

begin
  dn := Tf_ddp_GaussianaNormal.Create(nil, 0);

  min_dx_pcd := 10; // un valor grande para ser susitituido en la búsqueda

  for i := 0 to datosModelo_Opt.nVE - 1 do
  begin
    xmax := 2.5; // por poner algo * (nDiscsVsE[i] -1) / (nDiscsVsE[i] + 1);
    xmin := -xmax;
    adminEstados.Registrar_Continua(ixr + i, xmin, xmax,
      datosModelo_Opt.nDiscsVsE[i],
      {$IFDEF ADMINISTRADOR_DE_ESTADOS_MULTIPLANO}
       self.nombre + '_' + datosModelo_Opt.nombreVarE[i] + '['+ IntToStr(i+1) + ']' ,
      'p.u.GN' // unidades   (el espacio complicaba la lectura de archivos)
      {$ELSE}
       datosModelo_Opt.nombreVarE[i],
      'p.u. GN' // unidades
      {$ENDIF}
      );

    probs := datosModelo_Opt.ProbsVsE[i]; // referenciamos el vector
    area := 0;
    for j := 0 to datosModelo_opt.nDiscsVsE[i] - 1 do
    begin
      deltaArea := probs[j] / 2.0;
      area := area + deltaArea;
      xt := dn.t_area(area);
      adminEstados.xr_def[ixr + i].x[j] := xt;
      if j > 0 then
      begin
        dx_pcd := adminEstados.xr_def[ixr + i].x[j] -
          adminEstados.xr_def[ixr + i].x[j - 1];
        if dx_pcd < min_dx_pcd then
          min_dx_pcd := dx_pcd;
      end;
      area := area + deltaArea;
    end;
    adminEstados.xr_def[ixr + i].dx_pcd := min_dx_pcd;
  end;

  dn.Free;
end;

{$IFDEF INTERMEDIARIO_DE_COSTO_FUTURO}

procedure TFuenteSintetizadorCEGH.opt_nvers(var ivar, ivae, ires: integer);
var
  i: Integer;
begin

  for i := 0 to datosModelo_Opt.nVE - 1 do
  begin
    self.ivar := ivar;
    Inc(ivar);  //Agregamos las variables a las columnas del simplex
    {$IFDEF RDIN}
    self.ires := ires; //  X_s = A.X + B.r ----> filtro CEGH  //es una restricción por variable
    Inc(ires);
    {$ENDIF}
  end;

end;

procedure TFuenteSintetizadorCEGH.opt_cargue(s: TSimplex);
var
  i, jFila, kSel, DimRes: Integer;
  XsRed, XRed, R, MredB, MredB_t, MampXred, AMampXred, MredAMampXred,
     ABAmp, MredABAmp, MredABAmp_t, ZZt, JJt,GGt, ZR,Z: TMatR;
begin
  {$IFNDEF INTERMEDIARIO_DE_COSTO_FUTURO}
  inherited opt_cargue(s);
  {$ENDIF}



  {$IFDEF RDIN}

  if datosModelo_Sim.nVE = 0 then
      exit;

  DimRes:=0;

  //Restricción dinamica -----> XsRed= Mred.A.Mamp.Xred + Mred.A.BAmp_cte.W + Mred.B.R
  //LLamemos J = Mred.A.BAmp_cte y G = Mred.B
  // como R y W son ruido blanco gaussiano de norma 1, se tiene que la convinacion lineal
  // también es RBG de norma <> de 1
  //------------> J.W + G.R= Z.R
  // Tomando la matriz de covarianza de ambos lados llegamos a
  //------------> J.Jt + G.Gt=Z.Zt
  //Luego para obtener Z se reliza la raiz por potencia iterada

  XsRed:=TMatR.Create_Init(datosModelo_Sim.Dim_XRed,1);

  XRed:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,1);
  XRed.pon_columna(1,1,self.XRed);

  MampXred:= TMatR.Create_Init(datosModelo_Sim.Dim_X, 1);
  AMampXred:= TMatR.Create_Init(datosModelo_Sim.Dim_X, 1);
  MredAMampXred:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed, 1);
  R:= TMatR.Create_Init(datosModelo_Sim.Dim_X,1);
  MredB:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,datosModelo_Sim.Dim_X);
  MredB_t:= TMatR.Create_Init(datosModelo_Sim.Dim_X,datosModelo_Sim.Dim_XRed);
  ABAmp:= TMatR.Create_Init(datosModelo_Sim.Dim_X, datosModelo_Sim.Dim_X);
  MredABAmp:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,datosModelo_Sim.Dim_X);
  MredABAmp_t:= TMatR.Create_Init(datosModelo_Sim.Dim_X,datosModelo_Sim.Dim_XRed);
  JJt:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,datosModelo_Sim.Dim_XRed);
  GGt:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,datosModelo_Sim.Dim_XRed);
  ZZt:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,datosModelo_Sim.Dim_XRed);
  //Z:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,datosModelo_Sim.Dim_XRed);
  ZR:= TMatR.Create_Init(datosModelo_Sim.Dim_XRed,1);

  for jFila := 1 to R.nf do
     R.pon_e(jFila,1, bornera[jPrimer_RB_ + jFila - 1]); //Ruido Blanco

{  for jFila := 1 to W.nf do    //ESTO ESTA MAL, EL RUIDO ESTE RECIEN ESTÁ EN LA OPTIMIZACION, ASIQUE HAY Q HACER OTRA COSA
     W.pon_e(jFila,1, bornera[jPrimer_Wa__ + jFila - 1]); //Ruido Blanco para extension ruida   }

  if datosModelo_Sim.A_cte <> nil then
  begin
   //Mred.A.Mamp.Xred
   MampXred.Mult(datosModelo_Sim.MAmp_cte, XRed);
   AMampXred.Mult(datosModelo_Sim.A_cte, MampXred);
   MredAMampXred.Mult(datosModelo_Sim.MRed_cte, AMampXred);

   //Mred.B.(Mred.B)_t
   MredB.Mult(datosModelo_Sim.MRed_cte, datosModelo_Sim.B_cte);
   MredB_t:= MredB.Crear_Transpuesta;
   GGt.Mult(MredB, MredB_t);

   //Mred.A.BAmp_cte.(Mred.A.BAmp_cte )_t
   ABAmp.Mult(datosModelo_Sim.A_cte, datosModelo_Sim.BAmp_cte);
   MredABAmp.Mult(datosModelo_Sim.MRed_cte,ABAmp);
   MredABAmp_t:= MredABAmp.Crear_Transpuesta;
   JJt.Mult(MredABAmp, MredABAmp_t);

   //J.Jt + G.Gt=Z.Zt
   ZZt.suma(JJt,GGt);

   Z:= ZZt.RaizPorPotenciaIterada(DimRes, True);
   if DimRes < 0 then
      raise Exception.Create('TFuenteSintetizadorCEGH.opt_cargue, RaízPotenciaIterda autovalor negativo');

   ZR.Mult(Z,R);

   XsRed.Suma(MredAMampXred, ZR);

  end
  else
  begin
    kSel := kSelectorDesformador(datosModelo_Sim, nil);
    //Mred.A.Mamp.Xred
    MampXred.Mult(datosModelo_Sim.MAmp_mc[kSel], XRed);
    AMampXred.Mult(datosModelo_Sim.A_cte, MampXred);
    MredAMampXred.Mult(datosModelo_Sim.MRed_mc[kSel], AMampXred);


   //Mred.B.(Mred.B)_t
    MredB.Mult(datosModelo_Sim.MRed_mc[kSel], datosModelo_Sim.B_cte);
    MredB_t:= MredB.Crear_Transpuesta;
    GGt.Mult(MredB, MredB_t);

    //Mred.A.BAmp_cte.(Mred.A.BAmp_cte )_t
    ABAmp.Mult(datosModelo_Sim.A_cte, datosModelo_Sim.BAmp_mc[kSel]);
    MredABAmp.Mult(datosModelo_Sim.MRed_mc[kSel],ABAmp);
    MredABAmp_t:= MredABAmp.Crear_Transpuesta;
    JJt.Mult(MredABAmp, MredABAmp_t);

    ZZt.suma(JJt,GGt);

    Z:= ZZt.RaizPorPotenciaIterada(DimRes, True);
    if DimRes < 0 then
      raise Exception.Create('TFuenteSintetizadorCEGH.opt_cargue, RaízPotenciaIterda autovalor negativo');

    ZR.Mult(Z,R);

    XsRed.Suma(MredAMampXred, ZR);

  end;

  for i := 0 to datosModelo_Sim.nVE - 1 do
  begin

     //  -XRed_s + A'Xred + B'r = 0 restriccion dinamica

     // término - XsRed
     s.pon_e(ires + i, ivar + i, -1);


     // términos constantes
     s.pon_e(ires + i, s.nc, max(min( XsRed.e(i+ 1, 1), 3.7), -3.7) );
  end;


  XsRed.free;
  XRed.free;
  MampXred.free;
  AMampXred.free;
  MredAMampXred.free;
  R.free;
  MredB.free;
  MredB_t.free;
  ABAmp.free;
  MredABAmp.free;
  MredABAmp_t.free;
  JJt.free;
  GGt.free;
  ZZt.free;
  //Z.free;
  ZR.free;



  {$ENDIF}

end;


procedure TFuenteSintetizadorCEGH.registrarVarYResEnIntermediario(
  intermediario: TIntermediarioCostoFuturo);
var
  restricciones: TDAOfRestriccionGradiente;
  i: Integer;
  metodoDerivada: TMetodoDerivada;

begin
  inherited registrarVarYResEnIntermediario(intermediario);
  SetLength(restricciones,1);
  restricciones[0]:=nil;
  metodoDerivada := TMetodoDerivada.Create(DEVXR_CONTINUO, 1 , 1, 1 , 1);
  for i := 0 to datosModelo_Sim.nVE - 1 do
  begin
    intermediario.registrarVariableContinua(ixr + i, ivar + i,ires + i, restricciones,
    {$IFDEF ADMINISTRADOR_DE_ESTADOS_MULTIPLANO}
     self.nombre + '_' + datosModelo_Sim.nombreVarE[i] + '['+ IntToStr(i+1) + ']' ,
    'p.u.GN', metodoDerivada); // unidades   (el espacio complicaba la lectura de archivos)
    {$ELSE}
     datosModelo_Sim.nombreVarE[i],
    'p.u. GN'); // unidades
    {$ENDIF}
  end;
end;

procedure TFuenteSintetizadorCEGH.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  i: Integer;
begin


  {$IFDEF RDIN}

  for i := 0 to datosModelo_Sim.nVE - 1 do
  begin
    s.FijarRestriccionIgualdad(ires + i);

    s.cota_inf_set(ivar + i,-4);
    s.cota_sup_set(ivar + i,4);
  end;

  {$ENDIF}

end;

function TFuenteSintetizadorCEGH.getNombreVar(ivar: integer; var nombre: string
  ): boolean;
var
  iVariable: Integer;
begin

  Result := False;
  nombre:='';

  if datosModelo_Sim.nVE=0 then
     exit;

  iVariable:=ivar - self.ivar;
  if (iVariable>=0) and (iVariable<datosModelo_Sim.nVE) then
  begin
     nombre := self.Nombre + '_Xs' + '_' + datosModelo_Sim.nombreVarE[iVariable] + '['+ IntToStr(iVariable+1) + ']';
     Result := True;
  end;


end;

function TFuenteSintetizadorCEGH.getNombreRes(ires: integer; var nombre: string
  ): boolean;
var
  iVar: Integer;
begin


  Result := False;
  nombre:='';

  {$IFDEF RDIN}
  if datosModelo_Sim.nVE=0 then
    exit;

  iVar:=ires - self.ires;

  if (iVar>=0) and (iVar<datosModelo_Sim.nVE) then
  begin
     nombre := self.Nombre +  '_' + datosModelo_Sim.nombreVarE[iVar] + '['+ IntToStr(iVar+1) + ']_' +
         '-Xsred + AXred + Br=0';

    Result := True;
  end;
  {$ENDIF}

end;
{$ENDIF}

// las fuentes con estado tienen que calcular el delta costo
// por el delta_X resultante del sorteo
procedure TFuenteSintetizadorCEGH.PrepararPaso_ps;
var
  k: integer;
  dxred, dx: TDAOfNReal;
  kSel: integer;

begin
  // La variación del costo por la variación (involuntaria) del estado
  DeltaCosto := 0;
  calcular_Xs;

  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) then
  begin
    if datosModelo_Opt.nVE = 0 then
      exit;

    setlength(dxred, datosModelo_Opt.nVE);
    if flg_MODELO_ENTRADA_SALIDA then
       setlength(dx, datosModelo_Opt.A_nf)
    else
       setlength(dx, datosModelo_Opt.A_nc);

    for k := 0 to high(dx) do
      dx[k] := bornera[jPrimer_Xs + k] - bornera[jPrimer_X + k];

    if datosModelo_Opt.A_cte <> nil then
      ReducirEstado(dxred, 0, datosModelo_Opt, datosModelo_Opt.MRed_cte, dx)
    else
    begin
      kSel := kSelectorDesformador(datosModelo_Opt, nil);
      ReducirEstado(dxred, 0, datosModelo_Opt, datosModelo_Opt.MRed_mc[kSel], dx);
    end;

    // writeln( 'Fuente Sintetizador PreparaPaso_ps: ', self.nombre );
    for k := 0 to datosModelo_Opt.nVE - 1 do
      DeltaCosto := DeltaCosto + globs.CF.deltaCosto_vxr_continuo(
        ixr + k, globs.kPaso_Opt + 1, dxred[k]);
    setlength(dx, 0);
    setlength(dxred, 0);
  end;

end;

function TFuenteSintetizadorCEGH.dim_RB: integer;
begin
  Result := datosModelo_Sim.B_nc;
end;

function TFuenteSintetizadorCEGH.dim_X: integer;
begin
  if flg_MODELO_ENTRADA_SALIDA then
  begin
    Result :=
      datosModelo_Sim.A_nf +  // vector _x estado gaussiano, memoria de la salida
      datosModelo_Sim.A_nf;   // vector _y (  x pasados al mundo real ).
  end
  else
  begin
    Result :=
      datosModelo_Sim.A_nc +  // vector _x estado gaussiano, memoria de la salida
      datosModelo_Sim.A_nc;   // vector _y (  x pasados al mundo real ).
  end;

end;

function TFuenteSintetizadorCEGH.dim_Wa: integer;
begin

  if datosModelo_Opt.BAmp_cte <> nil then
    Result := datosModelo_Opt.BAmp_cte.nc
  else
  if datosModelo_Opt.BAmp_mc <> nil then
    Result := datosModelo_Opt.BAmp_mc[0].nc
  else
    Result := 0;

end;

// carga el deltacosto en el término indep del simplex
function TFuenteSintetizadorCEGH.calc_DeltaCosto: NReal;
begin
  Result := DeltaCosto;
end;

function mFilaPorColumna(a: TVectR; b: TDAOfNReal): NReal;
var
  acum: NREal;
  k: integer;
begin
  acum := 0;
  for k := 0 to high(b) do
    acum := acum + a.e(k + 1) * b[k];
  Result := acum;
end;

procedure TFuenteSintetizadorCEGH.SortearEntradaRB(var aRB: NReal);
var
  j, jUltimoRuido: integer;
  UltimoRND: NReal;

begin
  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) then
    jUltimoRuido := jUltimo_Wa_
  else
    jUltimoRuido := jULtimo_RB_;
  {$IFDEF DEBUG_SORTEOS}
  Write(fdebug_sorteos, globs.FechaInicioDelpaso.AsISOStr: 20);
  {$ENDIF}
  for j := jPrimer_RB_ to jUltimoRuido do
  begin
    repeat
      UltimoRND := fuenteGaussiana.rnd;
    until (-3.69 <= UltimoRND) and (UltimoRND <= 3.69);
    TVLArrOfNReal_0(pointer(@aRB)^)[j] := UltimoRND;
    {$IFDEF DEBUG_SORTEOS}
    Write(fdebug_sorteos, #9, UltimoRND: 12: 4);
    {$ENDIF}
  end;
{$IFDEF DEBUG_SORTEOS}
  writeln(fdebug_sorteos);
{$ENDIF}

end;

procedure TFuenteSintetizadorCEGH.ValorEsperadoEntradaRB(var aRB: Nreal);
var
  j, jUltimoRuido: integer;
begin
  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) then
    jUltimoRuido := jUltimo_Wa_
  else
    jUltimoRuido := jULtimo_RB_;

  for j := jPrimer_RB_ to jUltimoRuido do
    TVLArrOfNReal_0(pointer(@aRB)^)[j] := 0;
end;

// Hace efectivo el cambio de estado haciendo EstadoK_origen:= EstadoK_aux
procedure TFuenteSintetizadorCEGH.EvolucionarEstado;
var
  i: integer;
begin
  {$IFDEF RESUMEN_POSTIZADO}
  Write(fdebug, globs.kPaso_, #9, globs.kSubPaso_);
  for i := 0 to high(Bornera) do
    Write(fdebug, #9, Bornera[i]);
  writeln(fdebug);
  {$ENDIF}

  for i := 0 to dim_X - 1 do
    Bornera[jPrimer_X + i] := Bornera[jPrimer_Xs + i];

  if simularConDatosHistoricos then
  begin
    vswap(indicesDatosHistoricos, indicesDatosHistoricos_s);
    vswap(pesosDatosHistoricos, pesosDatosHistoricos_s);
  end;
end;

function TFuenteSintetizadorCEGH.Gaussianar_(datosModelo: TModeloCEGH;
  xNoGaussiana: NReal; kBorne: integer; fecha: TFecha): NReal;
begin
  //el false en usarProximosDeformadoresAlterados no esta bien. en verdad debería seleccionarse
  //los deformadores alterados que correspondan a la fecha, no necesariamente los proximos,
  //si al inicializar en sim_cronica_inicio se toman varios datos para atras.
  //Si se toma UN SOLO valor en el sim_cronica_inicio si esta bien porque tiene
  //que usar los deformadores de la fecha de inicio de la simulacion que vienen
  //cargados en pa
  Result := datosModelo.xTog(xNoGaussiana, kBorne + 1,
    kSelectorDesformador(datosmodelo, fecha) + 1);
end;

procedure TFuenteSintetizadorCEGH.GaussianarRafaga(var destino: TDAOfNReal;
  kBaseDestino: integer; const origen: TDAOfNReal; kBaseOrigen: integer;
  NBornesDestino, NRetardosXDestino: integer; NBornesOrigen: integer;
  datosModelo: TModeloCEGH; fecha: TFecha);

var
  kBorne, kSelector: integer;
  jRetardo: integer;
  j_x, j_y: integer;
  xFecha: TFecha;
begin
  xFecha := TFecha.Create_Clone(fecha);
  for jRetardo := 0 to NRetardosXDestino - 1 do
  begin
    kSelector := kSelectorDesformador(datosmodelo, xFecha) + 1;
    j_x := kBaseDestino + jRetardo * NBornesDestino;
    j_y := kBaseOrigen + jRetardo * NBornesOrigen;
    //Ver el comentario en Gaussianar_
    for kBorne := 0 to NBornesDestino - 1 do
      destino[j_x + kBorne] :=
        datosModelo.xTog(origen[j_y + kBorne], kBorne + 1, kSelector);
    xFecha.addHoras(-self.durPasoDeSorteoEnHoras);
  end;
  xFecha.Free;
end;


procedure TFuenteSintetizadorCEGH.calcular_Xs;
var
  i, j: integer;
  //  AiporX, BiporRB: NReal;
  //  Mi: TVectR;

  fechaProximoSorteo: TFecha;
  hayQueCalcularSalidas: boolean;
  dm: TModeloCEGH;
  mval: NReal;

  aPronostico: TPronostico;
  usarCono: TDAOfBoolean;
  kSesgo: TDAOfNInt;
  kFactor: TDAofNInt;
  kSerie: integer;

  kSelector, lugarValorActual, ultimoLugar, kBornera: integer;

  sesgo, factor: NReal;
  vectorEntrada: TDAofNReal;
  bornera_aux, bornera_entrada_aux: TDAofNReal;
  fdebug: TextFile;
  idbg: integer;
  kfuenteIN: TFuenteAleatoria;
  kborneIN: string;
  kEntrada, lugarBorne: integer;
  valorEntrada, valorEntrada_gaussiano: NReal;
  nombreBorneIN: string;
  lugarBorneIN: integer;

label  // por claridad del código - no sacar
  lbl_Optimizando,
  lbl_SimulandoConSeriesSinteticas,
  lbl_SimulandoConSeriesHistoricas,
  lbl_Continuar;

begin

  setlength(usarCono, escenarioSorteados.Count);
  setlength(kSesgo, escenarioSorteados.Count);
  setlength(kFactor, escenarioSorteados.Count);
  for kSerie := 0 to escenarioSorteados.Count - 1 do
  begin
    aPronostico := TPronostico(escenarioSorteados.items[kSerie]);
    usarCono[kSerie] := aPronostico.fechaEnRango(globs.FechaInicioDelpaso,
      kSesgo[kSerie], kFactor[kSerie]);
  end;

  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) then
    dm := datosModelo_Opt
  else
    dm := datosModelo_Sim;

  if dm.A_cte <> nil then
    kSelector := 0
  else
    kSelector := dm.kSelectorDeformador(globs.FechaInicioDelpaso);

  if (globs.EstadoDeLaSala <> CES_OPTIMIZANDO) then
    if simularConDatosHistoricos then
      goto lbl_SimulandoConSeriesHistoricas
    else
      goto lbl_SimulandoConSeriesSinteticas;

  lbl_Optimizando:
    hayQueCalcularSalidas := True;
  for i := 0 to dm.nBornesSalida - 1 do
  begin
    calcularSalidaBorne[i] := True;
    if usarCono[i] then
    begin
      aPronostico := TPronostico(escenarioSorteados.items[i]);
      if kSesgo[i] >= 0 then
      begin
        if kFactor[i] >= 0 then
          Bornera[jPrimer_Xs_x + i] :=
            dm.CalcularSalidaConSesgo(i + 1, @Bornera[jPrimer_X_x],
            @Bornera[jPrimer_rb_], aPronostico.sesgo[kSesgo[i]],
            aPronostico.factor[kFactor[i]], kSelector)
        else
          Bornera[jPrimer_Xs_x + i] :=
            dm.CalcularSalidaConSesgo(i + 1, @Bornera[jPrimer_X_x],
            @Bornera[jPrimer_rb_], aPronostico.sesgo[kSesgo[i]], 1.0, kSelector);
      end
      else
      begin // lods dos < 0 no se puede dar si usarCono = true
        Bornera[jPrimer_Xs_x + i] :=
          dm.CalcularSalidaConSesgo(i + 1, @Bornera[jPrimer_X_x],
          @Bornera[jPrimer_rb_], 0, aPronostico.factor[kFactor[i]], kSelector);
      end;
    end
    else
    {$IFDEF MODELO_ENTRADA_SALIDA}
    if flg_MODELO_ENTRADA_SALIDA = false then
    begin
      {$IFDEF DEBUGBORNERA}
      //debug
      AssignFile(fdebug, '/home/vcamacho/Documentos/CEGH_fraccionador/sala2120/bornera_in34.txt');
      rewrite(fdebug);

      Write(fdebug, #9, 'Bornera Antes');
      writeln(fdebug);
      for idbg := 0 to high(Bornera) do
        Write(fdebug, #13#10, Bornera[idbg]);
      writeln(fdebug);
      {$ENDIF}
      Bornera[jPrimer_Xs_x + i] :=
        dm.CalcularSalida(i + 1, @Bornera[jPrimer_X_x], @Bornera[jPrimer_rb_],
        kSelector);
     {$IFDEF DEBUGBORNERA}
      Write(fdebug, #9, 'Bornera Despues');
      writeln(fdebug);
      for idbg := 0 to high(Bornera) do
          Write(fdebug, #13#10, Bornera[idbg]);
      writeln(fdebug);
      closefile(fdebug);
      {$ENDIF}
    end
    else
    begin
      //cuando tengo modelo como entrada salida, es el vector de estados y la bornera externa que hay que
      //pasar por el filtro, es el borne de la fuente que se uso como entrada para hacer el CEGH
      {$IFDEF DEBUGBORNERA}
      AssignFile(fdebug, '/home/vcamacho/Documentos/CEGH_fraccionador/sala2120/bornera.txt');
      rewrite(fdebug);
      {$ENDIF}
      SetLength(bornera_entrada_aux, fuentesEntrada.Count); // todavia no esta para mas de 1 retardo
      for kEntrada := 0 to fuentesEntrada.Count - 1 do
      begin

        kfuenteIN := TFuenteAleatoria_Borne(fuentesEntrada[kEntrada]).fuente;
        kborneIN := TFuenteAleatoria_Borne(fuentesEntrada[kEntrada]).borne;

        //buscar el lugar del borne
      //  lugarBorne := searchinlist(kborneIN, kfuenteIN.NombresDeBornes_Publicados);
     //   lugarValorActual := kfuenteIN.jPrimer_X + lugarBorne;
     //   bornera_entrada_aux[kEntrada] := kfuenteIN.Bornera[lugarValorActual];
        lugarBorne := kfuenteIN.IdBorne(kborneIN);
        valorEntrada := kfuenteIN.Bornera[lugarBorne];
        //el nombre del borne de entrada en el modelo CEGH no tiene porque
        //llamarse igual que el nombre de la fuente de entrada.
        //Tengo que saberlo para los deformadores
        nombreBorneIN := dm.NombresDeBornes_Entradas[kEntrada];
        lugarBorneIN := searchinlist(nombreBorneIN, dm.NombresDeBornes_Publicados);
        valorEntrada_gaussiano := Gaussianar_(dm, valorEntrada, lugarBorneIN, globs.pasoToFechaOpt(globs.kPaso_Opt));//FechaInicioDelpaso);
        bornera_entrada_aux[kEntrada] := valorEntrada_gaussiano;

      end;

      {$IFDEF DEBUGBORNERA}
      ////////////debug
      WriteLn(fdebug, 'fuenteIN Bornera');
      writeln(fdebug);
      for idbg := 0 to high(kfuenteIN.Bornera) do
        Writeln(fdebug, kfuenteIN.Bornera[idbg]);
      writeln(fdebug);

       Write(fdebug, #9, 'Bornera Antes');
       writeln(fdebug);
      for idbg := 0 to high(Bornera) do
        Write(fdebug, #13#10, Bornera[idbg]);
      writeln(fdebug);
      {$ENDIF}

      Bornera[jPrimer_Xs_x + i] :=
        dm.CalcularSalidaModeloEntradaSalida(i + 1, @Bornera[jPrimer_X_x], @bornera_entrada_aux[0],
        @Bornera[jPrimer_rb_], kSelector);
     {$IFDEF DEBUGBORNERA}
     Write(fdebug, #9, 'Bornera Despues');
     writeln(fdebug);
     for idbg := 0 to high(Bornera) do
       Write(fdebug, #13#10, Bornera[idbg]);
     writeln(fdebug);

     Write(fdebug, #9, 'Bornera aux');
     writeln(fdebug);
     for idbg := 0 to high(bornera_aux) do
      Write(fdebug, #13#10, bornera_aux[idbg]);
     writeln(fdebug);

     Write(fdebug, #9, 'bornera_entrada_aux');
     writeln(fdebug);
     for idbg := 0 to high(bornera_entrada_aux) do
       Write(fdebug, #13#10, bornera_entrada_aux[idbg]);
     writeln(fdebug);

     closefile(fdebug);
    {$ENDIF}
    end;
    {$ELSE}
      Bornera[jPrimer_Xs_x + i] :=
        dm.CalcularSalida(i + 1, @Bornera[jPrimer_X_x], @Bornera[jPrimer_rb_],
        kSelector);
    {$ENDIF}

  end;
  goto lbl_Continuar;

  lbl_SimulandoConSeriesSinteticas:
    hayQueCalcularSalidas := False;

  for i := 0 to dm.nBornesSalida - 1 do
  begin
    aPronostico := escenarioSorteados[i] as TPronostico;
    begin
      // ya no es determinístico.
      calcularSalidaBorne[i] := True;
      if usarCono[i] then
      begin

        if kSesgo[i] >= 0 then
          sesgo := aPronostico.sesgo[kSesgo[i]]
        else
          sesgo := 0;

        if kFactor[i] >= 0 then
          factor := aPronostico.factor[kFactor[i]]
        else
          factor := 1;

        Bornera[jPrimer_Xs_x + i] :=
          dm.CalcularSalidaConSesgo(i + 1, @Bornera[jPrimer_X_x],
          @Bornera[jPrimer_rb_], sesgo, factor, kSelector);
      end
      else
      if flg_MODELO_ENTRADA_SALIDA = false then
      begin
       {$IFDEF DEBUGBORNERA}
      //debug
      AssignFile(fdebug, '/home/vcamacho/Documentos/CEGH_fraccionador/sala2120/bornera_in34.txt');
      rewrite(fdebug);

      Write(fdebug, #9, 'Bornera Antes');
      writeln(fdebug);
      for idbg := 0 to high(Bornera) do
        Write(fdebug, #13#10, Bornera[idbg]);
      writeln(fdebug);
      {$ENDIF}
        Bornera[jPrimer_Xs_x + i] :=
          dm.CalcularSalida(i + 1, @Bornera[jPrimer_X_x], @Bornera[jPrimer_rb_],
          kSelector);
      {$IFDEF DEBUGBORNERA}
       Write(fdebug, #9, 'Bornera Despues');
       writeln(fdebug);
       for idbg := 0 to high(Bornera) do
           Write(fdebug, #13#10, Bornera[idbg]);
       writeln(fdebug);
       closefile(fdebug);
       {$ENDIF}
      end
      else
      begin
        //cuando tengo modelo como entrada salida, es el vector de estados y la bornera externa que hay que
        //pasar por el filtro, es el borne de la fuente que se uso como entrada para hacer el CEGH
        {$IFDEF DEBUGBORNERA}
        AssignFile(fdebug, '/home/vcamacho/Documentos/CEGH_fraccionador/sala2120/bornera.txt');
        rewrite(fdebug);
        {$ENDIF}
        SetLength(bornera_entrada_aux, fuentesEntrada.Count); // todavia no esta para mas de 1 retardo
        for kEntrada := 0 to fuentesEntrada.Count - 1 do
        begin

          //kfuenteIN := TFuenteAleatoria_Borne(fuentesEntrada[kEntrada]).fuente;
          //kborneIN := TFuenteAleatoria_Borne(fuentesEntrada[kEntrada]).borne;
          //
          ////buscar el lugar del borne
          //lugarBorne := searchinlist(kborneIN, kfuenteIN.NombresDeBornes_Publicados);
          //
          //lugarValorActual := kfuenteIN.jPrimer_X + lugarBorne;
          //bornera_entrada_aux[kEntrada] := kfuenteIN.Bornera[lugarValorActual];

          //simulando
          kfuenteIN := TFuenteAleatoria_Borne(fuentesEntrada[kEntrada]).fuente;
          kborneIN := TFuenteAleatoria_Borne(fuentesEntrada[kEntrada]).borne;

          lugarBorne := kfuenteIN.IdBorne(kborneIN);
          valorEntrada := kfuenteIN.Bornera[lugarBorne];
          //el nombre del borne de entrada en el modelo CEGH no tiene porque
          //llamarse igual que el nombre de la fuente de entrada.
          //Tengo que saberlo para los deformadores
          nombreBorneIN := dm.NombresDeBornes_Entradas[kEntrada];
          lugarBorneIN := searchinlist(nombreBorneIN, dm.NombresDeBornes_Publicados);;
          valorEntrada_gaussiano := Gaussianar_(dm, valorEntrada, lugarBorneIN, globs.pasoToFechaOpt(globs.kPaso_Sim));
          bornera_entrada_aux[kEntrada] := valorEntrada_gaussiano;

        end;
        {$IFDEF DEBUGBORNERA}
        ////////////debug
        WriteLn(fdebug, 'fuenteIN Bornera');
        writeln(fdebug);
        for idbg := 0 to high(kfuenteIN.Bornera) do
          Writeln(fdebug, kfuenteIN.Bornera[idbg]);
        writeln(fdebug);

         Write(fdebug, #9, 'Bornera Antes');
         writeln(fdebug);
        for idbg := 0 to high(Bornera) do
          Write(fdebug, #13#10, Bornera[idbg]);
        writeln(fdebug);
        {$ENDIF}

        Bornera[jPrimer_Xs_x + i] :=
          dm.CalcularSalidaModeloEntradaSalida(i + 1, @Bornera[jPrimer_X_x], @bornera_entrada_aux[0],
          @Bornera[jPrimer_rb_], kSelector);
        {$IFDEF DEBUGBORNERA}
        Write(fdebug, #9, 'Bornera Despues');
        writeln(fdebug);
        for idbg := 0 to high(Bornera) do
          Write(fdebug, #13#10, Bornera[idbg]);
        writeln(fdebug);

        Write(fdebug, #9, 'Bornera aux');
        writeln(fdebug);
        for idbg := 0 to high(bornera_aux) do
         Write(fdebug, #13#10, bornera_aux[idbg]);
        writeln(fdebug);

        Write(fdebug, #9, 'bornera_entrada_aux');
        writeln(fdebug);
        for idbg := 0 to high(bornera_entrada_aux) do
          Write(fdebug, #13#10, bornera_entrada_aux[idbg]);
        writeln(fdebug);

        closefile(fdebug);
       {$ENDIF}

      end;

      {  Bornera[jPrimer_Xs_x + i] :=
          dm.CalcularSalida(i + 1, @Bornera[jPrimer_X_x], @Bornera[jPrimer_rb_],
          kSelector);  }
      hayQueCalcularSalidas := True;
    end;
  end;
  goto lbl_Continuar;

  lbl_SimulandoConSeriesHistoricas:
    hayQueCalcularSalidas := False;

  fechaProximoSorteo := TFecha.Create_OffsetHoras(globs.FechaInicioDelpaso,
    durPasoDeSorteoEnHoras);

  if sincronizarConSemillaAleatoria then
    datosHistoricos.calc_indices_y_pesos_dt(
      DespAnios_IniSim_IniDatosHistoricos - globs.ultimaSemillaFijada,
      fechaProximoSorteo.dt,
      indicesDatosHistoricos_s, pesosDatosHistoricos_s)
  else
  if sincronizarConHistoricos then
    datosHistoricos.calc_indices_y_pesos_dt(
      DespAnios_IniSim_IniDatosHistoricos,
      fechaProximoSorteo.dt,
      indicesDatosHistoricos_s, pesosDatosHistoricos_s)
  else
    datosHistoricos.calc_indices_y_pesos_dt(
      DespAnios_IniSim_IniDatosHistoricos - globs.kCronica_,
      fechaProximoSorteo.dt,
      indicesDatosHistoricos_s, pesosDatosHistoricos_s);



  for i := 0 to dm.nBornesSalida - 1 do
  begin
    mval := datosHistoricos.get_mval_(i, IndicesDatosHistoricos_s,
      PesosDatosHistoricos_s);
    Bornera[jPrimer_Xs_y + i] := mval;
    Bornera[jPrimer_Xs_x + i] := Gaussianar_(dm, mval, i, fechaProximoSorteo);
  end;
  fechaProximoSorteo.Free;


  lbl_Continuar:

(*
// si NRetardos_X > 1

Bien, una vez calculado el Xs correspondiente a los bornes de salida,
si NRetardos_X > 1 tenemos que rellenar el tramo de Xs que no corresponde
directamente a los bornes de salida copiando de X lo que le va a tocar
cuando se produzca el desplazamiento en "evolucionar estado" *)

    for j := jPrimer_Xs_x + dm.nBornesSalida to jUltimo_Xs_x do
      Bornera[j] := Bornera[j - dim_x - dm.nBornesSalida];

  // esto no se si importa, pero por las dudas lo hago.
  for j := jPrimer_Xs_y + dm.nBornesSalida to jUltimo_Xs_y do
    Bornera[j] := Bornera[j - dim_x - dm.nBornesSalida];

  (* fin del rellando de Xs e Ys *)


  if hayQueCalcularSalidas then
    calcularSalidasDeX(dm, True, calcularSalidaBorne);

  setlength(usarCono, 0);
  setlength(kSesgo, 0);
  setlength(kFactor, 0);
end;

destructor TFuenteSintetizadorCEGH.destroy;
begin

  {$IFDEF RESUMEN_POSTIZADO}
  closefile(fdebug);
  {$ENDIF}

  (* Globs se encarga de liberar las MadresUniformes
  if sorteadorDePronosticos_ <> nil then
    sorteadorDePronosticos_.Free;
    *)

  if modeloAuxiliar <> nil then
  begin
   {$IFDEF CEGH_CREATE_NOCOMPRATIDO}
    modeloAuxiliar.Free;
    modeloAuxiliar := nil;
    {$ELSE}
    Free_ModeloCEGH(modeloAuxiliar);
    {$ENDIF}
  end;

  if datosHistoricos <> nil then
  begin
    datosHistoricos.Free;
    datosHistoricos := nil;
  end;

  if escenariosDePronosticos <> nil then
  begin
    escenariosDePronosticos.Free;
    escenariosDePronosticos := nil;
  end;

  {$IFDEF CEGH_CREATE_NOCOMPRATIDO}
  datosModelo_Sim.Free;
  {$ELSE}
  Free_ModeloCEGH(datosModelo_Sim);
  {$ENDIF}

  setlength(calcularSalidaBorne, 0);
  setlength(todosLosBornesEnTrue, 0);
  setlength(XRed, 0);
  setlength(XsRed, 0);
  setLength(XRed_aux, 0);

  setlength(indicesDatosHistoricos, 0);
  setlength(pesosDatosHistoricos, 0);
  setlength(indicesDatosHistoricos_s, 0);
  setlength(pesosDatosHistoricos_s, 0);

  if fuenteGaussiana <> nil then
  begin
    fuenteGaussiana.Free;
  end;


  if fuentesEntrada <> nil then
  begin
    fuentesEntrada.Free;
  end;

   inherited destroy;
end;



procedure TFuenteSintetizadorCEGH.PubliVars;
var
  k: integer;
  NSeries: integer;

begin
  inherited PubliVars;

  NSeries := self.datosModelo_Sim.nBornesSalida;

  for k := jPrimer_RB_ to jUltimo_RB_ do
    PublicarVariableNR('RB_' + NombresDeBornes_Publicados[k - jPrimer_RB_],
      'p.u.', 12, 3, bornera[k], True);

  for k := jPrimer_Wa__ to jUltimo_Wa_ do
    PublicarVariableNR('Wa_' + IntToStr(1 + k - jPrimer_Wa__), 'p.u.',
      12, 3, bornera[k], True);

  for k := jPrimer_X_x to jUltimo_X_x do
    PublicarVariableNR('X_' + NombresDeBornes_Publicados[(k - jPrimer_X_x) mod
      NSeries], 'p.u.', 12, 3, bornera[k], True);

  for k := jPrimer_X_y to jUltimo_X_y do
    PublicarVariableNR('Y_' + NombresDeBornes_Publicados[(k - jPrimer_X_y) mod
      NSeries], '_', 12, 3, bornera[k], True);

  for k := jPrimer_Xs_x to jUltimo_Xs_x do
    PublicarVariableNR('Xs_' + NombresDeBornes_Publicados[(k - jPrimer_Xs_x) mod
      NSeries], 'p.u.', 12, 3, bornera[k], True);

  for k := jPrimer_Xs_y to jUltimo_Xs_y do
    PublicarVariableNR('Ys_' + NombresDeBornes_Publicados[(k - jPrimer_Xs_y) mod
      NSeries], '_', 12, 3, bornera[k], True);

  for k := jPrimer_BC to jUltimo_BC do
    PublicarVariableNR('BC_' + IntToStr(1 + k - jPrimer_BC), '_',
      12, 3, bornera[k], True);

  PublicarVariableVR('XRed', '-', 15, 15, XRed, False, True);

end;

(*
function TFuenteSintetizadorCEGH.getIndiceDato__(fecha: TFecha;
  nAnios_offsetDatos: integer): integer;
var
  iterFechaIniSorteo, iterFechaFinSorteo: TFecha;
  indiceDatos: integer;
  desp: NReal;
begin
  if SincronizarConHistoricos then
    indiceDatos := datosHistoricos.locate_fecha_(fecha, desp )
  else
    indiceDatos := datosHistoricos.locate_fecha_ignore_anio_(fecha, nAnios_offsetDatos, desp );

  if indiceDatos < 0 then
    raise Exception.Create(
      'Error en: TFuenteSintetizadorCEGH.getIndiceDto_InicioAnio ' + Nombre);
  Result := indiceDatos;
end;
  *)

procedure TFuenteSintetizadorCEGH.InitModeloFromFile;
var
  i: integer;
begin

  if nombreArchivoModelo.testearYResolver then
  begin
    {$IFDEF CEGH_CREATE_NOCOMPRATIDO}
    if datosModelo_Sim <> nil then
      datosModelo_Sim.Free
    else
      datosModelo_Sim := TModeloSintetizadorCEGH.CreateFromArchi(
        nombreArchivoModelo.archi);
    {$ELSE}
    Change_ModeloCEGH(nombreArchivoModelo.ArchiRef.get_archi, datosModelo_Sim);
    {$ENDIF}

    self.durPasoDeSorteoEnHoras := datosModelo_Sim.durPasoDeSorteoEnHoras;

    if NombresDeBornes_Publicados <> nil then
      NombresDeBornes_Publicados.Clear
    else
      NombresDeBornes_Publicados := TStringList.Create;

    // esto se inicaliza de nuevo en preparar memoria, pero se necesita
    // aquí para que el editor de SimRes3 funcione
    setlength(bornera, dim_RB + dim_X + dim_Xs + dim_BC);

    for i := 0 to datosModelo_Sim.NombresDeBornes_Publicados.Count - 1 do
    begin
      self.NombresDeBornes_Publicados.Add(
        datosModelo_Sim.NombresDeBornes_Publicados[i]);
      //    fuenteGaussiana:= Tf_ddp_GaussianaNormal.Create( 0 );
    end;

  end
  else
    raise ExceptionFileNotFound.Create(nombreArchivoModelo.ArchiRef.get_archi,
      exCreandoLaFuente +' '+ ClaseNombre);

  // si hay un modelo auxiliar para la optimización lo cargo.
  if self.usarModeloAuxiliar then
    if nombreArchivoModeloAuxiliar.testearYResolver then
    begin
      {$IFDEF CEGH_CREATE_NOCOMPRATIDO}
      if modeloAuxiliar <> nil then
        modeloAuxiliar.Free;
      modeloAuxiliar := TModeloSintetizadorCEGH.CreateFromArchi(
        nombreArchivoModeloAuxiliar.archi);
      {$ELSE}
      Change_ModeloCEGH(nombreArchivoModeloAuxiliar.ArchiRef.get_archi, modeloAuxiliar);
      {$ENDIF}
    end
    else
     raise ExceptionFileNotFound.Create(nombreArchivoModelo.ArchiRef.get_archi,
        exCreandoLaFuente + ClaseNombre);

  if self.usarModeloAuxiliar then
    datosModelo_Opt := modeloAuxiliar
  else
    datosModelo_Opt := datosModelo_Sim;

  setlength(XRed, datosModelo_Opt.nVE);
  setlength(XsRed, datosModelo_Opt.nVE);
  setlength(XRed_aux, datosModelo_Opt.nVE_aux);


  {$IFDEF RESUMEN_POSTIZADO}
  assignfile(fdebug, getDir_Dbg + DirectorySeparator + nombre +
    '_debug_resumen_postizado.xlt');
  rewrite(fdebug);
  {$ENDIF}

end;

procedure TFuenteSintetizadorCEGH.PrepararMemoria_pre(
  Catalogo: TCatalogoReferencias; globs: TGlobs);
begin
  inherited PrepararMemoria_pre(Catalogo, globs);
  InitModeloFromFile;
  if simularConDatosHistoricos then
    InitDatosHistoricosFromFile;
end;

procedure TFuenteSintetizadorCEGH.InitDatosHistoricosFromFile;
var
  i: integer;
  mismosBornes: boolean;
  archi: string;
begin

  try
    if nombreArchivoDatosHistoricos.flg_nubeseable then
      archi := nombreArchivoDatosHistoricos.ArchiRef.get_archi
    else
    begin
      if ucosa.Lista_caminos <> nil then
        archi := ucosa.Lista_caminos.Locate(nombreArchivoDatosHistoricos.ArchiRef.get_archi)
      else
        archi := nombreArchivoDatosHistoricos.ArchiRef.get_archi;
    end;

    datosHistoricos := TDatosHistoricos.CreateFromArchi( archi );

    if self.durPasoDeSorteoEnHoras <> Trunc(datosHistoricos.dt_EntrePuntos *
      dtToHora + 0.001) then
      raise Exception.Create(exArchivoDatosDuracionDistinta);

    mismosBornes := datosHistoricos.NombresDeBornes_Publicados.Count =
      NombresDeBornes_Publicados.Count;
    i := 0;
    while (i < datosHistoricos.NombresDeBornes_Publicados.Count) and mismosBornes do
    begin
      mismosBornes := NombresDeBornes_Publicados[i] =
        datosHistoricos.NombresDeBornes_Publicados[i];
      i := i + 1;
    end;

    if not mismosBornes then
      raise Exception.Create(exBornesArchivoDiferente);

  except
    on e: Exception do
      raise Exception.Create(exCEGHInitDatosHistoricosFromFile+ ' ' +
        e.Message + ' '+exLeyendoLaFuente+ ' ' + nombre);
  end;
end;

procedure TFuenteSintetizadorCEGH.InitFuenteEntrada;
begin
  //por ahora nada
end;

procedure TFuenteSintetizadorCEGH.calcularSalidasDeX(Xs: boolean);
var
  dm: TModeloCEGH;
begin
  if globs.EstadoDeLaSala = CES_SIMULANDO then
    dm := datosModelo_Sim
  else
    dm := datosModelo_Opt;
  calcularSalidasDeX(dm, Xs, todosLosBornesEnTrue);
end;

procedure TFuenteSintetizadorCEGH.calcularSalidasDeX(datosModelo: TModeloCEGH;
  Xs: boolean; calcularBorne: TDAOfBoolean);
var
  i, sel: integer;
  sg: NReal;
  fechaProximoSorteo: TFecha;
begin
  if Xs then
  begin

    fechaProximoSorteo := TFecha.Create_OffsetHoras(globs.FechaInicioDelpaso,
      durPasoDeSorteoEnHoras);
    sel := kSelectorDesformador(datosModelo, fechaProximoSorteo);
    //aplicar funciones deformantes
    for i := 0 to datosModelo.nBornesSalida - 1 do
    begin
      if calcularBorne[i] then
      begin
        sg := Bornera[jPrimer_Xs_x + i];
        bornera[jPrimer_Xs_y + i] :=
          datosModelo.gTox(sg, i + 1, sel + 1);
      end;
    end;
    fechaProximoSorteo.Free;
  end
  else
  begin
    sel := kSelectorDesformador(datosModelo, nil);
    //aplicar funciones deformantes
    for i := 0 to datosModelo.nBornesSalida - 1 do
    begin
      if calcularBorne[i] then
      begin
        sg := Bornera[jPrimer_X_x + i];
        bornera[jPrimer_X_y + i] := datosModelo.gTox(sg, i + 1, sel + 1);
      end;
    end;
  end;
end;

procedure cambioFichaPDFuenteSintetizadorCEGH(fuente: TCosa);
begin
  TFuenteSintetizadorCEGH(fuente).CambioFichaPD;
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(TFuenteSintetizadorCEGH.ClassName, TFuenteSintetizadorCEGH);
  {$IFDEF MODELO_ENTRADA_SALIDA}
//  registrarClaseDeCosa(TFichaEntradasFuenteSintetizador.ClassName, TFichaEntradasFuenteSintetizador);
  {$ENDIF}
  //  registrarClaseDeCosa(TFichaDeterminismo.ClassName, TFichaDeterminismo);
end;

procedure AlFinal;
begin
end;

procedure TFuenteSintetizadorCEGH.ReCalibrarPronosticos(datosModelo: TModeloCEGH;
  fechaIniSim: TFecha);
begin

  ucalibrarconopronosticos.CalibrarConoCentrado(datosModelo,
    escenariosDePronosticos, fechaIniSim);

  escenariosDePronosticos.CalcularMatricesRuida(datosModelo, globs);


end;

// intenta obtener los pronósticos desde las direcciones
// indicadas. El resultado es TRUE si logró obtener todos los pronósticos
// y FALSE en caso contrario.
function TFuenteSintetizadorCEGH.GetPronosticos(fechaIniSim: TFecha): boolean;
var
  rbt: TConsultaPronostico_Cliente;
  kSerie: integer;
  aProno: TPronostico;
  resConsulta: TList_FRVarPronostico;
  aVarProno: TFRVarPronostico;
  desconocidas: string;

begin
  // si no hay una url especificada no consultamos nada.
  if url_get = '' then
  begin
    Result := True;
    exit;
  end;

  rbt := TConsultaPronostico_Cliente.Create(url_get);
  for kSerie := 0 to datosModelo_Sim.NombresDeBornes_Publicados.Count - 1 do
  begin
    aProno := escenariosDePronosticos.items[0].items[0];
    //aProno := escenarioSorteados[kSerie];// pronosticos[kSerie];
    rbt.add(datosModelo_Sim.NombresDeBornes_Publicados[kSerie],
      globs.fechaIniSim.dt, datosModelo_Sim.durPasoDeSorteoEnHoras * 3600.0,
      datosModelo_Sim.CalcOrdenDelFiltro, aProno.NPCC);
  end;
  resConsulta := rbt.get_pronostico;
  rbt.Free;

  if resConsulta.Count <> datosModelo_Sim.NombresDeBornes_Publicados.Count then
    raise Exception.Create('Fuente sintetizador CEGH ' + self.nombre +
      ' consulto pronostico por: ' + IntToStr(
      datosModelo_Sim.NombresDeBornes_Publicados.Count) +
      ' series, pero obtuvo ' + IntToStr(resConsulta.Count) + ' fichas de resultado.');

  desconocidas := '';
  for kSerie := 0 to datosModelo_Sim.NombresDeBornes_Publicados.Count - 1 do
  begin
    //    aProno := escenarioDePronosticos.items[0].items[0];//escenarioSorteados[kSerie];
    aVarProno := resConsulta[kSerie];
    if aVarProno.NPCC = -1 then
      desconocidas := desconocidas + ', ' + aVarProno.nombre;
    if datosModelo_Sim.NombresDeBornes_Publicados[kSerie] <> aVarProno.nombre then
      raise Exception.Create('Error en nombre de pronóstico, se esperaba: ' +
        datosModelo_Sim.NombresDeBornes_Publicados[kSerie] + ' se obtuvo: ' +
        aVarProno.nombre);
  end;

  if desconocidas <> '' then
  begin
    writeln('Lo siento el servidor de pronósticos no reconoce las variables: ' +
      desconocidas);
    Result := False;
  end
  else
  begin
    for kSerie := 0 to datosModelo_Sim.NombresDeBornes_Publicados.Count - 1 do
    begin
      aProno := escenariosDePronosticos.items[0].items[0];//escenarioSorteados[kSerie];
      aVarProno := resConsulta[kSerie];
      aProno.Cambiar_GUIA(aVarProno.NPCC, aVarProno.NPLC, aVarProno.NPSA,
        aVarProno.NPAC, aVarProno.guia_p50);
    end;
    Result := True;
  end;

  resConsulta.Free;
end;

function TFuenteSintetizadorCEGH.getArchiRefLst: TListaDeArchiRef_Nubeseable;
var
   res: TListaDeArchiRef_Nubeseable;
begin
  res:= TListaDeArchiRef_Nubeseable.Create(capa,'FuenteSintetizador');
  if nombreArchivoDatosHistoricos <> nil then
     res.Add(nombreArchivoDatosHistoricos);
  if nombreArchivoModelo <> nil then
     res.Add(nombreArchivoModelo);
  if nombreArchivoModeloAuxiliar <> nil then
     res.Add(nombreArchivoModeloAuxiliar);
  Result:=res;
end;

function TFuenteSintetizadorCEGH.referenciaFuente(fuente: TFuenteAleatoria): boolean;
var
  res: boolean;
  i: integer;
begin
  res := False;

  {$IFDEF  MODELO_ENTRADA_SALIDA}
  if fuentesEntrada <> nil then
  begin
    for i := 0 to fuentesEntrada.Count - 1 do
    begin
      if (fuente = TFuenteAleatoria_Borne(fuentesEntrada[i]).fuente) then
      begin
        res := True;
      end;
    end;
  end;
  {$ENDIF}

  Result := res;
end;


initialization
  {$IFDEF DEBUG_SORTEOS}
  assignfile(fdebug_sorteos, 'c:\simsee\bin\debug_sorteos.xlt');
  rewrite(fdebug_sorteos);
  {$ENDIF}

  {$IFDEF LOG_APLICAR_FACTOR_EN_OPT}
  assignfile(flog_aplicar_factor_en_opt, 'sintetizador_factor_opt_log.xlt');
  rewrite(flog_aplicar_factor_en_opt);
  {$ENDIF}

  {$IFDEF LOG_RUIDA_PRONOS}
  assignfile(flog_ruida_pronos, 'sintetizador_flog_ruida_pronos.xlt');
  rewrite(flog_ruida_pronos);
  {$ENDIF}



finalization
{$IFDEF DEBUG_SORTEOS}
  closefile(fdebug_sorteos);
{$ENDIF}

{$IFDEF LOG_APLICAR_FACTOR_EN_OPT}
  closefile(flog_aplicar_factor_en_opt);
 {$ENDIF}

{$IFDEF LOG_RUIDA_PRONOS}
  CloseFile(flog_ruida_pronos);
{$ENDIF}

end.
