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_agosto2011sa';

  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

    // 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; 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;


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;

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


function LeerPlan( nid: integer ): TPlan;




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


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
  kAnio: integer;
  gwh: double;
  kAnioIni: integer;
  res: WideString;
  tasa, vartasa: double;
  k: integer;

begin
  kAnioIni := 2009;
  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;
  idplan: integer;
  res, 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 esta
    ts  := sql_func('SELECT nid FROM ' + tablaEvaluaciones + ' WHERE adn = ''' +
      adn + ''' LIMIT 1');
    if ts <> '' then
      a.idPlan := StrToInt(ts);
  end;

  if a.idPlan < 0 then
  begin
    a.idPlan := sql_nextnid(tablaEvaluaciones);

    sql      := 'INSERT INTO ' + tablaEvaluaciones
      + ' ( nid, 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) + ', ' + 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: 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'));
    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, adn, cnt_evaluaciones, cad,
          cad_min, cadpe5, cadpe5, cadpe5_min, cadpe5_max
          , cpialfa, vcads, vcadspe5, cpibeta  );
  end
  else
    a:= nil;
  Result := a;
end;


function Poblacion_selPadre(NIndividuos: integer; criterio: integer ): TPlan;
var
  p:      NReal;
  k:      integer;
  ds:     TResultadoQuery;
  r:      TDataRecord;
  idPlan: 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 ');
{$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'));
  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, 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;
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: 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;

  // 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];
  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);//para sacar informacion adicional
  leer_vcads;
  cpialfa:= calc_cpialfa( 0.5, vcads, vcadspe5, CAD );
  cpibeta:= calc_cpiBeta( 1.0, vcads, vcadspe5, CAD );

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
{$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"
    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;
    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/rchaer/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;

begin
  Inicializar;

{$IFDEF CLUSTER}
  uros.ipfija := '192.168.242.1'; // nodo01 del Cluster
  uros.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}

  IniciarPoblacion;

  optimizando := True;
  cnt_loop    := 0;
  while optimizando do
  begin

    a := Aparear;
    a.Evaluar;
    NotificarResultado(a);
    a.Free;
    Inc(cnt_loop);
    optimizando := cnt_loop < 50000;
    optimizando := optimizando and (not flgPararTarea );
  end;
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.

