unit uplanes;
{xDEFINE CLUSTER}
(* Si CLUSTER está definida conecta con el NODO1 del CLUSTER y por tunnel
   al port 80 del IIE para acceso a la DB vía roscon.
   Si CLUSTER no está definida conecta al puerto 80 del IIE para acceder
   a la DB vía roscon

   Esta variable es mejor definirla directamente en el script de compilación
   del CLUSTER así de afuera funciona conectado directo al IIE.

   *)

{xDEFINE WTI_EIA_LOW}
{$DEFINE WTI_EIA_REF}
{xDEFINE WTI_EIA_HIG}
(* Según cual de los tres aneriores están definidos se define el escenario
   del WTI.
   Se utiliza un sintetizador CEGH del WTI y se utiliza el escenario dela EIA para
   multiplicar las salidas del CEGH por un índice construido a partir del escenario.  *)

{$DEFINE SOLOGAS}
(* Si está definido SOLOGAS la expansión térmica se realiza en base a centrales
   de ciclo combinado a gas natural.
   Si no está definido SOLOGAS la expansión térmica se realiza en base a
   centrales de carbón. *)


{xDEFINE SINEOLICO}
(* Si SINEOLICO está definido la expansión se realiza sólo en base a térmicas
  esto se hizo para ver qué pasaba si se expande sólo en base a térmicas.
   Esta variable también cambia la "tabla de evaluaciones" en la que se almacenan
  los resultados en la DB del IIE. *)



(* SQL para crear tabla evaluaciones

CREATE TABLE `clbr_agosto2011sa` (
  `nid` int(11) NOT NULL DEFAULT '0',
  `poblacion` int(11) DEFAULT NULL,
  `adn` text,
  `dtc` datetime DEFAULT NULL,
  `dtu` datetime DEFAULT NULL,
  `cnt_evaluaciones` int(11) DEFAULT '0',
  `cad` double DEFAULT NULL,
  `cad_min` double DEFAULT NULL,
  `cad_max` double DEFAULT NULL,
  `cadpe5` double DEFAULT NULL,
  `cadpe5_min` double DEFAULT NULL,
  `cadpe5_max` double DEFAULT NULL,
  `vcads` text, `vcadspe5` text,
  `cpialfa` double DEFAULT '0',
  `haygas` tinyint(4) DEFAULT NULL,
  `sineolico` tinyint(4) NOT NULL DEFAULT '0',
  `idnodo` int(11) DEFAULT '0',
  `cpibeta` double DEFAULT '0',
  `aux` tinyint(4) DEFAULT '0',
  PRIMARY KEY (`nid`) )

vcads tiene el vector de los valores esperados de los CAD anuales, promedio de las diferentes evaluaciones.
vcadspe5 tiene el vector de los valores CADpe5 anuales, promedio de las diferentes evaluaciones.
cpialfa tien el costo asignado al plan con la aversion al riesgo alfa.

Cómo se calcula cpialfa a partir de vcads y vcadspe5 es parte de la investigación en curso.
Para eso se implementa la

function calc_cpialfa(
  const alfa: NReal;
  const vcads, vcadspe5: TDAOfNReal;
  const Cad: NReal
): NReal;

function calc_cpibeta(
  const beta: NReal;
  const vcads, vcadspe5: TDAOfNReal;
  const Cad: NReal
): NReal;

*)

interface

uses
  Classes, SysUtils,
  uauxiliares,
{$IFDEF WINDOWS}
  shellApi,
  Windows,
  Messages,
{$ELSE}
  baseunix,
{$ENDIF}
  uDataSetGenerico, urosx,
  xMatDefs,
  uConstantesSimSEE,
  ufechas,
  upreprocesador,
  Math,
  usalasdejuego,
  ucosa,
  uSustituirVariablesPlantilla,
  uInicioYFinal;


const
  // ultima version del historial
  UltimaVersion_historial = 1;

  // nmobre de la sala
  CarpetaSala = '';
  NombreSala  = 'x';

  TablaEvaluaciones = 'clbr_optgen_gpa';

  //HistorialPlano    = '/home/rchaer/historialplano.txt';
  // archivo usado para hacer la sustitución de variables y generar la sala
  ArchPlantillaSala = CarpetaSala + 'optgen_agosto2011_base.txt';


  // archivo con definición de variables a monitorear
  ArchMonitor_vcads = 'vcads.mon';
  // archivo de texto con el resultado del monitoreo (en formato SimRes3 ).
  ArchResMonitor_vcads = 'vcads_cronicos.xlt';  // no se usa aquí, está en la plantilla
  // plantilla SimRes3 para cálculo de los costos anuales a partir del ArchResMonitor_
  ArchPlantillaSimRes3_vcads = 'PlantillaSimres3_vcads.txt';

  // resultados
  Arch_vcads= 'vcads_VEyPE5.xlt';


  // archivo sala para ejecución
  ArchSala = NombreSala + '.ese';

  // archivo con resultado global de la simulación.
  ArchRes_begin = 'simcosto_';
  ArchRes_end = 'x100.xlt';


  AnioEolico = 2013; // posibilidad de ingreso de primeros proyectos
  AnioGas    = 2014; // gas disponible

  AEcoIni = 2009;
  AEcoFin = 2026;
  NFechas = AEcoFin + AEcoIni + 2; // agrego una más para la por defecto
  MaxNIncorporacion_eolico = 10;   // parques de 20 MW cada uno/año  = 200 MW
  MaxNIncorporacion_C180 = 3;      // 3 máquinas /año = 180x3 = 540 MW
  MaxNAparemientos = 8;

var
  // semilla aleatoria
  semillaAleatoria_: integer;


type

  TPlan = class;

  TPlan = class
    idPlan: integer; // número asignado por el servidor -1 si no fue asignado
    poblacion: Integer; //indica si provino de genetica o de gradiente promedio

    // ADN========
    unidades_eolico, unidades_C180: TDAOfNint;
    unidades_eolico_acum, unidades_C180_acum: TDAOFNInt;
    haygas: boolean;
    sineolico: boolean;

    //--------------------

    fechas_eolico, fechas_C180: TDAOfNInt; // otra forma de ver el ADN

    // EVALUACION
    cnt_evaluaciones:      integer;
    cad, cad_min, cad_max: NReal;
    CADpe5, cadpe5_min, cadpe5_max: NReal;

    cpialfa: NReal;
    vcads, vcadspe5: TDAOfNReal;
    cpibeta: NReal;

    constructor Create;
    constructor CreateRND;

    constructor Create_unserialize(
      idPlan: integer; poblacion: integer; adn: string;
      xcnt_evaluaciones: integer;
      xcad, xcad_min, xcad_max,
      xcadpe5, xcadpe5_min, xcadpe5_max: NReal;
      xcpialfa: NReal; xvcads, xvcadspe5: string; xcpibeta: NReal
      );

    function serialize_adn: string;

    constructor CreateReadFromFile(var f: textfile);
    procedure WriteToFile(var f: textfile);

    procedure Free;

    procedure CrearSala( conRuido: boolean );
    procedure Evaluar;

    procedure leer_vcads;
    function ArchiSimRes3: string;
    procedure ejecutarSimRe3_modotexto(archiSR3: string);


    // crea un clon exacto
    function clonar: TPlan;

    procedure mutar;

    // pasa de un vector que itene para cada año 0..n = 2008..2026 la cantidad de incorporaciones
    // a otro vector que tiene de 0..M-1  para cada incorporación el año en que se da
    function Unidades2Fechas(const unidades: TDAOfNInt): TDAOfNInt;

    // invierte lo anterior
    procedure Fechas2Unidades(var unidades: TDAOfNInt;
      const fechasUnidades: TDAOfNInt);

(*
    procedure acum_undidades; // llena los vectores acumulados de unidades
    procedure desacum_unidades; //
*)
  end;

  TDAofTPlan= array of TPlan;


var
  version_historial: integer;
  NAnios:     integer;
  fechas:     TDAOfFecha;
  Fijo_Regasificadora, Fijo_Puerto: NReal;
  optimizando, flg_Optimizando: boolean;
  // lo usamos para crear una carpeta en "/tmp/SimSEE/idEjecutor/"
  // y ponerla como tmp_rundir
  // que la usaremos para los resultados de las corridas y archivos de trabajo.
  // como cada tarea la ejecuta un núcleo no se interfieren
  // hay que hacer que los programas cmdopt, cmdsim, cmdsimres3 puedan recibir
  // el idEjecutor también para que todo lo que escriban lo hagan en esa carpeta.
  idEjecutor: string;
  idNodo: integer; // lo usamospara identificar quien hizo el último calculo.

  serie_WTI:  TDAOfNReal;



// crea la población y la llena desde el historial, marca el archivo de log.
procedure Inicializar;

// intenta ir optimizando --- a lo bruto.
procedure OptimizarPoblacion;

//calcula un nuevo plan con gpa
function nuevoPlanGPA(NT, NGamma: integer; criterio: integer): TPlan;

// auxiliar
function cambiarNumeralPorTab(const s: string): string;


function LeerPlan( nid: integer ): TPlan;


procedure CopiarArchivos(
  carpetaOrigen, carpetaDestino: string;
  archivos: array of string );

procedure descargarDatosADisco(NIndividuos: Integer; criterio: Integer);

implementation


procedure CopiarArchivos(
  carpetaOrigen, carpetaDestino: string;
  archivos: array of string );
var
 k: integer;
begin
 for k:= 0 to high( archivos ) do
 begin
  writeln( 'Copiando: '+carpetaOrigen+ archivos[k]+' -> '+ carpetaDestino+ archivos[k] );
  cp( carpetaOrigen+ archivos[k], carpetaDestino+ archivos[k] );
 end;
end;

(*
function calc_cpialfa(
  const alfa: NReal; const vcads, vcadspe5: TDAOfNReal;
  const Cad: NReal  ): NReal;
var
  k: integer;
  res: NReal;
  maxDesvioRelativo: NReal;
  desvioRelativo: NReal;
  n: integer;
begin
  n:= length( vcads );
  maxDesvioRelativo:= 0;

  for k:= 4 to n-1 do // 0=2009, 1=2010, 2=2011, 3=2012, 4=2013
  begin
    desvioRelativo:= ( vcadspe5[k] - vcads[k] ) / vcads[k] ; // estamos asumiendo vcads[k] > 0
    if desvioRelativo > maxDesvioRelativo then
      maxDesvioRelativo:= desvioRelativo;
  end;
  res:= Cad * ( ( 1- alfa ) + alfa * 10* maxDesvioRelativo * maxDesvioRelativo);
  result:= res;
end;
*)


function calc_cpialfa(
  const alfa: NReal; const vcads, vcadspe5: TDAOfNReal;
  const Cad: NReal  ): NReal;
var
  k: integer;
  res: NReal;
  suma, suma2: NReal;
  desvioRelativo: NReal;
  q, qm: NReal;
  n: integer;
begin
  n:= length( vcads );
  q:= 1/1.12;
  qm:= 1;
  suma:= 0;
  suma2:= 0;
  for k:= 0 to n-1 do // 0=2009, 1=2010, 2=2011, 3=2012, 4=2013
  begin
    desvioRelativo:= ( vcadspe5[k] - vcads[k] ) / vcads[k] ; // estamos asumiendo vcads[k] > 0
    suma:= suma + qm * desvioRelativo;
    suma2:= suma2 + qm;
    qm:= qm * q;
  end;
  res:= Cad * ( ( 1.0 - alfa ) + alfa * suma / suma2 );
  result:= res;
end;


function calc_cpibeta(
  const beta: NReal; const vcads, vcadspe5: TDAOfNReal;
  const Cad: NReal  ): NReal;
var
  k: integer;
  res: NReal;
  a: NReal;
  n: integer;
  q: NReal;
begin
  n:= length( vcads );
  a:= 0;
  q:= 1;
  for k:= 0 to n-1 do
  begin
    a:= a + ( vcadspe5[k] - vcads[k] )* q ;
    q:= q/ 1.12;
  end;
  res:= Cad  + a * beta;
  result:= res;
end;



function RuidoDeEntrada(incorporaciones: TDAOfNInt): TDAOfNInt;
var
  k, kModulo: integer;
  nAtrazados: integer;
  res: TDAOfNInt;
  n:   integer;
  nModulos, nAtrazar: integer;
  nr: NReal;
begin
  n := length(incorporaciones);
  setlength(res, n);
  nAtrazados := 0;
  res[0]     := incorporaciones[0];
  for k := 1 to n - 1 do
  begin
    nModulos := incorporaciones[k];
    nAtrazar := 0;
    for kModulo := 1 to nModulos do
    begin
      nr:= random;
      if nr < 0.5 then
        Inc(nAtrazar);
    end;
    res[k]     := nAtrazados + nModulos - nAtrazar;
    nAtrazados := nAtrazar;
  end;
  Result := res;
end;

function fichas_Incorporaciones(fechas: TDAofFecha; incorporaciones: TDAOfNInt;
  multiplicador_unidades: integer): WideString;
var
  res:      WideString;
  k, n:     integer;
  NModulos: integer;
begin
  n   := length(fechas);
  nModulos := 0;
  res := 'n= ' + IntToStr(n) + ';'#13#10;
  for k := 0 to n - 1 do
  begin
    nModulos := nModulos + incorporaciones[k];
    res      := res + ':= <+TFichaUnidades>'#13#10;
    res      := res + '  fecha= ' + fechas[k].asIsoStr + ';'#13#10;
    res      := res + '  expandida= 0;'#13#10;
    res      := res + '  esPeriodica= 0;'#13#10;
    res      := res + '  nUnidades= ' + IntToStr(nModulos * multiplicador_unidades) +
      ';'#13#10;
    res      := res + '<-TFichaUnidades>;'#13#10;
    res      := res + #13#10;
  end;
  Result := res;
end;


function ficha_CERO: WideString;
var
  res: WideString;
begin
  res    := 'n= 1;'#13#10;
  res    := res + ':= <+TFichaUnidades>'#13#10;
  res    := res + '  fecha= 1899-12-30;'#13#10;
  res    := res + '  expandida= 0;'#13#10;
  res    := res + '  esPeriodica= 0;'#13#10;
  res    := res + '  nUnidades= 0;'#13#10;
  res    := res + '<-TFichaUnidades>;'#13#10;
  res    := res + #13#10;
  Result := res;
end;


function fichas_multiplicadores_CEGH_WTI(WTI: array of double): WideString;
var
  res: WideString;
  k:   integer;
  n:   integer;

  procedure Ficha(anio: integer; multiplicador: double);
  begin
    res := res + ' := <+TFichaFuenteSintetizadorCEGH> '#13#10;
    res := res + 'fecha= ' + IntToStr(anio) + '-12-30; '#13#10;
    res := res + 'expandida= 0 ; '#13#10;
    res := res + 'esPeriodica= 0; '#13#10;
    res := res + 'multiplicar_vm= 1; '#13#10;
    res := res + 'modificadoresValEsp= [1| ' + FloatToStr(multiplicador) + ']; '#13#10;
    res := res + 'modificadoresDevEst= [1| 1.000]; '#13#10;
    res := res + '<-TFichaFuenteSintetizadorCEGH>; '#13#10;
  end;

begin
  n   := length(WTI);
  res := 'n= ' + IntToStr(n) + '; '#13#10;

  ficha(1980, WTI[0] / 70.0);
  for k := 1 to n - 1 do
    ficha(2009 + k, WTI[k] / 70.0);

  Result := res;
end;



function fichas_PTI_GN(hayGas: boolean): WideString;
var
  res: WideString;
  NTGs1, NTGs2: integer;

begin
  if hayGas then
  begin
    res := 'n= 2;'#13#10;
    res := res + ':= <+TFichaUnidades>'#13#10;
    res := res + '  fecha= 1899-12-30;'#13#10;
    res := res + '  expandida= 0;'#13#10;
    res := res + '  esPeriodica= 0;'#13#10;
    res := res + '  nUnidades= 0;'#13#10;
    res := res + '  <-TFichaUnidades>;'#13#10;
    res := res + '  := <+TFichaUnidades>'#13#10;
    res := res + '  fecha= 01/01/' + IntToStr(AnioGas) + ';'#13#10;
    res := res + '  expandida= 0;'#13#10;
    res := res + '  esPeriodica= 0;'#13#10;
    res := res + '  nUnidades= 6;'#13#10;
    res := res + '  <-TFichaUnidades>;'#13#10;
    res := res + ''#13#10;
  end
  else
  begin
    res := 'n= 1;'#13#10;
    res := res + ':= <+TFichaUnidades>'#13#10;
    res := res + '  fecha= 1899-12-30;'#13#10;
    res := res + '  expandida= 0;'#13#10;
    res := res + '  esPeriodica= 0;'#13#10;
    res := res + '  nUnidades= 0;'#13#10;
    res := res + '  <-TFichaUnidades>;'#13#10;
    res := res + ''#13#10;
  end;
  Result := res;
end;

function fichas_PTI_GO(hayGas: boolean): WideString;
var
  res: WideString;
begin
  if hayGas then
  begin
    res := 'n= 2;'#13#10;
    res := res + ':= <+TFichaUnidades>'#13#10;
    res := res + '  fecha= 1899-12-30;'#13#10;
    res := res + '  expandida= 0;'#13#10;
    res := res + '  esPeriodica= 0;'#13#10;
    res := res + '  nUnidades= 6;'#13#10;
    res := res + '  <-TFichaUnidades>;'#13#10;
    res := res + ':= <+TFichaUnidades>'#13#10;
    res := res + '  fecha= 1/1/' + IntToStr(AnioGas) + ';'#13#10;
    res := res + '  expandida= 0;'#13#10;
    res := res + '  esPeriodica= 0;'#13#10;
    res := res + '  nUnidades= 0;'#13#10;
    res := res + '  <-TFichaUnidades>;'#13#10;
    res := res + ''#13#10;
  end
  else
  begin
    res := 'n= 1;'#13#10;
    res := res + ':= <+TFichaUnidades>'#13#10;
    res := res + '  fecha= 1899-12-30;'#13#10;
    res := res + '  expandida= 0;'#13#10;
    res := res + '  esPeriodica= 0;'#13#10;
    res := res + '  nUnidades= 6;'#13#10;
    res := res + '  <-TFichaUnidades>;'#13#10;
    res := res + ''#13#10;
  end;
  Result := res;
end;

function GWH_anios( conRuido: boolean ): WideString;
var

  gwh: double;

  res: WideString;
  tasa, vartasa: double;
  k: integer;

begin

  gwh      := 8846.86;
  res      := '[66| ' + IntToStr(trunc(gwh + 0.5));
  tasa     := 3.04 / 100;
  for k := 2 to 66 do
  begin
    if conRuido then
      vartasa := (1 - random) * 2 // +/-1%
    else
      vartasa := 0;
    gwh     := gwh * (1 + tasa + vartasa / 100.0);
    res     := res + ', ' + IntToStr(trunc(gwh + 0.5));
    if (k mod 12) = 0 then
      res := res + #13#10;
  end;
  res    := res + ']';
  Result := res;
end;



function vserialize( v: TDAOfNReal ): string;
var
  k:   integer;
  res: string;

  procedure ws(n: integer);
  begin
    res := res + '#' + IntToStr(n);
  end;

begin
  res := '';
  ws(length(v));
  for k := 0 to high(v) do
    ws(trunc( v[k] ));
  Result := res;
end;

function vunserialize( s: string ): TDAOfNReal;
var
  n: integer;
  k: integer;
  res: TDAOfNReal;
  ts: string;
begin
  ts:= cambiarNumeralPorTab( s );
  n:= nextInt( ts );
  setlength( res, n );
  for k := 0 to n-1 do
    res[k]:= nextFloat( ts );
  Result := res;
end;


procedure vponder( var vcads, xvcads: TDAOfNReal; xcnt_evaluaciones: integer );
var
  k: integer;
begin
  for k:= 0 to high( vcads ) do
    vcads[k]:= ( vcads[k] + xvcads[k] * xcnt_evaluaciones ) / ( xcnt_evaluaciones + 1 );
end;

procedure NotificarResultado(a: TPlan);
var
  adn, resultados:              string;
  poblacion:            integer;
  n:                       integer;
  leyendo:                      boolean;
  k:                            integer;
  kClon:                        integer;
  ds:                           TResultadoQuery;
  r:                            TDataRecord;
  krow, nrows:                  integer;
  sql:                          string;
  ts:                           string;
  xvcads, xvcadspe5:            TDAOfNReal;
  xcpialfa, xcpibeta:           NReal;
  xcnt_evaluaciones:            integer;

begin
  if a.idPlan < 0 then
  begin
    adn := a.serialize_adn;
    // primero nos fijamos si existe otra entrada con el mismo adn
    ts  := sql_func('SELECT nid FROM ' + tablaEvaluaciones + ' WHERE adn = ''' +
      adn + ''' LIMIT 1');
    if ts <> '' then
      a.idPlan := StrToInt(ts);  //si ya existe le asigno el idPlan del que ya existia
  end;

  if a.idPlan < 0 then          //si el plan no existia
  begin
    a.idPlan := sql_nextnid(tablaEvaluaciones);
    writeln('ESTOY EN NOTIFICAR RESULTADO Y SOY DE LA POBLACION: ',a.poblacion);

    sql      := 'INSERT INTO ' + tablaEvaluaciones
      + ' ( nid, poblacion, haygas, sineolico, adn, dtc, dtu, cnt_evaluaciones, cad, cadpe5, cad_min, cadpe5_min, cad_max, cadpe5_max '
      + ', vcads, vcadspe5, cpialfa, cpibeta, idnodo '
      + ') VALUES ('
      + IntToStr(a.idPlan) + ', ' + IntToStr(a.poblacion) + ', '+  BoolToStr( a.haygas)+ ', ' + BoolToStr( a.sineolico )
      + ', ''' + adn + ''', now(), now(), ''' + IntToStr(
      1) + ''', ' + '''' + FloatToStrF(a.CAD, FFFixed, 12, 2) + ''', ' +
      '''' + FloatToStrF(a.CADpe5, FFFixed, 12, 2) + ''', ' + '''' +
      FloatToStrF(a.CAD, FFFixed, 12, 2) + ''', ' + '''' + FloatToStrF(
      a.CADpe5, FFFixed, 12, 2) + ''', ' + '''' + FloatToStrF(
      a.CAD, FFFixed, 12, 2) + ''', ' + '''' + FloatToStrF(
      a.CADpe5, FFFixed, 12, 2) + ''' '
      + ', '''+ vserialize( a.vcads )+''', '''+vserialize( a.vcadspe5 )+''', '''
      + FloatToStrF(a.cpialfa, FFFixed, 12, 2) + ''', '''
      + FloatToStrF(a.cpibeta, FFFixed, 12, 2) + ''', '
      +IntToStr( idNodo )
      +' )';

    if not sql_exec(sql) then
      raise Exception.Create('Imposible insertar PLAN, sql: ' + sql);
  end
  else
  begin
    r:= sql_ficha( 'SELECT cnt_evaluaciones, vcads, vcadspe5, cpialfa, cpibeta FROM '
        + tablaEvaluaciones + ' WHERE nid = '+IntToStr( a.idPlan )+ ' LIMIT 1 ');
    xcnt_evaluaciones:=r.GetByNameAsInt( 'cnt_evaluaciones' );
    xvcads:= vunserialize( r.GetByNameAsString('vcads' ));
    vponder( a.vcads, xvcads, xcnt_evaluaciones );
    xvcadspe5:= vunserialize( r.GetByNameAsString( 'vcadspe5' ));
    vponder( a.vcadspe5, xvcadspe5, xcnt_evaluaciones );
    setlength( xvcads, 0 );
    setlength( xvcadspe5, 0 );
    xcpialfa:= r.GetByNameAsFloat( 'cpialfa' );
    a.cpialfa:= ( a.cpialfa + xcpialfa * xcnt_evaluaciones ) / ( xcnt_evaluaciones + 1 );

    xcpibeta:= r.GetByNameAsFloat( 'cpibeta' );
    a.cpibeta:= ( a.cpibeta + xcpibeta * xcnt_evaluaciones ) / ( xcnt_evaluaciones + 1 );

    r.Free;

    sql := 'UPDATE ' + tablaEvaluaciones + ' SET ' +
      ' dtu = now(), ' + ' cad_min = LEAST( cad_min , ' + FloatToStr(
      a.CAD) + ' ), ' + ' cad_max = GREATEST( cad_max , ' + FloatToStr(
      a.CAD) + ' ), ' + ' cadpe5_min = LEAST( cadpe5_min , ' + FloatToStr(
      a.CADpe5) + ' ), ' + ' cadpe5_max = GREATEST( cadpe5_max , ' + FloatToStr(
      a.CADpe5) + ' ), ' + ' cad = (( cad * cnt_evaluaciones + ' + FloatToStr(
      a.CAD) + ')/ ( cnt_evaluaciones + 1 ) ), ' +
      ' cadpe5 = (( cadpe5 * cnt_evaluaciones + ' + FloatToStr(
      a.CADpe5) + ')/ ( cnt_evaluaciones + 1 ) ), ' +
      ' cnt_evaluaciones = cnt_evaluaciones +1 '
      +', vcads= '''+ vserialize( a.vcads )+''', vcadspe5= '''
      + vserialize(a.vcadspe5)+''''
      +', cpialfa= '''+FloatToStrF(a.cpialfa, FFFixed, 12, 2) + ''' '
      +', cpibeta= '''+FloatToStrF(a.cpibeta, FFFixed, 12, 2) + ''' '
      +', idnodo= '+IntToStr( idnodo )
      + ' WHERE nid = ' + IntToStr(
      a.idPlan);
    if not sql_exec(sql) then
      raise Exception.Create('Imposible insertar PLAN, sql: ' + sql);
  end;
end;


procedure RunOptSim(sala: string; var CAD_ve, CAD_VaR: NReal);
var
  fres:   Textfile;
var
  cmd:    string;
  params: array of string;
  s:      string;

begin
  randomize;
  semillaAleatoria_:= random( 29999 );

  setlength(params, 3);
  params[0] := 'sala=' + sala;
  params[1] := 'ejecutor=' + idEjecutor;
  params[2] := 'semilla='+ IntToStr( semillaAleatoria_ );

{$IFDEF LINUX}
  cmd := getDir_bin + 'cmdopt';
{$ELSE}
  cmd := getDir_bin + 'cmdopt.exe';
{$ENDIF}
  if not RunChildAndWAIT(cmd, params) then
    raise Exception.Create('no puede correr la cmdopt');

{$IFDEF LINUX}
  cmd := getDir_bin + 'cmdsim';
{$ELSE}
  cmd := getDir_bin + 'cmdsim.exe';
{$ENDIF}


  setlength(params, 4);
  params[0] := 'sala=' + sala;
  params[1] := 'ejecutor=' + idEjecutor;
  params[2] := 'monitores=' + ArchMonitor_vcads;
  params[3] := 'semilla='+ IntToStr( semillaAleatoria_ );

  if not RunChildAndWAIT(cmd, params) then
    raise Exception.Create('no puede correr la cmdsim');
  setlength(params, 0);

  try
    if tmp_rundir = '' then
      s := getDir_run + NombreSala + DirectorySeparator
    else
      s := getDir_run;
    s:= s+ ArchRes_begin + IntToStr( semillaAleatoria_ ) + ArchRes_end;
    assignFile(fres, s);
    Reset(fres);
    system.readln(fres, CAD_ve);
    system.readln(fres);
    system.readln(fres, CAD_VaR);
    CloseFile(fres);

  except
    raise Exception.Create('Error al leer archivo de resultados uplanes.425: ' + s);
  end;

end;


function Poblacion_count: integer;
var
  res: integer;

begin
{$IFDEF SOLOGAS}
{$IFDEF SINEOLICO}
  res := StrToInt(sql_func('SELECT count(*) FROM ' + tablaEvaluaciones+' WHERE haygas AND sineolico '));
{$ELSE}
  res    := StrToInt(sql_func('SELECT count(*) FROM ' + tablaEvaluaciones+' WHERE haygas '));
{$ENDIF}
{$ELSE}
  res    := StrToInt(sql_func('SELECT count(*) FROM ' + tablaEvaluaciones));
{$ENDIF}
  Result := res;
end;



function LeerPlan( nid: integer ): TPlan;
var
  p:      NReal;
  k:      integer;
  ds:     TResultadoQuery;
  r:      TDataRecord;
  idPlan, poblacion : integer;
  adn:    string;
  cnt_evaluaciones: integer;
  cad, cad_min, cad_max, cadpe5, cadpe5_min, cadpe5_max: NReal;
  a: TPlan;
  orderBy: string;
  vcads, vcadspe5: string;
  cpialfa, cpibeta: NReal;

begin
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones +
    ' WHERE nid= '+IntToStr( nid ) +' LIMIT 1');
  r := ds.Next;
  if ( r <> nil ) then
  begin
    idPlan := StrToInt(r.GetByNameAsString('nid'));
    poblacion := StrToInt(r.GetByNameAsString('poblacion'));
    adn := r.GetByNameAsString('adn');
    cnt_evaluaciones := r.GetByNameAsInt('cnt_evaluaciones');
    cad := r.GetByNameAsFloat('cad');
    cad_max := r.GetByNameAsFloat('cad_max');
    cad_min := r.GetByNameAsFloat('cad_min');
    cadpe5 := r.GetByNameAsFloat('cadpe5');
    cadpe5_min := r.GetByNameAsFloat('cadpe5_min');
    cadpe5_max := r.GetByNameAsFloat('cadpe5_max');
    vcads:= r.GetByNameAsString( 'vcads' );
    vcadspe5:= r.GetByNameAsString( 'vcadspe5' );
    cpialfa:= r.GetByNameAsFloat( 'cpialfa' );
    cpibeta:= r.GetByNameAsFloat( 'cpibeta' );

    a := TPlan.Create_Unserialize(idPlan, poblacion, adn, cnt_evaluaciones, cad,
          cad_min, cadpe5, cadpe5, cadpe5_min, cadpe5_max
          , cpialfa, vcads, vcadspe5, cpibeta  );
  end
  else
    a:= nil;
  Result := a;
end;

//NIndividuos es el total de la poblacion actual,
//criterio es segun el cual se optimiza
function Poblacion_selPadre(NIndividuos: integer; criterio: integer ): TPlan;
var
  p:      NReal;
  k:      integer;
  ds:     TResultadoQuery;
  r:      TDataRecord;
  idPlan: integer;
  poblacion: integer;
  adn:    string;
  cnt_evaluaciones: integer;
  cad, cad_min, cad_max, cadpe5, cadpe5_min, cadpe5_max: NReal;
  a: TPlan;
  orderBy: string;
  vcads, vcadspe5: string;
  cpialfa, cpibeta: NReal;

begin

  k := 0;
  while (random < 0.93) and (k < (NIndividuos - 1)) do
    Inc(k);


case criterio of
0: orderby:= ' ORDER BY cad ';
1: orderby:= ' ORDER BY cpialfa ';
2: orderby:= ' ORDER BY cadpe5 ';
3: orderby:= ' ORDER BY cpibeta ';
end;


{$IFDEF SOLOGAS}
{$IFDEF SINEOLICO}
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones +
    ' WHERE haygas AND sineolico '+orderBy+' LIMIT ' + IntToStr(k) + ', 1 '); //¿¿el orden es primero cortar en k y despues ordenar y tomar el primero??
{$ELSE}
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones +
    ' WHERE haygas '+orderBy+' LIMIT ' + IntToStr(k) + ', 1 ');
{$ENDIF}
{$ELSE}
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones + orderBy+' LIMIT ' + IntToStr(
    k) + ', 1 ');
{$ENDIF}

  r := ds.Next;
  idPlan := StrToInt(r.GetByNameAsString('nid'));
  poblacion := StrToInt(r.GetByNameAsString('poblacion'));
  adn := r.GetByNameAsString('adn');
  cnt_evaluaciones := r.GetByNameAsInt('cnt_evaluaciones');
  cad := r.GetByNameAsFloat('cad');
  cad_max := r.GetByNameAsFloat('cad_max');
  cad_min := r.GetByNameAsFloat('cad_min');
  cadpe5 := r.GetByNameAsFloat('cadpe5');
  cadpe5_min := r.GetByNameAsFloat('cadpe5_min');
  cadpe5_max := r.GetByNameAsFloat('cadpe5_max');
  vcads:= r.GetByNameAsString( 'vcads' );
  vcadspe5:= r.GetByNameAsString( 'vcadspe5' );
  cpialfa:= r.GetByNameAsFloat( 'cpialfa' );
  cpibeta:= r.GetByNameAsFloat( 'cpibeta' );

  a := TPlan.Create_Unserialize(idPlan, poblacion, adn, cnt_evaluaciones, cad,
        cad_min, cadpe5, cadpe5, cadpe5_min, cadpe5_max
        , cpialfa, vcads, vcadspe5, cpibeta   );
  Result := a;
end;



constructor TPlan.Create;
begin
  inherited Create;
  haygas      := True;
{$IFDEF SINEOLICO}
  sineolico:= True;
{$ELSE}
  sineolico:= false;
{$ENDIF}
  self.idPlan := -1; // sin identificar

  setlength(unidades_eolico, NAnios);
  setlength(unidades_C180, NAnios);
end;

constructor TPlan.CreateRND;
var
  kAnio: integer;

begin
  Create;

{$IFDEF SINEOLICO}
  sineolico:= true;
  for kAnio := 2013 to 2026 do
      unidades_eolico[kAnio - 2008] := 0;
{$ELSE}
  sineolico:= false;
  for kAnio := 2013 to 2026 do
  begin
    if random > 0.5 then
      unidades_eolico[kAnio - 2008] := random(MaxNIncorporacion_eolico) + 1
    else
      unidades_eolico[kAnio - 2008] := 0;
  end;
{$ENDIF}

{$IFDEF SOLOGAS}
  haygas := True;
{$ELSE}
  haygas := random > 0.5;
{$ENDIF}

  for kAnio:= AnioGas to 2026 do
  begin
    if random > 0.5 then
      unidades_C180[kAnio - 2008] := random(MaxNIncorporacion_C180) + 1
    else
      unidades_C180[kAnio - 2008] := 0;
  end;

  self.poblacion := 43366;   //indica que es genetico
end;

procedure TPlan.WriteToFile(var f: textfile);
var
  k: integer;

begin
  Write(f, idPlan);
  Write(f,
    #9, self.cnt_evaluaciones,
    #9, self.CAD,
    #9, self.CAD_min,
    #9, self.CAD_max,
    #9, self.CADpe5,
    #9, self.CADpe5_min,
    #9, self.CADpe5_max
    );

  if haygas then
    Write(f, #9, 1)
  else
    Write(f, #9, 0);

  if sineolico then
    Write(f, #9, 1)
  else
    Write(f, #9, 0);

  Write(f, #9, 'E');
  Write(f, #9, length(unidades_eolico));
  for k := 0 to high(unidades_eolico) do
    Write(f, #9, unidades_eolico[k]);
  Write(f, #9, 'C');
  Write(f, #9, length(unidades_C180));
  for k := 0 to high(unidades_C180) do
    Write(f, #9, unidades_C180[k]);

  writeln(f);
end;




constructor TPlan.CreateReadFromFile(var f: textfile);
var
  k:   integer;
  N:   integer;
  s:   string;
  pal: string;

begin
  inherited Create;
  self.idPlan := -1;

  readln(f, s);

  if version_historial > 0 then
    idPlan := nextInt(s);
  cnt_evaluaciones := nextInt(s);
  CAD      := nextFloat(s);
  CAD_min  := nextFloat(s);
  CAD_max  := nextFloat(s);

  CADpe5     := nextFloat(s);
  CADpe5_min := nextFloat(s);
  CADpe5_max := nextFloat(s);


  k      := nextInt(s);
  haygas := k = 1;
  k      := nextInt(s);
  sineolico := k = 1;
  pal    := nextPal(s);
  if pal <> 'E' then
    raise Exception.Create('Error leyendo plan, esperaba una E');
  N := nextInt(s);
  setlength(unidades_eolico, N);
  for k := 0 to high(unidades_eolico) do
    unidades_eolico[k] := nextInt(s);
  pal := nextPal(s);
  if pal <> 'C' then
    raise Exception.Create('Error leyendo plan, esperaba una C');
  N := nextInt(s);
  setlength(unidades_C180, N);
  for k := 0 to high(unidades_C180) do
    unidades_C180[k] := nextInt(s);

end;

// cambia # por tab y borra el primer caracter (que se supone es un # )
function cambiarNumeralPorTab(const s: string): string;
var
  res: string;
  k:   integer;
begin
  setlength(res, length(s));
  for k := 1 to length(s) do
    if s[k] = '#' then
      res[k] := #9
    else
      res[k] := s[k];
  Result := res;
end;


constructor TPlan.Create_unserialize(
  idPlan, poblacion: integer; adn: string;
  xcnt_evaluaciones: integer;
  xcad, xcad_min, xcad_max, xcadpe5, xcadpe5_min, xcadpe5_max: NReal ;
  xcpialfa: NReal; xvcads, xvcadspe5: string; xcpibeta: NReal );

var
  k:   integer;
  pal: string;
  N:   integer;
  ts:  string;
  cnt_unidades: integer;
begin
  Create;

  self.idPlan := idPlan;
  self.poblacion := poblacion;

  // decodificando el adn
  ts     := cambiarNumeralPorTab(adn);
  k      := nextInt(ts);
  haygas := k <> 0;

  N := nextInt(ts);
  setlength(unidades_eolico, N);
  cnt_unidades:= 0;
  for k := 0 to high(unidades_eolico) do
  begin
    unidades_eolico[k] := nextInt(ts);
    cnt_unidades:= cnt_unidades + unidades_eolico[k];
  end;
  sineolico:= cnt_unidades = 0;

  N := nextInt(ts);
  setlength(unidades_C180, N);
  for k := 0 to high(unidades_C180) do
    unidades_C180[k] := nextInt(ts);

  cnt_evaluaciones := xcnt_evaluaciones;
  cad     := xcad;
  cad_min := xcad_min;
  cad_max := xcad_max;
  cadpe5  := xcadpe5;
  cadpe5_min := xcadpe5_min;
  cadpe5_max := xcadpe5_max;

  cpialfa:= xcpialfa;

  ts:= cambiarNumeralPorTab( xvcads );
  n:= nextInt( ts );
  setlength( vcads, n );
  for k:= 0 to n-1 do
    vcads[k]:= nextfloat( ts );


  ts:= cambiarNumeralPorTab( xvcadspe5 );
  n:= nextInt( ts );
  setlength( vcadspe5, n );
  for k:= 0 to n-1 do
    vcadspe5[k]:= nextfloat( ts );

  cpibeta:= xcpibeta;

end;


function TPlan.serialize_adn: string;
var
  k:   integer;
  res: string;

  procedure ws(n: integer);
  begin
    res := res + '#' + IntToStr(n);
  end;

begin
  res := '';
  if haygas then
    ws(1)
  else
    ws(0);
  // vector de undiades eolicas
  ws(length(unidades_eolico));
  for k := 0 to high(unidades_eolico) do
    ws(unidades_eolico[k]);
  // vector de centrales termicas
  ws(length(unidades_C180));
  for k := 0 to high(unidades_C180) do
    ws(unidades_C180[k]);

  Result := res;
end;




procedure TPlan.Free;
begin
  setlength(unidades_eolico, 0);
  setlength(unidades_C180, 0);
  inherited Free;
end;

function viguales(v1, v2: TDAofNInt): boolean;
var
  k:   integer;
  res: boolean;
begin
  res := True;
  for k := 0 to high(v1) do
    if v1[k] <> v2[k] then
    begin
      res := False;
      break;
    end;
  Result := res;
end;



function TPlan.clonar: TPlan;
var
  k:    integer;
  bebe: TPlan;
begin
  bebe := TPlan.Create;
  bebe.haygas := self.haygas;
  bebe.sineolico:= self.sineolico;
  for k := 0 to high(bebe.unidades_eolico) do
    bebe.unidades_eolico[k] := self.unidades_eolico[k];
  for k := 0 to high(bebe.unidades_C180) do
    bebe.unidades_C180[k] := self.unidades_C180[k];
  Result := bebe;
end;




function mezclar(mama, papa: TPlan): TPlan;
var
  k:      integer;
  bebe:   TPlan;
  fp, fm: TDAOfNInt;
begin
  bebe := TPlan.Create;
  {$IFDEF SOLOGAS}
  bebe.haygas := True;
  {$ELSE}
  if random < 0.5 then
    bebe.haygas := papa.haygas
  else
    bebe.haygas := mama.haygas;
  {$ENDIF}


  {$IFDEF SINEOLICO}
  bebe.sineolico:= true;
  for k := 0 to high(bebe.unidades_eolico) do
      bebe.unidades_eolico[k] := 0;
  {$ELSE}
  bebe.sineolico:= true;
  for k := 0 to high(bebe.unidades_eolico) do
    if random < 0.5 then
      bebe.unidades_eolico[k] := papa.unidades_eolico[k]
    else
      bebe.unidades_eolico[k] := mama.unidades_eolico[k];
  {$ENDIF}

  for k := 0 to high(bebe.unidades_C180) do
    if random < 0.5 then
      bebe.unidades_C180[k] := papa.unidades_C180[k]
    else
      bebe.unidades_C180[k] := mama.unidades_C180[k];
  bebe.poblacion:=43366; //indica que este plan provino de la raza genetica
  Result := bebe;
end;


procedure adelantar(v: TDAOfNInt; j: integer);
var
  k: integer;
begin
  k := j - 2008;

  if (k < 0) or (k > high(v)) then
    raise Exception.Create('Error, adelantar: j: ' + IntToStr(j));

  if k = high(v) then
    Inc(v[k])
  else
  begin
    if (v[k + 1] > 0) then
    begin
      Inc(v[k]);
      Dec(v[k + 1]);
    end
    else
      Inc(v[k]);
  end;
end;


procedure atrazar(v: TDAOfNInt; j: integer);
var
  k: integer;
begin
  k := j - 2008;

  if (k < 0) or (k > high(v)) then
    raise Exception.Create('Error, atrazar: j: ' + IntToStr(j));

  if k = high(v) then
  begin
    if (v[k] > 0) then
      Dec(v[k]);
  end
  else
  begin
    if v[k] > 0 then
    begin
      Inc(v[k + 1]);
      Dec(v[k]);
    end;
  end;
end;

procedure TPlan.Mutar;
var
  j: integer;

begin

{$IFDEF SOLOGAS}
  haygas := True;
{$ELSE}
  if random < 0.05 then
  begin
    haygas := not haygas;
    exit;
  end;
{$ENDIF}

{$IFNDEF SINEOLICO}
  if random < 0.5 then
  begin
    j := random(length(unidades_eolico) - (AnioEolico - 2008)) + (AnioEolico - 2008);
    if random < 0.5 then
      unidades_eolico[j] := unidades_eolico[j] + random(4) + 1
    else
      unidades_eolico[j] := max(unidades_eolico[j] - random(4) - 1, 0);
  end
  else
{$ENDIF}
  begin
    j := random(length(unidades_C180) - (AnioGas - 2008)) + (AnioGas - 2008);
    if random < 0.5 then
      unidades_C180[j] := unidades_C180[j] + random(1) + 1
    else
      unidades_C180[j] := max(unidades_C180[j] - random(1) - 1, 0);
  end;
end;



procedure TPlan.CrearSala( conRuido: boolean );
var
  lpars:    TListaDeVariablesPP;
begin

  // limpio el directorio de salida
  limpiarCarpeta(getDir_run + NombreSala);

  lpars := TListaDeVariablesPP.Create;
  if conRuido then
    lpars.Agregar('unidades_eolico', fichas_Incorporaciones(
      fechas, RuidoDeEntrada(unidades_eolico), 10))
  else
    lpars.Agregar('unidades_eolico', fichas_Incorporaciones(
      fechas, unidades_eolico, 10));

  (*
  lpars.Agregar('multiplicadores_CEGH_WTI', fichas_multiplicadores_CEGH_WTI(
    Serie_WTI));
*)
    if conRuido then
      lpars.Agregar('unidades_CC180_GN', fichas_Incorporaciones(
        fechas, RuidoDeEntrada(unidades_C180), 1))
    else
      lpars.Agregar('unidades_CC180_GN', fichas_Incorporaciones(
        fechas, unidades_C180, 1));
(*
  // le metemos ruido a la proyección de demanda.
  lpars.Agregar('GWh_anios', GWh_anios( conRuido ) );
*)
  CopiarSustituyendo(getDir_run + ArchPlantillaSala, getDir_run + ArchSala, lpars);
  lpars.Free;
end;

procedure TPlan.Evaluar;
var
  archiSR3: string;

begin
  CrearSala( false );
  RunOptSim(getDir_run + ArchSala, CAD, CADpe5);
  if hayGas then
  begin
    CAD    := CAD + Fijo_Regasificadora;
    CADpe5 := CADpe5 + Fijo_Regasificadora;
  end
  else
  begin
    CAD    := CAD + Fijo_Puerto;
    CADpe5 := CADpe5 + Fijo_Puerto;
  end;

  archiSR3 := archiSimRes3;
  ejecutarSimRe3_modotexto(archiSR3);
  leer_vcads;
  cpialfa:= calc_cpialfa( 0.5, vcads, vcadspe5, CAD );
  cpibeta:= calc_cpiBeta( 1.0, vcads, vcadspe5, CAD );
  writeln('soy de la poblacion: ', self.poblacion);

end;


procedure TPlan.leer_vcads;

  procedure leer_vcads_(archi: string; var vcads, vcadspe5: TDAOfNREal);
  var
    f:     textfile;
    r:     string;
    kanio: integer;
    nAnios: integer;
    pal:   string;
  begin
    assignfile(f, archi);
    reset(f);
    readln(f, r); // nombre de la varcron
    readln(f, r); // encabezado

    NAnios:= 2025-2009+1;
    setlength( vcads, NAnios );
    setlength( vcadspe5, NAnios );

    for kanio := 0 to NAnios-1 do
    begin
      if not EOF(f) then
      begin
        readln(f, r);
        pal := nextpal(r);
        pal := nextpal(r);
        if r <> '' then
        begin
          vcads[kanio] := nextFloat(r);
          vcadspe5[kanio] := nextFloat(r)
        end
        else
        begin
          vcads[kanio] := 0;
          vcadspe5[kanio] := 0;
        end;
      end
      else
      begin
        vcads[kanio] := 0;
        vcadspe5[kanio] := 0;
      end;
    end;
    closefile(f);
  end;

begin
  leer_vcads_(getDir_run + Arch_vcads, vcads, vcadspe5 );
end;


function TPlan.ArchiSimRes3: string;
var
  sustitutor: TSustituirVariablesPlantilla;
  f:    TArchiTexto;
  sala: TSalaDeJuego;
  archisimres: string;
  res:  string;

begin
  uInicioYFinal.AlInicio;
  f := TArchiTexto.CreateForRead(getDir_run + ArchSala, True);
  f.rd('sala', TCosa(sala));
  f.Free;
  uInicioYFinal.AlFinal;

  sustitutor := TSustituirVariablesPlantilla.Create;
  res := sustitutor.sustituirVariables(getDir_run + archPlantillaSimRes3_vcads,
    sala, semillaAleatoria_);
  sustitutor.Free;
  Result := res;
end;


procedure TPlan.ejecutarSimRe3_modotexto(archiSR3: string);
var
  cmd:    string;
  params: array of string;
begin
  setlength(params, 3);
  params[0] := archiSR3;
  params[1] := 'autocerrar';
  params[2] := idEjecutor;
{$IFDEF LINUX}
  cmd := getDir_bin + 'cmdsimres3';
{$ELSE}
  cmd := getDir_bin + 'cmdsimres3.exe';
{$ENDIF}
  if not RunChildAndWAIT(cmd, params) then
    raise Exception.Create('no puede correr la cmdopt');
  setlength(params, 0);
end;




// pasa de un vector que itene para cada año 0..n = 2008..2026 la cantidad de incorporaciones
// a otro vector que tiene de 0..M-1  para cada incorporación el año en que se da
function TPlan.Unidades2Fechas(const unidades: TDAOfNInt): TDAOfNInt;
var
  j, k, h: integer;
  NUnidades: integer;
  res: TDAofNInt;
begin
  // cuento el total de unidades
  NUnidades := 0;
  for k := 0 to high(unidades) do
    NUnidades := NUnidades + unidades[k];

  setlength(res, NUnidades - 1);
  j := 0;
  for k := 0 to high(unidades) do
  begin
    h := unidades[k];
    while h > 0 do
    begin
      res[j] := k;
      Inc(j);
      Dec(h);
    end;
  end;
  Result := res;
end;


// invierte lo anterior
procedure TPlan.Fechas2Unidades(var unidades: TDAOfNInt;
  const fechasUnidades: TDAOfNInt);
var
  k, j, h: integer;
begin
  for k := 0 to high(unidades) do
    unidades[k] := 0;
  for j := 0 to high(fechasUnidades) do
  begin
    k := fechasUnidades[j];
    Inc(unidades[k]);
  end;
end;

function Aparear: TPlan;
var
  k: integer;
  papa, mama: TPlan;
  a: TPlan;
  NINdividuos: integer;
  criterio: integer;

begin

//obs: lo que viene a continuacion se puede resumir poniendo NIndividuos:=Poblacion_Count();
{$IFDEF SOLOGAS}
{$IFDEF SINEOLICO}
  NIndividuos := StrToInt(sql_func(
    'SELECT count(*) FROM ' + tablaEvaluaciones + ' WHERE haygas AND sineolico '));
{$ELSE}
  NIndividuos := StrToInt(sql_func(
    'SELECT count(*) FROM ' + tablaEvaluaciones + ' WHERE haygas '));
{$ENDIF}
{$ELSE}
  NIndividuos := StrToInt(sql_func('SELECT count(*) FROM ' + tablaEvaluaciones));
{$ENDIF}


(**
// implementamos cuatro criterios de búsqueda simultáneos
  if random < 0.5 then
    if random < 0.5 then
      criterio:= 0
    else
      criterio:= 1
  else
    if random < 0.5 then
      criterio:= 2
    else
      criterio:= 3;
*)
  criterio := 0; // optimizamos en valor esperado.

  mama := Poblacion_selPadre(NIndividuos, criterio);
  if ( random > 0.001 ) then // factor de inovación
  begin
    papa := Poblacion_selPadre(NIndividuos, criterio);
    a    := mezclar(mama, papa);
    while random > 0.3 do  // factor de mutación
      a.mutar;
    papa.Free;
    mama.Free;
    result:= a;
  end
  else
  begin  // (1- factorDeInovacion ) = "repeticion asegurada"
    mama.poblacion := 43366;           //indica que proviene del algoritmo genetico
    Result := mama;
  end;
end;

procedure Inicializar;
var
  k: integer;
begin
  SysUtils.DecimalSeparator := '.';

  Fijo_Regasificadora := 450 * power(1 / 1.12, AnioGas - 2009);
  Fijo_Puerto := 130 * power(1 / 1.12, AnioGas - 2009);

  NAnios := 2026 - 2009 + 2;
  setlength(fechas, NAnios);

  fechas[0] := TFecha.Create_AnioMesDia(1980, 1, 1);
  for k := 1 to high(fechas) do
    fechas[k] := TFecha.Create_AnioMesDia(2008 + k, 5, 1);
end;

procedure IniciarPoblacion;
var
  a: TPlan;
  narranque: integer;
begin
  SysUtils.DecimalSeparator := '.';
  narranque := 2;
  while Poblacion_Count < narranque do
  begin
    a := TPlan.CreateRND;
    writeln('pertenezco a la poblacion =', a.poblacion);
    a.Evaluar;
    NotificarResultado(a);
  end;
end;

{$IFDEF CLUSTER}
function flgPararTarea: boolean;
var
  f:    textfile;
  s:    string;
  ntareas: integer;
  res:  integer;
  resb: boolean;

begin
  resb     := False;
  filemode := 2;
  assignfile(f, '/home/simsee/flg_parar_ntareas.txt');
  {$I-}
  reset(f);
  {$I+}
  if ioresult = 0 then
  begin
    {$I-}
    readln(f, s);
    {$I+}
    res := ioresult;
    closefile(f);
    if res = 0 then
    begin
      val(s, ntareas, res);
      if res = 0 then
      begin
        if ntareas > 0 then
        begin
          resb := True;
          Dec(ntareas);
          if ntareas >= 0 then
          begin
            rewrite(f);
            writeln(f, ntareas);
            closefile(f);
          end;
        end
        else
          erase(f);
      end;
    end;
  end;
  Result := resb;
end;
{$ELSE}

(*
create table flgparartarea (
  nid int,
  cnt int,
  idnodo int,
  PRIMARY KEY( nid )
)
*)
function flgPararTarea: boolean;
var
  nid: string;
begin
  nid:= urosx.sql_func('SELECT nid FROM flgparartarea WHERE cnt> 0 AND idnodo IN ( -1, '+IntToStr( idNodo )+') LIMIT 1' );
  if nid <> '' then
  begin
    urosx.sql_exec( 'UPDATE flgparartarea SET cnt= cnt-1 WHERE nid = '+nid+' LIMIT 1');
    result:= true;
  end
  else
    result:= false;
end;
{$ENDIF}

procedure OptimizarPoblacion;
var
  buscando: boolean;
  cnt_generaciones: integer;
  a:      TPlan;
  resNot: integer;
  kNew:   integer;
  cnt_loop: integer;
  a_gpa: TPlan;
  NINdividuos: NInt;

begin
  Inicializar;

{$IFDEF CLUSTER}
  urosx.ipfija := '192.168.242.1'; // nodo01 del Cluster
  urosx.puerto := 2281;
  // entrada del tunel ( ssh -L 192.168.242.1:2281:iie.fing.edu.uy:80 cluster )
{$ELSE}
  urosx.ipfija := '';
  urosx.puerto := 80;
  urosx.host   := 'iie.fing.edu.uy';
{$ENDIF}

//OJO!! borrar registros de la base para empezar de cero
// sql_exec('DELETE FROM ' + tablaEvaluaciones);


  IniciarPoblacion;         //inicializa población con 2 miembros

    //descargar contenido de la base de datos a disco
  descargarDatosADisco(Poblacion_count, 1);

      //calcular geneticos
    a := Aparear;
    a.Evaluar;
    NotificarResultado(a);
    a.Free;

        a := Aparear;
    a.Evaluar;
    NotificarResultado(a);
    a.Free;

        a := Aparear;
    a.Evaluar;
    NotificarResultado(a);
    a.Free;

      (*
         NIndividuos:= Poblacion_count;
         a_gpa := nuevoPlanGPA(NIndividuos, NIndividuos-1, 1);
         a_gpa.Evaluar;
         NotificarResultado(a_gpa);
         a_gpa.Free;
       *)

  //descargar contenido de la base de datos a disco
  descargarDatosADisco(Poblacion_count, 1);

//empieza la optimizacion
  optimizando := True;
  cnt_loop    := 0;
  while optimizando do
  begin
    //calcular geneticos
    a := Aparear;
    a.Evaluar;
    NotificarResultado(a);
    a.Free;
    (*
    //calcular gpa's
    NIndividuos := Poblacion_count;
    if (NIndividuos > 2) and ((NIndividuos mod 10) = 0) then
    begin
         a_gpa := nuevoPlanGPA(NIndividuos, NIndividuos-5, 1);
         a_gpa.Evaluar;
         NotificarResultado(a_gpa);
         a_gpa.Free;
         descargarDatosADisco(Poblacion_count, 1);
    end;
    *)

    NIndividuos := Poblacion_count;
    if ((NIndividuos mod 50) = 0) then
    begin
      descargarDatosADisco(NIndividuos, 1);
    end;

    Inc(cnt_loop);
    optimizando := cnt_loop < 1000;   //con 100 demora 2horas y media
    optimizando := optimizando and (not flgPararTarea );

  end;

     descargarDatosADisco(Poblacion_count, 1);
  end;
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//AQUI COMIENZA LA PARTE uplanesGPA
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
function obtener_dsBaseDeDatos(N, NIndividuos, criterio: integer): TResultadoQuery;
var
  ds :                 TResultadoQuery;
  orderby:             String;
  begin
      case criterio of
           0: orderby:= ' ORDER BY cad ';
           1: orderby:= ' ORDER BY cpialfa ';
           2: orderby:= ' ORDER BY cadpe5 ';
           3: orderby:= ' ORDER BY cpibeta ';
           end;

{$IFDEF SOLOGAS}
{$IFDEF SINEOLICO}
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones +
    ' WHERE haygas AND sineolico '+orderBy+' LIMIT ' + IntToStr(NIndividuos-N) + ', ' + IntToStr(N) + ' ');   //lo primero es el desplazamiento, lo segundo es la cantidad de elementos que quiero tomar
{$ELSE}
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones +
    ' WHERE haygas '+orderBy+' LIMIT ' + IntToStr(NIndividuos-N) + ', ' + IntToStr(N) + ' ');
{$ENDIF}
{$ELSE}
  ds := sql_query('SELECT * FROM ' + tablaEvaluaciones +orderBy+' LIMIT ' + IntToStr(NIndividuos-N) + ', ' + IntToStr(N) + ' ');
{$ENDIF}
        writeln('\n tamano del registro que devuelve obtener_dsBaseDeDatos = ', ds.nrows);
        Result := ds;

end;

function decodificarPlan(r: TDataRecord): TPlan;
var
  a: TPlan;
  idPlan, poblacion: integer;
  adn:    string;
  cnt_evaluaciones: integer;
  cad, cad_min, cad_max, cadpe5, cadpe5_min, cadpe5_max: NReal;
  vcads, vcadspe5: string;
  cpialfa, cpibeta: NReal;
begin
    idPlan := StrToInt(r.GetByNameAsString('nid'));
    poblacion := StrToInt(r.GetByNameAsString('poblacion'));
    adn := r.GetByNameAsString('adn');
    cnt_evaluaciones := r.GetByNameAsInt('cnt_evaluaciones');
    cad := r.GetByNameAsFloat('cad');
    cad_max := r.GetByNameAsFloat('cad_max');
    cad_min := r.GetByNameAsFloat('cad_min');
    cadpe5 := r.GetByNameAsFloat('cadpe5');
    cadpe5_min := r.GetByNameAsFloat('cadpe5_min');
    cadpe5_max := r.GetByNameAsFloat('cadpe5_max');
    vcads:= r.GetByNameAsString( 'vcads' );
    vcadspe5:= r.GetByNameAsString( 'vcadspe5' );
    cpialfa:= r.GetByNameAsFloat( 'cpialfa' );
    cpibeta:= r.GetByNameAsFloat( 'cpibeta' );

    a := TPlan.Create_Unserialize(idPlan, poblacion, adn, cnt_evaluaciones, cad,
          cad_min, cadpe5, cadpe5, cadpe5_min, cadpe5_max
          , cpialfa, vcads, vcadspe5, cpibeta   );
    Result := a;
end;

function obtener_planesBaseDeDatos(N: Integer; ds: TResultadoQuery): TDaOfTPlan;
var
   i     : Integer;
   atp   : TDAOfTPlan;
   r     : TDataRecord;
begin
     setlength(atp, N);

     for i := 0 to N-1 do
     begin
         r := ds.next;
         atp[i] := decodificarPlan(r);
     end;
     Result:= atp;
end;

function obtener_pid(planBaseDeDatos: TDaofTPlan): TDAOfNInt;
var
  arn     : TDAOfNInt;
  N, i    : Integer;
begin
     N := length(planBaseDeDatos);
     setlength(arn, N);
     for i := 0 to N-1 do
     begin
         arn[i] := planBaseDeDatos[i].idPlan;
     end;
     Result := arn;

end;

//busca un plan completo conociendo solamente el idPlan
function buscarPlan(idPlan: Integer; planBaseDeDatos: TDaofTPlan): TPlan;
var

   N:                       Integer;
   i:                       Integer;
   encontre:                Boolean;
   count:                   Integer;
begin
     N := length(planBaseDeDatos);
     count:=-1;
     encontre:=FALSE;
     while (not (encontre)) and (count < N) do
     begin
          if (idPlan = planBaseDeDatos[i].idPlan) then
             encontre := TRUE;
          count := count+1;
     end;

     if (encontre and (count < N)) then
        Result:= planBaseDeDatos[count] //devuelve el encontrado
     else begin
         Result:= planBaseDeDatos[1];
         writeln( '******** error: plan no encontrado!!! ***********');
     end;

end;

function calcular_Deltaxk(planes: TDaofTPlan; xAster: TPlan): TDAOfDAofNReal;
var
   anr     :   TDAOfDAofNReal;
   N       :   Integer;
   i,j     :   Integer;
   lx      :   Integer;
   auxArr  :   TDaOfNReal;
begin
     N:= length(planes); //cantidad de planes de Gamma'
     setlength(anr,N); //el vector tiene N diferencias, i.e. xk-x* con k=0,...,N-1
     //a su vez cada elemento tiene una cantidad fija de variables (lx):
     lx:=length(planes[0].unidades_eolico); //GENERALIZAR PARA OTROS ADN
     setlength(auxArr, lx);

     for i:= 0 to N-1 do
     begin
          for j:= 0 to lx-1 do
          begin
               auxArr[j] := planes[i].unidades_eolico[j]-xAster.unidades_eolico[j];     //GENERALIZAR PARA OTROS ADN
          end;
          anr[i] := auxArr;
     end;
     Result:= anr;
end;

function calcular_rk(Deltaxk: TDAOfDAofNReal): TDAOfNReal;
var
 aux, vD: TDAOfNReal;
 N:   Integer;
 xl:  Integer;
 i,j: Integer;
 begin
  N:= length(Deltaxk);     //cantidad de planes en gamma'
  setlength(aux,N);

  xl:= length(Deltaxk[0]); //tamaño de un vector x
  setlength(vD, xl);

     for i:=0 to N-1 do
     begin
          vD := Deltaxk[i];

          aux[i]:= 0;
          for j:= 0 to xl-1 do
          begin
              aux[i] := aux[i] + sqr(vD[j]);
          end;
          aux[i] := sqrt(aux[i]);
     end;

  Result:= aux;

end;

function calcular_Deltafk(planes: TDAofTPlan; xAster: TPlan): TDAOfNReal;
var
   auxf: TDAOfNReal;
   i:    Integer;
   N:    NInt;
begin

     N := length(planes); //cantidad de elementos de gamma'
     setlength(auxf, N);

     for i:= 0 to N-1 do
     begin
          auxf[i] := planes[i].cpialfa - xAster.cpialfa;  //GENERALIZAR PARA CUALQUIER F DE ACUERDO A CRITERIO!!!
     end;
     Result:= auxf;
end;

function calcular_dk(rk: TDAOfNReal; Deltafk: TDAOfNReal): TDaofNReal;
var
N, i:     Integer;
auxr:     TDaOfNreal;
begin
     N    := length(rk);
     setlength(auxr,N);
     for i:= 0 to N-1 do
     begin
           if not (rk[i] = 0) then
              auxr[i] := Deltafk[i]/rk[i];        //OJO, el caso en que rk[i]=0 tiene que ser considerado aparte!!
     end;
     Result:= auxr;

end;

function calcular_S(dk: TDaOfNReal): NReal;
var
   i: Integer;
   aux: NReal;
begin
      aux:= 0.0;
      for i:= 0 to length(dk)-1 do
      begin
           aux:= aux+dk[i];
      end;
      Result:= aux;

end;

function calcular_xgp(S: NReal; Deltafk: TDaOFNreal; Deltaxk: TDAOfDAOfNReal;  rk : TDaofNReal): TPlan;

var
  i, j, N, lue:  Integer;
  xa:            TDaOfNInt;
  xp:            TPlan;
  acumR:         NReal;
  xr:            TDAOfNReal;
begin
  //supongo que x = unidades_eolico      OJO!!! GENERALIZAR PARA CUANDO EL ADN ES OTRA COSA!!
  setlength(xr, length(Deltaxk[0]));
  xr        := Deltaxk[0];
  lue       := length(xr);
  N         := length(Deltafk); //la cantidad de elementos de gammaprima
  setlength(xa, lue); //este va a ser el nuevo x (adn)

  for j := 0 to lue-1 do
  begin
       acumR := 0.0;
       xa[j] := 0;

       for i:= 0 to N-1 do
       begin
            xr := Deltaxk[i];
            acumR := acumR + ((-Deltafk[i]/rk[i])*xr[j])/S ;
       end;
       xa[j] := trunc(acumR);       //truncar a enteros para que sea una cantidad de unidades válida
  end;

  //crear plan
  xp := TPlan.Create;
  for j := 0 to lue-1 do
  begin
     xp.unidades_eolico[j] := xa[j];    //TENGO LA DUDA SI ALCANZA CON PONER: xp.unidades_eolico := xa;
  end;

  xp.poblacion:=472; //indica que este plan es de la raza gpa
  Result:= xp;

  end;

procedure descargarDatosADisco(NIndividuos: Integer; criterio: Integer);
var
arrPlanes	:	TDAOfTPlan;
ds		:	TResultadoQuery;
arrPID	        :	TDAOFNInt;
arrFX	        :	TDAOFNInt;
plan		:	TPlan;
fileOut		:	Text;
i               :       Integer;
f_x             :       NReal;
begin

setlength(arrPlanes, NIndividuos);
ds	        :=   obtener_dsBaseDeDatos(NIndividuos, NIndividuos, criterio);
arrPlanes	:=   obtener_planesBaseDeDatos(NIndividuos, ds);

//abrir archivo para guardar
assign (fileOut, 'salida_optgen_gpa.txt');
rewrite (fileOut);

for i := 0 to NIndividuos -1 do
begin
	plan	:=	arrPlanes[i];
	case criterio of
		0: f_x := plan.cad;
		1: f_x := plan.cpialfa;
		2: f_x := plan.cadpe5;
		3: f_x := plan.cpibeta;
	end;
	//writeln(f, plan.idPlan, '  ', f_x, '  ',plan.poblacion);
        writeln('////////////LISTA DE PLANES/////////////');
        writeln('idPlan = ', plan.idPlan, '  f_x = ', ' ', plan.poblacion);
        writeln(fileOut, plan.idPlan, '  ', f_x, '  ', plan.poblacion);

end;
writeln('//////////////////FIN LISTA DE PLANES//////////////////');

close(fileOut);

end;

/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//función principal
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// obtiene un nuevo plan mediante un algoritmo de gradiente promedio con puntajes
// utilizando resultados previos de la base de datos.
// inputs:    NT          - el subconjunto del total de la poblacion (NIndividuos) que considero para la evaluacion
//            NGamma      - los que tomo en cada colección para reducir T a Gamma
//            criterio    - entero que indica la función a minimizar
// outputs:   TPlan       - nuevo plan para probar
function nuevoPlanGPA(NT, NGamma: integer; criterio: integer): TPlan;
var
  orderBy:                          String;
  NIndividuos, i:                   Integer;
  //estructuras de datos de SQL:
  dsBaseDeDatos:                    TResultadoQuery;
  //estructuras de datos para los planes
  xAster:                           TPlan;
  planesBaseDeDatos:                TDAOfTPlan;
  planesGamma, planesGamma_p:       TDAOfTPlan;
  pidSegun_cEvaluacion:             TDAOfNInt;
  //calculo de gp
  Deltaxk:                          TDAOfDAOfNReal;
  rk, Deltafk, dk:                  TDAOfNReal;
  S:                                NReal;
  xgp:                              TPlan;
begin

  if criterio = 777 then           //criterio aleatorio
  begin
    if random < 0.5 then
       if random < 0.5 then
          criterio:= 0
       else
          criterio:= 1
    else
    if random < 0.5 then
       criterio:= 2
    else
        criterio:= 3;
  end;

  case criterio of
      0: orderby    := ' ORDER BY cad ';
      1: orderby    := ' ORDER BY cpialfa ';
      2: orderby    := ' ORDER BY cadpe5 ';
      3: orderby    := ' ORDER BY cpibeta ';
  end;

  //1.1 obtener individuos de la base de datos, ordenados por criterio de evaluacion (menor f)
  NIndividuos                := Poblacion_count;
  dsBaseDeDatos              := obtener_dsBaseDeDatos(NT, NIndividuos,criterio);
  planesBaseDeDatos          := obtener_planesBaseDeDatos(NT, dsBaseDeDatos);
  pidSegun_cEvaluacion       := obtener_pid(planesBaseDeDatos);

  //1.2 asignar el plan optimo actual (xAster)
  xAster                     := planesBaseDeDatos[0];

  //2.1 calcular Gamma. . .
  //planesGamma              := calcular_Gamma(NGamma, planesBaseDeDatos, vectoresCon_pid);
  setlength(planesGamma, NGamma);
  setlength(planesGamma_p, NGamma-1);

  //sacar el plan xAster de planesGamma.
  //esto que sigue a lo groncho es para debug
  for i := 0 to NGamma-2 do
  begin
      planesGamma_p[i]    :=   planesBaseDeDatos[i+1];
  end;


  //Calcular cantidades
  Deltaxk    :=        calcular_Deltaxk(planesGamma_p, xAster);
  Deltafk    :=        calcular_Deltafk(planesGamma_p, xAster);
  rk         :=        calcular_rk(Deltaxk);
  dk         :=        calcular_dk(rk, Deltafk);

  S          :=        calcular_S(dk);
  xgp        :=        calcular_xgp(S, Deltafk, Deltaxk, rk);

  //1.2 obtener un registro con los primeros NGamma ordenados por cercania al xAster: vSegun_cCercania
  //. . .
  //pidSegun_cCercania := obtener_pid();

  //2.1 asignar coeficientes de puntaje

  //2.2 asignar puntajes a los elementos de vSegun_cEvaluacion

  //2.3 asignar puntajes a los elementos de vSegun_cCercania

  //3 calcular Gamma

  //4.1 calcular Delta f_k y Delta x_k

  //4.2 calcular S

  //4.3 calcular nuevo plan

  //4.4 devolverlo
  Result          :=   xgp;

end;




initialization
  idEjecutor := '';
  version_historial := -1; // no versionado

(* serie 1
  setlength( serie_WTI, 11 );
  serie_WTI[0]:= 78.4;
  serie_WTI[1]:= 78.4;
  serie_WTI[2]:= 80.78;
  serie_WTI[3]:= 83.16;
  serie_WTI[4]:= 85.68;
  serie_WTI[5]:= 88.27;
  serie_WTI[6]:= 90.86;
  serie_WTI[7]:= 93.59;
  serie_WTI[8]:= 96.53;
  serie_WTI[9]:= 96.53;
  serie_WTI[10]:= 96.53;
*)

(* BCU2010 - escenario alto
  setlength( serie_WTI, 22 );
  serie_WTI[0]:= 78.4; // 1980 ficha inicial
  serie_WTI[1]:= 78.4; // 2010
  serie_WTI[2]:= 83.1;
  serie_WTI[3]:= 88.09;
  serie_WTI[4]:= 93.38;
  serie_WTI[5]:= 98.98;
  serie_WTI[6]:= 104.92;
  serie_WTI[7]:= 111.21;
  serie_WTI[8]:= 117.88;
  serie_WTI[9]:= 124.96;
  serie_WTI[10]:= 132.46;
  serie_WTI[11]:= 140.4;
  serie_WTI[12]:= 148.83;
  serie_WTI[13]:= 157.76;
  serie_WTI[14]:= 167.22;
  serie_WTI[15]:= 177.25;
  serie_WTI[16]:= 187.89;
  serie_WTI[17]:= 199.16;
  serie_WTI[18]:= 211.11;
  serie_WTI[19]:= 223.78;
  serie_WTI[20]:= 237.21;
  serie_WTI[21]:= 251.44;
*)


(*
                         x  Low  Ref  Hgh
serie_WTI[0]:=  2008  78.4  100.0  100.0  100.0
serie_WTI[1]:=  2010  78.4  92.0  99.2  107.5
serie_WTI[2]:=  2011  83.1  84.0  98.3  115.0
serie_WTI[3]:=  2012  88.09  76.0  97.5  122.5
serie_WTI[4]:=  2013  93.38  68.0  96.7  130.0
serie_WTI[5]:=  2014  98.98  60.0  95.8  137.5
serie_WTI[6]:=  2015  104.92  52.0  95.0  145.0
serie_WTI[7]:=  2016  111.21  52.0  97.6  153.2
serie_WTI[8]:=  2017  117.88  52.0  100.2  161.4
serie_WTI[9]:=  2018  124.96  52.0  102.8  169.6
serie_WTI[10]:=  2019  132.46  52.0  105.4  177.8
serie_WTI[11]:=  2020  140.4  52.0  108.0  186.0
serie_WTI[12]:=  2021  148.83  52.0  109.4  188.0
serie_WTI[13]:=  2022  157.76  52.0  110.8  190.0
serie_WTI[14]:=  2023  167.22  52.0  112.2  192.0
serie_WTI[15]:=  2024  177.25  52.0  113.6  194.0
serie_WTI[16]:=  2025  187.89  52.0  115.0  196.0
serie_WTI[17]:=  2026  199.16  52.0  116.8  197.6
serie_WTI[18]:=  2027  211.11  52.0  118.6  199.2
serie_WTI[19]:=  2028  223.78  52.0  120.4  200.8
serie_WTI[20]:=  2029  237.21  52.0  122.2  202.4
serie_WTI[21]:=  2030  251.44  52.0  124.0  204.0
serie_WTI[??]:=  2031    51.8  125.8  205.2
serie_WTI[??]:=  2032    51.6  127.6  206.4
serie_WTI[??]:=  2033    51.4  129.4  207.6
serie_WTI[??]:=  2034    51.2  131.2  208.8
serie_WTI[??]:=  2035    51.0  133.0  210.0
*)


{$IFDEF WTI_EIA_LOW}
  (* escenario EIA2010 low*)
  setlength(serie_WTI, 27);
  serie_WTI[0]  := 100;
  serie_WTI[1]  := 92;
  serie_WTI[2]  := 84;
  serie_WTI[3]  := 76;
  serie_WTI[4]  := 68;
  serie_WTI[5]  := 60;
  serie_WTI[6]  := 52;
  serie_WTI[7]  := 52;
  serie_WTI[8]  := 52;
  serie_WTI[9]  := 52;
  serie_WTI[10] := 52;
  serie_WTI[11] := 52;
  serie_WTI[12] := 52;
  serie_WTI[13] := 52;
  serie_WTI[14] := 52;
  serie_WTI[15] := 52;
  serie_WTI[16] := 52;
  serie_WTI[17] := 52;
  serie_WTI[18] := 52;
  serie_WTI[19] := 52;
  serie_WTI[20] := 52;
  serie_WTI[21] := 52;
  serie_WTI[22] := 51.8;
  serie_WTI[23] := 51.6;
  serie_WTI[24] := 51.4;
  serie_WTI[25] := 51.2;
  serie_WTI[26] := 51;
{$ENDIF}

{$IFDEF WTI_EIA_REF}

  (* escenario EIA2010 ref*)
  setlength(serie_WTI, 27);
  serie_WTI[0]  := 100;
  serie_WTI[1]  := 99.1666666666667;
  serie_WTI[2]  := 98.3333333333333;
  serie_WTI[3]  := 97.5;
  serie_WTI[4]  := 96.6666666666666;
  serie_WTI[5]  := 95.8333333333333;
  serie_WTI[6]  := 95;
  serie_WTI[7]  := 97.6;
  serie_WTI[8]  := 100.2;
  serie_WTI[9]  := 102.8;
  serie_WTI[10] := 105.4;
  serie_WTI[11] := 108;
  serie_WTI[12] := 109.4;
  serie_WTI[13] := 110.8;
  serie_WTI[14] := 112.2;
  serie_WTI[15] := 113.6;
  serie_WTI[16] := 115;
  serie_WTI[17] := 116.8;
  serie_WTI[18] := 118.6;
  serie_WTI[19] := 120.4;
  serie_WTI[20] := 122.2;
  serie_WTI[21] := 124;
  serie_WTI[22] := 125.8;
  serie_WTI[23] := 127.6;
  serie_WTI[24] := 129.4;
  serie_WTI[25] := 131.2;
  serie_WTI[26] := 133;
{$ENDIF}

{$IFDEF WTI_EIA_HIGH}
  (* escenario EIA2010 high*)
  setlength(serie_WTI, 27);
  serie_WTI[0]  := 100;
  serie_WTI[1]  := 107.5;
  serie_WTI[2]  := 115;
  serie_WTI[3]  := 122.5;
  serie_WTI[4]  := 130;
  serie_WTI[5]  := 137.5;
  serie_WTI[6]  := 145;
  serie_WTI[7]  := 153.2;
  serie_WTI[8]  := 161.4;
  serie_WTI[9]  := 169.6;
  serie_WTI[10] := 177.8;
  serie_WTI[11] := 186;
  serie_WTI[12] := 188;
  serie_WTI[13] := 190;
  serie_WTI[14] := 192;
  serie_WTI[15] := 194;
  serie_WTI[16] := 196;
  serie_WTI[17] := 197.6;
  serie_WTI[18] := 199.2;
  serie_WTI[19] := 200.8;
  serie_WTI[20] := 202.4;
  serie_WTI[21] := 204;
  serie_WTI[22] := 205.2;
  serie_WTI[23] := 206.4;
  serie_WTI[24] := 207.6;
  serie_WTI[25] := 208.8;
  serie_WTI[26] := 210;
{$ENDIF}

end.
