unit uHidroConEmbalseBinacional;
{$DEFINE CONCONTROLCRECIDA}
//{$Define LECTURA BARRIDO ESTADOS}
{$DEFINE COSTOSHIDROPOSITIVOS}

{$DEFINE HIDRO_DERIVADA_SIMETRICA}

interface

uses
  Classes,
  Math, xMatDefs, uSimplex, ucosa, uGlobs, uFechas, uNodos,
  SysUtils,
  uEstados,
  uFichasLPD,
  uGeneradores,
  uconstantesSimSEE,
  uFuentesAleatorias, uCosaConNombre, uevapUruguay, math01, compol,
  uFuncionesReales,uparseadorsupersimple,
  ufuncionesbasicas;

resourcestring
  rsGHidraulicoEmbalseBinacional = 'Generador hidráulico con embalse binacional';
  mesFuenteAleatConPaso1h =
    'Generador hidráulico con embalse binacional, necesita una fuente aleatoria con paso de sorteo = 1h. ';
  mesElParque = 'El parque ';
  mesConectadoAFuente = ' está conectado a la fuente ';
  mesConPasoDeSorteo = ' con paso de sorteo = ';

const
  ro_Agua = 1000; // kg/m3 densidad del agua
  g_Gravitacion = 9.8; // N/kg constante gravitatoria

type
  THidroConEmbalseBinacional = class; // forward declaration

(* Para describir el embalse, damos el volumen máximo turbinable Vmax
que corresponde al volumen (en m3 ) que almacena el embalse entre las
cotas hmin y hmax.
Y el volumen almacenado entre hmin y hmed siendo hmed = (hmax+hmin)/2

Las cotas están medidas desde algún nivel (por ejemplo el del mar).
Para poder calcular el salto se suministra también la cota de aguas abajo
o de descarga de la turbina referida al mismo nivel. (hDescarga [m])
El nivel de descarga puede ser especificado dando su valor con la variable
hDescarga o mediante la referencia a otra central en cuyo caso se considera
que el nivel de descarga es el del lago de la otra central más el valor
hDescarga. En este caso la variable hDescarga se utiliza para tener en
cuenta cambios en la referencia de niven entre una central y otra.
Si todas las cotas están referidas al nivel del mar no hay cambios de
referencias y hDescarga se pondrá en cero.

Suponemos que el área del embalse crece linealmente con la cota
A(z) = a + b * z
V(z) = integral( A(z) )= a*z + 1/2 * b z^2

con z= (h-hmin)/(hmax-hmin)

Vmax - Vmin = V(1) = a+ 0.5 b
Vhmed - Vmin= V(0.5) = 0.5 a + 0.5^3 b

=> Vmax-Vmin - 2*(Vhmed- Vmin)= 0.5 b - 0.5^2 b =  0.5^2 b
=>  b = 4*( (Vmax-Vmin)-2* (Vhmed-Vmin) )
.:  a = Vmax-Vmin - 0.5 b

V= ( 1/2*b/dhmax^2 * dh + a/dhmax ) dh + Vmin =

Pérdida de Salto por Caudal Erogado.
====================================
El caudal erogado QErogado [m3/s] es calculado al final de cada paso
de simulación como la suma del caudal vertido más el caudal turbinado.
Dicho caudal puede afectar el nivel de aguas abajo reducciendo el salto
efectivo en la central. Para tener en cuenta este efecto se usan los
parámetros: caQE y cbQE calculados para modelar la pérdida de salto
de acuerdo a la siguiente ecuación:

dh(QE) = caQE* QE + cbQE* QE^2
*)

  { TFichaHidroConEmbalseBinacional }

  TFichaHidroConEmbalseBinacional = class(TFichaLPD)
  public
    (**************************************************************************)
    (*              A T R I B U T O S   P E R S I S T E N T E S               *)
    (**************************************************************************)

    hmax: NReal; //[m] cota maxima
    hmin: NReal; //[m] cota minima
    // descripción de la geometria del lago
    PuntosCotaVolumen_h: TDAOfNReal;
    PuntosCotaVolumen_V: TDAOfNReal;
    hDescarga: NReal; //[m] cota de la descarga para cálculo del salto
    // Coeficientes de afectación del salto por caudal erogado
    // dh(QE) = caQE* QE + cbQE* QE^2
    caQE: NReal;
    cbQE: NReal;
    ren: NReal;       //[pu] rendimiento complexivo de turbina y generador
    Pmax_Gen: NReal;  //[MW] Potencia maxima hidraulica
    Qmax_Turb: NReal; //[m3/s]
    fDispo: NReal;    //[pu] factor de disponibilidad fortuita
    tRepHoras: NReal;
    // filtración = filtracion_Ca + filtracion_Cb * ( h- hmin )
    filtracion_Ca: NReal; //[m3/s]
    filtracion_Cb: NReal; //[m2/s]
    // Caudal de aportes por debajo del cual consideramos ambiente MUY SECO
    // para el cálculo de la evaporación
    QaMuySeco: NReal; //[m3/s]
    //La cota minima a partir de la cual se puede verter y la cota maxima a
    //partir de la cual el máximo vertimiento es constante
    cotaMV0, cotaMV1: NReal;
    //El caudal que se puede verter con la cota maxima.
    //QMV0 se omite porque siempre es 0
    QMV1: NReal;
    centralesAguasArriba: TListaCentralesAguasArriba {of TGeneradorHidraulico};
    central_lagoDescarga: TGeneradorHidraulico;
    HayRestriccionEmaxPasoDeTiempo: boolean; // indica si se aplica la restricción
    EmaxPasoDeTiempo: NReal; // Energía maxima generable en un paso de tiempo
    HayRestriccionQTmin: boolean; // indica si se aplica la restricción
    QTmin: NReal; // caudal mínimo de la central
    ImponerQminPorPoste: boolean;
    (* rch080402 agrego esto para dar la opción de regular el uso de Salto y Palmar *)
    hObjetivo: NReal; // [m] cota objetivo
    delta_cva_ParaControlDeCota: NReal; // USD/Hm3 aplicable para control de cota
    flg_controlCotaObjetivoInferior: boolean;
    flg_controlCotaObjetivoSuperior: boolean;
    cv_USD_Hm3_ValorizadoManual: NReal;
    // generación para Argentina en MW para cada hora del paso de tiempo
    P_AG: TDAofNReal;
    //Caudal Erogado para Cálculo de Energía Embalsada
    QE_CEE: NReal;
    hVistaMin: NReal;

    //JFP 2/12/15: Cambio de 2 a 3 puntos (cota, erogado mínimo) para aproximar curva vertidos por polinomio de grado 2.
    //Activar o no control de crecida por cota.
    flg_ControlCrecidaPorCota: boolean;
    //Altura a la cual se activa el control de crecida en m
    cotaControlCrecida_Inicio: NReal;
    //Cota media y a pleno del control de crecida en m
    cotaControlCrecida_Medio: NReal;
    cotaControlCrecida_Pleno: NReal;

    // caudal en m3/s mínimo a erorgar para cada cota del control de crecida.
    QE_ControlDeCrecidaInicio: NReal;
    QE_ControlDeCrecidaMedio: NReal;
    QE_ControlDeCrecidaAPleno: NReal;


    saltoMinimoOperativo: NReal; // [m] salto mínimo operativo de las turbinas
    //cv incurrido por Hm^3h por estar por arriba de cotaActivacionControlCrecida en USD/Hm^3h
    flg_CalcularEvaporacionDelLago: boolean;
    flg_CalcularFiltracionDelLago: boolean;
    // Pagos a los generadores
    PagoPorDisponibilidad_USD_MWh: NReal; // [USD/MWh] Pago por Potencia
    PagoPorEnergia_USD_MWh: NReal; // [USD/MWh] Pago por Potencia

    //JFP: Agrego para control de cota por curva de remanso
    PuntosControlCrecidaPorCotaYAportes_h: TDAOfNReal; // cotas [m]
    PuntosControlCrecidaPorCotaYAportes_QA: TDAOfNReal;// Aportes[m3/s]
    flg_ControlCrecidaPOrCotaYAportes: boolean;  // indica si está operativo el control

    //JFP 23/9/15: Agrego erogado mínimo a Uruguay por navegabilidad independiente del erogado mínimo de la central.
    QTMinUY: Nreal;

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


    constructor Create(capa: integer; fecha: TFecha; periodicidad: TPeriodicidad;
      hmin_, hmax_: NReal; PuntosCotaVolumen_h, PuntosCotaVolumen_V: TDAOfNReal;
      hDescarga: NReal; central_lagoDescarga: TGeneradorHidraulico;
      centralesAguasArriba: TListaCentralesAguasArriba;
      caQE, cbQE, ren_, Pmax_Gen_, Qmax_Turb_: NReal; fDispo_: NReal;
      tRepHoras: NReal; filtracion_Ca, filtracion_Cb, QaMuySeco: NReal;
      cotaMV0, cotaMV1, QMV1: NReal; HayRestriccionEmaxPasoDeTiempo: boolean;
      EmaxPasoDeTiempo: NReal; HayRestriccionQTmin: boolean;
      QTmin: NReal; ImponerQminPorPoste: boolean;
      ControlarCotaPorDebajoDeObjetivo: boolean;
      ControlarCotaPorEnciaDeObjetivo: boolean; hObjetivo: NReal;
      Delta_cvaUSD_Hm3ParaControlDeCota: NReal; cv_USD_Hm3_ValorizadoManual: NReal;
      P_AG: TDAOfNreal; QE_CEE: NReal; hVistaMin: NReal;
      saltoMinimoOperativo: NReal;
      cotaControlCrecida_inicio, cotaControlCrecida_Medio,
      cotaControlCrecida_pleno, QE_ControlDeCrecidaInicio,
      QE_ControlDeCrecidaMedio, QE_ControlDeCrecidaAPleno: NReal;
      flg_CalcularEvaporacionDelLago: boolean; flg_CalcularFiltracionDelLago: boolean;
      PagoPorDisponibilidad_USD_MWh: NReal; PagoPorEnergia_USD_MWh: NReal;
      PuntosControlCrecidaPorCotaYAportes_h, PuntosControlCrecidaPorCotaYAportes_QA:
      TDAOfNReal; flg_ControlCrecidaPOrCotaYAportes, flg_ControlCrecidaPorCota: boolean;
      QTMinUY: NReal);

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

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

  { T_CotaToEnergiaMenosEnergia_func }
  // Clase auxiliar para resolver por métdo dicotómico la función CotaToEnergía
  T_EnergiaToCota_func_ = class(  T_ProblemaFx_Cero )
    central: THidroConEmbalseBinacional;
    EnergiaDada: NReal;
    constructor Create( central: THidroConEmbalseBinacional );
    function f(x: NReal): NReal; override;
  end;

  { THidroConEmbalseBinacional }

  THidroConEmbalseBinacional = class(TGeneradorHidraulico)
  private
    function dDEEmax_dV(V: NReal): NReal;
  public
    (**************************************************************************)
    (*              A T R I B U T O S   P E R S I S T E N T E S               *)
    (**************************************************************************)

    //Variables de Estado
    // discretizacion de la altura y de la diferencia de enegía
    hini: NReal; // cota inicial
    dEEini: NReal; // diferencia de Energía Embalsada a favor de Uy al inicio.
    NDiscH, nDiscDE: integer;
    fuenteDeAportes: TFuenteAleatoria;
    nombreBorne: string;
    flg_ValorizadoManual: boolean;

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

    pa: TFichaHidroConEmbalseBinacional;
    numeroBorne: integer;

    //----------- variables auxiliares
    // Calcular con cambioFicha.
    polinomioCotaVolumen: TPoliR;
    polinomioCotaMaxAporte: TPoliR;
    //Polinomio que aproxima curva de erogado mínimo en función del volúmen (para control de cota)
    polinomioErogadoMinVol: TPoliR;

    V_hmin: NReal; //[Hm3] volumen mínimo almacenable
    V_hmax: NReal; //[Hm3] volumen máximo almacenable
    V_hmed: NReal; //[Hm3] volumen con la cota media


    ro_g_ren: NReal; // ro_Agua * g_gravitacion * ren /(1E6*3600)
    dhmax: NReal; // hmax - hmin
    VTmin: NReal; // volumen turbinado mínimo en el paso para cumplir con QTmin
    QTmin_CalcVTminsobreHorasDelPaso: NReal;
    // caudal en Hm3/h para restricciones por poste.
    QTmin_CalcVTminsobreSegundosDelPaso: NReal;

    //Variables auxiliares que buscan hacer respetar curva de cota máxima admisible en función de aportes
    h_max_segun_Aportes: NReal;//cota de toma máxima según curva
    VTmin_segun_Aportes: NReal;
    //volúmen (hm3) erogado mínimo en el paso para cumplir h_actual<h_max_segun_Aportes
    QTmin_segun_Aportes: NReal;
    //Erogado (m3/s) mínimo en el paso para cumplir h_actual<h_max_segun_Aportes

{$IFDEF CONCONTROLCRECIDA}
    V_ControlCrecida_Inicio: NReal; // [Hm3] al que se inicia el control de crecida

    // varialbes auxiliares de .
    hs_SinErogado: NReal;
    V_ErogadoMinimo_Ctrl_Crecida: NReal;
    Q_ErogadoMinimo_Ctrl_Crecida: NReal;


    // auxiliar para preparar_ps
    auxParaCalculos_cv: NReal;
    V_EmbalsadoInicioVertedero: NReal;
    V_EmbalsadoFinalVertedero: NReal;
    Delta_V_Embalsado_Vertedero: NReal;

    V_EmbalsadoInicioProteccion: NReal;
    V_EmbalsadoProteccionAPleno: NReal;
    Delta_V_Embalsado_Proteccion: NReal;
    r_QE_Proteccion: NReal;

    // Tolerancia en VolumenErogadoMìnimo del paso
    VMinMin_1h3porSem: NReal;

{$ENDIF}

    AplicarRestriccionDeErogadoMinimo: boolean;

    h_actual: NReal; // cota actual. Es la de toma.

    // Diferencia de Energía Embalsada
    // en MWh.
    X_dEE_actual: NReal;
    // EEmbalsadaUy-EEmbalsdaAg.  dEE(k+1) = dEE(k) + ( GenAg- GenUy )
    Xs_dEE_actual: NReal;
    // EEmbalsadaUy-EEmbalsdaAg.  dEE(k+1) = dEE(k) + ( GenAg- GenUy )

    RecorteAg: NReal; // recorte del programa Argentino en el paso de tiempo MWh
    EnergiaAG, EnergiaUY: NReal; // energías tomadas en el Paso de Tiempo MWh
    h_vistaUY, h_vistaAG: NReal;

    EnergiaAlmacenada: NReal;
    EnergiaVertida: NReal;
    EAportesPropios: NReal;

    Vs_SinErogado: NReal;
    dEEs_SinErogado: NReal;
    // valor máximo de la diferencia de energía embalsada con el embalse a full.
    DEE_MAXIMA: NReal;

    // Valor máximo de la diferencia de energía embalsada determinado a partir
    // del nivel del embalse al inicio de paso.
    DEE_Max_: NReal;
    DEE_Max_s: NReal;


    dEE_inc, dEE_dec: NReal; // entrada y salida de diferencia de energía embalsada

    // variables calculadas por paso de tiempo durante la simulación
    P_Ag_programada, P_Ag_despachada, P_AG_recortada, P_Uy_despachada: TDAOfNReal;
    // potencias despachadas para Argentina. Uruguay sale por diferencia

    //JFP 23/9/15:Potencia mínima a generar por SG UY para cumplir con la mitad del erogado mínimo por navegalibilidad QTminUY
    P_Uy_QTminUY: TDAofNReal;
    EnergiaUY_min: NReal;


    //JFP: Compras mínimas exigidas por la central por control de crecidas
    P_MW_Compras_Min:NReal;

    salto_actual: NReal; // salto actual efectivo
    QErogado_IterAnterior: NReal;
    // Usamos esta variable para almacenar el QErogado en la
    // iteración anterior. Esto se hace en leerResultadosDelPaso
    // antes de cargar el nuevo valor de QErogado.
    QMaxVert: NReal;

    ce_MAXTURB0: NReal;

    (******** Esta es la variable de estado ******)
    X_VolumenEmbalsado: NReal; // volumen actual
    Xs_VolumenEmbalsado: NReal; // volumen actual

    PmaxParaQmax: NReal; // Pontecia máxima por máquina considerando Qmax y la cota
    NMaquinasDisponibles: integer;
    Pmax_Central: NReal; // [MW] Potencia Máxima disponible en la central
    PDisponible_Central: NReal; // MW Disponibles Gen x Disp. Para remuneración.
    Pmax_Gen: NReal; // [MW] Potencia máxima generable por turbina-generador
    Qmax: NReal; // [m3/s] Caudal máximo turbinable por turbina-generador


    dh_RedQE: NReal; // [m] Guarda la pérdida de salto por caulda erogado
    // variables auxiliares para la iteración por caudal erogado
    // Si está EnIteracion, el rango de potencias se fija en
    // el procedimiento NecesitoIterar para evitar oscilaciones
    Pmax_Central_CotaInf, Pmax_Central_CotaSup: TDAOfNReal;
    // se pone a false, en sorteosDelPaso y a true al pasar por NecesitoIterar
    EnIteracion: boolean;

    PuedoGenerar: boolean;
    // indica si la Central está en condiciones de ofrecer potencia o no
    cv_agua_USD_MWh: NReal; // costo variable de generación

    cv_agua_USD_Hm3_Dec: NReal; // valor del Agua expresado en USD/MWh
    cv_dEE_USD_MWh_Dec: NReal; // valor de la diferencia de energía embalzada
    cv_dEE_USD_MWh_Inc: NReal; //valor de la diferencia de energía embalzada


    Qevap: NReal; // caudal perdido por evaporacion
    Qfilt: NReal; // caudal perdido por filtración
    VPerdidas: NReal; //( QEvap+QFilt )* dt


    P_AG_fuente: TDAofNReal;
    //JFP: compras de argentina en MW ingresadas a partir de fuente uniforme o CEGH.

    P_to_P: TFRenR;   //se usa en prepararmemoria

    // variables auxiliares para las funciones cota-volumen y su inversa
    EsConico: boolean;
    embalse_cb, embalse_ca, embalse_c1, embalse_c2, embalse_c3,
    embalse_c4, embalse_c5: NReal;

    flg_ModificandoQEmaxParaEstabilidad: boolean;
    flg_RecortandoAportesParaEstabilidad: boolean;

    //Coeficientes de amortiguamiento, el otro es 1 - alfa
    alfa: NReal;

    // tabla para interpolación de la energía embalsada
    EAcumMax, EAcumMin, EAcumMaxMenosMin: NReal;
    hEAcumMax, hEAcumMin, dhEAcumMaxMenosMin: NReal;

    d_DEE_tablaAprox: NReal;
    kEnergiaEmbalsadaToCota: array[0..1999] of NReal;

    //JFP 25/11/2015: Agrego posibilidad de ingresar fuente de compras de Argentina. La fuente debe ser horaria y se
    //suma a las compras de Argentina ingresadas en cada ficha.
    fuenteDeComprasDeArgentina: TFuenteAleatoria;
    nombreBorne_fuenteDeComprasDeArgentina: string;
    nroBornefuenteDeComprasDeArgentina: integer;


    constructor Create(capa: integer; nombre: string; nacimiento, muerte: TFecha;
      lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  flg_CalcularGradienteDeInversion: boolean; hIni: NReal; dEEIni: NReal;
  NDiscH, nDiscDE: integer; fuenteDeAportes: TFuenteAleatoria;
  nombreBorne: string; flg_ValorizadoManual: boolean; TonCO2xMWh: NReal;
  LowCostMustRun, CleanDevelopmentMechanism: boolean;
  fuenteDeComprasDeArgentina: TFuenteAleatoria;
  nombreBorne_fuenteDeComprasDeArgentina: string;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string);

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

    procedure PrepararMemoria( Catalogo: TCatalogoReferencias; globs: TGlobs); override;
    procedure RegistrarParametrosDinamicos( CatalogoReferencias: TCatalogoReferencias ); override;

    function PotenciaFirme: NReal; override;

    function InfoAd_: string; override;
    class function DescClase: string; override;

    //      procedure Sim_Inicio; override;
    procedure Sim_Cronica_Inicio; override;
    function get_pa_FD(kTipoUnidad: integer): NReal; override;
    function get_pa_TMR(kTipoUnidad: integer): NReal; override;

    procedure SorteosDelPaso(sortear: boolean); override;
    procedure PrepararPaso_ps; override;

    procedure AgregarDefinicionesEvaluador (eval:TEvaluadorExpresionesSimples);override;

    procedure calcular_derivadas(var cv_agua_USD_Hm3_Dec,
      cv_agua_USD_Hm3_Inc, cv_dEE_USD_MWh_Inc, cv_dEE_USD_MWh_Dec: NReal;
      dCFddEEpu_Dec, dCFddEEpu_Inc, dCFdV_Dec, dCFdV_Inc: NReal);

    // JFP: 29/9/15: Determina los APortes propios, el Volumen y la diferencia de energía embalsada al final del paso si no hay
    // erogado y solo hay aportes propios.
    procedure CalcularAportesPropiosVolumenYDEEFinalSinErogado;

    function ivarVertimientosMiosYAguasAbajo: TDAofNInt;

    procedure opt_nvers(var ivar, ivae, ires: integer); override;
    procedure opt_cargue(s: TSimplex); override;
    procedure EvolucionarEstado; override;

    function ErogadoMinimo_Ctrl_Crecida(Vol_ini: NReal): NReal;

    procedure ResolverEncadenamientos(s: TSimplex); override;
    procedure opt_fijarRestriccionesDeCaja(s: TSimplex); override;
    procedure opt_leerSolucion(s: TSimplex); override;


    function opt_necesitoIterar(kIteracion: integer;
      var errRelativo: NReal): boolean;
      override;

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

    procedure PosicionarseEnEstrellita; override;
    procedure ActualizarEstadoGlobal(flg_Xs: boolean); override;

    procedure AcumAux1(peso: NReal); override;
    procedure SetAux1; override;

    procedure optx_nvxs(var ixr, ixd, iauxr, iauxd: integer); override;
    procedure optx_RegistrarVariablesDeEstado(adminEstados: TAdminEstados);
      override;

    procedure Free; override;

    // geometría del embalse
    function CotaToEnergia(h: NReal): NReal;
    function CotaToVolumen(h: NReal): NReal;
    function VolumenToCota(Vol: NReal): NReal;

    //Volúmen mínimo a erogar según aportes y cota proyectada al final del paso (hm3)
    function VTminPorCurvaAportes(Aportes, cota_actual: NReal): NReal;

    function CotaToSuperficie(h: NReal): NReal;
    function hVerticeCono: NReal;

    procedure dEEToCota(var hvistaUy, hvistaAg: NReal; dEE_actual, h_actual: NReal);

    function CotaTodEE(h_actual, h_vista: NReal): NReal;

    function DEEpu_y_V_to_VOLvisto_UY(DEE_pu, V: Nreal): Nreal;

    procedure CambioFichaPD; override;

    procedure PubliVars; override;

    function CotaAguasArriba: NReal; override;
    // Calcula la cota de la descarga para poder calcular el Salto
    function CotaDescarga: NReal; override;

    function centralLagoDescarga: TGeneradorHidraulico; override;

    // imprime tabla de valores del agua en USD/Hm3
    procedure opt_PrintResultados_Encab(var fsal: textfile); override;
    procedure opt_PrintResultados(var fsal: textfile); override;

    procedure sim_FinCronicaPrintEstadoFinal(var fsal: textfile); override;

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

    private
       EnergiaToCota_func: T_EnergiaToCota_func_;

  end;

procedure THidroConEmbalseBinacional_cambioFichaPD(Actor: TCosa);

procedure AlInicio;
procedure AlFinal;


implementation


(** Resolución del corto en CERO de la función CotaToEnergia(h) - Energia
para calcular la Cota dada una Energía ***)
  constructor T_EnergiaToCota_func_.Create(
    central: THidroConEmbalseBinacional);
  begin
    inherited Create;
    self.central:= central;
    EnergiaDada:= 0;
  end;

  function T_EnergiaToCota_func_.f(x: NReal): NReal;
  begin
    Result := central.CotaToEnergia(x) - EnergiaDada;
  end;



{$IFDEF LECTURA BARRIDO ESTADOS}
  ffelipe: TextFile;
{$ENDIF}



////funcion a anular para calcular coeficiente c1 según condicion inicial Vini
//function f_zero_c1(c1: NReal): Extended;
//var
//  x1,x2,Vol_ini,res:Extended;
//begin
//  x1:=aux_central.x1;
//  x2:=aux_central.x2;
//  Vol_ini:=aux_central.Vol_ini_;
//
//  result := 1-exp(c1*x2-c1*x1)*(Vol_ini-x1)/(Vol_ini-x2);
//
//end;

constructor THidroConEmbalseBinacional.Create(capa: integer; nombre: string;
  nacimiento, muerte: TFecha; lpdUnidades, lpd: TFichasLPD; nodo: TNodo;
  flg_CalcularGradienteDeInversion: boolean; hIni: NReal; dEEIni: NReal;
  NDiscH, nDiscDE: integer; fuenteDeAportes: TFuenteAleatoria;
  nombreBorne: string; flg_ValorizadoManual: boolean; TonCO2xMWh: NReal;
  LowCostMustRun, CleanDevelopmentMechanism: boolean;
  fuenteDeComprasDeArgentina: TFuenteAleatoria;
  nombreBorne_fuenteDeComprasDeArgentina: string;
  xFuenteIdxP: TFuenteAleatoria; xBorneIdxP: string );

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

  EnergiaToCota_func:= T_EnergiaToCota_func_.Create( self );

  flg_ModificandoQEmaxParaEstabilidad := False;
  flg_RecortandoAportesParaEstabilidad := False;

  Self.lpd := lpd;
  self.hini := hIni;
  self.dEEIni := dEEIni;

  self.NDiscH := NDiscH;
  self.nDiscDE := nDiscDE;
  self.fuenteDeAportes := fuenteDeAportes;
  self.nombreBorne := nombreBorne;
  self.flg_ValorizadoManual := flg_ValorizadoManual;
  self.fuenteDeComprasDeArgentina := fuenteDeComprasDeArgentina;
  self.nombreBorne_fuenteDeComprasDeArgentina := nombreBorne_fuenteDeComprasDeArgentina;

  nroBornefuenteDeComprasDeArgentina := -1;
end;

function THidroConEmbalseBinacional.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('hIni', hIni);
  Result.addCampoDef('dEEIni', dEEIni);
  Result.addCampoDef('NDiscH', NDiscH);
  Result.addCampoDef('nDiscDE', nDiscDE);
  Result.addCampoDef('lpd', TCosa(lpd));
  Result.addCampoDef_ref('fuenteDeAportes', TCosa(fuenteDeAportes), Self);
  Result.addCampoDef('nombreBorne', nombreBorne);
  Result.addCampoDef('flg_ValorizadoManual', flg_ValorizadoManual);
  Result.addCampoDef_ref('fuenteDeComprasDeArgentina', TCosa(fuenteDeComprasDeArgentina), self, 140 );
  Result.addCampoDef('nombreBorne_fuenteDeComprasDeArgentina', nombreBorne_fuenteDeComprasDeArgentina, 140 );
end;

procedure THidroConEmbalseBinacional.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  EnergiaToCota_func:= T_EnergiaToCota_func_.Create( self );
  flg_ModificandoQEmaxParaEstabilidad := False;
  flg_RecortandoAportesParaEstabilidad := False;
  pa := nil;
  nodo := nil;
end;

procedure THidroConEmbalseBinacional.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
  lpd.Propietario := self;
  if f.Version < 140 then
  begin
    self.fuenteDeComprasDeArgentina := nil;
    self.nombreBorne_fuenteDeComprasDeArgentina := '';
  end;
  nroBornefuenteDeComprasDeArgentina := -1;
end;




procedure THidroConEmbalseBinacional.PrepararMemoria(
  Catalogo: TCatalogoReferencias; globs: TGlobs);
var
  auxf: TFRenR;
  kBornePotencia: integer;
begin
  inherited prepararMemoria( Catalogo, globs);
  setlength(P_AG_fuente, ceil(globs.HorasDelPaso));
  setlength(P_Ag_programada, globs.NPostes);
  setlength(P_Uy_QTminUY, globs.NPostes);
  setlength(P_Ag_despachada, globs.NPostes);
  setlength(P_Ag_recortada, globs.NPostes);
  setlength(P_Uy_despachada, globs.NPostes);
  setlength(Pmax_Central_CotaInf, globs.NPostes);
  setlength(Pmax_Central_CotaSup, globs.NPostes);
  setlength(Pmax_Central_CotaSup, globs.NPostes);
  dh_RedQE := 0;
  polinomioCotaVolumen := TPoliR.Create_Init(2);
  polinomioCotaMaxAporte := TPoliR.Create_Init(2);
  polinomioErogadoMinVol := TPoliR.Create_Init(2);
  VMinMin_1h3porSem := 1 / 168 * globs.HoraDeInicioDelPaso;   // 1Hm3 / semana
  numeroBorne := fuenteDeAportes.idBorne(nombreBorne);

  if fuenteDeComprasDeArgentina <> nil then
  begin
    if not (fuenteDeComprasDeArgentina.durPasoDeSorteoEnHoras = 1) then
      raise Exception.Create(mesFuenteAleatConPaso1h + mesElParque +
        nombre + mesConectadoAFuente + fuenteDeComprasDeArgentina.nombre +
        mesConPasoDeSorteo + IntToStr(
        fuenteDeComprasDeArgentina.durPasoDeSorteoEnHoras));

    if nroBornefuenteDeComprasDeArgentina = -1 then
      // la primera vez definimos los bornes
    begin
      nroBornefuenteDeComprasDeArgentina :=
        fuenteDeComprasDeArgentina.IdBorne(nombreBorne_fuenteDeComprasDeArgentina);

      P_to_P := TFRenR_ComprasArg.Create(capa);


      auxf := TFf_xmult_Buffer.Create(capa, P_to_P, 1, @P_AG_fuente, @globs.kSubPaso_);

      kBornePotencia := fuenteDeComprasDeArgentina.registrarFuncion(auxf,
        nombreBorne_fuenteDeComprasDeArgentina, -1);
    end;

  end;

end;

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

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

function THidroConEmbalseBinacional.PotenciaFirme: NReal;
begin
  Result := (paUnidades.nUnidades_Operativas[0]) * pa.Pmax_Gen * pa.ren;
end;

class function THidroConEmbalseBinacional.DescClase: string;
begin
  Result := rsGHidraulicoEmbalseBinacional;
end;

function THidroConEmbalseBinacional.get_pa_FD(kTipoUnidad: integer): NReal;
begin
  Result := pa.fDispo;
end;

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



procedure THidroConEmbalseBinacional.SorteosDelPaso(sortear: boolean);
begin

  EnIteracion := False;
  if globs.ObligarDisponibilidad_1_ then
  begin
    NMaquinasDisponibles := paUnidades.nUnidades_Operativas[0];
    Pmax_Gen := pA.Pmax_gen;
    Qmax := pA.Qmax_Turb;
  end
  else if (sortear) then
  begin
    ActualizarProbabilidadesReparacionYRotura_(pa.fDispo, pa.tRepHoras);
    NMaquinasDisponibles := Sorteos_RepRotUnidades;
    Pmax_Gen := pA.Pmax_gen;
    Qmax := pA.Qmax_Turb;
  end
  else
  begin
    NMaquinasDisponibles := paUnidades.nUnidades_Operativas[0];
    Pmax_Gen := pA.Pmax_gen * pA.fdispo;
    Qmax := pA.Qmax_Turb * pA.fdispo;
  end;
  PDisponible_Central := NMaquinasDisponibles * Pmax_Gen;
end;


function THidroConEmbalseBinacional.centralLagoDescarga: TGeneradorHidraulico;
begin
  Result := pa.central_lagoDescarga;
end;

function THidroConEmbalseBinacional.CotaAguasArriba: NReal;
begin
  Result := h_actual;
end;

function THidroConEmbalseBinacional.CotaDescarga: NReal;
begin
  if pa.central_lagoDescarga = nil then
    Result := pa.hDescarga
  else
    Result := pa.central_LagoDescarga.cotaAguasArriba;
end;

procedure THidroConEmbalseBinacional.opt_PrintResultados_Encab(var fsal: textfile);
begin
  Write(fsal, #9, FloatToStrF(VolumenToCota(X_VolumenEmbalsado), ffgeneral, 6, 3));
  //  write( fsal, #9, FloatToStrF( h_vistaUY, ffgeneral, 6, 3) );
end;

procedure THidroConEmbalseBinacional.opt_PrintResultados(var fsal: textfile);
begin
  Write(fsal, #9, FloatToStrF(cv_agua_USD_Hm3_Dec, ffgeneral, 6, 3));
  //  write( fsal, #9, FloatToStrF( cv_dEE_USD_MWh_Dec, ffgeneral, 6,3 ) );
end;

procedure THidroConEmbalseBinacional.sim_FinCronicaPrintEstadoFinal(
  var fsal: textfile);
begin
  writeln(fsal, Nombre + '.h_actual = ' + FloatToStr(self.h_actual));
  writeln(fsal, Nombre + '.X_DEE_actual = ' + FloatToStr(self.X_DEE_actual));
end;

procedure THidroConEmbalseBinacional.dump_Variables(var f: TextFile;
  charIndentacion: char);
begin
  inherited dump_Variables(f, charIndentacion);
  writeln(f, charIndentacion, 'h_real[m]= ', FloatToStrF(h_actual, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'salto_actual[m]= ',
    FloatToStrF(salto_actual, ffFixed, 10, 3));

  writeln(f, charIndentacion, 'QAportePropio[m^3/s]= ',
    FloatToStrF(QAportePropio, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'QFilt[m^3/s]= ', FloatToStrF(QFilt, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'QEvap[m^3/s]= ', FloatToStrF(QEvap, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'QMaxVert[m^3/s]= ',
    FloatToStrF(QMaxVert, ffFixed, 10, 3));

  writeln(f, charIndentacion, 'VolumenEmbalsado[hm^3]= ',
    FloatToStrF(X_VolumenEmbalsado, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'VMax[hm^3]= ', FloatToStrF(V_hmax, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'VAportePropio[hm^3]= ',
    FloatToStrF(VAportePropio, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'VPerdidas[hm^3]= ',
    FloatToStrF(VPerdidas, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'ComprasArg(Fuente)[MW]= ',
    FloatToStrF(P_AG_fuente[0], ffFixed, 10, 3));
  writeln(f, charIndentacion, 'ComprasArg(ficha)[MW]= ',
    FloatToStrF(P_Ag_despachada[0], ffFixed, 10, 3));
  writeln(f, charIndentacion, 'NMaquinasDisponibles[u]= ',
    FloatToStrF(NMaquinasDisponibles, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'Pmax_Central_CotaInf[MW]= ',
    FloatToStrF(Pmax_Central_CotaInf[0], ffFixed, 10, 3));
  writeln(f, charIndentacion, 'Pmax_Central_CotaSup[MW]= ',
    FloatToStrF(Pmax_Central_CotaSup[0], ffFixed, 10, 3));
  writeln(f, charIndentacion, 'QErogado_[m^3/s]= ',
    FloatToStrF(QErogado_, ffFixed, 10, 3));

  (*
  writeln(f, charIndentacion, 'cv_agua_USD_MWh_Inc[USD/MWh]= ', FloatToStrF(cv_agua_USD_MWh_Inc, ffFixed, 10, 3));
  writeln(f, charIndentacion, 'cv_agua_USD_MWh_Dec[USD/MWh]= ', FloatToStrF(cv_agua_USD_MWh_Dec, ffFixed, 10, 3));
*)
  writeln(f);
end;

procedure THidroConEmbalseBinacional.EvolucionarEstado;
begin
  X_VolumenEmbalsado := Xs_VolumenEmbalsado;
  X_dEE_actual := Xs_dEE_actual;
  h_actual := VolumenToCota(X_VolumenEmbalsado);
  DEE_max_ := CotaToEnergia(h_actual) - EAcumMin;

  dEEToCota(h_vistaUy, h_vistaAg, X_dEE_actual, h_actual);
end;

function THidroConEmbalseBinacional.ErogadoMinimo_Ctrl_Crecida(Vol_ini: NReal): NReal;
var
//  a, b, c, V, k: NReal;//coeficientes polinomio
{  k1, c1,
  cntIters: word;
  converged: boolean;
  c1_min, c1_max, dc1, f_zero_max, f_zero,
 }

  V_ini, V_fin, dt, VA_paso: NReal;//cte. para solución de ec. diferencial


  V_erogado_paso, acum_erogado, dif_V: NReal;
  cant_disc_integral, i: integer;

begin

  //V'(t)  = -a*V(t)^2-b* V(t) - c
  // Solución en : http://www.wolframalpha.com/input/?i=y%27%28x%29++%3D+a*y%28x%29*y%28x%29%2B+b+*+y%28x%29+%2B+c

  //paso de m3/s a hm3/s la función QE(V) para que quede coherente. También cambio de signo coeficientes.
  //a := -polinomioErogadoMinVol.a[2] / 1e6;
  //b := -polinomioErogadoMinVol.a[1] / 1e6;
  //c := -polinomioErogadoMinVol.a[0] / 1e6;


  //JFP 19/9/2016: Calculo el volúmen final integrando numéricamente
  V_ini := Vol_ini;

  cant_disc_integral := 1000;
  dt := globs.SegundosDelPaso / cant_disc_integral;

  VA_paso := (QAportePropio - Qevap - Qfilt) * dt / 1e6;
  acum_erogado := 0;
  V_ini := Vol_ini;
  for i := 1 to cant_disc_integral do
  begin
    V_fin := V_ini + VA_paso;
    if V_fin > V_ControlCrecida_Inicio then
    begin
      if V_fin > self.V_EmbalsadoProteccionAPleno then
        V_Erogado_Paso:= pa.QE_ControlDeCrecidaAPleno * dt / 1e6
      else
        V_erogado_paso := polinomioErogadoMinVol.Valx(V_fin)  * dt / 1e6;
      V_fin := V_ini - V_erogado_paso + VA_paso;
      if V_fin < V_ControlCrecida_Inicio then
      begin
        dif_V := V_ControlCrecida_Inicio - V_fin;
        V_erogado_paso := V_erogado_paso - dif_V;
        V_fin := V_ControlCrecida_Inicio;
      end;
      acum_erogado := acum_erogado + V_erogado_paso;
    end;
    V_ini := V_fin;
  end;

 // V := V_fin;

{JFP 19/9/16:Solución analítica
  //raices reales, cambia la sol de la ec diferencial :http://www.wolframalpha.com/input/?i=y%27%28x%29++%3Dk*+%28y%28x%29-%28a%2Bi*b%29%29*%28y%28x%29-%28a-i*b%29%29
  //V'=k(V-x1)(V-x2)
  if (b * b - 4 * a * c >= 0) then
  begin
    //if (a < 1e-8) then
    //begin // una recta, 1 raíz sola, V'=k(V-x1):http://www.wolframalpha.com/input/?i=y%27%28x%29++%3Dk*+%28y%28x%29-x1%29
    //  k := b;
    //  x1 := -c / k;
    //  //cte por condicion inicial
    //  c1 := Vol_ini - x1;
    //  V := c1 * exp(k * globs.SegundosDelPaso) + x1;
    //end
    //else
    begin
      k := a;
      x1 := (-b + sqrt(b * b - 4 * a * c)) / (2 * a); //raices reales
      x2 := (-b - sqrt(b * b - 4 * a * c)) / (2 * a);
      // cte por condicion inicial
      c1 := ln((-x1 + Vol_ini) / (Vol_ini - x2)) / (x1 - x2);
      //Calculo c1 iterando ya que x2<Vini<x1 y el logaritmo queda negativo.
      //Dicot(
      //  f_zero_c1,
      //  -100, 100, 1e-4,
      //  10000,
      //  c1, f_zero,
      //  cntIters,
      //  converged);
      //
      //solución
      V := (x2 * exp(c1 * x1 + k * x1 * globs.SegundosDelPaso) - x1 *
        exp(c1 * x2 + k * x2 * globs.SegundosDelPaso)) /
        (exp(c1 * x1 + k * x1 * globs.SegundosDelPaso) -
        exp(c1 * x2 + k * x2 * globs.SegundosDelPaso));
    end;
  end
  else
  begin//raíces complejas
    //cte por condicion inicial
    k1 := arctan((Vol_ini * 2 * a + b) / (sqrt(4 * a * c - b * b))) *
      2 / sqrt(4 * a * c - b * b);
    //solucion
    V := (sqrt(4 * a * c - b * b) * tan(1 / 2 *
      ((k1 + globs.SegundosDelPaso) * sqrt(4 * a * c - b * b))) - b) / (2 * a);
  end;
}

  //no puede haber erogados minimos por debajo del inicio del control de crecida
  //if (h_actual<40.106) and (h_actual>40.105) then
  //Result:=(Vol_ini-V)*1e6/globs.SegundosDelPaso;

  Result := acum_erogado * 1e6 / globs.SegundosDelPaso;
  //  if (h_actual<=83) and (h_actual>82.6) then
  //    begin
  //      WriteLn('Ctrl de Crecida por cota = '+FloatToStr(Result)+' m3/s !!!. Cota Real SG = '+FloatToStr(h_actual));
  ////      ReadLn();
  //    end;

  //Result:=min((Vol_ini-V)*1e6/globs.SegundosDelPaso,(Vol_ini-V_ControlCrecida_Inicio)*1e6/globs.SegundosDelPaso);

end;


procedure THidroConEmbalseBinacional.calcular_derivadas(
  var cv_agua_USD_Hm3_Dec, cv_agua_USD_Hm3_Inc, cv_dEE_USD_MWh_Inc,
  cv_dEE_USD_MWh_Dec: NReal; dCFddEEpu_Dec, dCFddEEpu_Inc, dCFdV_Dec, dCFdV_Inc: NReal);

//JFP y PS 28/9: Agrego procedimiento para calcular las derivadas parciales del CF
//respecto del volùmen (V) y respecto de la diferencia de energìa embalsada (dEE)
// CF=CF(...,V,dEE_pu,...)
// dEE_pu=DEE/DEE_MAX
// DEE_MAX=CotaToEnergia(h_actual)-EacumMin
//*********************************
//dCF/dV=dCF/dV+(dCF/ddEE_p.u)*(-(DEE/DEE_MAX^2)*dDEE_MAX/dV)
//dCF/ddEE=(dCF/dEE_pu)/DEE_MAX
var
  dDEE_MAXdV: NReal;
begin

  dDEE_MAXdV:=dDEEmax_dV(Vs_SinErogado);

  cv_agua_USD_Hm3_Dec := -(dCFdV_Dec - dCFddEEpu_Inc * dDEE_MAXdV *
    dEEs_SinErogado / (DEE_Max_s * DEE_Max_s)) * globs.fActPaso;
  cv_agua_USD_Hm3_Inc := -(dCFdV_Inc - dCFddEEpu_Dec * dDEE_MAXdV *
    dEEs_SinErogado / (DEE_Max_s * DEE_Max_s)) * globs.fActPaso;

  {$IFDEF HIDRO_DERIVADA_SIMETRICA}
    cv_agua_USD_Hm3_Dec := (cv_agua_USD_Hm3_Dec + cv_agua_USD_Hm3_Inc) / 2;
    cv_agua_USD_Hm3_Inc := cv_agua_USD_Hm3_Dec;
  {$ENDIF}


  //WriteLn(dCFdV_Dec:10:3,#9,- dCFddEEpu_Inc * dDEE_MAXdV *
  //  dEEs_SinErogado / (DEE_Max_s * DEE_Max_s):10:3);

  cv_dEE_USD_MWh_Inc := -(dCFddEEpu_Inc / DEE_Max_s) * globs.fActPaso;
  cv_dEE_USD_MWh_Dec := -(dCFddEEpu_Dec / DEE_Max_s) * globs.fActPaso;

  {$IFDEF COSTOSHIDROPOSITIVOS}
  if cv_agua_USD_Hm3_Inc < 1E-2 then
    cv_agua_USD_Hm3_Inc := 1e-2;

  if cv_agua_USD_Hm3_Dec < 1E-2 then
    cv_agua_USD_Hm3_Dec := 1e-2;

  if cv_dEE_USD_MWh_Inc < 1E-2 then
    cv_dEE_USD_MWh_Inc:= 1e-2;

  if cv_dEE_USD_MWh_Dec < 1E-2 then
    cv_dEE_USD_MWh_Dec := 1e-2;

  {$ENDIF}

end;
//procedure THidroConEmbalseBinacional.calcular_derivadas(
//  var cv_agua_USD_Hm3_Dec, cv_agua_USD_Hm3_Inc, cv_dEE_USD_MWh_Inc,
//  cv_dEE_USD_MWh_Dec: NReal; dCFddEEpu_Dec, dCFddEEpu_Inc, dCFdV_Dec, dCFdV_Inc: NReal);
//
////JFP 14/9: Agrego procedimiento para calcular las derivadas parciales del CF respecto del volùmen (V) y respecto de la diferencia de energìa embalsada (dEE)
//// CF=CF(...,V,dEE_pu,...)
//// dEE_pu=DEE/DEE_MAX
//// DEE_MAX=CotaToEnergia(h_actual)-EacumMin
////*********************************
////dCF/dV=dCF/dV+(dCF/ddEE_p.u)*(-(DEE/DEE_MAX^2)*dDEE_MAX/dV)
////dCF/ddEE=(dCF/dEE_pu)/DEE_MAX
//var
//  Delta_V, Delta_V_red, dDEE_MAXdV_Inc, dDEE_MAXdV_Dec: NReal;
//begin
//
//  Delta_V := (V_hmax - V_hmin) / NDiscH;
//  //deltas en volúmen (hm3) para cálculo de dDEE_MAXdV
//
//  if Vs_SinErogado >= V_hmax then
//  begin
//    dDEE_MAXdV_Dec := (CotaToEnergia(VolumenToCota(V_hmax)) -
//      CotaToEnergia(VolumenToCota(V_hmax - Delta_V))) / Delta_V;
//    dDEE_MAXdV_Inc := dDEE_MAXdV_Dec;
//  end
//  else if Vs_SinErogado <= V_hmin then
//  begin
//    dDEE_MAXdV_Inc := (CotaToEnergia(VolumenToCota(V_hmin + Delta_V)) -
//      CotaToEnergia(VolumenToCota(V_hmin))) / Delta_V;
//    dDEE_MAXdV_Dec := dDEE_MAXdV_Inc;
//  end
//  else
//  begin
//    Delta_V_red := min(Delta_V, min(abs(Vs_SinErogado - V_hmin),
//      abs(Vs_SinErogado - V_hmax)));
//    dDEE_MAXdV_Inc := (CotaToEnergia(VolumenToCota(Vs_SinErogado + Delta_V_red)) -
//      CotaToEnergia(VolumenToCota(Vs_SinErogado))) / Delta_V_red;
//    dDEE_MAXdV_Dec := (CotaToEnergia(VolumenToCota(Vs_SinErogado)) -
//      CotaToEnergia(VolumenToCota(Vs_SinErogado - Delta_V_red))) / Delta_V_red;
//  end;
//
//  //WriteLn(ffelipe,dDEE_MAXdV_Dec,dDEE_MAXdV_Inc,h_actual);
//
//
//  cv_agua_USD_Hm3_Dec := -(dCFdV_Dec - dCFddEEpu_Inc * dDEE_MAXdV_Dec *
//    dEEs_SinErogado / (DEE_Max_s * DEE_Max_s)) * globs.fActPaso;
//  cv_agua_USD_Hm3_Inc := -(dCFdV_Inc - dCFddEEpu_Dec * dDEE_MAXdV_Inc *
//    dEEs_SinErogado / (DEE_Max_s * DEE_Max_s)) * globs.fActPaso;
//
//  cv_dEE_USD_MWh_Inc := -(dCFddEEpu_Inc / DEE_Max_s) * globs.fActPaso;
//  cv_dEE_USD_MWh_Dec := -(dCFddEEpu_Dec / DEE_Max_s) * globs.fActPaso;
//
//  {$IFDEF COSTOSHIDROPOSITIVOS}
//  if cv_agua_USD_Hm3_Inc < 1E-2 then
//    cv_agua_USD_Hm3_Inc := 1e-2;
//
//  if cv_agua_USD_Hm3_Dec < 1E-2 then
//    cv_agua_USD_Hm3_Dec := 1e-2;
//
//  {$ENDIF}
//
//end;

procedure THidroConEmbalseBinacional.PrepararPaso_ps;
var
  kposte, jhora, jHoraDelDia, resCode,k: integer;
  vaux, V_sobre_nivel_de_riesgo, QTminUY_aux, Qdisp, Pmax_Central_aux,
  PmaxParaQdisp: NReal;

  dCFdV_Inc, dCFdV_Dec, aux: NReal;
  dCFddEEpu_Inc, dCFddEEpu_Dec: NReal;

  volMV0, volMV1, QMaxTurbinable_Central, QMax_Erogable, VMaxErogable_Central: NReal;
  auxParaCalculos: NReal;

  factorRed: NReal;
  //  MargenAg: NReal;

  EEAg: NReal;
  d_RecorteAg: NReal;
  ce_MAXTURB: NReal;
  ffelipe2:TextFile;
  nombre_archi:string;
  Qmax_disp: NReal;

begin




  //  if ((globs.kPaso_=11) and (globs.kCronica=21) and (globs.EstadoDeLaSala = CES_SIMULANDO)) then
  // PuedoGenerar:=true;
  if globs.cntIteracionesDelPaso = 1 then
  begin

    if flg_ValorizadoManual then
    begin
      cv_agua_USD_Hm3_Inc := pa.cv_USD_Hm3_ValorizadoManual * globs.fActPaso;
      cv_agua_USD_Hm3_Dec := cv_agua_USD_Hm3_Inc;
      cv_dEE_USD_MWh_Inc := cv_agua_USD_Hm3_Inc;
      cv_dEE_USD_MWh_Dec := cv_agua_USD_Hm3_Inc;
      // JFP 1/9/15: Agrego provisoriamente para probar poder valorizar manualmente central.
    end
    else
    begin
      globs.CF.devxr_continuo(ixr, globs.kPaso_Opt + 1, dCFdV_Inc, dCFdV_Dec, resCode, aux);
      globs.CF.devxr_continuo(ixr + 1, globs.kPaso_Opt + 1, dCFddEEpu_Inc,
        dCFddEEpu_Dec, resCode, aux);

    end;

    calcular_derivadas(cv_agua_USD_Hm3_Dec, cv_agua_USD_Hm3_Inc,
      cv_dEE_USD_MWh_Inc, cv_dEE_USD_MWh_Dec,
      dCFddEEpu_Dec, dCFddEEpu_Inc, dCFdV_Dec, dCFdV_Inc);

  end;

   if ((h_actual>35) and (h_vistaUY<35)) then
   BEGIN
     h_actual:=h_actual;
     h_vistaUY:=h_vistaUY;
   END;

    (**** AGREGADO PARA CONTROL DE COTA OBJETIVO DURANTE LA SIMULACION****)
    if globs.EstadoDeLaSala = CES_SIMULANDO then
    begin
      if pa.flg_controlCotaObjetivoInferior and (h_vistaUY < pa.hObjetivo) then
      begin
        cv_agua_USD_Hm3_Dec := cv_agua_USD_Hm3_Dec + pa.delta_cva_ParaControlDeCota;
        //    cv_agua_USD_Hm3_Inc:= cv_agua_USD_Hm3_Inc+ pa.delta_cva_ParaControlDeCota;
      end;

      if pa.flg_controlCotaObjetivoSuperior and (h_vistaUY > pa.hObjetivo) then
      begin
        cv_agua_USD_Hm3_Dec := cv_agua_USD_Hm3_Dec - pa.delta_cva_ParaControlDeCota;
        //    cv_agua_USD_Hm3_Inc:= cv_agua_USD_Hm3_Inc- pa.delta_cva_ParaControlDeCota;
      end;
    end;

  //{$IFDEF COSTOSHIDROPOSITIVOS}
  //  if cv_agua_USD_Hm3_Inc < 1E-2 then
  //    cv_agua_USD_Hm3_Inc := 1e-2;
  //
  //  if cv_agua_USD_Hm3_Dec < 1E-2 then
  //    cv_agua_USD_Hm3_Dec := 1e-2;
  //{$ENDIF}

  //JFP 8/10/15: Busco el mínimo entre el Qmáx de las turbinas y el Qmax que se lograría con el agua embalsada.
  Qmax_disp := min(Qmax,(Vs_SinErogado-V_hmin) *
    1e6 / globs.SegundosDelPaso / NMaquinasDisponibles);
  dh_RedQE := ReduccionDeCotaPorCaudalErogado(NMaquinasDisponibles * Qmax_disp);
  salto_actual := max(0.1, h_actual - CotaDescarga - dh_RedQE);
  ce_MAXTURB0 := salto_actual * ro_g_ren;
  //ro_g_ren= pA.ren * ro_Agua * g_gravitacion / (1.0E6 * 3600.0);

  self.dh_RedQE := ReduccionDeCotaPorCaudalErogado(QErogado_);
  salto_actual := max(0.1, h_actual - CotaDescarga - dh_RedQE);


  ce := salto_actual * ro_g_ren;
  ce_MAXTURB := min(ce_MAXTURB0, ce);

  auxParaCalculos := 1 / (1.0E6 * ce);


  // supongo que puedo generar, luego si el salto no es suficiente
  // o si todas las unidades están indisponibles lo bajo a false
  PuedoGenerar := True;

  if salto_actual < pa.saltoMinimoOperativo then
    self.PuedoGenerar := False; // no puedo mover las turbinas


  // calculamos el valor del agua en USD/MWh
  cv_agua_USD_MWh := cv_agua_USD_Hm3_Dec * auxParaCalculos;


  // en la v_ADME_1.05c cambio a control de vertido en base al Vs_SinErogado

  if Vs_SinErogado < V_EmbalsadoInicioVertedero then
    QMaxVert := 0.0
  else
  begin
    if Vs_SinErogado < V_EmbalsadoFinalVertedero then
      QMaxVert := pa.QMV1 * (Vs_SinErogado - V_EmbalsadoInicioVertedero) /
        Delta_V_Embalsado_Vertedero
    else
      QMaxVert := pa.QMV1;
  end;


  PmaxParaQmax := Qmax_disp * ce_MAXTURB * 3600;
  if NMaquinasDisponibles > 0 then
  begin
    Pmax_Central := NMaquinasDisponibles * min(Pmax_Gen, PMaxParaQmax);
    QMaxTurbinable_Central := PMax_Central / (ce * 3600.0);
  end
  else
  begin
    PMax_Central := 0;
    QMaxTurbinable_Central := 0;
  end;

  if PMax_Central <= 0.01 then
  begin
    PuedoGenerar := False;
    Qmaxturbinable_Central :=0;
    PMax_Central := 0;
  end;

  //if globs.cntIteracionesDelPaso = 1 then
  //begin
  //  for k := 0 to globs.NPostes - 1 do
  //    Pmax_Central_CotaSupTotal[k] := Pmax_Central
  //end
  //else
  //begin
  //  Qmaxturbinable_Central := 0;
  //  for k := 0 to globs.NPostes - 1 do
  //  begin
  //    Pmax_Central_CotaSup[k] := min((Pmax_Central_CotaSup[k] + P[k]) / 2.0,Pmax_Central);
  //    Qmaxturbinable_Central :=
  //      Qmaxturbinable_Central + Pmax_Central_CotaSup[k] * globs.DurPos[k];
  //  end;
  //  QMaxTurbinable_Central :=
  //    QMaxTurbinable_Central / (ce * globs.SegundosDelPaso);
  //end;
  //
  //NoSePuedeTurbinar:

  QMax_Erogable := QMaxTurbinable_Central + QMaxVert;
  VMaxErogable_Central := QMax_Erogable * globs.SegundosDelPaso * (0.95 / 1.0E6);


  (**
  // si llegué al fondo para Uruguay limito la potencia
  if self.h_vistaUY <= self.pa.hVistaMin then
  begin
    vaux:= ( QAportePropio  * ce * 3600 / 2 );
   for kposte := 0 to globs.NPostes-1 do
     PMax_Central[kposte]:= min( PMax_Central[kposte], PParaArgentina[kposte]+vaux);
  end;
  **)

  // chequeamos que sea posible cumplir con lo programado por los hermanos argentinos.
  // si no es posible le recortamos el programa.
  for kposte := 0 to globs.NPostes - 1 do
    if P_Ag_despachada[kposte] > PMax_Central then
    begin
      d_recorteAg := (P_Ag_despachada[kposte] - PMax_Central) *
        globs.DurPos[kposte];
      recorteAg := recorteAg + d_recorteAg;
      energiaAg := energiaAg - d_recorteAg;
      P_Ag_despachada[kposte] := PMax_Central;
    end;



  EnergiaAlmacenada := cotaToEnergia(self.h_actual);

  EAportesPropios := (ce * 1.0E6) * VAportePropio; // energía de los aportes propios

  EEAg := min(EnergiaAlmacenada + EAportesPropios - X_DEE_actual -
    self.EAcumMin, // a eso tiene derecho, pero por lad dudas verifico si es posible
    EnergiaAlmacenada + EAportesPropios / 2 // esto es lo que es posible máximo
    );



  if EEAg < 0 then
    EEAg := 0;

  if (energiaAg > EEAg) then // no los dejo fondear
  begin
    factorRed := EEAg / energiaAg * 0.98;
    for kPoste := 0 to globs.NPostes - 1 do
      P_Ag_despachada[kposte] := P_Ag_despachada[kposte] * factorRed;
    EnergiaAg := EnergiaAg * factorRed;
  end;


  for kPoste := 0 to globs.NPostes - 1 do
    P_Ag_recortada[kposte] := P_Ag_programada[kposte] - P_Ag_despachada[kposte];


  //JFP 8/10/15: Veo que tanto puede generar UY para respetar su erogado minimo ( pa.QTMinUY)
  for kPoste := 0 to globs.NPostes - 1 do
  begin
    P_Uy_QTminUY[kposte] := pa.QTMinUY * 3600 * ce;
    //lo que tendría que generar para respetar erogado mínimo de UY
    P_Uy_QTminUY[kposte] := Min(P_Uy_QTminUY[kposte], Pmax_Central -
      P_Ag_despachada[kposte]);
    P_Uy_QTminUY[kposte] := max(P_Uy_QTminUY[kposte],0);
    //en total la central no puede generar masV_ErogadoMinimo_Ctrl_Crecida de Pmax_Central.
  end;


 { for kPoste := 0 to globs.NPostes - 1 do
    begin
    if (P_Ag_despachada[kposte]+P_Uy_QTminUY[kposte])>PMax_Central then   // JFP 14/10/15: Esta condición se va a verificar con cotas bajas del lago, cuando haya poca disponibilidad de energía
         if X_dEE_actual>0 then //Si la diferencia de energía es a favor de Uy, entonces le exijo primero a Arg despachar lo que previó y luego si sobra energía le exijo a Uy que genere lo correspondiente a su erogado mínimo por navegabilidad, etc.
            begin
            P_Ag_despachada[kposte]:= min(PMax_Central,P_Ag_despachada[kposte]);
            P_Uy_QTminUY[kposte]:= PMax_Central-P_Ag_despachada[kposte];
            end
         else
            begin
            P_Uy_QTminUY[kposte]:=min(P_Uy_QTminUY[kposte],PMax_Central);
            P_Ag_despachada[kposte]:= PMax_Central-P_Uy_QTminUY[kposte];
            end;
     end; }

  ///***JFP 18/9/15 :actualizo de la hidroconembalse***///
  if pA.HayRestriccionQTmin or pa.flg_ControlCrecidaPOrCotaYAportes then
  begin
    VTmin := X_VolumenEmbalsado - V_hmin + VAportePropio - VPerdidas;
    VTmin := 0.95 * VTmin; // lo bajo un poco cumplo si realmente puedo
    //VTmin := min(PA.QTmin * globs.SegundosDelPaso / 1.0E6, VTmin);

    QTmin_segun_Aportes := 0;
    if pa.flg_ControlCrecidaPOrCotaYAportes then
    begin
      VTmin_segun_Aportes := VTminPorCurvaAportes(QAportePropio, h_actual);
      //volumen a evacuar en el paso para respetar la cota máxima según aportes
      QTmin_segun_Aportes := VTmin_segun_Aportes * 1e6 / globs.SegundosDelPaso;
      //Erogado mínimo (m3/s) en el paso para respetar la cota máxima según aportes
    end;

    QTmin_CalcVTminsobreSegundosDelPaso := Max(PA.QTmin, QTmin_segun_Aportes);
    // la restriccion resulta de la mayor entre lo que se ingresa a la ficha y la curva cota-aportes

    VTmin := min(QTmin_CalcVTminsobreSegundosDelPaso * globs.SegundosDelPaso /
      1.0E6, VTmin);

    VTmin := min(VMaxErogable_Central * 0.95, VTmin);

    QTmin_CalcVTminsobreHorasDelPaso := VTMin * globs.invHorasDelPaso;
    AplicarRestriccionDeErogadoMinimo := VTmin > VMinMin_1h3porSem;
  end
  else
  begin
    VTmin := 0;
    QTmin_CalcVTminsobreHorasDelPaso := 0;
    AplicarRestriccionDeErogadoMinimo := False;
  end;


  // ahora chequeamos si X_VolumenEmbalsado+VAportePropio - VPerdias > V(cotamaxop)
  // si eso pasa, imponemos un ErogadoMinimo que crece linealmente
  // dese 0 a la cota del maximo operativo hasta el Máximo del vertedero
  // para una coto 2m por arriba del máximo operativo.
  // En el futuro tenemos que dejar agregar la curva de erogado mínimo
  V_sobre_nivel_de_riesgo := Vs_SinErogado - V_ControlCrecida_Inicio;

  if (V_sobre_nivel_de_riesgo > 0) and (pa.flg_ControlCrecidaPorCota = True) then
  begin
    Q_ErogadoMinimo_Ctrl_Crecida := ErogadoMinimo_Ctrl_Crecida(X_VolumenEmbalsado);
    // si el erogado mínimo es superior al Máximo Erogable lo acotamos
    if Q_ErogadoMinimo_Ctrl_Crecida > QMax_Erogable * 0.9 then
      Q_ErogadoMinimo_Ctrl_Crecida := QMax_Erogable * 0.9;

    V_ErogadoMinimo_Ctrl_Crecida :=
      Q_ErogadoMinimo_Ctrl_Crecida * globs.SegundosDelPaso / 1.0E6;

    // Imponemos el erogado como el máximo entre el requerido por l econtrol de crecida
    // y el requerido por otras razones
    if V_ErogadoMinimo_Ctrl_Crecida > VTMin then
    begin
      VTMin := V_ErogadoMinimo_Ctrl_Crecida;
      VTmin := min(VMaxErogable_Central, VTmin);
      QTmin_CalcVTminsobreHorasDelPaso := VTMin * globs.invHorasDelPaso;
      AplicarRestriccionDeErogadoMinimo := VTmin > VMinMin_1h3porSem;
    end;
  end;

  P_MW_Compras_Min:=ce*min(QTmin_CalcVTminsobreHorasDelPaso,QMaxTurbinable_Central*3600/1e6)*1e6;

  if (globs.cntIteracionesDelPaso = 1) then
    for k := 0 to globs.NPostes - 1 do
    begin
      Pmax_Central_CotaInf[k] := max(P_Ag_despachada[k] + P_Uy_QTminUY[k],P_MW_Compras_Min);
      Pmax_Central_CotaInf[k] := min(Pmax_Central_CotaInf[k],Pmax_Central);
      Pmax_Central_CotaSup[k] := max(P_Ag_despachada[k] + Pmax_Central/2,P_MW_Compras_Min);
      Pmax_Central_CotaSup[k] := min(Pmax_Central_CotaSup[k],Pmax_Central);
    end
  else
    for k := 0 to globs.NPostes - 1 do
    begin
      Pmax_Central_CotaInf[k] := max((0.9 * Pmax_Central_CotaInf[k] + 0.1 * P[k]),P_MW_Compras_Min);
      Pmax_Central_CotaInf[k] := min(Pmax_Central_CotaInf[k],Pmax_Central);
      Pmax_Central_CotaSup[k] := max((Pmax_Central_CotaSup[k] + P[k]) / 2.0,Pmax_Central_CotaInf[k]);
      Pmax_Central_CotaSup[k] := min(Pmax_Central_CotaSup[k] ,Pmax_Central);
    end;

end;

procedure THidroConEmbalseBinacional.AgregarDefinicionesEvaluador(
  eval: TEvaluadorExpresionesSimples);
var
  af: TFunc_F_FF_OfObject;
begin
  af:= TFunc_F_FF_OfObject.Create( 'DEEpu_y_V_to_VOLvisto_UY', self.DEEpu_y_V_to_VOLvisto_UY );
  eval.CatalogoFuncionesDeUsuario.Add( af );
end;

procedure THidroConEmbalseBinacional.opt_nvers(var ivar, ivae, ires: integer);
begin
  self.ivar := ivar;

  if pa.ImponerQminPorPoste then
    ivar := ivar + globs.NPostes + globs.NPostes // PGen por poste y VVertimiento
  else
    ivar := ivar + globs.NPostes + 1; // PGen por poste y VVertimiento


{$IFDEF CONCONTROLCRECIDA}
  self.ires := ires; // 0 <= volumen_s
  ires := ires + 1;   // probando no usar <= Vmax
{$ELSE}
  // 0 <= volumen_s
  // Volumne_s <= Vmáx  ( dos restricciones )
  ires := ires + 2;
{$ENDIF}


  ires := ires + 1; //    EE - dEE > - EE_min
  // o lo que es lo mismo hvista_uy > hvista_min
  // no controlo que Argentina no vaya por abajo de h_min


  if (PuedoGenerar) and pA.HayRestriccionEmaxPasoDeTiempo then
    Inc(ires);

  if AplicarRestriccionDeErogadoMinimo then
    if pa.ImponerQminPorPoste then
      Inc(ires, globs.NPostes)
    else
      Inc(ires);
end;
function THidroConEmbalseBinacional.dDEEmax_dV(V: NReal): NReal;
var
  deltah: NReal;
  hD: NReal;
  c1, c2, c3,dhdV,dEEmaxdh: NReal;
  EnergiaEmbalsada,h: NReal;
begin
//  DEEmax=E(h(V))
//  dDEEmax_dV=dE/dh*dh/dV

//***  dh/dV   ***
if EsConico then
  dhdV := embalse_c3/(2*sqrt(embalse_c3 * V + embalse_c4))
else
  dhdV :=1/ embalse_c1 ;

h:=VolumenToCota(V);

//***  dEEmax/dh   ***
deltah := h - pA.hmin;
hD := CotaDescarga + ReduccionDeCotaPorCaudalErogado(pa.QE_CEE) - pA.hmin;

if EsConico then
begin
  c1 := -embalse_c1 * hD;
  c2 := (embalse_c1 - 2 * embalse_c2 * hD) * 0.5;
  c3 := 2 * embalse_c2 / 3;

  EnergiaEmbalsada := ro_g_ren * (3*c3*deltah*deltah+2*c2*deltah+c1);
end
else
begin
  EnergiaEmbalsada := ro_g_ren * embalse_c1 * (deltah-hD);
end;
dEEmaxdh := EnergiaEmbalsada * 1E6;


Result:= dEEmaxdh*dhdV;

end;


function THidroConEmbalseBinacional.CotaToEnergia(h: NReal): NReal;
var
  dh: NReal;
  hD: NReal;
  c1, c2, c3: NReal;
  EnergiaEmbalsada: NReal;
begin
  dh := h - pA.hmin;
  hD := CotaDescarga + ReduccionDeCotaPorCaudalErogado(pa.QE_CEE) - pA.hmin;

  if EsConico then
  begin
    c1 := -embalse_c1 * hD;
    c2 := (embalse_c1 - 2 * embalse_c2 * hD) * 0.5;
    c3 := 2 * embalse_c2 / 3;
    EnergiaEmbalsada := ro_g_ren * ((c3 * dh + c2) * dh + c1) * dh;
  end
  else
  begin
    EnergiaEmbalsada := ro_g_ren * embalse_c1 * (0.5 * dh - hD) * dh;
  end;
  Result := EnergiaEmbalsada * 1E6;
end;

procedure THidroConEmbalseBinacional.opt_cargue(s: TSimplex);
var
  ibaseres: integer;
  iposte: integer;
  jres: integer;
  invCEPorUnoESeis: NReal;
  VolDePartida: NReal;
  aux: NReal;
  EcotaInf: NReal;

begin

  invCEPorUnoESeis := 1 / (ce * 1.0E6);
  ibaseres := nodo.ires;

  // Tenemos que aportar a las restricciones de demanda del nodo al que está
  // conectado el generador
  for iposte := 0 to globs.NPostes - 1 do
  begin
    s.pon_e(ibaseres + iposte, ivar + iposte, 1);
    s.acum_e(ibaseres + iposte, s.nc, -P_AG_despachada[iposte]);
  end;

  ivert := ivar + globs.NPostes;

  // Ahora agregamos a la función de UTILIDAD (-costo)
  for iposte := 0 to globs.NPostes - 1 do
    s.pon_e(s.nf, ivar + iposte, -(cv_dEE_USD_MWh_Dec + cv_agua_USD_MWh) *
      globs.durpos[iposte]);// JFP 14/9/15


  if pa.ImponerQminPorPoste then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(s.nf, ivert + iposte, -(cv_dEE_USD_MWh_Dec + cv_agua_USD_MWh) / invCEPorUnoESeis);
    //  Vertimiento// JFP 14/9/15
  end
  else
    s.pon_e(s.nf, ivert, -(cv_dEE_USD_MWh_Dec + cv_agua_USD_MWh) / invCEPorUnoESeis);
  //  Vertimiento // JFP 14/9/15


  // no ponemos esto pue no entra en la optimización del paso.
  //  s.acum_e( s.nf, s.nc, cv_agua_USD_Hm3_Inc * VAportePropio - cv_agua_USD_Hm3_Dec * VPerdidas); // Aporte

  // restriccion de volumen >= 0 = Vmín
  jres := ires;
  if (PuedoGenerar) then
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(jres, ivar + iposte, -globs.durpos[iposte] * invCEPorUnoESeis);
  if pa.ImponerQminPorPoste then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(jres, ivert + iposte, -1);
  end
  else
    s.pon_e(jres, ivert, -1);  // vertimiento

  VolDePartida := (X_VolumenEmbalsado - V_hmin + VAportePropio - VPerdidas);
  if VolDePartida < 0.01 then
  begin
    // esto no debe pasar.
    VolDePartida := 0.01;

  end;
  s.pon_e(jres, s.nc, VolDePartida);


{$IFNDEF CONCONTROLCRECIDA}
  // restricción de volumen <= Vmax
  Inc(jres);
  if (PuedoGenerar) then
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(jres, ivar + iposte, globs.durpos[iposte] * invCEPorUnoESeis);
  if pa.ImponerQminPorPoste then
  begin
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(jres, ivert + iposte, 1);
  end
  else
    s.pon_e(jres, ivert, 1);  // vertimiento
  s.pon_e(jres, s.nc, (Vmax - V_hmin) - VolDePartida);


  //??? ojo revisar si al agregar ImponerQminPorPoste no hay que tocar esto.
  //Si hay que cambiarlo, hay que permitir violar todos los postes, aunque con uno solo
  //alcanzaría
  s.permitirViolarBordeSupParaSatisfacerRestriccion(jres,
    ivarVertimientosMiosYAguasAbajo);
{$ENDIF}


(***
EReal + deeUy_s >= EAcumMin
o lo que es equivalente hVistaUy_s >= hVistaMin
************)
  Inc(jres);
  for iposte := 0 to globs.NPostes - 1 do
    s.pon_e(jres, ivar + iposte, -globs.durpos[iposte]);

  // calculamos el término independiente y vemos que sea cumplible.
  aux := DEE_max_ + EAportesPropios + X_DEE_actual + 2 * EnergiaAg;



  if (aux < (EnergiaAg + 10)) then
    //JFP:Uruguay no puede tomar energía porque el problema queda infactible por no cumplirse h_vistaUY>hEAcumMin;
  begin
    // si es necesario aflojo para poder cumplir con el programa Argentino
    aux := EnergiaAg + 10;
    // podríamos marcar la restricción como de igualdad
    // restauro el límite inferior para que sea factible
    for iposte := 0 to globs.NPostes - 1 do
      Pmax_Central_CotaInf[iposte] := P_Ag_despachada[iposte];
  end
  else
  begin
    // si estoy iterando controlo que no halla convertido en infactible el problema
    // al mover las cotas inferiores de la potencia para la convergencia de la iteración
    // si es así las aflojo
    ECotaInf := 0;
    for iposte := 0 to globs.NPostes - 1 do
      ECotaInf := ECotaInf + PMax_Central_CotaInf[iposte] * globs.DurPos[iposte];

    if (aux < (ECotaInf+10)) then
      //JFP 26/11/2015: Aca tengo que recortar la potencia minima de uruguay para que el problema no sea infactible.
    begin
      // Volvemos a aflojar las cotas inferiores de las potencias
      for iposte := 0 to globs.NPostes - 1 do
      begin
          Pmax_Central_CotaInf[iposte] :=
            min(Pmax_Central_CotaInf[iposte] * aux /
              ECotaInf * 0.99, Pmax_Central);
          assert(Pmax_Central_CotaInf[iposte] <P_Ag_despachada[iposte],
          'Error,THidroConEmbalseBinacional.opt_cargue. Pmax_Central_CotaInf[iposte] <P_Ag_despachada[iposte]');
      end;
    end;


  s.pon_e(jres, s.nc, aux);



(*************
Ereal - deeUy_s >= EAcumMin
o lo que es equivalente hVistaAg_s >= hVistaMin
*************)
(********** no pongo esta
  inc( jres );
  for iposte:= 0 to globs.NPostes - 1 do
    s.pon_e( jres, ivar+iposte, +globs.durpos[iposte] );
  s.pon_e(
    jres, s.nc,
    dEE_Max - 2*EnergiaAg - deeUy -EAportesPropios);
****)


  // Restricción de Energía máxima en el paso de tiempo
  if (PuedoGenerar) and pA.HayRestriccionEmaxPasoDeTiempo then
  begin
    Inc(jres);
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(jres, ivar + iposte, -globs.durpos[iposte]);
    s.pon_e(jres, s.nc, pA.EmaxPasoDeTiempo);
  end;

  // Restricción de caudal erogado mínimo por navegabilidad
  if AplicarRestriccionDeErogadoMinimo then
  begin
    Inc(jres);
    if pa.ImponerQminPorPoste then
    begin
      for iposte := 0 to globs.NPostes - 1 do
      begin
        if (PuedoGenerar) then
        begin
          s.pon_e(jres, ivar + iposte, globs.durpos[iposte] * invCEPorUnoESeis);
        end;
        s.pon_e(jres, ivert + iposte, 1);  // vertimiento
        s.pon_e(jres, s.nc, -QTmin_CalcVTminsobreHorasDelPaso * globs.DurPos[iposte]);
        Inc(jres);
      end;
    end
    else
    begin
      if (PuedoGenerar) then
      begin
        for iposte := 0 to globs.NPostes - 1 do
          s.pon_e(jres, ivar + iposte, globs.durpos[iposte] * invCEPorUnoESeis);
      end;
      s.pon_e(jres, ivert, 1);  // vertimiento
      s.pon_e(jres, s.nc, -VTmin);
    end;
  end;

end;

end;


procedure THidroConEmbalseBinacional.ResolverEncadenamientos(s: TSimplex);
var
  iCentrales: integer;
  gh: TFichaCentralAguasArriba;
begin
  // Aportes de las centrales aguas arriba
  // sumamos los aportes de las centrales aguas arriba
  // sobre la restricción de vertimiento
  for iCentrales := 0 to pa.centralesAguasArriba.Count - 1 do
  begin
    gh := TFichaCentralAguasArriba(pa.centralesAguasArriba[iCentrales]);
    gh.Central.CargarAportesAFilaCentralAguasAbajo(
      ires, // fila en la que cargar los aportes
      gh.coef, // coeficiente de llegada por el que multiplicar los aportes
      self.cv_agua_USD_Hm3_Inc,
      // valor del agua a considerar en la central aguas abajo.
      s);
  end;
{$IFNDEF CONCONTROLCRECIDA}
  for iCentrales := 0 to pa.centralesAguasArriba.Count - 1 do
  begin
    gh.Central.CargarAportesAFilaCentralAguasAbajo(
      ires + 1, // fila en la que cargar los aportes
      -gh.coef, // coeficiente de llegada por el que multiplicar los aportes
      0,   // si había algo que cargar lo cargó la anterior.
      s);
  end;
{$ENDIF}
end;


procedure THidroConEmbalseBinacional.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
  qmax_Hm3PorHora: double;
begin
  // Le fijamos como cota máxima PMax a la potencia en todos los postes


  if PuedoGenerar then
    for iposte := 0 to globs.NPostes - 1 do
    begin
      s.cota_inf_set(ivar + iposte, PMax_Central_CotaInf[iposte]);
      s.cota_sup_set(ivar + iposte, PMax_Central_CotaSup[iposte]);
    end
    else
    for iposte := 0 to globs.NPostes - 1 do
      s.FijarVariable(ivar + iposte, 0);

  if pa.ImponerQminPorPoste then
  begin
    qmax_Hm3PorHora := QMaxVert * globs.SegundosDelPaso / 1.0E6 / globs.HorasDelPaso;
    for iposte := 0 to globs.NPostes - 1 do
      s.cota_sup_set(ivert + iposte, qmax_Hm3PorHora * globs.DurPos[iposte]);
  end
  else
    s.cota_sup_set(ivert, QMaxVert * globs.SegundosDelPaso / 1.0E6);

end;


procedure THidroConEmbalseBinacional.dEEToCota(
  var hvistaUy, hvistaAg: NReal;
  dEE_actual, h_actual: NReal);

var
  EEReal: NReal;

  function EEToCota(EE: NReal): NReal;
  var
    res: NReal;
    kEE: integer;
  begin
    kEE := trunc((EE - EAcumMin) / EAcumMaxMenosMin * 1999 + 0.5);
    if (kEE > 1999) then
    begin
      res := kEnergiaEmbalsadaToCota[1999] + (kEnergiaEmbalsadaToCota[1999] -
        kEnergiaEmbalsadaToCota[1998]) * (kEE - 1999);
    end
    else
    if kEE >= 0 then
      res := kEnergiaEmbalsadaToCota[kEE]
    else
    begin
      res := kEnergiaEmbalsadaToCota[0] + (kEnergiaEmbalsadaToCota[1] -
        kEnergiaEmbalsadaToCota[0]) * kEE;
    end;
    Result := res;
  end;

begin
  EEReal := CotaToEnergia(h_actual);

  if abs(dEE_actual) > d_DEE_tablaAprox then
  begin
    hVistaUy := EEToCota(EEREal + dEE_actual);
    hVistaAg := EEToCota(EEReal - dEE_actual);
    assert((hVistaUy - h_actual) * (hVistaAg - h_actual) <= 0,
      'Error,THidroConEmbalseBinacional.dEEToCota. Cotas vistas del mismo lado: ' +
      'h_actual=' + FloatToStr(h_actual) + '/' + 'h_vistaUY=' +
      FloatToStr(h_vistaUY) + '/' + 'h_vistaAG=' + FloatToStr(h_vistaAG));
  end
  else
  begin
    hVistaUy := h_actual;
    hVistaAg := h_actual;
  end;
end;

function THidroConEmbalseBinacional.CotaTodEE(h_actual, h_vista: NReal): NReal;
var
  EEReal, EEUy: NReal;
  dEE_actual: NReal;
begin
  EEReal := CotaToEnergia(h_actual);
  EEUy := CotaToEnergia(h_vista);

  dEE_actual := EEUy - EEReal;

  Result := dEE_actual;
end;

function THidroConEmbalseBinacional.DEEpu_y_V_to_VOLvisto_UY(DEE_pu, V: Nreal
  ): Nreal;
var
  h_UY,h_ARG,DEE_MWh,Vol_UY,
  DEE_max__,hEAcumMin_,eAcumMin_:NReal;
begin

  hEAcumMin_ := pa.hVistaMin;
  eAcumMin_ := cotaToEnergia(hEAcumMin_);
  DEE_max__ := CotaToEnergia(VolumenToCota(V)) - eAcumMin_;

  DEE_MWh := ((DEE_pu - 0.5) / 0.5) * DEE_max__;
  dEEToCota(h_UY, h_ARG, DEE_MWh, VolumenToCota(V));
  Vol_UY:= CotaToVolumen(h_UY)/2;
  Result:=Vol_UY;
end;

procedure THidroConEmbalseBinacional.Sim_Cronica_Inicio;
begin
  inherited Sim_Cronica_Inicio;
  QErogado_ := 0;

  QErogado_IterAnterior := 0; // para que de igual al correrlo dos veces seguidas

  VErogado := 0;
  QVertido := 0;
  VVertido := 0;
  QTurbinado := 0;
  VTurbinado := 0;
  EnergiaGenerada := 0;
  X_VolumenEmbalsado := CotaToVolumen(hini);

  h_actual := hini;

  // suponemos aportes cero, en preparar paso_ps que haga las cuentas bien.
  DEE_max_ := CotaToEnergia(h_actual) - EAcumMin;
  X_DEE_actual := DEEini;

  dEEToCota(h_vistaUy, h_vistaAg, X_DEE_actual, h_actual);
end;

procedure THidroConEmbalseBinacional.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
begin
  costoDirectoDelPaso := 0;

  if pa.PagoPorDisponibilidad_USD_MWh <> 0 then
    Ingreso_PorDisponibilidad_ :=
      Pmax_Central * pa.PagoPorDisponibilidad_USD_MWh * globs.HorasDelPaso
  else
    Ingreso_PorDisponibilidad_ := 0;

  if PuedoGenerar then
  begin
    // recuperamos los valores de Potencia despachada
    EnergiaGenerada := 0;
    EnergiaAG := 0;
    for iposte := 0 to globs.NPostes - 1 do
    begin
      P[iposte] := s.xval(ivar + iposte);
      Lambda_P[iPoste]:= s.xmult( ivar + iposte ) / globs.durpos[iposte];
      cv_Spot[iPoste]:= Nodo.cmarg[iposte] - Lambda_P[iPoste];
      P_Uy_despachada[iposte] := P[iposte] - P_Ag_despachada[iposte];
      EnergiaGenerada := EnergiaGenerada + P[iposte] * globs.durpos[iposte];
      EnergiaAG := EnergiaAG + P_Ag_despachada[iposte] * globs.durpos[iposte];
    end;
    EnergiaUy := EnergiaGenerada - EnergiaAG;
    Ingreso_PorEnergia_ := EnergiaUy * pa.PagoPorEnergia_USD_MWh;
  end
  else
  begin
    for iposte := 0 to globs.NPostes - 1 do
    begin
      P[iposte] := 0;
      P_Ag_recortada[iposte] := P_Ag_programada[iposte];
      Lambda_P[iPoste]:= 0;
      cv_Spot[iPoste]:=get_cv_falla; // para que en el ordenamiento quede último, con costo variable igual a la falla;
    end;
    //vclear( cv_Spot );
    EnergiaGenerada := 0;
    EnergiaAg := 0;
    EnergiaUy := 0;
    Ingreso_PorEnergia_ := 0;
  end;



  if pa.ImponerQminPorPoste then
  begin
    VVertido := 0;

    for iposte := 0 to globs.NPostes - 1 do
      VVertido := VVertido + s.xval(ivert + iposte);
  end
  else
    VVertido := s.xval(ivert);


  VTurbinado := EnergiaGenerada / (ce * 1.0E6);
  VErogado := VTurbinado + VVertido;

  QVertido := VVertido * (1.0E6 * globs.invSegundosDelPaso);
  QTurbinado := VTurbinado * (1.0E6 * globs.invSegundosDelPaso);
  QErogado_ := VErogado * (1.0E6 * globs.invSegundosDelPaso);


  Xs_VolumenEmbalsado := s.yval(ires) + V_hmin;

  dEE_Dec := EnergiaUy;
  dEE_Inc := EnergiaAg;


  Xs_DEE_actual := X_DEE_actual + (dEE_Inc - dEE_Dec);

  if (VVertido > 0.1) then
  begin
    EnergiaVertida := VVertido * (ce * 1.0E6);
    if Xs_dEE_actual > 0 then
    begin
      if Xs_dEE_actual > EnergiaVertida then
      begin
        dEE_Dec := dEE_Dec + EnergiaVertida;
        Xs_dEE_actual := Xs_dEE_actual - EnergiaVertida;
      end
      else
      begin
        dEE_Dec := dEE_Dec + Xs_dEE_actual;
        Xs_dEE_actual := 0;
      end;
    end
    else
    begin
      if (-Xs_dEE_actual) > EnergiaVertida then
      begin
        dEE_Inc := dEE_Inc + EnergiaVertida;
        Xs_dEE_actual := Xs_dEE_actual + EnergiaVertida;
      end
      else
      begin
        dEE_Inc := dEE_Inc - Xs_dEE_actual;
        Xs_dEE_actual := 0;
      end;
    end;
  end;

end;


function THidroConEmbalseBinacional.opt_necesitoIterar(kIteracion: integer;
  var errRelativo: NReal): boolean;
var
  qm: NReal;
  alfa: NReal;
  k: integer;
begin


  qm := max(QErogado_, QErogado_IterAnterior);
  if qm > 1 then
    errRelativo := abs(QErogado_ - QErogado_IterAnterior) / qm
  else
    errRelativo := 0;

  alfa := 0.7;
  QErogado_ := alfa * QErogado_IterAnterior + (1 - alfa) * QErogado_;
  QErogado_IterAnterior := QErogado_;
  Result := errRelativo > 0.1;
end;


function THidroConEmbalseBinacional.getNombreVar(ivar: integer;
  var nombre: string): boolean;
var
  iaux: integer;
begin
  if (ivar >= self.ivar) and (ivar < self.ivar + globs.NPostes) then
  begin
    nombre := self.Nombre + '_P[MW]' + IntToStr(ivar - self.ivar + 1);
    Result := True;
  end
  else

  if pa.ImponerQminPorPoste then
  begin
    iaux := ivar - ivert + 1;
    if (iaux >= 1) and (iaux <= globs.npostes) then
    begin
      nombre := self.Nombre + '_Vertimiento[Hm3]' + IntToStr(iaux);
      Result := True;
    end
    else
      Result := False;
  end
  else
  begin
    if (ivar = ivert) then
    begin
      nombre := self.Nombre + '_Vertimiento[Hm3]';
      Result := True;
    end
    else
      Result := False;
  end;
end;

function THidroConEmbalseBinacional.getNombreRes(ires: integer;
  var nombre: string): boolean;
var
  kres, cnt_res: integer;
  buscando: boolean;
  res: boolean;

  function check(condicion: boolean; cnt: integer; texto: string): boolean;
  var
    icond: integer;
    res: boolean;
  begin
    res := False;
    if buscando and condicion then
    begin
      for icond := 0 to cnt - 1 do
      begin
        if kres = cnt_res then
        begin
          nombre := self.nombre + texto + '_' + IntToStr(icond + 1);
          buscando := False;
          res := True;
          break;
        end
        else
          Inc(cnt_res);
      end;
    end;
    Result := res;
  end;

begin
  kres := ires - self.ires + 1;
  cnt_res := 1;
  buscando := True;
  res :=
    check(True, 1, '_VOL>=0') or check(True, 1, '_VOL>=0');

  {$IFNDEF CONCONTROLCRECIDA}
  res := res or check(True, 1, '_VOL<=Vmax');
  {$ENDIF}

  if (PuedoGenerar) then
    res := res or check(True, 1, 'hvista_uy > hv_min') or
      check(pa.HayRestriccionEmaxPasoDeTiempo, 1, '_res-EMax');

  if pa.ImponerQminPorPoste then
    res := res or check(AplicarRestriccionDeErogadoMinimo, globs.NPostes,
      '_res-QTMin')
  else
    res := res or check(AplicarRestriccionDeErogadoMinimo, 1, '_res-QTMin');

  Result := res;
end;

procedure THidroConEmbalseBinacional.PubliVars;
begin
  inherited PubliVars;
  PublicarVariableVR('P_Uy_despachada', '[MW]', 6, 1, P_Uy_despachada, True, True);
  PublicarVariableVR('P_Ag_despachada', '[MW]', 6, 1, P_Ag_despachada, True, True);
  PublicarVariableVR('P_Ag_recortada', '[MW]', 6, 1, P_Ag_recortada, True, True);

  PublicarVariableNR('QAportesP', '[m3/s]', 8, 1, QAportePropio, True);
  PublicarVariableNR('QTurbinado', '[m3/s]', 8, 1, QTurbinado, True);
  PublicarVariableNR('QVertido', '[m3/s]', 8, 1, QVertido, True);
  PublicarVariableNR('h_real', '[m]', 6, 1, h_actual, True);
  PublicarVariableNR('h_vistaUY', '[m]', 6, 1, h_vistaUY, True);
  PublicarVariableNR('h_vistaAG', '[m]', 6, 1, h_vistaAG, True);
  PublicarVariableNR('dh_RedQE', '[USD/Hm3]', 6, 2, dh_RedQE, True);
  PublicarVariableNR('CV_aguaDec', '[USD/Hm3]', 6, 1, cv_agua_USD_Hm3_Dec, True);
  PublicarVariableNR('CV_aguaInc', '[USD/Hm3]', 6, 1, cv_agua_USD_Hm3_Inc, True);
  PublicarVariableNR('CV_DEE_Dec', '[USD/MWh]', 6, 1, cv_dEE_USD_MWh_Dec, True);
  PublicarVariableNR('DEE', '[MWh]', 6, 1, X_DEE_actual, True);

  PublicarVariableVR('P', '[MW]', 6, 1, P, True, False);
  PublicarVariableNR('CV_DEE_Inc', '[USD/MWh]', 6, 1, cv_dEE_USD_MWh_Inc, False);
  PublicarVariableNR('Vertimiento', '[Hm^3]', 15, 1, VVertido, False);
  PublicarVariableNR('Cota', '[m]', 6, 1, h_actual, False);
  PublicarVariableNR('Vol', '[Hm^3]', 15, 1, X_VolumenEmbalsado, False);
  PublicarVariableNI('NMaqsDisponibles', '-', NMaquinasDisponibles, False);

  PublicarVariableNR('QErogado_IterAnterior', '[m3/s]', 8, 1,
    QErogado_IterAnterior, False);

  PublicarVariableNR('QErogado', '[m3/s]', 8, 1, QErogado_, False);
  PublicarVariableNR('QEvaporación', '[m3/s]', 8, 1, QEvap, False);
  PublicarVariableNR('QFiltración', '[m3/s]', 8, 1, QFilt, False);
end;

function THidroConEmbalseBinacional.ivarVertimientosMiosYAguasAbajo: TDAofNInt;
var
  nCentrales: integer;
  iter: TGeneradorHidraulico;
  res: TDAofNInt;
begin
  nCentrales := 1; //yo

  iter := centralLagoDescarga;  // agregado
  while iter <> nil do
  begin
    nCentrales := nCentrales + 1;
    iter := iter.centralLagoDescarga;
  end;

  SetLength(res, nCentrales);
  nCentrales := 0;
  iter := self;
  while iter <> nil do
  begin
    res[nCentrales] := iter.ivert;
    nCentrales := nCentrales + 1;
    iter := iter.centralLagoDescarga;
  end;
  Result := res;
end;

procedure THidroConEmbalseBinacional.optx_nvxs(var ixr, ixd, iauxr, iauxd: integer);
begin
  if not flg_ValorizadoManual then
  begin
    self.ixr := ixr;
    ixr := ixr + 2;

    Self.iauxr := iauxr;
    iauxr := iauxr + 1;
  end;
end;

procedure THidroConEmbalseBinacional.PosicionarseEnEstrellita;
var
  energia: Nreal;
begin
  EnIteracion := False;
  if not flg_ValorizadoManual then
  begin
    X_VolumenEmbalsado := globs.CF.xr[ixr];
    h_actual := VolumenToCota(X_VolumenEmbalsado);
    QErogado_ := globs.Auxs_r0[iauxr][globs.CF.ordinalEstrellaActual];

    QErogado_IterAnterior := QErogado_;

    energia := CotaToEnergia(h_actual);
    DEE_max_ := CotaToEnergia(h_actual) - EAcumMin;
    X_DEE_actual := ((globs.CF.xr[ixr + 1] - 0.5) / 0.5) * DEE_max_;

    if h_actual<30.01 then
      energia:=energia;
    // JFP 10/9/15: Paso de la VE en p.u a X_DEE_actual en MWh
{$IFDEF LECTURA BARRIDO ESTADOS}
    // if ((round(h_actual)=34) and (globs.kPaso_=2)) then
    //WriteLn(ffelipe,globs.kPaso_:3,#9,h_vistaUy:3,#9,h_vistaAG:3,#9,X_DEE_actual:2,#9,h_actual:3,globs.CF.xr[ixr + 1]:3);
{$ENDIF}
  end;

end;

procedure THidroConEmbalseBinacional.ActualizarEstadoGlobal(flg_Xs: boolean);

begin

  if flg_Xs then
  begin
    CalcularAportesPropiosVolumenYDEEFinalSinErogado;
    if not self.flg_ValorizadoManual then
    begin
      globs.CF.xr[ixr] := Vs_SinErogado;
      globs.CF.xr[ixr + 1] := dEEs_SinErogado / DEE_max_s * 0.5 + 0.5;
    end;
  end
  else if not self.flg_ValorizadoManual then
  begin
    globs.CF.xr[ixr] := X_VolumenEmbalsado;
    globs.CF.xr[ixr + 1] := X_DEE_actual / DEE_max_ * 0.5 + 0.5;
    // JFP 10/9/15: Paso de la VE en MWh a p.u
  end;

end;

procedure THidroConEmbalseBinacional.CalcularAportesPropiosVolumenYDEEFinalSinErogado;
var
  kposte, jhora, jHoraDeLaSem: integer;

begin

  QAportePropio := Self.fuenteDeAportes.bornera[Self.numeroBorne];

  QAportePropio := max(0, QAportePropio);



  if pa.flg_CalcularFiltracionDelLago then
    QFilt := pa.filtracion_Ca + pa.filtracion_Cb * (h_actual - pa.hmin)
  else
    QFilt := 0.0;

  if pa.flg_CalcularEvaporacionDelLago then
    QEvap := CotaToSuperficie(h_actual) * CoeficienteDeEvaporacion_mps(
      globs.MesInicioDelPaso, QAportePropio, pa.QaMuySeco)
  else
    QEvap := 0.0;


  VAportePropio := QAportePropio * globs.SegundosDelPaso / 1.0E6;
  VPerdidas := (QFilt + QEvap) * globs.SegundosDelPaso / 1.0E6;

  // acotamos a que no pueda perderse más que lo que hay
  VPerdidas := max(0, min(VPerdidas, X_VolumenEmbalsado - V_hmin - (10 / 1.0E6)));

  // no dejo desfondar el lago.
  Vs_SinErogado := max(X_VolumenEmbalsado + VAportePropio - VPerdidas, V_hmin);

  hs_SinErogado:=VolumenToCota(Vs_SinErogado);


  vclear(P_Ag_programada);
  for jhora := 0 to ceil(globs.HorasDelPaso - 1) do
  begin
    kposte := globs.kPosteHorasDelPaso[jhora];

    jHoraDeLaSem := globs.HoraDeInicioDelPaso + (globs.DiaDeLaSemanaInicioDelPaso - 1) *
      24 + jHora;//JF 31/8/15: Cambio para que lea bien las compras de Argentina
    if (jHoraDeLaSem > high(pa.P_AG)) then
      jHoraDeLaSem := jHoraDeLaSem - length(pa.P_AG);

    P_Ag_programada[kposte] :=
      P_Ag_programada[kposte] + pa.P_AG[jHoraDeLaSem] + P_AG_fuente[jHora];
  end;

  EnergiaAg := 0;
  RecorteAg := 0;
  for kposte := 0 to globs.NPostes - 1 do
  begin
    EnergiaAg := EnergiaAg + P_Ag_programada[kposte];
    P_Ag_programada[kposte] := P_Ag_programada[kposte] / globs.DurPos[kposte];
    P_Ag_despachada[kposte] := P_Ag_programada[kposte];
  end;

  //JFP 28/9/15: Asumo que los 300 m3/s de erogado mínimo para Uruguay equivalen a 75 MW.
  // No lo puedo calcular exacto porque depende del ce que se calcula en prepararPaso_ps y pueden haber iteraciones.
  for kposte := 0 to globs.NPostes - 1 do
  begin
    P_Uy_QTminUY[kposte] := 75;
  end;

  EnergiaUY_min := 0;
  for kposte := 0 to globs.NPostes - 1 do
  begin
    EnergiaUY_min := EnergiaUY_min + P_Uy_QTminUY[kposte] * globs.DurPos[kposte];
  end;


  dEEs_SinErogado := X_DEE_actual + EnergiaAg -EnergiaUY_min ;

  DEE_max_s := CotaToEnergia(VolumenToCota(Vs_SinErogado)) - EAcumMin;

end;

procedure THidroConEmbalseBinacional.AcumAux1(peso: NReal);
begin
  if flg_ValorizadoManual then
    exit;
  globs.Auxs_r1[iauxr][globs.CF.ordinalEstrellaActual] :=
    globs.Auxs_r1[iauxr][globs.CF.ordinalEstrellaActual] + Self.QErogado_ * peso;
end;

procedure THidroConEmbalseBinacional.SetAux1;
begin
  if flg_ValorizadoManual then
    exit;
  globs.Auxs_r1[iauxr][globs.CF.ordinalEstrellaActual] := Self.QErogado_;
end;

procedure THidroConEmbalseBinacional.optx_RegistrarVariablesDeEstado(
  adminEstados: TAdminEstados);
begin
  if flg_ValorizadoManual then
    exit;

  adminEstados.Registrar_Continua(
    ixr,
    V_hmin,
    V_hmax,
    NDiscH,
    nombre + '_Vol', // nombre de la variable
    'Hm3' // unidades
    );

  adminEstados.RegistrarTraduccion_Continua(ixr,
    nombre + '_Cota',
    'm', self.VolumenToCota);



  adminEstados.Registrar_Continua(
    //JFP 10/9/15: Cambio rango de variable de estado de [-DEE_MAXIMA,DEE_MAXIMA]  a [0,1] para que
    ixr + 1, 0,
    //represente el porcentaje de diferencia de energía embalsada respecto del màximo según la cota actual.
    1,
    self.nDiscDE,
    nombre + '_dEE', // nombre de la variable
    'p.u' // unidades
    );
end;

procedure THidroConEmbalseBinacional.Free;
begin
  lpd.Free;
  setlength(P_Uy_despachada, 0);
  setlength(P_Ag_programada, 0);
  setlength(P_Uy_QTminUY, 0);
  setlength(P_Ag_despachada, 0);
  setlength(P_Ag_recortada, 0);
  setlength(Pmax_Central_CotaInf, 0);
  setlength(Pmax_Central_CotaSup, 0);


  if self.polinomioCotaMaxAporte <> nil then
    self.polinomioCotaMaxAporte.Free;

  if polinomioCotaVolumen <> nil then
    polinomioCotaVolumen.Free;

  if self.polinomioErogadoMinVol <> nil then
    self.polinomioErogadoMinVol.Free;


  EnergiaToCota_func.Free;
  inherited Free;

end;

function THidroConEmbalseBinacional.CotaToVolumen(h: NReal): NReal;
var
  dh: NReal;
begin
  dh := h - pA.hmin;
  if EsConico then
    Result := (embalse_c2 * dh + embalse_c1) * dh
  else
    Result := embalse_c1 * dh;
end;



function THidroConEmbalseBinacional.CotaToSuperficie(h: NReal): NReal;
var
  dh: NReal;
begin
  dh := h - pA.hmin;
  if EsConico then
    Result := (2 * embalse_c2 * dh + embalse_c1) * 1.0E6
  else
    Result := embalse_c1 * 1.0E6;
end;


function THidroConEmbalseBinacional.hVerticeCono: NReal;
begin
  Result := pA.hmin - embalse_c1 / (2 * embalse_c2);
end;


function THidroConEmbalseBinacional.VolumenToCota(Vol: NReal): NReal;
begin
  if EsConico then
    Result := sqrt(embalse_c3 * Vol + embalse_c4) + embalse_c5
  else
    Result := Vol / embalse_c1 + pA.hmin;
end;

function THidroConEmbalseBinacional.VTminPorCurvaAportes(Aportes,
  cota_actual: NReal): NReal;
var
  aportes_paso: NReal;
  cota_proy: NReal;
begin
  aportes_paso := Aportes;
  cota_proy := VolumenToCota(Vs_SinErogado);

  if (aportes_paso < self.pA.PuntosControlCrecidaPorCotaYAportes_QA[0]) or
    (aportes_paso > self.pA.PuntosControlCrecidaPorCotaYAportes_QA[2]) then
    if Aportes < Self.pa.PuntosControlCrecidaPorCotaYAportes_QA[0] then
      if cota_proy > self.pa.PuntosControlCrecidaPorCotaYAportes_h[0] then
        Result := Self.CotaToVolumen(cota_proy) - Self.CotaToVolumen(
          Self.pa.PuntosControlCrecidaPorCotaYAportes_h[0])
      else
        Result := 0;
  if aportes_paso > Self.pa.PuntosControlCrecidaPorCotaYAportes_QA[2] then
    if cota_proy > Self.pa.PuntosControlCrecidaPorCotaYAportes_h[2] then
      Result := Self.CotaToVolumen(cota_proy) - Self.CotaToVolumen(
        Self.pa.PuntosControlCrecidaPorCotaYAportes_h[2])
    else
      Result := 0
  else
  if cota_proy >= Self.polinomioCotaMaxAporte.Valx(aportes_paso) then
  begin
    Result := Self.CotaToVolumen(cota_proy) - Self.CotaToVolumen(
      Self.polinomioCotaMaxAporte.Valx(aportes_paso));
  end
  else
    Result := 0;

  Result := Max(Result, 0);
end;

procedure THidroConEmbalseBinacional.CambioFichaPD;
var
  //  h: NReal;
  dh: NReal;
  //  QE: NReal;
  j: integer;
  Eaux: NReal;
  //  salto: NReal;
  //  perdida_hPorQE: NReal;
  //  buscando: boolean;
  h1{, h2, E1, E2}: NReal;

  //  dEEMax: NReal;
  EacumEmbalse: NReal;
  Eacum: NReal;
  MaximoDeLaEnergiaEmbalsada: NReal;
  //  hVertice: NReal;

  cntIters: word;
  converged: boolean;

  hmed: NReal;

  dVmax, dVmed, alfa_QE_Proteccion: NReal;
  ErogadoMinVol_vol, ErogadoMinVol_Erogado: TDAofNReal;
begin

  polinomioCotaMaxAporte.AproxTabla2D(2,
    self.pa.PuntosControlCrecidaPorCotaYAportes_QA,
    self.pa.PuntosControlCrecidaPorCotaYAportes_h);

  polinomioCotaVolumen.AproxTabla2D(2, self.pa.PuntosCotaVolumen_h,
    self.pa.PuntosCotaVolumen_V);
  V_hmin := polinomioCotaVolumen.valx(pa.hmin);
  V_hmax := polinomioCotaVolumen.valx(pA.hmax);
  hmed := (pa.hmax + pa.hmin) / 2;
  V_hmed := polinomioCotaVolumen.valx(hmed);

  dVmax := V_hmax - V_hmin;
  dVmed := V_hmed - V_hmin;


  //TODO maxDiferenciaEnergiaEmbalsada
  //  dEEMax:= pa.maxDiferenciaEnergiaEmbalsada;

  ro_g_ren := pA.ren * ro_Agua * g_gravitacion / (1.0E6 * 3600.0);

  dhmax := (pA.hmax - pA.hmin);

  embalse_cb := 4.0 * (dVmax - 2.0 * dVmed);
  embalse_ca := dVmax - embalse_cb / 2.0;
  if (embalse_cb < 0) then
    raise Exception.Create('Revise los datos del embalse(' + Nombre +
      '), el área decrece al aumentar la cota.');
  if (embalse_ca < 0) then
    raise Exception.Create('Revise los datos del embalse(' + Nombre +
      '), el volumen parece anularse antes de la cota mínima.');

  embalse_c1 := embalse_ca / dhmax;

  if EsCero(embalse_cb) then
  begin
    EsConico := False;
  end
  else
  begin
    EsConico := True;
    embalse_c2 := embalse_cb / 2.0 / sqr(dhmax);
    embalse_c3 := 1 / embalse_c2;
    embalse_c4 := sqr(embalse_c1 / (2 * embalse_c2));
    embalse_c5 := pA.hmin - (embalse_c1 / (2 * embalse_c2));
  end;




  // recalculo de la energía embalsada.
  //  QE:= pa.QE_CEE;

  dh := (pA.hmax - pA.hmin) / 1999;

  EAcumEmbalse := CotaToEnergia(pa.hmax);

  //  hVertice:= hVerticeCono;

  hEAcumMin := pa.hVistaMin;
  eAcumMin := cotaToEnergia(hEAcumMin);

  DEE_MAXIMA := (EAcumEmbalse - eAcumMin);

  // buscamos hEAcumMax
  EAcumMax := EAcumEmbalse + DEE_MAXIMA;

  hEAcumMax := pa.hmax + (pa.hmax - hEAcumMin);

  EnergiaToCota_func.EnergiaDada:= EAcumMax;
  converged:= EnergiaToCota_func.Dicot(
    hEAcumMin, hEAcumMax,  dh,          {extremos y tolerancia}
    100,          {n£mero m ximo de iteraciones}
    hEAcumMax, EAcum,     {ra¡z y f(ra¡z)}
    cntIters          {n£mero de iteraciones realizadas}
  );
  if not converged then
    Raise Exception.Create(' No pudo resolver CotaToEnergía ' );

  // calculo de la inversa
  MaximoDeLaEnergiaEmbalsada := eAcumMax;

  d_DEE_TablaAprox := (MaximoDeLaEnergiaEmbalsada - eAcumMin) / 1999;
  kEnergiaEmbalsadaToCota[0] := hEAcumMin;
  kEnergiaEmbalsadaToCota[1999] := hEAcumMax;
  h1 := hEAcumMin;



  for j := 1 to 1998 do
  begin
    Eaux := d_DEE_TablaAprox * j + EAcumMin;

    EnergiaToCota_func.EnergiaDada:= EAux;
    Converged:= EnergiaToCota_func.Dicot(
      h1, hEAcumMax, dh,          {extremos y tolerancia}
      100,          {n£mero m ximo de iteraciones}
      h1, EAcum,     {ra¡z y f(ra¡z)}
      cntIters          {n£mero de iteraciones realizadas}
      );
    if not converged then
      Raise Exception.Create(' No pudo resolver CotaToEnergía ' );

    kEnergiaEmbalsadaToCota[j] := h1;

  end;


  EAcumMaxMenosMin := EAcumMax - EAcumMin;
  dhEAcumMaxMenosMin := hEAcumMax - hEAcumMin;


  //***JFP 15/9/15: Copio control de crecida de uhidroconembalse****

  {$IFDEF CONCONTROLCRECIDA}

  // inicializamos el volumen de inicio del control de crecida.
  self.V_ControlCrecida_Inicio := self.CotaToVolumen(pa.cotaControlCrecida_Inicio);

  // calculo Volúmenes embalsados al inicio y fin del vertedero para facilitar cálculos
  V_EmbalsadoInicioVertedero := CotaToVolumen(pa.cotaMV0);
  V_EmbalsadoFinalVertedero := CotaToVolumen(pa.cotaMV1);
  Delta_V_Embalsado_Vertedero := V_EmbalsadoFinalVertedero - V_EmbalsadoInicioVertedero;

  // Cálculo de la constante k_QE para la fórmular de Caudal erogado para
  // protección de la presa.
  V_EmbalsadoInicioProteccion := CotaToVolumen(pa.cotaControlCrecida_Inicio);
  V_EmbalsadoProteccionAPleno := CotaToVolumen(pa.cotaControlCrecida_Pleno);
  Delta_V_Embalsado_Proteccion :=
    V_EmbalsadoProteccionAPleno - V_EmbalsadoInicioProteccion;
  alfa_QE_Proteccion := pa.QE_ControlDeCrecidaAPleno /
    (Delta_V_Embalsado_Proteccion * 1e6); // [1/s]
  r_QE_Proteccion := 1.0E6 / (globs.SegundosDelPaso) *
    (1 - exp(-alfa_QE_Proteccion * globs.SegundosDelPaso));

  {$ENDIF}

  //JFP: calculo polinomio para aproximar control de crecida por cota
  SetLength(ErogadoMinVol_vol, 3);
  ErogadoMinVol_vol[0] := CotaToVolumen(pa.cotaControlCrecida_Inicio);
  ErogadoMinVol_vol[1] := CotaToVolumen(pa.cotaControlCrecida_Medio);
  ErogadoMinVol_vol[2] := CotaToVolumen(pa.cotaControlCrecida_Pleno);

  SetLength(ErogadoMinVol_Erogado, 3);
  ErogadoMinVol_Erogado[0] := pa.QE_ControlDeCrecidaInicio;
  ErogadoMinVol_Erogado[1] := pa.QE_ControlDeCrecidaMedio;
  ErogadoMinVol_Erogado[2] := pa.QE_ControlDeCrecidaAPleno;

  polinomioErogadoMinVol.AproxTabla2D(2, ErogadoMinVol_vol, ErogadoMinVol_Erogado);

  //libero memoria
  SetLength(ErogadoMinVol_vol, 0);
  SetLength(ErogadoMinVol_Erogado, 0);

  recalcular_parametros_dhqe( pa.caQE, pa.cbQE );
end;


{*********************************
*Métodos de TFichaHidroConEmbalseBinacional*
*********************************}

constructor TFichaHidroConEmbalseBinacional.Create(capa: integer;
  fecha: TFecha; periodicidad: TPeriodicidad; hmin_, hmax_: NReal;
  PuntosCotaVolumen_h, PuntosCotaVolumen_V: TDAOfNReal; hDescarga: NReal;
  central_lagoDescarga: TGeneradorHidraulico;
  centralesAguasArriba: TListaCentralesAguasArriba;
  caQE, cbQE, ren_, Pmax_Gen_, Qmax_Turb_: NReal; fDispo_: NReal;
  tRepHoras: NReal; filtracion_Ca, filtracion_Cb, QaMuySeco: NReal;
  cotaMV0, cotaMV1, QMV1: NReal; HayRestriccionEmaxPasoDeTiempo: boolean;
  EmaxPasoDeTiempo: NReal; HayRestriccionQTmin: boolean; QTmin: NReal;
  ImponerQminPorPoste: boolean; ControlarCotaPorDebajoDeObjetivo: boolean;
  ControlarCotaPorEnciaDeObjetivo: boolean; hObjetivo: NReal;
  Delta_cvaUSD_Hm3ParaControlDeCota: NReal; cv_USD_Hm3_ValorizadoManual: NReal;
  P_AG: TDAOfNreal; QE_CEE: NReal; hVistaMin: NReal; saltoMinimoOperativo: NReal;
  cotaControlCrecida_inicio, cotaControlCrecida_Medio, cotaControlCrecida_pleno,
  QE_ControlDeCrecidaInicio, QE_ControlDeCrecidaMedio, QE_ControlDeCrecidaAPleno: NReal;
  flg_CalcularEvaporacionDelLago: boolean; flg_CalcularFiltracionDelLago: boolean;
  PagoPorDisponibilidad_USD_MWh: NReal; PagoPorEnergia_USD_MWh: NReal;
  PuntosControlCrecidaPorCotaYAportes_h, PuntosControlCrecidaPorCotaYAportes_QA:
  TDAOfNReal;
  flg_ControlCrecidaPOrCotaYAportes, flg_ControlCrecidaPorCota: boolean; QTMinUY: NReal);
begin
  inherited Create(capa, fecha, periodicidad);
  self.hmin := hmin_;
  self.hmax := hmax_;

  self.PuntosCotaVolumen_h := PuntosCotaVolumen_h;
  self.PuntosCotaVolumen_V := PuntosCotaVolumen_V;

  self.hDescarga := hDescarga;
  self.central_lagoDescarga := central_lagoDescarga;
  self.caQE := caQE;
  self.cbQE := cbQE;
  self.ren := ren_;
  self.Pmax_Gen := Pmax_Gen_;
  self.Qmax_Turb := Qmax_Turb_;
  self.fDispo := fDispo_;
  self.tRepHoras := tRepHoras;

  Self.filtracion_Ca := filtracion_Ca;
  Self.filtracion_Cb := filtracion_Cb;
  Self.QaMuySeco := QaMuySeco;

  self.cotaMV0 := cotaMV0;
  self.cotaMV1 := cotaMV1;
  self.QMV1 := QMV1;

  self.centralesAguasArriba := centralesAguasArriba;

  self.HayRestriccionEmaxPasoDeTiempo := HayRestriccionEmaxPasoDeTiempo;
  self.EmaxPasoDeTiempo := EmaxPasoDeTiempo;
  self.HayRestriccionQTmin := HayRestriccionQTmin;
  self.QTmin := QTmin;
  self.ImponerQminPorPoste := ImponerQminPorPoste;

  self.flg_controlCotaObjetivoInferior := ControlarCotaPorDebajoDeObjetivo;
  self.flg_controlCotaObjetivoSuperior := ControlarCotaPorEnciaDeObjetivo;
  self.hObjetivo := hObjetivo;
  self.delta_cva_ParaControlDeCota := Delta_cvaUSD_Hm3ParaControlDeCota;
  self.cv_USD_Hm3_ValorizadoManual := cv_USD_Hm3_ValorizadoManual;

  self.P_AG := P_AG;

  self.QE_CEE := QE_CEE;
  self.hVistaMin := hVistaMin;
  self.saltoMinimoOperativo := saltoMinimoOperativo;

  self.cotaControlCrecida_inicio := cotaControlCrecida_inicio;
  self.cotaControlCrecida_Medio := cotaControlCrecida_Medio;
  self.cotaControlCrecida_pleno := cotaControlCrecida_pleno;

  self.QE_ControlDeCrecidaInicio := QE_ControlDeCrecidaInicio;
  self.QE_ControlDeCrecidaMedio := QE_ControlDeCrecidaMedio;
  self.QE_ControlDeCrecidaAPleno := QE_ControlDeCrecidaAPleno;

  self.flg_CalcularEvaporacionDelLago := flg_CalcularEvaporacionDelLago;
  self.flg_CalcularFiltracionDelLago := flg_CalcularFiltracionDelLago;
  self.PagoPorDisponibilidad_USD_MWh := PagoPorDisponibilidad_USD_MWh;
  self.PagoPorEnergia_USD_MWh := PagoPorEnergia_USD_MWh;

  self.PuntosControlCrecidaPorCotaYAportes_h := PuntosControlCrecidaPorCotaYAportes_h;
  Self.PuntosControlCrecidaPorCotaYAportes_QA := PuntosControlCrecidaPorCotaYAportes_QA;
  self.flg_ControlCrecidaPOrCotaYAportes := flg_ControlCrecidaPOrCotaYAportes;
  self.flg_ControlCrecidaPorCota := flg_ControlCrecidaPorCota;
  self.QTMinUY := QTMinUY;

end;

function TFichaHidroConEmbalseBinacional.Rec: TCosa_RecLnk;
begin
  Result:=inherited Rec;
  Result.addCampoDef('hmin', hmin);
  Result.addCampoDef('hmax', hmax);
  Result.addCampoDef('PuntosCotaVolumen_h', PuntosCotaVolumen_h);
  Result.addCampoDef('PuntosCotaVolumen_V', PuntosCotaVolumen_V);
  Result.addCampoDef('hDescarga', hDescarga);
  Result.addCampoDef('caQE', caQE);
  Result.addCampoDef('cbQE', cbQE);
  Result.addCampoDef('ren', ren);
  Result.addCampoDef('Pmax_Gen', Pmax_Gen);
  Result.addCampoDef('Qmax_Turb', Qmax_Turb);
  Result.addCampoDef('fDispo', fDispo);
  Result.addCampoDef('tRepHoras', tRepHoras);
  Result.addCampoDef('filtracion_Ca', filtracion_Ca);
  Result.addCampoDef('filtracion_Cb', filtracion_Cb);
  Result.addCampoDef('QaMuySeco', QaMuySeco);
  Result.addCampoDef('cotaMV0', cotaMV0);
  Result.addCampoDef('cotaMV1', cotaMV1);
  Result.addCampoDef('QMV1', QMV1);
  Result.addCampoDef_ref('central_lagoDescarga', TCosa(central_lagoDescarga), Self);
  Result.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba));
  Result.addCampoDef('HayRestriccionEmaxPasoDeTiempo', HayRestriccionEmaxPasoDeTiempo);
  Result.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo);
  Result.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin);
  Result.addCampoDef('QTmin', QTmin);
  Result.addCampoDef('ImponerQminPorPoste', ImponerQminPorPoste);
  Result.addCampoDef('hObjetivo', hObjetivo);
  Result.addCampoDef('cva_delta', delta_cva_ParaControlDeCota);
  Result.addCampoDef('flg_controlCotaObjetivoInferior', flg_controlCotaObjetivoInferior);
  Result.addCampoDef('flg_controlCotaObjetivoSuperior', flg_controlCotaObjetivoSuperior);
  Result.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual);
  Result.addCampoDef('PotenciaParaArgentina', P_AG);
  Result.addCampoDef('QE_CEE', QE_CEE);
  Result.addCampoDef('hVistaMin', hVistaMin);
  Result.addCampoDef('cotaControlCrecida_inicio', cotaControlCrecida_inicio);
  Result.addCampoDef('cotaControlCrecida_pleno', cotaControlCrecida_pleno);
  Result.addCampoDef('QE_ControlDeCrecidaAPleno', QE_ControlDeCrecidaAPleno, 135, 0, '26910 * 2' );
  Result.addCampoDef('saltoMinimoOperativo', saltoMinimoOperativo);
  Result.addCampoDef('flg_CalcularEvaporacionDelLago', flg_CalcularEvaporacionDelLago, 83, 0, 'true' );
  Result.addCampoDef('flg_CalcularFiltracionDelLago', flg_CalcularFiltracionDelLago, 83, 0, 'true' );
  Result.addCampoDef('PagoPorDisponibilidad_USD_MWh', PagoPorDisponibilidad_USD_MWh, 98 );
  Result.addCampoDef('PagoPorEnergia_USD_MWh', PagoPorEnergia_USD_MWh, 98 );
  Result.addCampoDef('PuntosControlCrecidaPorCotaYAportes_h', PuntosControlCrecidaPorCotaYAportes_h, 135 );
  Result.addCampoDef('PuntosControlCrecidaPorCotaYAportes_QA', PuntosControlCrecidaPorCotaYAportes_QA, 135 );
  Result.addCampoDef('flg_ControlCrecidaPOrCotaYAportes', flg_ControlCrecidaPOrCotaYAportes, 135 );
  Result.addCampoDef('QTMinUY', QTMinUY, 136 );
  Result.addCampoDef('QE_ControlDeCrecidaInicio', QE_ControlDeCrecidaInicio, 141 );
  Result.addCampoDef('QE_ControlDeCrecidaMedio', QE_ControlDeCrecidaMedio, 141 );
  Result.addCampoDef('cotaControlCrecida_Medio', cotaControlCrecida_Medio, 141 );
  Result.addCampoDef('flg_ControlCrecidaPorCota', flg_ControlCrecidaPorCota, 141 );
end;

procedure TFichaHidroConEmbalseBinacional.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  PagoPorDisponibilidad_USD_MWh := 0.0;
  PagoPorEnergia_USD_MWh := 0.0;
end;

function Estimar_ControCrecida_hMed_con_QE_Lineal_con_Vol(
  const PuntosCotaVolumen_h, PuntosCotaVolumen_V: TDAOfNReal;
  hInicioControl, hControlAPleno: NReal): NReal;
var
  p: TPoliR;
  VolIni, VolPleno, VolMed: NReal;
  res: NReal;
begin
  p := TPoliR.Create_Init(2);
  p.AproxTabla2D(2, PuntosCotaVolumen_h, PuntosCotaVolumen_V);
  VolIni := p.Valx(hInicioControl);
  VolPleno := p.Valx(hControlAPleno);
  VolMed := (VolIni + VolPleno) / 2.0;
  res := (-p.a[1] + sqrt(sqr(p.a[1]) - 4 * p.a[2] * (p.a[0] - VolMed))) / (2 * p.a[2]);
  p.Free;
  Result := res;
end;



procedure TFichaHidroConEmbalseBinacional.AfterRead(f:TArchiTexto);
//var
//  genOtroPaisSemanal: TDAofNReal;
//  Vmax, Vhmed: NReal;
begin
  inherited AfterRead(f);
  if f.Version < 135 then
  begin
    setlength(PuntosControlCrecidaPorCotaYAportes_h, 3);
    PuntosControlCrecidaPorCotaYAportes_h[0] := 35.5;
    PuntosControlCrecidaPorCotaYAportes_h[1] := 35.39;
    PuntosControlCrecidaPorCotaYAportes_h[2] := 35.04;
    setlength(PuntosControlCrecidaPorCotaYAportes_QA, 3);
    PuntosControlCrecidaPorCotaYAportes_QA[0] := 1000;
    PuntosControlCrecidaPorCotaYAportes_QA[1] := 4000;
    PuntosControlCrecidaPorCotaYAportes_QA[2] := 8000;
    flg_ControlCrecidaPOrCotaYAportes := False;
  end;
  if f.Version < 136 then
    QTMinUY := 300;

  if f.Version < 141 then
  begin
    flg_ControlCrecidaPorCota := True;
    QE_ControlDeCrecidaInicio := 0.0;
    QE_ControlDeCrecidaMedio := QE_ControlDeCrecidaAPleno / 2;
    cotaControlCrecida_Medio :=
      Estimar_ControCrecida_hMed_con_QE_Lineal_con_Vol(
      PuntosCotaVolumen_h, PuntosCotaVolumen_V, cotaControlCrecida_Inicio,
      cotaControlCrecida_Pleno);
  end;
end;



function TFichaHidroConEmbalseBinacional.infoAd_: string;
begin
  Result := 'PMáxGen= ' + FloatToStrF(Pmax_Gen, ffGeneral, 10, 1) +
    ' MW, ' + 'QMáxTurb= ' + FloatToStrF(Qmax_Turb, ffGeneral, 10, 1) +
    ' Hm^3/s, ' + 'ren= ' + FloatToStrF(ren, ffGeneral, 10, 2) +
    ' p.u., ' + 'fDisp= ' + FloatToStrF(fDispo, ffGeneral, 10, 2) +
    ' p.u., ' + 'tRep= ' + FloatToStrF(tRepHoras, ffGeneral, 10, 1) +
    'h, ' + 'hMín= ' + FloatToStrF(hmin, ffGeneral, 10, 2) + ' m, ' +
    'hMáx= ' + FloatToStrF(hmax, ffGeneral, 10, 2) + ' m, ' +
    'hDescarga= ' + FloatToStrF(hDescarga, ffGeneral, 10, 2) + 'm, ' +
    'Vmáx= ' + FloatToStrF(PuntosCotaVolumen_V[high(PuntosCotaVolumen_V)],
    ffGeneral, 10, 1) + ' m^3' + 'QE_CEE= ' + FloatToStrF(QE_CEE, ffGeneral, 10, 1) +
    ' Hm^3/s, ' + 'hVistaMin= ' + FloatToStrF(hVistaMin, ffGeneral, 10, 2) + ' MWh';
end;


procedure TFichaHidroConEmbalseBinacional.Free;
begin
  SetLength(PuntosCotaVolumen_h, 0);
  SetLength(PuntosCotaVolumen_V, 0);
  setlength(PuntosControlCrecidaPorCotaYAportes_h, 0);
  setlength(PuntosControlCrecidaPorCotaYAportes_QA, 0);
  centralesAguasArriba.Free;
  SetLength(P_AG, 0);
  inherited Free;
end;













































































procedure THidroConEmbalseBinacional_cambioFichaPD(Actor: TCosa);
begin
  (Actor as THidroConEmbalseBinacional).cambioFichaPD;
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(THidroConEmbalseBinacional.ClassName,
    THidroConEmbalseBinacional);
  registrarClaseDeCosa(TFichaHidroConEmbalseBinacional.ClassName,
    TFichaHidroConEmbalseBinacional);
end;

procedure AlFinal;
begin
end;

{$IFDEF LECTURA BARRIDO ESTADOS}
initialization
  AssignFile(ffelipe, 'ffelipe2.txt');
  Rewrite(ffelipe);

{WriteLn(ffelipe, 'kPaso'+#9+
                 'hUY'+#9+
                 'hARG'+#9+
                 'difU-A'+#9+
                 'hr' +#9+
                'DEE_p.u' ); }

  WriteLn(ffelipe, 'dDEE_MAXdV_Dec (USD/hm3)' + #9 + 'dDEE_MAXdV_Inc (USD/hm3)' +
    #9 + 'Cota[m}]');

finalization
  CloseFile(ffelipe);
{$ENDIF}
end.
