unit uHidroConEmbalse;
{$DEFINE RDIN} // OJO, este define tiene que cambiarse aquí y en la Central de Bombeo

{$DEFINE COSTOSHIDROPOSITIVOS}

{xDEFINE LOG_APORTES_OPT}

{xDEFINE CONTROL_CRECIDA_POR_VOL_LINEAL}
{$DEFINE ErogadoMinimo_FELIPE_OCT2016}
{$DEFINE LIMITE_QITER_OCT2016}
{xDEFINE DEBUG_CAMBIO_FICHA_PD}

{$DEFINE ENGANCHE_CE}

// Si está definida impone que la variable de estado es el volúmen
// sino es la cota.
{$DEFINE XVE_Volumen}


// Prueba.. ... para imponer en los bordes del intervalo de discretización
// que multiplique por 2 (Dos, en el bode de menor cota) o por 0 (Cero, en el de
// mayor cota.
{xDEFINE DERIV_20}

// Determna si la Central proyecta el estado final sin erogado para cálculo del
// valor del agua o no.
{$DEFINE HIDRO_PROYECTA_ESTADO}


// Durante la optmización usa el mismo método de derviación
// cotinua que durante la simlación. Si no está definido, usa
// un método de derivada en "estrellita" que puede ser más eficiente
{$DEFINE OPT_DERIV_CONTINUA}


// Chequea que la decremental sea superior a la incrementa, si no sucede
// las intercambia
{xDEFINE HIDRO_DERIVADA_MONOTONA}

// Si se define, luego de calcular las derivadas incremental y decremental
// pone ambas iguales al promedio.
{$DEFINE HIDRO_DERIVADA_SIMETRICA}

// Si se define, luego de calcular las derivadas incremental y decremental
// pone ambas iguales al maximo. Esta opción es incompatible con la anterior
{xDEFINE HIDRO_DERIVADA_MAX}



// Itera sobre la cota para cálculo del coeficiente energético
// si la cota varia sustancialmente durante el paso
{$DEFINE USAR_APRI}

(**
REVISIONES.

rch+20120426. v3.40
Agregué en el cálculo del máximo volumen exigible en las restricciones
de erogado mínimo que tenga en cuenta además del volúmen embalsado y los aportes, la
capacidad de extraer ese volúmen mediante turivinado+vertido. Tal como estaba no se hacía
ese control y en situaciones en que el lago se encuentra por debajo del vertedero
si se le pedía un erogado por encima del máximo turbinable no lo lograba.
Ahora, para determinar si puede cumplir con una condición de Erogado Mínimo,
Limita el volumen de la condición a no superar ni el volumen embalsado + Aportes - pérdidas del paso
y a no superar el máximo volumen erogable (turbinado + vertido). En esta versión se
agregó el control del volumen erogable.

h_actual = Cota vista para manejo del stock. Refleja siempre la cota al inicio del paso.
h_real = Cota física para cálculo del salto y del coeficiente energético. Si hay una fuente
       que fija la cota física se toma de ahí. Sino, es igual a h_actual si no hay iteraciones
       y si las hay refleja la cota media del paso para cálculo del coeficiente energético.

**)

interface

uses
  Classes,
  Math, SysUtils,
  xMatDefs, MatReal, uSimplex, ucosa, uGlobs, uFechas, uNodos,
  uEstados,
  uFichasLPD,
  uGeneradores,
  uconstantesSimSEE,
  uFuentesAleatorias, uCosaConNombre, uevapUruguay,
  uparseadorsupersimple,ufuncionesbasicas,
  {$IFDEF INTERMEDIARIO_DE_COSTO_FUTURO}
  uRandDispos,
  uodt_types,
  uFuncionesReales,
  uintermediariocostofuturo,
  {$ENDIF}
  compol;

resourcestring
  rsHidroelectricaEmbalse = 'Hidroeléctrica con embalse';

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


type

  { TauxialiarControlDeCota }

  TAuxialiarControlDeCota = class
    Cota : NReal;
    cva_ : NReal;
    constructor Create( cota, cva: NReal);
    function cva( indice: TFuenteAleatoria; nborne: integer ): NReal;
  end;


  TDAOFTauxialiarControlDeCota = array of TauxialiarControlDeCota;


  THidroConEmbalse = 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= V(1) = a+ 0.5 b
Vhmed= V(0.5) = 0.5 a + 0.5^3 b

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

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

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
*)

  { TFichaHidroConEmbalse }
  TFichaHidroConEmbalse_auxRec = class // Auxiliar para lectura
  var
    Vmax, Vhmed: NReal;
    vdummy: NReal;
    hObjetivo_aux: NReal;
    delta_cva_ParaControlDeCota_aux : NReal;
  end;

  TFichaHidroConEmbalse = class(TFichaLPD)
  public
    // límites operativos
    hmax: NReal; //[m] cota maxima  de operación
    hmin: NReal; //[m] cota minima  de operación

    // descripción de la geometria del lago
    PuntosCotaVolumen_h: TDAOfNReal;
    PuntosCotaVolumen_V: TDAOfNReal;

    // Si la fuente en lugar de caudal en m3/s es de escurrimiento
    // en mm/mes hay que especificar el área de la cuenca a considerar
    AreaCuenca_ha: NReal;

    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;

    //JFP 20/10/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;


    centralesAguasArriba: TListaCentralesAguasArriba; //of TFichaCentralAguasArriba;
    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 para asegurar navegabilidad

    PuntosControlCrecidaPorCotaYAportes_h: TDAOfNReal;
    PuntosControlCrecidaPorCotaYAportes_QA: TDAOfNReal;

    //JFP:Erogado mínimo con posibilidad de fallar
    flg_ErogadoMin_Falla: boolean;
    cv_USD_hm3_falla_ErogadoMin: NReal;
    QErogadoMin_Falla: NReal;

    flg_ControlCrecidaPOrCotaYAportes: boolean;
    ImponerQminPorPoste: boolean;
    DAOfhObjetivo: TDAofNReal; // [m] cota objetivo

    DAOfdelta_cva_ParaControlDeCota: TDAofNReal; // USD/Hm3 aplicable para control de cota

    indiceAjusteControlDeCota: TFuenteAleatoria;
    borneAjusteControlDeCota: string;


    (* rch080402 agrego esto para dar la opción de regular el uso de Salto y Palmar *)
    flg_controlCotaObjetivoInferior_sim: boolean;
    flg_controlCotaObjetivoSuperior_sim: boolean;
    flg_controlCotaObjetivoInferior_opt: boolean;
    flg_controlCotaObjetivoSuperior_opt: boolean;
    flg_ValorAguaExacto_hObjetivo: boolean;
    flg_ControlCondicional: boolean;



    //(13/05/15)Juan Felipe.Agrego posibilidad de ingresarle el valor exacto del agua
    //por debajo de la cota objetivo. Si la cota es superiora al objetivo, impongo erogado mínimo para bajarla.
    cv_USD_Hm3_ValorizadoManual: NReal;



    tomarCotaDeLaFuente: boolean;
    fuenteCota: TFuenteAleatoria;
    borneCota: string;

    saltoMinimoOperativo: NReal; // [m] salto mínimo operativo de las turbinas

    flg_CalcularEvaporacionDelLago: boolean;
    flg_CalcularFiltracionDelLago: boolean;
    PorcentajeFiltracion: NReal; // MC y LD Porcentaje del Filtrado que se eroga

    // Pagos a los generadores
    PagoPorDisponibilidad_USD_MWh: NReal; // [USD/MWh] Pago por Potencia
    PagoPorEnergia_USD_MWh: NReal; // [USD/MWh] Pago por Potencia


    // cv_Spot_Acordado
    cv_Spot_acordado: NReal;
    flg_Aplica_cv_Spot_Acordado: boolean;
    P_forzada: NReal;

    numeroBorneCota: integer;
    numeroBorneAjusteControlDeCota: integer;

    constructor Create(
      capa: integer; fecha: TFecha; periodicidad: TPeriodicidad;
      hmin_, hmax_: NReal; PuntosCotaVolumen_h,
  PuntosCotaVolumen_V: TDAOfNReal; AreaCuenca_ha: NReal; 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,
  QE_ControlDeCrecidaInicio, QE_ControlDeCrecidaMedio,
  QE_ControlDeCrecidaAPleno: NReal; HayRestriccionEmaxPasoDeTiempo: boolean;
  EmaxPasoDeTiempo: NReal; HayRestriccionQTmin: boolean; QTmin: NReal;
  flg_Aplica_cv_Spot_Acordado: Boolean; cv_Spot_acordado, P_forzada: NReal;
  PuntosControlCrecidaPorCotaYAportes_h: TDAOfNReal;
  PuntosControlCrecidaPorCotaYAportes_QA: TDAOfNReal;
  flg_ControlCrecidaPOrCotaYAportes, flg_ControlCrecidaPorCota: boolean;
  ImponerQminPorPoste: boolean; ControlarCotaPorDebajoDeObjetivo_sim,
  ControlarCotaPorEnciaDeObjetivo_sim: boolean;
  ControlarCotaPorDebajoDeObjetivo_opt,
  ControlarCotaPorEnciaDeObjetivo_opt: boolean;
  flg_ValorAguaExacto_hObjetivo: boolean; flg_ControlCondicional: boolean;
  DAofhObjetivo: TDAofNReal; DAofDelta_cvaUSD_Hm3ParaControlDeCota: TDAofNReal;

  IndiceAjusteControlDeCota: TFuenteAleatoria; borneAjusteControlDeCota: string;

  cv_USD_Hm3_ValorizadoManual: NReal; tomarCotaDeLaFuente: boolean;
  fuenteCota: TFuenteAleatoria; borneCota: string; saltoMinimoOperativo: NReal;
  cotaControlCrecida_Inicio, cotaControlCrecida_Medio,
  cotaControlCrecida_Pleno: NReal; flg_CalcularEvaporacionDelLago: boolean;
  flg_CalcularFiltracionDelLago: boolean; PorcentajeFiltracion: NReal;
  PagoPorDisponibilidad_USD_MWh: NReal; PagoPorEnergia_USD_MWh: NReal;
  QErogadoMin_Falla, cv_USD_hm3_falla_ErogadoMin: Nreal;
  flg_ErogadoMin_Falla: boolean);

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

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

    // Retorna el registro aplicable al control de cota inferior  o nil si no aplica
    function getControlDeCotaAplicable_inf( h_actual: NReal ): TAuxialiarControlDeCota;

    // Retorna el registro aplicable al control de cotas superior o nil si no aplica
    function getControlDeCotaAplicable_sup( h_actual: NReal ): TAuxialiarControlDeCota;



  private
    px: TFichaHidroConEmbalse_auxRec;

    // Lista auxiliar del control de cota.
    lstAuxiliaresControlDeCota: TList;
    // Se llama en AfterRead, crea la lista auxiliar para control de cota
    // y la ordena por orden creciente de cota.
    procedure Crear_lstAuxiliaresControlDecota;
    procedure Destruir_lstAuxiliaresControlDecota;


    procedure LoadBefore_13_AfterRead(f: TArchiTexto; var Vmax, Vhmed: NReal);
    procedure LoadBefore_13_Rec(var res: TCosa_RecLnk; var Vmax, Vhmed: NReal);
    procedure LoadBefore_14_AfterRead(f: TArchiTexto; var Vmax, Vhmed: NReal);
    procedure LoadBefore_14_Rec(var res: TCosa_RecLnk; var Vmax, Vhmed: NReal);
    procedure LoadBefore_17_AfterRead(f: TArchiTexto; var Vmax, Vhmed: NReal);
    procedure LoadBefore_17_Rec(var res: TCosa_RecLnk; var Vmax, Vhmed: NReal);
    procedure LoadBefore_26_AfterRead(f: TArchiTexto; var Vmax, Vhmed: NReal);
    procedure LoadBefore_26_Rec(var res: TCosa_RecLnk; var Vmax, Vhmed: NReal);
    procedure LoadBefore_28_AfterRead(f: TArchiTexto;
      var Vmax, Vhmed, vdummy: NReal);
    procedure LoadBefore_28_Rec(var res: TCosa_RecLnk;
      var Vmax, Vhmed, vdummy: NReal);

  end;

  { THidroConEmbalse }

  THidroConEmbalse = class(TGeneradorHidraulico)
  public

    //Variables de Estado
    NDisc: integer; // discretizacion del estado
    hini, hiniError: NReal; // cota inicial
    aplicarErrorOpt, aplicarErrorSim: boolean;
    fuenteDeAportes: TFuenteAleatoria;
    nombreBorne: string;
    // Si es TRUE, la fuente suministra el escurrimiento en mm/mes
    // y para calcular el caudal hay que multiplicar por el área
    // y dividir por los segundos del mes.  (mm/mes) /1000 * Area[há]*100*100 /(730*3600)
    // si es false, la fuente
    // suministra el caudal medio en m3/s.
    flg_FuenteDeEscurrimientos: boolean;
    flg_ValorizadoManual: boolean;

    pa: TFichaHidroConEmbalse;

    numeroBorne: integer;

    //Variables de control
    QErogado_falla: TDAofNReal;
    // ERogado ficticio para cuantificar costo de no erogar lo minimo requerido

    //----------- variables auxiliares
    // Calcular con cambioFicha.
    polinomioCotaVolumen: TPoliR;
    polinomioCotaMaxAporte: TPoliR;
    {$IFNDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
    polinomioErogadoMinVol: TPoliR;
    {$ENDIF}

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

    // Factor Escurrimiento To Caudal
    fEscurrimientoToCaudal: NReal;

    V_ControlCrecida_Inicio: NReal; // [Hm3] al que se inicia el control de crecida
    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

    AplicarRestriccionDeErogadoMinimo: boolean;

    h_actual: NReal; // cota actual. Es la de toma.
    h_real: NReal;   //cota actual sin considerar la fuenteCota
    dh_err: NReal;

    // variables auxiliares para iterar sobre la cota para cálculo del coeficiente energético
    apri_a, apri_b: NReal;
    apri_z1, apri_z2, apri_s, apri_delta_v, apri_z_aster: 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 Embalsado al inicio del paso
    Xs_VolumenEmbalsado: NReal; // Volumen Embalsado al final del paso

    PmaxParaQmax: NReal; // Pontecia máxima por máquina considerando Qmax y la cota
    NMaquinasDisponibles: integer;

    cv_agua_PenalidadPorRiesgoDePresa_USD_Hm3: NReal;
    // penalidad por exceder la cota máxima de operación.

    Pmax_Central: NReal; // [MW] Potencia Máxima disponible en la central
    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
    P_Central_CotaSup: TDAOfNReal;


    PuedoGenerar: boolean;
    // indica si la Central está en condiciones de ofrecer potencia o no
    cv_USD_MWh: NReal; // costo variable de generación
    cv_agua_USD_Hm3_Dec: NReal; // valor del Agua expresado en USD/MWh
    Dual_RestriccionDinamica_USDxHm3: NReal; // Debiera ser muy parecida al cv_agua

    Qevap: NReal; // caudal perdido por evaporacion
    Qfilt: NReal; // caudal perdido por filtración
    Qfilt_Ero:NReal; //caudal del filtrado que se eroga
    VPerdidas: NReal; //( QEvap+(1-Porc_Filtrado)*QFilt )* dt

    // variables auxiliares para las funciones cota-volumen y su inversa
    EsConico: boolean;
    embalse_cb, embalse_ca: NReal;
    embalse_c1, embalse_c2, embalse_c3_: NReal;
    embalse_c4_, embalse_c5_: NReal;

    flg_ModificandoQEmaxParaEstabilidad: boolean;
    flg_RecortandoAportesParaEstabilidad: boolean;


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


{$IFDEF RDIN}
    //Posición de la variable Xs_VolumenEmbalsado
    ivarDin: integer;
{$ENDIF}

    Vs_SinErogado: NReal;
    hs_SinErogado: NReal;//JFP 9/10/15: Cota proyectada sin erogado.

    // varialbes auxiliares de prepararPaso_ps
    V_ErogadoMinimo_Ctrl_Crecida: NReal;
    Q_ErogadoMinimo_Ctrl_Crecida: NReal;
    V_sobre_nivel_de_riesgo: 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;

    {$IFDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
    Delta_V_Embalsado_Proteccion: NReal;
    r_QE_Proteccion: NReal;
    {$ENDIF}


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

    // Guarda inicio de restricciones de erogado mínimo
    jres_QErogadoMin: integer;

    constructor Create(capa: integer; nombre: string; nacimiento, muerte: TFecha;
      lpdUnidades, lpd: TFichasLPD; nodo: TNodo; hIni, hIniError: NReal;
      aplicarErrorOpt, aplicarErrorSim: boolean; NDisc_: integer;
      fuenteDeAportes: TFuenteAleatoria; nombreBorne: string;
      flg_FuenteDeEscurrimientos: boolean; flg_ValorizadoManual: boolean;
      flg_CalcularGradienteDeInversion: boolean; TonCO2xMWh: NReal;
      LowCostMustRun, CleanDevelopmentMechanism: boolean;
      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;
    //JFP 20/10/2015: Devuelve el erogado mínimo en m3/s en función del volúmen por encima del volúmen
    //de inicio del control de crecida
    function ErogadoMinimo_Ctrl_Crecida(Vol_ini: NReal): NReal;

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

    //      procedure Sim_Inicio; override;
    procedure Sim_Cronica_Inicio; override;

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

    // Procedimiento auxiliar usado en PrepararPaso_ps
    procedure calcularDerivadas_SegunEstadoActual(
      var cv_agua_USD_Hm3_Inc, cv_agua_USD_Hm3_Dec: NReal);
    {$IFDEF ENGANCHE_CE}
    function Ce_Enganche (Vol: Nreal): Nreal;
    {$ENDIF}

    function ivarVertimientosMiosYAguasAbajo: TDAofNInt;

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

    procedure EvolucionarEstado; override;


    procedure ResolverEncadenamientos(s: TSimplex); override;
    procedure opt_fijarRestriccionesDeCaja(s: TSimplex); override;
    procedure opt_leerSolucion(s: TSimplex); override;
    {$IFDEF INTERMEDIARIO_DE_COSTO_FUTURO}
    procedure registrarVarYResEnIntermediario(intermediario:TIntermediarioCostoFuturo);override;
    {$ENDIF}


    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 CotaToVolumen(h: NReal): NReal;
    function VolumenToCota(Vol: NReal): NReal;

    //Volúmen mínimo a erogar según aportes y cota de toma actual (hm3)
    function VTminPorCurvaAportes(Aportes, cota_actual: NReal): NReal;

    // derivada dV/dh  [Hm3/m]
    function dVoldCota(h: NReal): NReal;

    // Determina los APortes propios y el Volumen al final del paso si no hay
    // erogado y solo hay aportes propios.
    procedure CalcularAportesPropiosYVolumenFinalSinErogado;

    // resultado m2
    function CotaToSuperficie_(h: 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 dump_Variables(var f: TextFile; charIndentacion: char); override;
    procedure sim_FinCronicaPrintEstadoFinal(var fsal: textfile); override;

    function vertimientoPorPoste: boolean; override;

    function get_pa_FD(kTipoUnidad: integer): NReal; override;
    function get_pa_TMR(kTipoUnidad: integer): NReal; override;

    {$IFDEF ENGANCHE_CE}
    procedure AgregarDefinicionesEvaluador (eval:TEvaluadorExpresionesSimples);override;
    {$ENDIF}

    private
      dummy_flg_nubeseable: boolean;

  end;

procedure THidroConEmbalse_cambioFichaPD(Actor: TCosa);

procedure AlInicio;
procedure AlFinal;

implementation

uses uActores;


{$IFDEF LOG_APORTES_OPT}
var
  flogAportesOpt: textfile;
{$ENDIF}

{ TauxialiarControlDeCota }

constructor TAuxialiarControlDeCota.Create(cota, cva: NReal);
begin
    self.cota := cota;
    self.cva_ := cva;
end;

function TAuxialiarControlDeCota.cva(indice: TFuenteAleatoria; nborne: integer
  ): NReal;
begin
  if indice = nil then
    result:= cva_
  else
    result:= cva_ * indice.Bornera[nborne];
end;


{$IFDEF DBG_HIDRO_CON_EMBALSE}
var
  flog: textfile;
  flg_flog_open: boolean;

{$ENDIF}

constructor THidroConEmbalse.Create(capa: integer; nombre: string; nacimiento,
  muerte: TFecha; lpdUnidades, lpd: TFichasLPD; nodo: TNodo; hIni,
  hIniError: NReal; aplicarErrorOpt, aplicarErrorSim: boolean; NDisc_: integer;
  fuenteDeAportes: TFuenteAleatoria; nombreBorne: string;
  flg_FuenteDeEscurrimientos: boolean; flg_ValorizadoManual: boolean;
  flg_CalcularGradienteDeInversion: boolean; TonCO2xMWh: NReal; LowCostMustRun,
  CleanDevelopmentMechanism: boolean; xFuenteIdxP: TFuenteAleatoria;
  xBorneIdxP: string);
begin
  inherited Create(capa, nombre, nacimiento, muerte, lpdUnidades, nodo,
    TonCO2xMWh, LowCostMustRun, CleanDevelopmentMechanism,
    flg_CalcularGradienteDeInversion, xFuenteIdxP, xBorneIdxP );
  flg_ModificandoQEmaxParaEstabilidad := False;
  flg_RecortandoAportesParaEstabilidad := False;

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

  self.hiniError := hIniError;
  self.aplicarErrorOpt := aplicarErrorOpt;
  self.aplicarErrorSim := aplicarErrorSim;

  self.NDisc := NDisc_;
  self.fuenteDeAportes := fuenteDeAportes;
  self.nombreBorne := nombreBorne;
  self.flg_FuenteDeEscurrimientos := flg_FuenteDeEscurrimientos;
  self.flg_ValorizadoManual := flg_ValorizadoManual;
end;

function THidroConEmbalse.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef('hIni', hIni);
  Result.addCampoDef('hIniError', hiniError, 133);
  Result.addCampoDef('aplicarErrorOpt', aplicarErrorOpt, 133);
  Result.addCampoDef('aplicarErrorSim', aplicarErrorSim, 133);
  Result.addCampoDef('NDisc', NDisc);
  Result.addCampoDef('lpd', TCosa(lpd));
  Result.addCampoDef_ref('fuenteDeAportes', TCosa(fuenteDeAportes), Self);
  Result.addCampoDef('nombreBorne', nombreBorne);
  Result.addCampoDef('flg_FuenteDeEscurrimientos', flg_FuenteDeEscurrimientos, 104);
  Result.addCampoDef('flg_ValorizadoManual', flg_ValorizadoManual);
  Result.addCampoDef('flg_nubeseable', dummy_flg_nubeseable, 167, 169 );
end;

procedure THidroConEmbalse.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  flg_FuenteDeEscurrimientos := False;

  if Version < 133 then
  begin
    Self.hiniError := 0.0;
    self.aplicarErrorOpt := False;
    self.aplicarErrorSim := False;
  end;
end;

procedure THidroConEmbalse.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);
  flg_ModificandoQEmaxParaEstabilidad := False;
  flg_RecortandoAportesParaEstabilidad := False;
  pa := nil;
  nodo := nil;
  lpd.Propietario := self;
end;


procedure THidroConEmbalse.PrepararMemoria(Catalogo: TCatalogoReferencias;
  globs: TGlobs);
begin
  inherited prepararMemoria(Catalogo, globs);
  setlength(P_Central_CotaSup, globs.NPostes);
  dh_RedQE := 0;
  VMinMin_1h3porSem := 1 / 168 * globs.HorasDelPaso;    // 1Hm3 / semana
  polinomioCotaVolumen := TPoliR.Create_Init(2);
  polinomioCotaMaxAporte := TPoliR.Create_Init(2);
  {$IFNDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
  polinomioErogadoMinVol := TPoliR.Create_Init(2);
  {$ENDIF}

  numeroBorne := fuenteDeAportes.idBorne(nombreBorne);


  setlength(QErogado_falla, globs.NPostes);

  {$IFDEF DBG_HIDRO_CON_EMBALSE}
  if not flg_flog_open then
  begin
    assignfile(flog, 'hidroemblog_' + globs.EscenarioActivo.nombre + '.xlt');
    rewrite(flog);
    writeln(flog, 'kEstrella'#9' kPaso'#9'X_Vol'#9'Xs_Vol'#9'QTurb'#9'cvaUSD/MWh');
    flg_flog_open := True;
  end;
  {$ENDIF}

end;

procedure THidroConEmbalse.RegistrarParametrosDinamicos(
  CatalogoReferencias: TCatalogoReferencias);
var
  i: integer;
  ficha: TFichaHidroConEmbalse;
begin
  inherited registrarParametrosDinamicos(CatalogoReferencias);
  lpd.expandirFichas(CatalogoReferencias, globs);
  lpd.RegistrarFichasAActualizar(Self, globs.ActualizadorLPD, @pA, nil,
    THidroConEmbalse_cambioFichaPD);
  for i := 0 to lpd.Count - 1 do
  begin
    ficha := TFichaHidroConEmbalse(lpd[i]);
    if ficha.fuenteCota <> nil then
      ficha.numeroBorneCota := ficha.fuenteCota.IdBorne(ficha.borneCota);
    if ficha.indiceAjusteControlDeCota <> nil then
      ficha.numeroBorneAjusteControlDeCota:= ficha.indiceAjusteControlDeCota.IdBorne( ficha.borneAjusteControlDeCota );
  end;
end;

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

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

class function THidroConEmbalse.DescClase: string;
begin
  Result := rsHidroelectricaEmbalse;
end;

procedure THidroConEmbalse.SorteosDelPaso(sortear: boolean);
begin
  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) and aplicarErrorOpt then
    dh_err := (SorteadorUniforme.rnd - 0.5) * 2 * hiniError
  else
    dh_err := 0;

  if hayForzamientos or 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
    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;
end;


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

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

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

{$IFDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
function THidroConEmbalse.ErogadoMinimo_Ctrl_Crecida(Vol_ini: NReal): NReal;
begin
  Result := V_sobre_nivel_de_riesgo * r_QE_Proteccion;
end;

{$ELSE}
{$IFDEF ErogadoMinimo_FELIPE_OCT2016}
function THidroConEmbalse.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;

{$ELSE}
function THidroConEmbalse.ErogadoMinimo_Ctrl_Crecida(Vol_ini: NReal): NReal;
var
  a, b, c, V, k, x1, x2: NReal;//coeficientes polinomio
  k1, c1: NReal;//cte. para solución de ec. diferencial

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;

  //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);
      //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
    //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 := (Vol_ini - V) * 1e6 / globs.SegundosDelPaso;

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

{$ENDIF}
{$ENDIF}
procedure THidroConEmbalse.opt_PrintResultados_Encab(var fsal: textfile);
begin
  Write(fsal, #9, {globs.cf.ordinalEstrellaActual}FloatToStrF(
    VolumenToCota(X_VolumenEmbalsado), ffgeneral, 6, 3));
end;

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

procedure THidroConEmbalse.dump_Variables(var f: TextFile; charIndentacion: char);
begin
  inherited dump_Variables(f, charIndentacion);
  writeln(f, charIndentacion, 'h_actual[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, 'VolumenAlmacenado[hm^3]= ',
    FloatToStrF(Xs_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, '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 THidroConEmbalse.sim_FinCronicaPrintEstadoFinal(var fsal: textfile);
begin
  writeln(fsal, Nombre + '.h_Real = ' + FloatToStr(self.h_real));
end;

procedure THidroConEmbalse.EvolucionarEstado;
begin
  X_VolumenEmbalsado := Xs_VolumenEmbalsado;
  h_actual := VolumenToCota(X_VolumenEmbalsado);
end;


function CompareCotas_ControlDeCota(Item1, Item2: TauxialiarControlDeCota): integer;
var
  a1, a2: TauxialiarControlDeCota;
begin
  a1 := Item1;
  a2 := Item2;
  if a1.Cota > a2.Cota then
    Result := 1
  else if a1.Cota = a2.Cota then
    Result := 0
  else
    Result := -1;
end;


procedure THidroConEmbalse.calcularDerivadas_SegunEstadoActual(
  var cv_agua_USD_Hm3_Inc, cv_agua_USD_Hm3_Dec: NReal);
var
  dCFdV_Inc, dCFdV_Dec: NReal;
  resCode: integer;
  aux: NReal;
  {$IFNDEF XVE_Volumen}
  dhdv: NReal;
  {$ENDIF}
  cv_agua_USD_Hm3_Dec_aux,cv_agua_USD_Hm3_Inc_aux: NReal;

  ControlDeCotaRec: TAuxialiarControlDeCota;
  cvaControlDeCota: NReal;

begin
  // calculamos el valor del agua en USD/MWh
  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;
  end
  else
  begin
{$IFDEF DERIV_20}
    if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
      globs.CF.devxr_estrella_20(ixr, globs.kPaso_Opt + 1, dCFdV_Inc, dCFdV_Dec)
    else
      globs.CF.devxr_continuo_20(ixr, globs.kPaso_Opt + 1, dCFdV_Inc, dCFdV_Dec);
{$ELSE}
    if globs.EstadoDeLaSala = CES_OPTIMIZANDO then
    begin
{$IFDEF OPT_DERIV_CONTINUA}
      globs.CF.devxr_continuo(ixr, globs.kPaso_Opt + 1, dCFdV_Inc, dCFdV_Dec, resCode, aux);
{$ELSE}
      globs.CF.devxr_estrella(ixr, globs.kPaso_Opt + 1, dCFdV_Inc, dCFdV_Dec, resCode);
{$ENDIF}
    end
    else
    begin
      globs.CF.devxr_continuo(ixr, globs.kPaso_Opt + 1, dCFdV_Inc,
        dCFdV_Dec, resCode, aux);
    end;
{$ENDIF}

    cv_agua_USD_Hm3_Inc := -dCFdV_Inc * globs.fActPaso;
    cv_agua_USD_Hm3_Dec := -dCFdV_Dec * globs.fActPaso;

{$IFNDEF XVE_Volumen}
    dhdV := 1 / dVoldCota(self.h_actual);
    cv_agua_USD_Hm3_Inc := cv_agua_USD_Hm3_Inc * dhdV;
    cv_agua_USD_Hm3_Dec := cv_agua_USD_Hm3_Dec * dhdV;
{$ENDIF}
  end;


{$IFDEF HIDRO_DERIVADA_MONOTONA}
  if cv_agua_USD_Hm3_Dec < cv_agua_USD_Hm3_Inc then
    vswap(cv_agua_USD_Hm3_Inc, cv_agua_USD_Hm3_Dec);
{$ENDIF}

{$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}

{$IFDEF HIDRO_DERIVADA_MAX}
  cv_agua_USD_Hm3_Dec := max(cv_agua_USD_Hm3_Dec, cv_agua_USD_Hm3_Inc);
  cv_agua_USD_Hm3_Inc := cv_agua_USD_Hm3_Dec;
{$ENDIF}


 cv_agua_USD_Hm3_Dec_aux := cv_agua_USD_Hm3_Dec ;
 cv_agua_USD_Hm3_Inc_aux := cv_agua_USD_Hm3_Inc;

  if ((
  (globs.EstadoDeLaSala = CES_OPTIMIZANDO) and pa.flg_controlCotaObjetivoInferior_opt) or
    ((globs.EstadoDeLaSala = CES_SIMULANDO) and
    pa.flg_controlCotaObjetivoInferior_sim)) then
    begin
       ControlDeCotaRec:= pa.getControlDeCotaAplicable_inf( h_actual );
       if ControlDeCotaRec <> nil then
        begin
          cvaControlDeCota:= ControlDeCotaRec.cva( pa.indiceAjusteControlDeCota, pa.numeroBorneAjusteControlDeCota );
          if not pa.flg_ValorAguaExacto_hObjetivo then
          begin
            cv_agua_USD_Hm3_Dec_aux := cv_agua_USD_Hm3_Dec + cvaControlDeCota;
            cv_agua_USD_Hm3_Inc_aux := cv_agua_USD_Hm3_Inc + cvaControlDeCota;
          end
          else
          begin
            if pa.flg_ControlCondicional then
            begin
              cv_agua_USD_Hm3_Dec_aux := max( cv_agua_USD_Hm3_Dec, cvaControlDeCota );
              cv_agua_USD_Hm3_Inc_aux := max( cv_agua_USD_Hm3_Inc, cvaControlDeCota );
            end
            else
            begin
              cv_agua_USD_Hm3_Dec_aux := cvaControlDeCota;
              cv_agua_USD_Hm3_Inc_aux := cvaControlDeCota;
            end;
          end;
        end;
      cv_agua_USD_Hm3_Dec := cv_agua_USD_Hm3_Dec_aux;
      cv_agua_USD_Hm3_Inc := cv_agua_USD_Hm3_Inc_aux;
      end;


  if (((globs.EstadoDeLaSala = CES_OPTIMIZANDO) and
    pa.flg_controlCotaObjetivoSuperior_opt) or
    ((globs.EstadoDeLaSala = CES_SIMULANDO) and
    pa.flg_controlCotaObjetivoSuperior_sim))  then
    begin
      ControlDeCotaRec:= pa.getControlDeCotaAplicable_sup( h_actual );

      if ControlDeCotaRec <> nil then
      begin
        cvaControlDeCota:= ControlDeCotaRec.cva( pa.indiceAjusteControlDeCota, pa.numeroBorneAjusteControlDeCota );
        if not pa.flg_ValorAguaExacto_hObjetivo then
        begin
          cv_agua_USD_Hm3_Dec_aux := cv_agua_USD_Hm3_Dec - cvaControlDeCota;
          cv_agua_USD_Hm3_Inc_aux := cv_agua_USD_Hm3_Inc - cvaControlDeCota;
        end
        else
        begin
          if pa.flg_ControlCondicional then
          begin
            cv_agua_USD_Hm3_Dec_aux := min( cv_agua_USD_Hm3_Dec,  cvaControlDeCota );
            cv_agua_USD_Hm3_Inc_aux := min( cv_agua_USD_Hm3_Inc, cvaControlDeCota );
          end
          else
          begin
            cv_agua_USD_Hm3_Dec_aux := cvaControlDeCota;
            cv_agua_USD_Hm3_Inc_aux := cvaControlDeCota;
          end;
         end;
        end;
      cv_agua_USD_Hm3_Dec := cv_agua_USD_Hm3_Dec_aux;
      cv_agua_USD_Hm3_Inc := cv_agua_USD_Hm3_Inc_aux;
    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}

end;


{$IFDEF ENGANCHE_CE}
function THidroConEmbalse.Ce_Enganche(Vol: Nreal): Nreal;
var
  dh_RedQE,Qmax,h_actual,salto_actual,ce_MAXTURB0:NReal;
  NMaquinasInstaladas:Integer;
begin
  h_actual:=VolumenToCota(Vol);
  NMaquinasInstaladas := paUnidades.nUnidades_Instaladas[0];
  Qmax := pA.Qmax_Turb;

  dh_RedQE := ReduccionDeCotaPorCaudalErogado(NMaquinasInstaladas * Qmax);
  salto_actual := max(0.1, h_actual - CotaDescarga - dh_RedQE);
  ce_MAXTURB0 := salto_actual * ro_g_ren;

  Result:=ce_MAXTURB0;

end;
{$ENDIF}
procedure THidroConEmbalse.PrepararPaso_ps;
var
  ce_MAXTURB: NReal;
  VMaxErogable_Central: NReal;
  QMax_Erogable: NReal;
  QMaxTurbinable_Central: NReal;
  //ffelipe: TextFile;
  //cotas:ARRAY [1..24] OF Double;
  //cota1:NReal;

  alfa, beta: NReal;
  k: integer;

  {$IFDEF USAR_APRI}
  apri_i1, apri_i2: NReal;
  {$ENDIF}
begin

  //cota1:=VolumenToCota(8002.238388);
  //AssignFile(ffelipe, 'ffelipe2.txt');
  //Rewrite(ffelipe);
  //WriteLn(ffelipe, 'cota'+#9+ 'Volumen');

  //cotas[1]:=40.1;
  //for k:=1 to 23 do
  //cotas[k+1]:=cotas[k]+0.1;

  //for k:=1 to 24 do
  //WriteLn(ffelipe, cotas[k],CotaToVolumen(cotas[k]));

  //CloseFile(ffelipe);


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

 {$IFNDEF HIDRO_PROYECTA_ESTADO}
  CalcularAportesPropiosYVolumenFinalSinErogado;
 {$ENDIF}


  if globs.cntIteracionesDelPaso = 1 then
  begin

    if globs.EstadoDeLaSala = CES_SIMULANDO then
      if not self.pa.tomarCotaDeLaFuente then
        h_real := h_actual
      else
        h_real := pa.fuenteCota.Bornera[pa.numeroBorneCota];
    // ELSE lo hace en PosicionarseEnEstrellita

    calcularDerivadas_SegunEstadoActual(
      cv_agua_USD_Hm3_Inc, cv_agua_USD_Hm3_Dec);

  end;

  alfa := 0.3;
  beta := 1 - alfa;

  QErogado_ := alfa * QErogado_IterAnterior + beta * QErogado_;
  QErogado_IterAnterior := QErogado_;


  {$IFDEF USAR_APRI}
  // en la primer pasada no hay nada que calcular.
  if (globs.cntIteracionesDelPaso > 1) and not self.pa.tomarCotaDeLaFuente then
  begin
    h_real := h_actual;

    apri_delta_v := (Xs_VolumenEmbalsado - X_VolumenEmbalsado) * 1.0e6;
    if abs(apri_delta_v) > 0.01 then
    begin
      apri_z1 := h_real - pa.hmin;
      apri_z2 := VolumenToCota(Xs_VolumenEmbalsado) - pa.hmin;
      apri_s := pa.hmin - CotaDescarga;
      if EsConico then
      begin
        apri_i2 := ((1 / 3.0 * apri_b * apri_z2 + (apri_a + apri_s * apri_b) / 2.0) *
          apri_z2 + apri_s * apri_a) * apri_z2;

        apri_i1 := ((1 / 3.0 * apri_b * apri_z1 + (apri_a + apri_s * apri_b) / 2.0) *
          apri_z1 + apri_s * apri_a) * apri_z1;

        apri_z_aster := (apri_i2 - apri_i1) / apri_delta_v;
      end
      else
        apri_z_aster := (((apri_a / 2.0) * apri_z2 + apri_s * apri_a) *
          apri_z2 - ((apri_a / 2.0) * apri_z1 + apri_s * apri_a) * apri_z1) /
          apri_delta_v;


      h_real := apri_z_aster + CotaDescarga;
    end;
  end;
  {$ENDIF}



  dh_RedQE := ReduccionDeCotaPorCaudalErogado(NMaquinasDisponibles * Qmax);
  salto_actual := max(0.1, h_real - CotaDescarga - dh_RedQE);
  ce_MAXTURB0 := salto_actual * ro_g_ren;

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

  dh_RedQE := ReduccionDeCotaPorCaudalErogado(QErogado_);
  salto_actual := max(0.1, h_real - CotaDescarga - dh_RedQE);


  {$IFDEF GLOBS_LOG}
  globs.log_Writeln_(Nombre + 'PreapararPaso_ps' + #9 + 'QErogado_:' +
    #9 + FloatToStr(QErogado_) + #9 + 'Salto_actual:' + #9 +
    floatToStr(salto_actual) + #9 + 'QMaxVert:' + #9 + FloatToStr(QMaxVert) +
    #9 + 'pa.QMV1:' + #9 + FloatToStr(pa.QMV1) + #9 + 'Vs_SinErogado:' +
    #9 + FloatToStr(Vs_SinErogado) + #9 + 'V_EmbalsadoInicioVertedero:' +
    #9 + FloatToStr(V_EmbalsadoInicioVertedero) + #9 + 'Delta_V_Embalsado_Vertedero:' +
    #9 + FloatToStr(Delta_V_Embalsado_Vertedero)
    );
  {$ENDIF}

  ce := salto_actual * ro_g_ren;
  ce_MAXTURB := min(ce_MAXTURB0, ce);
  auxParaCalculos_cv := 1 / (1.0E6 * ce);

  cv_USD_MWh := cv_agua_USD_Hm3_Dec * auxParaCalculos_cv;


  // en base al volumen sin erogado calcula el vertimiento posible



  (*** así estaba en al v_ADME_1.05b

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

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


  // en la v_ADME_1.05c cambio a control de vertido en base al Vs_SinErogado
  if max(0.1, VolumenToCota(Vs_SinErogado) - CotaDescarga) <
    pa.saltoMinimoOperativo then
    self.PuedoGenerar := False; // no puedo mover las turbinas

  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 * 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
    PuedoGenerar := False;



  if globs.cntIteracionesDelPaso = 1 then
  begin
    for k := 0 to globs.NPostes - 1 do
      P_Central_CotaSup[k] := Pmax_Central;
  end
  else
  begin
    Qmaxturbinable_Central := 0;
    for k := 0 to globs.NPostes - 1 do
    begin
      {$IFDEF LIMITE_QITER_OCT2016}
      P_Central_CotaSup[k] := min((P_Central_CotaSup[k] + P[k]) / 2.0, Pmax_Central);
      {$ELSE}
      P_Central_CotaSup[k] := (P_Central_CotaSup[k] + P[k]) / 2.0;
      {$ENDIF}
      Qmaxturbinable_Central :=
        Qmaxturbinable_Central + P_Central_CotaSup[k] * globs.DurPos[k];
    end;
    QMaxTurbinable_Central :=
      QMaxTurbinable_Central / (ce * globs.SegundosDelPaso);
  end;



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

  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 := QTmin_CalcVTminsobreHorasDelPaso > 0.01;
  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
    {$IFDEF ErogadoMinimo_FELIPE_OCT2016}
    Q_ErogadoMinimo_Ctrl_Crecida := ErogadoMinimo_Ctrl_Crecida(X_VolumenEmbalsado);
    {$ELSE}
    Q_ErogadoMinimo_Ctrl_Crecida := ErogadoMinimo_Ctrl_Crecida(Vs_SinErogado);
    {$ENDIF}
    // 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;
end;

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

  ivar:= ivar + globs.NPostes; // PGen por poste

   // Vertimientos
   if pa.ImponerQminPorPoste then
      ivar := ivar +  globs.NPostes
   else
      ivar := ivar + 1;

   // Variable de falla en el ergoado minimo
  if pa.flg_ErogadoMin_Falla then
   if pa.ImponerQminPorPoste then
      ivar := ivar +  globs.NPostes
   else
      ivar := ivar + 1;

  {$IFDEF RDIN}
  ivarDin := ivar;
  Inc(ivar);
  {$ENDIF}

  self.ires := ires; // 0 <= volumen_s   o X_s = f(X, u, r )
  Inc(ires);

  if (PuedoGenerar) and pA.HayRestriccionEmaxPasoDeTiempo then
    Inc(ires);
  //Erogado minimo
  if AplicarRestriccionDeErogadoMinimo then
    if pa.ImponerQminPorPoste then
      Inc(ires, globs.NPostes)
    else
      Inc(ires);

  //Erogado minimo con posibilidad de falla
  if pa.flg_ErogadoMin_Falla then
    if pa.ImponerQminPorPoste then
      Inc(ires, globs.NPostes)
    else
      Inc(ires);

end;

procedure THidroConEmbalse.opt_cargue(s: TSimplex);
var
  ibaseres: integer;
  iposte: integer;
  jres: integer;
  invCEPorUnoESeis: NReal;
begin

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

  // **********************************
  // aporte a las restricciones de nodo como generador.
  ibaseres := nodo.ires;
  for iposte := 0 to globs.NPostes - 1 do
    s.pon_e(ibaseres + iposte, ivar + iposte, 1);
  // fin aporte a restricción de nodo
  //********************************


  // cargamos ivert con el índice en de columna donde empiezan los vertimientos
  ivert := ivar + globs.NPostes;

  // *****************************
  // Ahora agregamos a la función de UTILIDAD (-costo)
  {$IFDEF RDIN}
  // -costo = -( Xs - X ) * dCF/dX  = (Xs + -X)* cv_Dec
  {$IFNDEF INTERMEDIARIO_DE_COSTO_FUTURO}
  s.pon_e(s.nf, ivarDin, cv_agua_USD_Hm3_Dec);
  s.acum_e(s.nf, s.nc, -cv_agua_USD_Hm3_Dec * Vs_SinErogado);
  {$ENDIF}
  {$ELSE}
  // afectación del futuro por los turbinados
  for iposte := 0 to globs.NPostes - 1 do
    s.pon_e(s.nf, ivar + iposte, -cv_USD_MWh * globs.durpos[iposte]);

  // afectación del futuro por los vertimientos
  if pa.ImponerQminPorPoste then
    for iposte := 0 to globs.NPostes - 1 do
      s.pon_e(s.nf, ivert + iposte, -cv_agua_USD_Hm3_Dec)
  else
    s.pon_e(s.nf, ivert, -cv_agua_USD_Hm3_Dec);

  // afectación del futuro por aportes - pérdidas (constantes del paso)
  s.acum_e(s.nf, s.nc, (cv_agua_USD_Hm3_Inc * VAportePropio -
    cv_agua_USD_Hm3_Dec * VPerdidas)); // Aporte
  {$ENDIF}
  // afectación del futuro por erogado de falla
  if pa.flg_ErogadoMin_Falla then
    if pa.ImponerQminPorPoste then
      for iposte := 0 to globs.NPostes - 1 do
        s.pon_e(s.nf, ivert + globs.NPostes + iposte, -pa.cv_USD_hm3_falla_ErogadoMin)
    else
      s.pon_e(s.nf, ivert + 1, -pa.cv_USD_hm3_falla_ErogadoMin);


  // fin de carga en la función de utilidad
  // *************************************++


  // *****************************************************
  // Ecuación de balance Vk+1 - V_hmin = Vk - V_hmin - Turbinados - Vertidos + Aportes >= 0
  jres := ires;

  // los turbinados
  // 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

  {$IFDEF RDIN}
  // término - X_Vs
  s.pon_e(jres, ivarDin, -1);

  // términos constantes
  s.pon_e(jres, s.nc, Vs_SinErogado);
  {$ELSE}
  // términos constantes
  s.pon_e(jres, s.nc, Vs_SinErogado - V_hmin);
  {$ENDIF}


  // fin de la ecuación de balance de volúmens
  //***********************************************************

  // 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
  // y Seguridad de la presa.
  if AplicarRestriccionDeErogadoMinimo then
  begin
    Inc(jres);
    jres_QErogadoMin := 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;
      Dec(jres);
    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;


  // Restricción de caudal erogado mínimo con posibilidad de falla
  if pa.flg_ErogadoMin_Falla 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, ivert + globs.NPostes + iposte, 1);  // Erogado falla
        s.pon_e(jres, s.nc, -pa.QErogadoMin_Falla * 3600 / 1e6 * 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, ivert + 1, 1);  // Erogado Falla
      s.pon_e(jres, s.nc, -pa.QErogadoMin_Falla / 1e6 * globs.SegundosDelPaso);
    end;
  end;

end;


function THidroConEmbalse.vertimientoPorPoste: boolean;
begin
  Result := pa.ImponerQminPorPoste;
end;




procedure THidroConEmbalse.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
      {$IFDEF RDIN}
      0, // la restricción dinámica calcula todas las afectaciones de costos
      {$ELSE}
      self.cv_agua_USD_Hm3_Inc,
      {$ENDIF}
      // valor del agua a considerar en la central aguas abajo.
      s);
  end;
end;

procedure THidroConEmbalse.opt_fijarRestriccionesDeCaja(s: TSimplex);
var
  iposte: integer;
  qmax_Hm3PorHora: double;
begin
  {$IFDEF RDIN}
  s.FijarRestriccionIgualdad(ires);
  {$ENDIF}

  // Le fijamos como cota máxima PMax a la potencia en todos los postes
  if PuedoGenerar then
  begin
    if globs.cntIteracionesDelPaso > 1 then
    begin
      if (not hayForzamientos) then
      begin
        for iposte := 0 to globs.NPostes - 1 do
          s.cota_sup_set(ivar + iposte, P_Central_CotaSup[iposte]);
      end
      else
      begin
        for iposte := 0 to globs.NPostes - 1 do
        begin
          if paForzamiento.flg_fijarP then
             s.FijarVariable(ivar + iposte, paForzamiento.P[0])
          else if paForzamiento.activar_Pmax then
               s.cota_sup_set(ivar + iposte, paForzamiento.P_max)
           else if paForzamiento.activar_Pmin then
                s.cota_inf_set(ivar + iposte, paForzamiento.P_max)
        end;
      end;
    end
    else

    if (not hayForzamientos) then
    begin
      for iposte := 0 to globs.NPostes - 1 do
        s.cota_sup_set(ivar + iposte, PMax_Central);
    end
    else
    begin
      for iposte := 0 to globs.NPostes - 1 do
      begin
        if paForzamiento.flg_fijarP then
           s.FijarVariable(ivar + iposte, paForzamiento.P[0])
        else if paForzamiento.activar_Pmax then
             s.cota_sup_set(ivar + iposte, paForzamiento.P_max)
         else if paForzamiento.activar_Pmin then
              s.cota_inf_set(ivar + iposte, paForzamiento.P_max)
      end;
    end;
  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
      // atención 11/2/2010 le pongo *10 a la cota sup para que desborde si precisa.
      s.cota_sup_set(ivert + iposte, qmax_Hm3PorHora * globs.DurPos[iposte]);
  end
  else
    s.cota_sup_set(ivert, QMaxVert * globs.SegundosDelPaso / 1.0E6);

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

  {$IFDEF RDIN}
  s.cota_inf_set(ivarDin, V_hmin);
  s.cota_sup_set(ivarDin, 10 * V_hmax  ); // Solo por ponerle algún límite.
  {$ENDIF}

  if QMaxVert = 0 then
  begin
    if pa.ImponerQminPorPoste then
      for iposte := 0 to globs.NPostes - 1 do
        s.FijarVariable(ivert + iposte, 0)
    else
      s.FijarVariable(ivert, 0);
  end;
end;

procedure THidroConEmbalse.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;

  h_actual := self.hini;

  if not self.pa.tomarCotaDeLaFuente then
    h_real := h_actual
  else
    h_real := pa.fuenteCota.Bornera[pa.numeroBorneCota];

  if self.aplicarErrorSim then
    h_actual := h_actual + ((self.SorteadorUniforme.rnd - 0.5) * 2) * self.hiniError;

  X_VolumenEmbalsado := CotaToVolumen(h_actual);
  // para que se copie al inicio del paso a X_VolumenEmbalsadoç
  Xs_VolumenEmbalsado := X_VolumenEmbalsado;

  {$IFDEF GLOBS_LOG}
  globs.log_Writeln_(Nombre + '.Sim_Cronica_INicio' + #9 + 'h_actual:' +
    #9 + FloatToStr(h_actual) + #9 + 'hINi:' + #9 + floatToStr(hini));
  {$ENDIF}

end;


procedure THidroConEmbalse.opt_leerSolucion(s: TSimplex);
var
  iposte: integer;
  //  Delta_volumen: NReal;
  Costo_Volumen_No_Erogado, VErogado_falla: NReal;
begin



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

  CostoDirectoDelPaso := 0;

  Costo_Volumen_No_Erogado := 0;

  if pa.flg_ErogadoMin_Falla then
    if pa.ImponerQminPorPoste then
      for iposte := 0 to globs.NPostes - 1 do
      begin
        VErogado_falla := s.xval(ivert + globs.NPostes + iposte);
        QErogado_falla[iposte] := VErogado_falla * 1e6 / (globs.DurPos[iposte] * 3600);
        Costo_Volumen_No_Erogado :=
          Costo_Volumen_No_Erogado + VErogado_falla * pa.cv_USD_hm3_falla_ErogadoMin;
      end
    else
    begin
      VErogado_falla := s.xval(ivert + 1);
      for iposte := 0 to globs.NPostes - 1 do
        QErogado_falla[iposte] := VErogado_falla * 1e6 / globs.SegundosDelPaso;
      Costo_Volumen_No_Erogado := VErogado_falla * pa.cv_USD_hm3_falla_ErogadoMin;
    end;

  CostoDirectoDelPaso := CostoDirectoDelPaso + Costo_Volumen_No_Erogado;

  if PuedoGenerar then
  begin
    // recuperamos los valores de Potencia despachada
    EnergiaGenerada := 0;
    for iposte := 0 to globs.NPostes - 1 do
    begin
      P[iposte] := s.xval(ivar + iposte);
      if not pa.flg_Aplica_cv_Spot_Acordado then
      begin
        Lambda_P[iPoste ]:= s.xmult( ivar + iposte ) / globs.durpos[iposte];
        cv_Spot[iPoste]:= Nodo.cmarg[iposte] - Lambda_P[iPoste ];
        // rch@201805120928 mmm no me arrepentí de esto ... en las centrales
        // encadenadas (Bonete) el valor del agua no representa el valor correcto.
        // cv_Spot[iPoste]:= max(0,min(Nodo.cmarg[iposte] - Lambda_P[iPoste ],cv_USD_MWh));// TODO arreglar esto
      end
      else
         if P[iposte]>=pa.P_forzada then
            cv_Spot[iPoste]:= pa.cv_Spot_acordado
         else
            cv_Spot[iPoste]:= 0;

      EnergiaGenerada := EnergiaGenerada + P[iposte] * globs.durpos[iposte];
    end;
    Ingreso_PorEnergia_ := EnergiaGenerada * pa.PagoPorEnergia_USD_MWh;
  end
  else
  begin
    vclear( P );
    for iposte := 0 to globs.NPostes - 1 do
    begin
      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;
    EnergiaGenerada := 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);

  if AplicarRestriccionDeErogadoMinimo then
  begin
    if pa.ImponerQminPorPoste then
    begin
      for iposte := 0 to globs.NPostes - 1 do
        Dual_QErogadoMin[iposte] := s.ymult(jres_QErogadoMin + iposte);
    end
    else
    begin
      Dual_QErogadoMin[0] := s.ymult(jres_QErogadoMin);
      for iposte := 1 to globs.NPostes - 1 do
        Dual_QErogadoMin[iposte] := Dual_QErogadoMin[0];
    end;
  end
  else
    vclear(Dual_QErogadoMin);

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


  {$IFDEF RDIN}
  Xs_VolumenEmbalsado := s.xval(ivarDin);
  Dual_RestriccionDinamica_USDxHm3 := -s.ymult(ires);
 {$ELSE}
  Xs_VolumenEmbalsado := s.yval(ires) + V_hmin;
 {$ENDIF}


  //  Delta_volumen := Xs_VolumenEmbalsado - X_VolumenEmbalsado;


(*** Agrego que durante la optimización contabilice la penalidad del control en el costo directo
del paso para que la política de operación tenga en consideración la penalidad.
    Tengase en cuenta que por hacer esto el CF(X,k) tiene sumada/restada la penalidad y por  tanto no
representa la suma de los costos directos. **
  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) and pa.flg_controlCotaObjetivoInferior_opt then
  begin
   if  (h_actual < pa.hObjetivo) then
 //      if Delta_volumen < 0 then
          CostoDirectoDelPaso := CostoDirectoDelPaso - Delta_volumen * pa.delta_cva_ParaControlDeCota
    end;

  if (globs.EstadoDeLaSala = CES_OPTIMIZANDO) and pa.flg_controlCotaObjetivoSuperior_opt then
  begin
   if  (h_actual > pa.hObjetivo) then
 //      if Delta_volumen > 0 then
          CostoDirectoDelPaso := CostoDirectoDelPaso + Delta_volumen *pa.delta_cva_ParaControlDeCota
         end;

   **)

  {$IFDEF DBG_HIDRO_CON_EMBALSE}
  if flg_flog_open then
    writeln(flog, globs.CF.ordinalEstrellaActual, #9, globs.kPaso_,
      #9, X_VolumenEmbalsado, #9, Xs_VolumenEmbalsado, #9, QTurbinado, #9, cv_USD_MWh);
  {$ENDIF}

end;

{$IFDEF INTERMEDIARIO_DE_COSTO_FUTURO}
procedure THidroConEmbalse.registrarVarYResEnIntermediario(
  intermediario: TIntermediarioCostoFuturo);
var
  ControlDeCotaRec: TAuxialiarControlDeCota;
  cvaControlDeCota: NReal;
  restriccion:TRestriccionGradiente;
begin
  inherited registrarVarYResEnIntermediario(intermediario);
  restriccion:=nil;


  // vemos si estamos controlando tanto en simulacion como en optimizacion por cota inferior
  if ((
  (globs.EstadoDeLaSala = CES_OPTIMIZANDO) and pa.flg_controlCotaObjetivoInferior_opt) or
    ((globs.EstadoDeLaSala = CES_SIMULANDO) and
    pa.flg_controlCotaObjetivoInferior_sim)) then
    begin
      ControlDeCotaRec:= pa.getControlDeCotaAplicable_inf( h_actual );
      if ControlDeCotaRec <> nil then
      begin
        cvaControlDeCota:= ControlDeCotaRec.cva( pa.indiceAjusteControlDeCota, pa.numeroBorneAjusteControlDeCota );
        if not pa.flg_ValorAguaExacto_hObjetivo then
          // aca se se le suma el control de cota
          restriccion:=TRestriccionGradiente.Create(SUMAR,-1*cvaControlDeCota) // ponemos menos porque el costo variable del agua es menos el gradiente
        else
          if pa.flg_ControlCondicional then
            // aca la variable tiene que ser mayor que el control de cota
            restriccion:=TRestriccionGradiente.Create(MENOR,-1*cvaControlDeCota) // lo mismo, menor y menos para que el costo del agua sea mayor que
          else
            // aca tiene que ser igual
            restriccion:=TRestriccionGradiente.Create(IGUAL,-1*cvaControlDeCota) // no hace falta seguir repitiendo
      end;
    end;

  // todo lo mismo pero con cota superior
  if (((globs.EstadoDeLaSala = CES_OPTIMIZANDO) and
    pa.flg_controlCotaObjetivoSuperior_opt) or
    ((globs.EstadoDeLaSala = CES_SIMULANDO) and
    pa.flg_controlCotaObjetivoSuperior_sim))  then
    begin
      ControlDeCotaRec:= pa.getControlDeCotaAplicable_sup( h_actual );
      if ControlDeCotaRec <> nil then
      begin
        cvaControlDeCota:= ControlDeCotaRec.cva( pa.indiceAjusteControlDeCota, pa.numeroBorneAjusteControlDeCota );
        if not pa.flg_ValorAguaExacto_hObjetivo then
          // aca se le resta
          restriccion:=TRestriccionGradiente.Create(SUMAR,cvaControlDeCota) // ponemos positivo porque el costo variable del agua es menos el gradiente, no voy a seguir repitiendo por que esta todo dado vuelta...
        else
          if pa.flg_ControlCondicional then
            // aca tiene que ser menor
            restriccion:=TRestriccionGradiente.Create(MENOR,-1*cvaControlDeCota) // lo mismo, menor y menos para que el costo del agua sea mayor que
          else
            // aca tiene que ser igual
          restriccion:=TRestriccionGradiente.Create(IGUAL,-1*cvaControlDeCota) // no hace falta seguir repitiendo
        end;
    end;

  intermediario.registrarVariableContinua( ixr, ivarDin, restriccion, nombre + '_Vol', // nombre de la variable
    'Hm3');

end;
{$ENDIF}

function THidroConEmbalse.opt_necesitoIterar(kIteracion: integer;
  var errRelativo: NReal): boolean;
var
  qm: NReal;
begin
  qm := max(QErogado_, QErogado_IterAnterior);
  if qm > 1 then
    errRelativo := abs(QErogado_ - QErogado_IterAnterior) / qm
  else
    errRelativo := 0;
  Result := errRelativo > 0.1;
end;



function THidroConEmbalse.getNombreVar(ivar: integer; var nombre: string): boolean;
var
  iaux: integer;
begin
  {$IFDEF RDIN}
  if ivar = ivarDin then
  begin
      nombre:= self.Nombre+'_Xs_VolumenEmbalsado[hm3]';
      result:= true;
      exit;
  end;
  {$ENDIF}

  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 if pa.flg_ErogadoMin_Falla and (iaux > globs.npostes) and (iaux <= 2 * globs.npostes) then
    begin
      nombre := self.Nombre + '_ErogadoFalla[Hm3]' + IntToStr(iaux - globs.npostes);
      Result := True;
    end
    else
     Result := False;
  end
  else
  begin
    if (ivar = ivert) then
    begin
      nombre := self.Nombre + '_Vertimiento[Hm3]';
      Result := True;
    end
    else if  pa.flg_ErogadoMin_Falla and  (ivar = ivert + 1) then
    begin
      nombre := self.Nombre + '_ErogadoFalla[Hm3]';
      Result := True;
    end
    else
     Result := False;
  end;
end;

function THidroConEmbalse.getNombreRes(ires: integer; var nombre: string): boolean;
var
  jres: integer;
  iposte: integer;
  ires_Vs_gt_0, ires_EMax, ires_QEMin_1: integer;
begin
  jres := self.ires;
  ires_Vs_gt_0 := jres;
  Inc(jres);

  if (PuedoGenerar and pa.HayRestriccionEmaxPasoDeTiempo) then
  begin
    ires_EMax := jres;
    Inc(jres);
  end
  else
    ires_Emax := -1;

  if self.AplicarRestriccionDeErogadoMinimo then
  begin
    ires_QEMin_1 := jres;
    Inc(jres);
  end
  else
    ires_QEMin_1 := -1;


  if (ires = ires_Vs_gt_0) then
  begin
   {$IFDEF RDIN}
   nombre := self.nombre + 'XV-Erog+Apo-XsV=0';
   {$ELSE}
    nombre := self.nombre + '_VOL>=0';
   {$ENDIF}
    Result := True;
    exit;
  end;


  if ires = ires_EMax then
  begin
    nombre := self.nombre + '_res-EMax';
    Result := True;
    exit;
  end;


  if self.AplicarRestriccionDeErogadoMinimo then
    if pa.ImponerQminPorPoste then
    begin
      iposte := (ires - ires_QEMin_1 + 1);
      if (iposte >= 0) and (iposte <= globs.NPostes) then
      begin
        nombre := self.nombre + '_res-QTMin_Poste' + IntToStr(iposte);
        Result := True;
        exit;
      end;
    end
    else
    begin
      if ires = ires_QEMin_1 then
      begin
        nombre := self.nombre + '_res-QTMin_Paso';
        Result := True;
        exit;
      end;
    end;

  Result := False;
end;

procedure THidroConEmbalse.PubliVars;
begin
  inherited PubliVars;
  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, 2, h_real, True);
  PublicarVariableNR('h', '[m]', 6, 2, h_actual, True);
  PublicarVariableNR('ce', '[MWh/m3]', 12, 6, ce, True);
  PublicarVariableNR('dh_RedQE', '[m]', 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);
  PublicarVariableVR('Dual_QErogadoMin', '[USD/hm3]', 6, 2, Dual_QErogadoMin,
    True, True);
  PublicarVariableNR('hs_SinErogado', '[m]', 6, 1, hs_SinErogado, True);
  PublicarVariableNR('Vs_SinErogado', '[Hm3]', 6, 1, Vs_SinErogado, True);
  {$IFDEF RDIN}
  PublicarVariableNR('Dual_RestriccionDinamica_USDxHm3', '[USD/Hm3]',
    6, 1, Dual_RestriccionDinamica_USDxHm3, True);
  {$ENDIF}
  PublicarVariableNR('CV_USD_MWh', '[USD/MWh]', 6, 1, cv_USD_MWh, True);
  PublicarVariableNR('Vertimiento', '[Hm^3]', 15, 1, VVertido, False);
  PublicarVariableNR('Cota', '[m]', 6, 1, h_actual, False);
  PublicarVariableNR('Vol', '[Hm^3]', 15, 1, self.X_VolumenEmbalsado, True);
  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);
  PublicarVariableVR('QErogadoFalla', '[m3/s]', 6, 2, QErogado_falla,
    True, True);
end;

function THidroConEmbalse.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 THidroConEmbalse.optx_nvxs(var ixr, ixd, iauxr, iauxd: integer);
begin
  if not flg_ValorizadoManual then
  begin
    self.ixr := ixr;
    ixr := ixr + 1;
  end;
  Self.iauxr := iauxr;
  iauxr := iauxr + 1;
end;

procedure THidroConEmbalse.PosicionarseEnEstrellita;
begin
  {$IFDEF XVE_Volumen}
  if not flg_ValorizadoManual then
    X_VolumenEmbalsado := globs.CF.xr[ixr];

  h_actual := VolumenToCota(X_VolumenEmbalsado);

  if self.aplicarErrorOpt then
  begin
    h_actual := h_actual + dh_err;
    X_VolumenEmbalsado := CotaToVolumen(h_actual);
  end;

  Xs_VolumenEmbalsado := X_VolumenEmbalsado; // es necesario

  {$ELSE}
  if not flg_ValorizadoManual then
    h_actual := globs.CF.xr[ixr];

  if self.aplicarErrorOpt then
    h_actual := h_actual + dh_err;

  X_VolumenEmbalsado := CotaToVolumen(h_actual);
  Xs_VolumenEmbalsado := X_VolumenEmbalsado; // es necesario
  {$ENDIF}

  QErogado_ := globs.Auxs_r0[iauxr][globs.CF.ordinalEstrellaActual];

  //Para que tenga el mismo estado de iteraciones al posicionarse en la estrella y
  //de igual en la optimización monohilo y multihilo
  QErogado_IterAnterior := QErogado_;


  if not self.pa.tomarCotaDeLaFuente then
    h_real := h_actual
  else
    h_real := pa.fuenteCota.Bornera[pa.numeroBorneCota];

end;

procedure THidroConEmbalse.CalcularAportesPropiosYVolumenFinalSinErogado;

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


  if flg_FuenteDeEscurrimientos then
    QAportePropio := QAportePropio * fEscurrimientoToCaudal;
    (*
      Assert(QAportePropio >= 0, 'El generador hidráulico con embalse ' +
        nombre + ' tiene caudal de aportes propios negativo. Fuente: ' +
        fuenteDeAportes.nombre + ', Borne: ' + nombreBorne + FloatToStr(QAportePropio));
      *)
  QAportePropio := max(0, QAportePropio);

  {$IFDEF LOG_APORTES_OPT}
  if ( nombre = 'SG' ) and ( globs.CF.ordinalEstrellaActual = 0 ) then
       writeln( flogAportesOpt, self.nombre, #9,  globs.kPaso_Opt, #9, globs.kCronica, #9, globs.cntIteracionesDelPaso, #9, globs.CF.ordinalEstrellaActual, #9, QAportePropio );
  {$ENDIF}

  if pa.flg_CalcularFiltracionDelLago then
  begin
    QFilt := pa.filtracion_Ca + pa.filtracion_Cb * (h_real - pa.hmin);
    QFilt_Ero := (1 - pa.PorcentajeFiltracion) * QFilt
  end
  else
    QFilt := 0.0;

  if pa.flg_CalcularEvaporacionDelLago then
    QEvap := CotaToSuperficie_(h_real) * 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);



    {$IFDEF GLOBS_LOG}
  globs.log_Writeln_(Nombre + 'CalcAportesYVsSinErogado' + #9 +
    'Vs_SinErogado:' + #9 + FloatToStr(Vs_SinErogado) + #9 +
    'X_VolumenEmbalsado:' + #9 + floatToStr(X_VolumenEmbalsado) + #9 +
    'VAportePropio:' + #9 + FloatToStr(VAportePropio) + #9 + 'VPerdidas:' +
    #9 + FloatToStr(VPerdidas) + #9 + 'V_hmin:' + #9 + FloatToStr(V_hmin)
    );
    {$ENDIF}

end;

procedure THidroConEmbalse.ActualizarEstadoGlobal(flg_Xs: boolean);
begin
  {$IFDEF HIDRO_PROYECTA_ESTADO}
  if flg_Xs then
  begin
    CalcularAportesPropiosYVolumenFinalSinErogado;
    if not self.flg_ValorizadoManual then
     {$IFDEF XVE_Volumen}
      globs.CF.xr[ixr] := Vs_SinErogado;
      {$ELSE}
    globs.CF.xr[ixr] := VolumenToCota(Vs_SinErogado);
      {$ENDIF}
  end
  else if not self.flg_ValorizadoManual then
  {$IFDEF XVE_Volumen}
    globs.CF.xr[ixr] := X_VolumenEmbalsado;
  {$ELSE}
  globs.CF.xr[ixr] := VolumenToCota(X_VolumenEmbalsado);
  {$ENDIF}
  {$ELSE}
  if self.flg_ValorizadoManual then
    exit;
  {$IFDEF XVE_Volumen}
  globs.CF.xr[ixr] := X_VolumenEmbalsado;
  {$ELSE}
  globs.CF.xr[ixr] := VolumenToCota(X_VolumenEmbalsado);
  {$ENDIF}
  {$ENDIF}
end;


procedure THidroConEmbalse.AcumAux1(peso: NReal);
begin
  globs.Auxs_r1[iauxr][globs.CF.ordinalEstrellaActual] :=
    globs.Auxs_r1[iauxr][globs.CF.ordinalEstrellaActual] + Self.QErogado_ * peso;
end;

procedure THidroConEmbalse.SetAux1;
begin
  globs.Auxs_r1[iauxr][globs.CF.ordinalEstrellaActual] := Self.QErogado_;
end;

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

{$IFDEF XVE_Volumen}
  adminEstados.Registrar_Continua(
    ixr,
    V_hmin,
    V_hmax,
    ndisc,
    nombre + '_Vol', // nombre de la variable
    'Hm3' // unidades
    );
  adminEstados.RegistrarTraduccion_Continua(ixr,
    nombre + '_Cota',
    'm', self.VolumenToCota);
{$ELSE}
  adminEstados.Registrar_Continua(
    ixr,
    pa.hmin,
    pa.hmax,
    ndisc,
    nombre + '_Cota', // nombre de la variable
    'm' // unidades
    );
  adminEstados.RegistrarTraduccion_Continua(ixr,
    nombre + '_Vol',
    'Hm3', self.CotaToVolumen);

{$ENDIF}
end;

procedure THidroConEmbalse.Free;
begin
  if polinomioCotaVolumen <> nil then
    polinomioCotaVolumen.Free;
  if self.polinomioCotaMaxAporte <> nil then
    self.polinomioCotaMaxAporte.Free;
  {$IFNDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
  if self.polinomioErogadoMinVol <> nil then
    self.polinomioErogadoMinVol.Free;
  {$ENDIF}
  if lpd <> nil then
    lpd.Free;
  setlength(P_Central_CotaSup, 0);
  setlength(QErogado_falla, 0);
  inherited Free;
end;

// h [m]  V [hm3]
function THidroConEmbalse.CotaToVolumen(h: NReal): NReal;
var
  dh: NReal;
  dV: NReal;
begin
  dh := h - pA.hmin;
  if EsConico then
    dV := (embalse_c2 * dh + embalse_c1) * dh
  else
    dV := embalse_c1 * dh;
  Result := V_hmin + dV;
end;


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


function THidroConEmbalse.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 THidroConEmbalse.VTminPorCurvaAportes(Aportes, cota_actual: NReal): NReal;
var
  aportes_paso: NReal;
  cota_proy: NReal;
begin
  //si el embalse es compartido al 50 %, entonces los aportes ingresados se
  //deben multiplicar x 2 para el control de cota máxima admisible según aportes.
  aportes_paso := Aportes * 2;
  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;

function THidroConEmbalse.VolumenToCota(Vol: NReal): NReal;
var
  dV: NReal;
begin
  dV := Vol - V_hmin;

  if EsConico then
    Result := sqrt(embalse_c3_ * dV + embalse_c4_) + embalse_c5_
  else
    Result := dV / embalse_c1 + pA.hmin;
end;


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

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

{$IFDEF ENGANCHE_CE}
procedure THidroConEmbalse.AgregarDefinicionesEvaluador(
  eval: TEvaluadorExpresionesSimples);
var
  af: TFunc_F_F_OfObject;
begin
  af:= TFunc_F_F_OfObject.Create( 'CE_'+self.nombre, self.Ce_Enganche );
  eval.CatalogoFuncionesDeUsuario.Add( af );
end;
{$ENDIF}

procedure THidroConEmbalse.CambioFichaPD;
var
  hmed: NReal;
  dVmax, dVmed: NReal;
  ErogadoMinVol_vol, ErogadoMinVol_Erogado: TDAofNReal;

begin

{$IFDEF DEBUG_CAMBIO_FICHA_PD}
  writeln('CAMBIO FICHA PD ' + Self.nombre + ', FechaFicha: ' +
    pa.fecha.AsISOStr + ', FechaOptSim: ' + globs.FechaInicioDelpaso.AsISOStr +
    ', Capa: ' + IntToStr(pa.capa));
{$ENDIF}
  polinomioCotaMaxAporte.AproxTabla2D(2,
    self.pa.PuntosControlCrecidaPorCotaYAportes_QA,
    self.pa.PuntosControlCrecidaPorCotaYAportes_h);

  polinomioCotaVolumen.AproxTabla2D(2, self.pa.PuntosCotaVolumen_h,
    self.pa.PuntosCotaVolumen_V);

  if flg_FuenteDeEscurrimientos then
    fEscurrimientoToCaudal := 1.0 / 1000 * pa.AreaCuenca_ha * 100 * 100 / (730 * 3600);

  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;

  ActualizarProbabilidadesReparacionYRotura_(pa.fDispo, pa.tRepHoras);
  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;


  {$IFDEF USAR_APRI}
  apri_a := embalse_ca * 1E6 / dhmax;
  apri_b := embalse_cb * 1E6 / sqr(dhmax);
  {$ENDIF}


//  if EsCero(embalse_cb) then
  if embalse_cb < 1E-5 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));
(*  otra forma de calcular lo mismo
   embalse_c3_ := 2.0 / ( embalse_cb/ sqr( dhmax) );
   embalse_c4_ := sqr( ( embalse_ca / dhmax)  / ( embalse_cb / sqr(dhmax) ));
   embalse_c5_ := pa.hmin - ( ( embalse_ca / dhmax)  / ( embalse_cb / sqr(dhmax) ));
   *)
  end;

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


  {$IFNDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
  V_EmbalsadoInicioProteccion := CotaToVolumen(ErogadoMinVol_vol[0]);
  V_EmbalsadoProteccionAPleno := CotaToVolumen(ErogadoMinVol_vol[2]);
  polinomioErogadoMinVol.AproxTabla2D(2, ErogadoMinVol_vol, ErogadoMinVol_Erogado);
  {$ENDIF}

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

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

  {$IFDEF CONTROL_CRECIDA_POR_VOL_LINEAL}
  // 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}

  recalcular_parametros_dhqe( pa.caQE, pa.cbQE );

end;

{*********************************
*Métodos de TFichaHidroConEmbalse*
*********************************}

constructor TFichaHidroConEmbalse.Create(capa: integer; fecha: TFecha;
  periodicidad: TPeriodicidad; hmin_, hmax_: NReal; PuntosCotaVolumen_h,
  PuntosCotaVolumen_V: TDAOfNReal; AreaCuenca_ha: NReal; 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,
  QE_ControlDeCrecidaInicio, QE_ControlDeCrecidaMedio,
  QE_ControlDeCrecidaAPleno: NReal; HayRestriccionEmaxPasoDeTiempo: boolean;
  EmaxPasoDeTiempo: NReal; HayRestriccionQTmin: boolean; QTmin: NReal;
  flg_Aplica_cv_Spot_Acordado: Boolean; cv_Spot_acordado, P_forzada: NReal;
  PuntosControlCrecidaPorCotaYAportes_h: TDAOfNReal;
  PuntosControlCrecidaPorCotaYAportes_QA: TDAOfNReal;
  flg_ControlCrecidaPOrCotaYAportes, flg_ControlCrecidaPorCota: boolean;
  ImponerQminPorPoste: boolean; ControlarCotaPorDebajoDeObjetivo_sim,

  // Control de cota
  ControlarCotaPorEnciaDeObjetivo_sim: boolean;
  ControlarCotaPorDebajoDeObjetivo_opt,
  ControlarCotaPorEnciaDeObjetivo_opt: boolean;
  flg_ValorAguaExacto_hObjetivo: boolean; flg_ControlCondicional: boolean;
  DAofhObjetivo: TDAofNReal; DAofDelta_cvaUSD_Hm3ParaControlDeCota: TDAofNReal;
  IndiceAjusteControlDeCota: TFuenteAleatoria;
  borneAjusteControlDeCota: string;

  cv_USD_Hm3_ValorizadoManual: NReal;
  tomarCotaDeLaFuente: boolean; fuenteCota: TFuenteAleatoria;
  borneCota: string; saltoMinimoOperativo: NReal; cotaControlCrecida_Inicio,
  cotaControlCrecida_Medio, cotaControlCrecida_Pleno: NReal;
  flg_CalcularEvaporacionDelLago: boolean;
  flg_CalcularFiltracionDelLago: boolean; PorcentajeFiltracion: NReal;
  PagoPorDisponibilidad_USD_MWh: NReal; PagoPorEnergia_USD_MWh: NReal;
  QErogadoMin_Falla, cv_USD_hm3_falla_ErogadoMin: Nreal;
  flg_ErogadoMin_Falla: boolean);
begin
  inherited Create(capa, fecha, periodicidad);
  self.hmin := hmin_;
  self.hmax := hmax_;

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

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

  self.AreaCuenca_ha := AreaCuenca_ha;
  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.PorcentajeFiltracion:=PorcentajeFiltracion;
  Self.QaMuySeco := QaMuySeco;

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

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

  self.centralesAguasArriba := centralesAguasArriba;

  self.HayRestriccionEmaxPasoDeTiempo := HayRestriccionEmaxPasoDeTiempo;
  self.EmaxPasoDeTiempo := EmaxPasoDeTiempo;
  self.HayRestriccionQTmin := HayRestriccionQTmin;
  self.QTmin := QTmin;
  self.ImponerQminPorPoste := ImponerQminPorPoste;
  self.flg_Aplica_cv_Spot_Acordado:= flg_Aplica_cv_Spot_Acordado;
  self.cv_Spot_acordado:=cv_Spot_acordado;
  self.P_forzada:= P_forzada;

  self.flg_controlCotaObjetivoInferior_sim := ControlarCotaPorDebajoDeObjetivo_sim;
  self.flg_controlCotaObjetivoSuperior_sim := ControlarCotaPorEnciaDeObjetivo_sim;
  self.flg_controlCotaObjetivoInferior_opt := ControlarCotaPorDebajoDeObjetivo_opt;
  self.flg_controlCotaObjetivoSuperior_opt := ControlarCotaPorEnciaDeObjetivo_opt;

  self.DAOfhObjetivo := DAofhObjetivo;
  self.DAofdelta_cva_ParaControlDeCota := DAofDelta_cvaUSD_Hm3ParaControlDeCota;
  self.flg_ValorAguaExacto_hObjetivo := flg_ValorAguaExacto_hObjetivo;
  self.flg_ControlCondicional:= flg_ControlCondicional;
  self.cv_USD_Hm3_ValorizadoManual := cv_USD_Hm3_ValorizadoManual;

  self.indiceAjusteControlDeCota:= IndiceAjusteControlDeCota;
  self.borneAjusteControlDeCota:= borneAjusteControlDeCota;

  Self.tomarCotaDeLaFuente := tomarCotaDeLaFuente;
  self.fuenteCota := fuenteCota;
  self.borneCota := borneCota;

  self.saltoMinimoOperativo := saltoMinimoOperativo;

  self.cotaControlCrecida_Inicio := cotaControlCrecida_Inicio;
  self.cotaControlCrecida_Medio := cotaControlCrecida_Medio;
  self.cotaControlCrecida_Pleno := cotaControlCrecida_Pleno;

  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.flg_ErogadoMin_Falla := flg_ErogadoMin_Falla;
  self.cv_USD_hm3_falla_ErogadoMin := cv_USD_hm3_falla_ErogadoMin;
  self.QErogadoMin_Falla := QErogadoMin_Falla;

end;


procedure TFichaHidroConEmbalse.LoadBefore_13_Rec(var res: TCosa_RecLnk;
  var Vmax, Vhmed: NReal);
begin
  res.addCampoDef('hmin', hmin, 0, 13);
  res.addCampoDef('hmax', hmax, 0, 13);
  res.addCampoDef('Vmax', Vmax, 0, 13);
  res.addCampoDef('Vhmed', Vhmed, 0, 13);
  res.addCampoDef('hDescarga', hDescarga, 0, 13);
  res.addCampoDef('caQE', caQE, 0, 13);
  res.addCampoDef('cbQE', cbQE, 0, 13);
  res.addCampoDef('ren', ren, 0, 13);
  res.addCampoDef('Pmax_Gen', Pmax_Gen, 0, 13);
  res.addCampoDef('Qmax_Turb', Qmax_Turb, 0, 13);
  res.addCampoDef('fDispo', fDispo, 0, 13);
  res.addCampoDef('filtracion_Ca', filtracion_Ca, 0, 13);
  res.addCampoDef('filtracion_Cb', filtracion_Cb, 0, 13);
  res.addCampoDef('QaMuySeco', QaMuySeco, 0, 13);
  res.addCampoDef('cotaMV0', cotaMV0, 0, 13);
  res.addCampoDef('cotaMV1', cotaMV1, 0, 13);
  res.addCampoDef('QMV1', QMV1, 0, 13);
  res.addCampoDef_ref('central_lagoDescarga', TCosa(central_lagoDescarga), Self, 0, 13);
  res.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba), 0, 13);
  res.addCampoDef('HayRestriccionEmaxPasoDeTiempo',
    HayRestriccionEmaxPasoDeTiempo, 0, 13);
  res.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo, 0, 13);
  res.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin, 0, 13);
  res.addCampoDef('QTmin', QTmin, 0, 13);
  res.addCampoDef('hObjetivo', px.hObjetivo_aux, 0, 13);
  res.addCampoDef('cva_delta', px.delta_cva_ParaControlDeCota_aux, 0, 13);
  res.addCampoDef('flg_controlCotaObjetivoInferior',
    flg_controlCotaObjetivoInferior_sim, 0, 13);
  res.addCampoDef('flg_controlCotaObjetivoSuperior',
    flg_controlCotaObjetivoSuperior_sim, 0, 13);
  res.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual, 0, 13);
end;


procedure TFichaHidroConEmbalse.LoadBefore_14_Rec(var res: TCosa_RecLnk;
  var Vmax, Vhmed: NReal);
begin
  res.addCampoDef('hmin', hmin, 13, 14);
  res.addCampoDef('hmax', hmax, 13, 14);
  res.addCampoDef('Vmax', Vmax, 13, 14);
  res.addCampoDef('Vhmed', Vhmed, 13, 14);
  res.addCampoDef('hDescarga', hDescarga, 13, 14);
  res.addCampoDef('caQE', caQE, 13, 14);
  res.addCampoDef('cbQE', cbQE, 13, 14);
  res.addCampoDef('ren', ren, 13, 14);
  res.addCampoDef('Pmax_Gen', Pmax_Gen, 13, 14);
  res.addCampoDef('Qmax_Turb', Qmax_Turb, 13, 14);
  res.addCampoDef('fDispo', fDispo, 13, 14);
  res.addCampoDef('filtracion_Ca', filtracion_Ca, 13, 14);
  res.addCampoDef('filtracion_Cb', filtracion_Cb, 13, 14);
  res.addCampoDef('QaMuySeco', QaMuySeco, 13, 14);
  res.addCampoDef('cotaMV0', cotaMV0, 13, 14);
  res.addCampoDef('cotaMV1', cotaMV1, 13, 14);
  res.addCampoDef('QMV1', QMV1, 13, 14);
  res.addCampoDef_ref('central_lagoDescarga', TCosa(central_lagoDescarga),
    Self, 13, 14);
  res.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba), 13, 14);
  res.addCampoDef('HayRestriccionEmaxPasoDeTiempo',
    HayRestriccionEmaxPasoDeTiempo, 13, 14);
  res.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo, 13, 14);
  res.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin, 13, 14);
  res.addCampoDef('QTmin', QTmin, 13, 14);
  res.addCampoDef('hObjetivo', px.hObjetivo_aux, 13, 14);
  res.addCampoDef('cva_delta', px.delta_cva_ParaControlDeCota_aux, 13, 14);
  res.addCampoDef('flg_controlCotaObjetivoInferior',
    flg_controlCotaObjetivoInferior_sim, 13, 14);
  res.addCampoDef('flg_controlCotaObjetivoSuperior',
    flg_controlCotaObjetivoSuperior_sim, 13, 14);
  res.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual, 13, 14);
  res.addCampoDef('tomarCotaDeLaFuente', tomarCotaDeLaFuente, 13, 14);
  res.addCampoDef_ref('fuenteCota', TCosa(fuenteCota), self, 13, 14);
  res.addCampoDef('borneCota', borneCota, 13, 14);
end;

procedure TFichaHidroConEmbalse.LoadBefore_17_Rec(var res: TCosa_RecLnk;
  var Vmax, Vhmed: NReal);
begin
  res.addCampoDef('hmin', hmin, 14, 17);
  res.addCampoDef('hmax', hmax, 14, 17);
  res.addCampoDef('Vmax', Vmax, 14, 17);
  res.addCampoDef('Vhmed', Vhmed, 14, 17);
  res.addCampoDef('hDescarga', hDescarga, 14, 17);
  res.addCampoDef('caQE', caQE, 14, 17);
  res.addCampoDef('cbQE', cbQE, 14, 17);
  res.addCampoDef('ren', ren, 14, 17);
  res.addCampoDef('Pmax_Gen', Pmax_Gen, 14, 17);
  res.addCampoDef('Qmax_Turb', Qmax_Turb, 14, 17);
  res.addCampoDef('fDispo', fDispo, 14, 17);
  res.addCampoDef('tRepHoras', tRepHoras, 14, 17);
  res.addCampoDef('filtracion_Ca', filtracion_Ca, 14, 17);
  res.addCampoDef('filtracion_Cb', filtracion_Cb, 14, 17);
  res.addCampoDef('QaMuySeco', QaMuySeco, 14, 17);
  res.addCampoDef('cotaMV0', cotaMV0, 14, 17);
  res.addCampoDef('cotaMV1', cotaMV1, 14, 17);
  res.addCampoDef('QMV1', QMV1, 14, 17);
  res.addCampoDef_ref('central_lagoDescarga', TCosa(central_lagoDescarga),
    Self, 14, 17);
  res.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba), 14, 17);
  res.addCampoDef('HayRestriccionEmaxPasoDeTiempo',
    HayRestriccionEmaxPasoDeTiempo, 14, 17);
  res.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo, 14, 17);
  res.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin, 14, 17);
  res.addCampoDef('QTmin', QTmin, 14, 17);
  res.addCampoDef('hObjetivo', px.hObjetivo_aux, 14, 17);
  res.addCampoDef('cva_delta', px.delta_cva_ParaControlDeCota_aux, 14, 17);
  res.addCampoDef('flg_controlCotaObjetivoInferior',
    flg_controlCotaObjetivoInferior_sim, 14, 17);
  res.addCampoDef('flg_controlCotaObjetivoSuperior',
    flg_controlCotaObjetivoSuperior_sim, 14, 17);
  res.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual, 14, 17);
  res.addCampoDef('tomarCotaDeLaFuente', tomarCotaDeLaFuente, 14, 17);
  res.addCampoDef_ref('fuenteCota', TCosa(fuenteCota), self, 14, 17);
  res.addCampoDef('borneCota', borneCota, 14, 17);
end;

procedure TFichaHidroConEmbalse.LoadBefore_26_Rec(var res: TCosa_RecLnk;
  var Vmax, Vhmed: NReal);
begin
  res.addCampoDef('hmin', hmin, 17, 26);
  res.addCampoDef('hmax', hmax, 17, 26);
  res.addCampoDef('Vmax', Vmax, 17, 26);
  res.addCampoDef('Vhmed', Vhmed, 17, 26);
  res.addCampoDef('hDescarga', hDescarga, 17, 26);
  res.addCampoDef('caQE', caQE, 17, 26);
  res.addCampoDef('cbQE', cbQE, 17, 26);
  res.addCampoDef('ren', ren, 17, 26);
  res.addCampoDef('Pmax_Gen', Pmax_Gen, 17, 26);
  res.addCampoDef('Qmax_Turb', Qmax_Turb, 17, 26);
  res.addCampoDef('fDispo', fDispo, 17, 26);
  res.addCampoDef('tRepHoras', tRepHoras, 17, 26);
  res.addCampoDef('filtracion_Ca', filtracion_Ca, 17, 26);
  res.addCampoDef('filtracion_Cb', filtracion_Cb, 17, 26);
  res.addCampoDef('QaMuySeco', QaMuySeco, 17, 26);
  res.addCampoDef('cotaMV0', cotaMV0, 17, 26);
  res.addCampoDef('cotaMV1', cotaMV1, 17, 26);
  res.addCampoDef('QMV1', QMV1, 17, 26);
  res.addCampoDef_ref('central_lagoDescarga', TCosa(central_lagoDescarga),
    Self, 17, 26);
  res.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba), 17, 26);
  res.addCampoDef('HayRestriccionEmaxPasoDeTiempo',
    HayRestriccionEmaxPasoDeTiempo, 17, 26);
  res.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo, 17, 26);
  res.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin, 17, 26);
  res.addCampoDef('QTmin', QTmin, 17, 26);
  res.addCampoDef('ImponerQminPorPoste', ImponerQminPorPoste, 17, 26);
  res.addCampoDef('hObjetivo', px.hObjetivo_aux, 17, 26);
  res.addCampoDef('cva_delta', px.delta_cva_ParaControlDeCota_aux, 17, 26);
  res.addCampoDef('flg_controlCotaObjetivoInferior',
    flg_controlCotaObjetivoInferior_sim, 17, 26);
  res.addCampoDef('flg_controlCotaObjetivoSuperior',
    flg_controlCotaObjetivoSuperior_sim, 17, 26);
  res.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual, 17, 26);
  res.addCampoDef('tomarCotaDeLaFuente', tomarCotaDeLaFuente, 17, 26);
  res.addCampoDef_ref('fuenteCota', TCosa(fuenteCota), self, 17, 26);
  res.addCampoDef('borneCota', borneCota, 17, 26);
end;

procedure TFichaHidroConEmbalse.LoadBefore_28_Rec(var res: TCosa_RecLnk;
  var Vmax, Vhmed, vdummy: NReal);
begin
  res.addCampoDef('hmin', hmin, 26, 28);
  res.addCampoDef('hmax', hmax, 26, 28);
  res.addCampoDef('Vmax', Vmax, 26, 28);
  res.addCampoDef('Vhmed', Vhmed, 26, 28);
  res.addCampoDef('hDescarga', hDescarga, 26, 28);
  res.addCampoDef('caQE', caQE, 26, 28);
  res.addCampoDef('cbQE', cbQE, 26, 28);
  res.addCampoDef('ren', ren, 26, 28);
  res.addCampoDef('Pmax_Gen', Pmax_Gen, 26, 28);
  res.addCampoDef('Qmax_Turb', Qmax_Turb, 26, 28);
  res.addCampoDef('fDispo', fDispo, 26, 28);
  res.addCampoDef('tRepHoras', tRepHoras, 26, 28);
  res.addCampoDef('filtracion_Ca', filtracion_Ca, 26, 28);
  res.addCampoDef('filtracion_Cb', filtracion_Cb, 26, 28);
  res.addCampoDef('QaMuySeco', QaMuySeco, 26, 28);
  res.addCampoDef('cotaMV0', cotaMV0, 26, 28);
  res.addCampoDef('cotaMV1', cotaMV1, 26, 28);
  res.addCampoDef('QMV1', QMV1, 26, 28);
  res.addCampoDef_ref('central_lagoDescarga', TCosa(central_lagoDescarga),
    Self, 26, 28);
  res.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba), 26, 28);
  res.addCampoDef('HayRestriccionEmaxPasoDeTiempo',
    HayRestriccionEmaxPasoDeTiempo, 26, 28);
  res.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo, 26, 28);
  res.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin, 26, 28);
  res.addCampoDef('QTmin', QTmin, 26, 28);
  res.addCampoDef('ImponerQminPorPoste', ImponerQminPorPoste, 26, 28);
  res.addCampoDef('hObjetivo', px.hObjetivo_aux, 26, 28);
  res.addCampoDef('cva_delta', px.delta_cva_ParaControlDeCota_aux, 26, 28);
  res.addCampoDef('flg_controlCotaObjetivoInferior',
    flg_controlCotaObjetivoInferior_sim, 26, 28);
  res.addCampoDef('flg_controlCotaObjetivoSuperior',
    flg_controlCotaObjetivoSuperior_sim, 26, 28);
  res.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual, 26, 28);
  res.addCampoDef('tomarCotaDeLaFuente', tomarCotaDeLaFuente, 26, 28);
  res.addCampoDef_ref('fuenteCota', TCosa(fuenteCota), self, 26, 28);
  res.addCampoDef('borneCota', borneCota, 26, 28);
  res.addCampoDef('cotaActivacionControlCrecida', vdummy, 26, 28);
  res.addCampoDef('penalidadControlCrecida', vdummy, 26, 28);
end;


procedure TFichaHidroConEmbalse.LoadBefore_13_AfterRead(f: TArchiTexto;
  var Vmax, Vhmed: NReal);
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;
  flg_controlCotaObjetivoInferior_opt := False;
  flg_controlCotaObjetivoSuperior_opt := False;
  flg_ValorAguaExacto_hObjetivo := False;
  flg_ControlCondicional:= False;
  tomarCotaDeLaFuente := False;
  fuenteCota := nil;
  borneCota := '';
  Self.tRepHoras := 48;
  ImponerQminPorPoste := False;
  cotaControlCrecida_Inicio := hmax;
  cotaControlCrecida_Pleno := cotaControlCrecida_Inicio + 2.0;
end;


procedure TFichaHidroConEmbalse.LoadBefore_14_AfterRead(f: TArchiTexto;
  var Vmax, Vhmed: NReal);
begin
  flg_controlCotaObjetivoInferior_opt := False;
  flg_controlCotaObjetivoSuperior_opt := False;
  flg_ValorAguaExacto_hObjetivo := False;
  flg_ControlCondicional:= False;
  tRepHoras := 48;
  ImponerQminPorPoste := False;
  cotaControlCrecida_Inicio := hmax;
  cotaControlCrecida_Pleno := cotaControlCrecida_Inicio + 2.0;
  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;

procedure TFichaHidroConEmbalse.LoadBefore_17_AfterRead(f: TArchiTexto;
  var Vmax, Vhmed: NReal);
begin
  flg_controlCotaObjetivoInferior_opt := False;
  flg_controlCotaObjetivoSuperior_opt := False;
  flg_ValorAguaExacto_hObjetivo := False;
  flg_ControlCondicional:= False;
  ImponerQminPorPoste := False;
  cotaControlCrecida_Inicio := hmax;
  cotaControlCrecida_Pleno := cotaControlCrecida_Inicio + 2.0;
  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;

procedure TFichaHidroConEmbalse.LoadBefore_26_AfterRead(f: TArchiTexto;
  var Vmax, Vhmed: NReal);
begin
  flg_controlCotaObjetivoInferior_opt := False;
  flg_controlCotaObjetivoSuperior_opt := False;
  flg_ValorAguaExacto_hObjetivo := False;
  flg_ControlCondicional:= False;
  cotaControlCrecida_Inicio := hmax;
  cotaControlCrecida_Pleno := cotaControlCrecida_Inicio + 2.0;
  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;


procedure TFichaHidroConEmbalse.LoadBefore_28_AfterRead(f: TArchiTexto;
  var Vmax, Vhmed, vdummy: NReal);
begin
  flg_controlCotaObjetivoInferior_opt := False;
  flg_controlCotaObjetivoSuperior_opt := False;
  flg_ValorAguaExacto_hObjetivo := False;
  flg_ControlCondicional:= False;
  cotaControlCrecida_Inicio := hmax;
  cotaControlCrecida_Pleno := cotaControlCrecida_Inicio + 2.0;
  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;



function TFichaHidroConEmbalse.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  LoadBefore_13_Rec(Result, px.Vmax, px.vhmed);
  loadBefore_14_Rec(Result, px.Vmax, px.vhmed);
  loadBefore_17_Rec(Result, px.Vmax, px.vhmed);
  loadBefore_26_Rec(Result, px.Vmax, px.vhmed);
  loadBefore_28_Rec(Result, px.Vmax, px.vhmed, px.vdummy);
  Result.addCampoDef('hmin', hmin, 28);
  Result.addCampoDef('hmax', hmax, 28);
  Result.addCampoDef('PuntosCotaVolumen_h', PuntosCotaVolumen_h, 28);
  Result.addCampoDef('PuntosCotaVolumen_V', PuntosCotaVolumen_V, 28);
  Result.addCampoDef('AreaCuenca_ha', AreaCuenca_ha, 104);
  Result.addCampoDef('hDescarga', hDescarga, 28);
  Result.addCampoDef('caQE', caQE, 28);
  Result.addCampoDef('cbQE', cbQE, 28);
  Result.addCampoDef('ren', ren, 28);
  Result.addCampoDef('Pmax_Gen', Pmax_Gen, 28);
  Result.addCampoDef('Qmax_Turb', Qmax_Turb, 28);
  Result.addCampoDef('fDispo', fDispo, 28);
  Result.addCampoDef('tRepHoras', tRepHoras, 28);
  Result.addCampoDef('filtracion_Ca', filtracion_Ca, 28);
  Result.addCampoDef('filtracion_Cb', filtracion_Cb, 28);
  Result.addCampoDef('QaMuySeco', QaMuySeco, 28);
  Result.addCampoDef('cotaMV0', cotaMV0, 28);
  Result.addCampoDef('cotaMV1', cotaMV1, 28);
  Result.addCampoDef('QMV1', QMV1, 28);
  Result.addCampoDef('QE_ControlDeCrecidaAPleno', QE_ControlDeCrecidaAPleno, 84);
  Result.addCampoDef_Ref('central_lagoDescarga', TCosa(central_lagoDescarga),
    Self, 28);
  Result.addCampoDef('centralesAguasArriba', TCosa(centralesAguasArriba), 28);
  Result.addCampoDef('HayRestriccionEmaxPasoDeTiempo',
    HayRestriccionEmaxPasoDeTiempo, 28);
  Result.addCampoDef('EmaxPasoDeTiempo', EmaxPasoDeTiempo, 28);
  Result.addCampoDef('HayRestriccionQTmin', HayRestriccionQTmin, 28);
  Result.addCampoDef('QTmin', QTmin, 28);
  Result.addCampoDef('PuntosControlCrecidaPorCotaYAportes_h',
    PuntosControlCrecidaPorCotaYAportes_h, 120);
  Result.addCampoDef('PuntosControlCrecidaPorCotaYAportes_QA',
    PuntosControlCrecidaPorCotaYAportes_QA, 120);
  Result.addCampoDef('flg_ControlCrecidaPOrCotaYAportes',
    flg_ControlCrecidaPOrCotaYAportes, 120);
  Result.addCampoDef('ImponerQminPorPoste', ImponerQminPorPoste, 28);

  Result.addCampoDef('hObjetivo', px.hObjetivo_aux, 28,171);
  Result.addCampoDef('cva_delta', px.delta_cva_ParaControlDeCota_aux, 28,171);
  Result.addCampoDef('DAOfhObjetivo', DAOfhObjetivo, 171);
  Result.addCampoDef('DAOfdelta_cva_ParaControlDeCota', DAOfdelta_cva_ParaControlDeCota, 171);

  Result.addCampoDef_ref('indiceAjusteControlDeCota',
    TCosa(indiceAjusteControlDeCota), self, 174 ); // ver qie version poner
  Result.addCampoDef('borneAjusteControlDeCota',
    borneAjusteControlDeCota, 174 );


  Result.addCampoDef('flg_controlCotaObjetivoInferior',
    flg_controlCotaObjetivoInferior_sim, 28, 129);
  Result.addCampoDef('flg_controlCotaObjetivoSuperior',
    flg_controlCotaObjetivoSuperior_sim, 28, 129);

  Result.addCampoDef('flg_controlCotaObjetivoInferior_sim',
    flg_controlCotaObjetivoInferior_sim, 129);
  Result.addCampoDef('flg_controlCotaObjetivoSuperior_sim',
    flg_controlCotaObjetivoSuperior_sim, 129);
  Result.addCampoDef('flg_controlCotaObjetivoInferior_opt',
    flg_controlCotaObjetivoInferior_opt, 129);
  Result.addCampoDef('flg_controlCotaObjetivoSuperior_opt',
    flg_controlCotaObjetivoSuperior_opt, 129);
  Result.addCampoDef('flg_ValorAguaExacto_hObjetivo',
    flg_ValorAguaExacto_hObjetivo, 131);
  Result.addCampoDef('flg_ControlCondicional',
    flg_ControlCondicional, 158 );
  Result.addCampoDef('cv_USD_MWh_ValorizadoManual', cv_USD_Hm3_ValorizadoManual);
  Result.addCampoDef('tomarCotaDeLaFuente', tomarCotaDeLaFuente);
  Result.addCampoDef_Ref('fuenteCota', TCosa(fuenteCota), self);
  Result.addCampoDef('borneCota', borneCota);

  Result.addCampoDef('cotaActivacionControlCrecida', px.vdummy, 28, 29);
  Result.addCampoDef('penalidadControlCrecida', px.vdummy, 28, 29);

  Result.addCampoDef('cotaControlCrecida_Inicio', cotaControlCrecida_Inicio, 29);
  Result.addCampoDef('cotaControlCrecida_Pleno', cotaControlCrecida_Pleno, 29);
  Result.addCampoDef('saltoMinimoOperativo', saltoMinimoOperativo, 30);
  Result.addCampoDef('flg_CalcularEvaporacionDelLago',
    flg_CalcularEvaporacionDelLago, 83);
  Result.addCampoDef('flg_CalcularFiltracionDelLago',
    flg_CalcularFiltracionDelLago, 83);
  Result.addCampoDef('PagoPorDisponibilidad_USD_MWh',
    PagoPorDisponibilidad_USD_MWh, 98);
  Result.addCampoDef('PagoPorEnergia_USD_MWh', PagoPorEnergia_USD_MWh, 98);
  Result.addCampoDef('QE_ControlDeCrecidaInicio', QE_ControlDeCrecidaInicio, 137);
  Result.addCampoDef('QE_ControlDeCrecidaMedio', QE_ControlDeCrecidaMedio, 137);
  Result.addCampoDef('cotaControlCrecida_Medio', cotaControlCrecida_Medio, 137);
  Result.addCampoDef('flg_ControlCrecidaPorCota', flg_ControlCrecidaPorCota, 137);
  Result.addCampoDef('QErogadoMin_Falla', QErogadoMin_Falla, 144);
  Result.addCampoDef('flg_ErogadoMin_Falla', flg_ErogadoMin_Falla, 144);
  Result.addCampoDef('cv_USD_hm3_falla_ErogadoMin', cv_USD_hm3_falla_ErogadoMin, 144);
  Result.addCampoDef('Porcentaje_Filtrado', PorcentajeFiltracion, 156);
  Result.addCampoDef('flg_Aplica_cv_Spot_Acordado',
    flg_Aplica_cv_Spot_Acordado, 162);
  Result.addCampoDef('cv_Spot_acordado', cv_Spot_acordado, 162);
  Result.addCampoDef('P_forzada', P_forzada, 163);
end;

procedure TFichaHidroConEmbalse.BeforeRead(version, id_hilo: integer);
begin
  inherited BeforeRead(version, id_hilo);
  px := TFichaHidroConEmbalse_auxRec.Create;

  AreaCuenca_ha := 0.0;
  if Version < 137 then
  begin
    cotaControlCrecida_Medio := 1;
    QE_ControlDeCrecidaInicio := 2;
    QE_ControlDeCrecidaMedio := 3;
    flg_ControlCrecidaPorCota := False;
  end;
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 TFichaHidroConEmbalse.AfterRead(f:TArchiTexto);
begin
  inherited AfterRead(f);


  if f.Version < 28 then
  begin
    // calculo la tabla PuntosCotaVolumen a partir de los datos Vmax y Vhmed
    setlength(PuntosCotaVolumen_h, 3);
    setlength(PuntosCotaVolumen_V, 3);
    PuntosCotaVolumen_h[0] := self.hmin;
    PuntosCotaVolumen_h[1] := (self.hmin + self.hmax) / 2.0;
    PuntosCotaVolumen_h[2] := self.hmax;
    PuntosCotaVolumen_V[0] := 0;
    PuntosCotaVolumen_V[1] := px.Vhmed;
    PuntosCotaVolumen_V[2] := px.Vmax;
  end;


  if f.Version < 29 then
  begin
    cotaControlCrecida_Inicio := hmax;
    cotaControlCrecida_Pleno := cotaControlCrecida_Inicio + 2.0;
  end;

  if f.Version < 30 then
  begin
    saltoMinimoOperativo := 0.1;
  end;

  if f.Version < 83 then
  begin
    flg_CalcularEvaporacionDelLago := True;
    flg_CalcularFiltracionDelLago := True;
  end;

  if f.Version < 85 then
    QE_ControlDeCrecidaAPleno := QMV1;

  if f.Version < 98 then
  begin
    PagoPorDisponibilidad_USD_MWh := 0.0;
    PagoPorEnergia_USD_MWh := 0.0;
  end;

  if f.Version < 129 then
  begin
    flg_controlCotaObjetivoInferior_opt := False;
    flg_controlCotaObjetivoSuperior_opt := False;
  end;
  if f.Version < 131 then
    flg_ValorAguaExacto_hObjetivo := False;


  if f.Version < 138 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;
  if f.Version < 144 then
  begin
    flg_ErogadoMin_Falla := False;
    QErogadoMin_Falla := 0;
    cv_USD_hm3_falla_ErogadoMin := 0;
  end;

  if f.Version < 156 then
    PorcentajeFiltracion := 0.0;

  if f.Version < 158 then
    flg_ControlCondicional:= false;

  if f.version <171 then
  begin
    SetLength(DAOfhObjetivo,1);
    SetLength(DAOfdelta_cva_ParaControlDeCota,1);
    DAOfhObjetivo[0] := px.hObjetivo_aux;
    DAOfdelta_cva_ParaControlDeCota[0] := px.delta_cva_ParaControlDeCota_aux;
  end;

  px.Free;

  Crear_lstAuxiliaresControlDecota;

end;


function TFichaHidroConEmbalse.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';
end;


procedure TFichaHidroConEmbalse.Free;
begin
  SetLength(PuntosCotaVolumen_h, 0);
  SetLength(PuntosCotaVolumen_V, 0);
  setlength(PuntosControlCrecidaPorCotaYAportes_h, 0);
  setlength(PuntosControlCrecidaPorCotaYAportes_QA, 0);

  if lstAuxiliaresControlDeCota <> nil then
    Destruir_lstAuxiliaresControlDecota;

  if centralesAguasArriba <> nil then
    centralesAguasArriba.Free;

  {$IFDEF DBG_HIDRO_CON_EMBALSE}
  if flg_flog_open then
  begin
    closefile(flog);
    flg_flog_open := False;
  end;
  {$ENDIF}

  inherited Free;
end;

function TFichaHidroConEmbalse.getControlDeCotaAplicable_inf(h_actual: NReal
  ): TAuxialiarControlDeCota;
var
  res:TAuxialiarControlDeCota;
  k: integer;
  aRec: TAuxialiarControlDeCota;
  buscando: boolean;

begin
  res:= nil;
  result:= nil;

  if lstAuxiliaresControlDeCota =  nil then exit;
  k:= lstAuxiliaresControlDeCota.Count -1;
  if k < 0 then exit;
  aRec:= lstAuxiliaresControlDeCota[k];
  if aRec.Cota < h_actual then exit; // estoy por arriba de la primer cota de control

  res:= aRec;
  buscando:= true;
  dec( k );
  while buscando and ( k >= 0 ) do
  begin
    aRec:=lstAuxiliaresControlDeCota[k];
    if aRec.Cota < h_actual then
      buscando:= false
    else
    begin
      res:= aRec;
      dec( k );
    end;
  end;
  result:= res;
end;

function TFichaHidroConEmbalse.getControlDeCotaAplicable_sup(h_actual: NReal
  ): TAuxialiarControlDeCota;
var
  res:TAuxialiarControlDeCota;
  kControlDeCota,NControlDeCota: integer;
  aRec: TAuxialiarControlDeCota;
  buscando: boolean;

begin
  res:= nil;
  result:= nil;

  if lstAuxiliaresControlDeCota = nil then
    exit;
  kControlDeCota:= 0;
  NControlDeCota:= lstAuxiliaresControlDeCota.Count;
  if NControlDeCota = 0 then
    exit;
  aRec:= lstAuxiliaresControlDeCota[kControlDeCota];
  if h_actual < aRec.Cota then exit; // estoy por debajo de la primer cota de control
  res:= aRec;
  buscando:= true;
  inc( kControlDeCota );
  while buscando and ( kControlDeCota < lstAuxiliaresControlDeCota.count  ) do
  begin
    aRec:=lstAuxiliaresControlDeCota[kControlDeCota];
    if h_actual < aRec.Cota then
      buscando:= false
    else
    begin
      res:= aRec;
      inc( kControlDeCota );
    end;
  end;
  result:= res;
end;


procedure TFichaHidroConEmbalse.Crear_lstAuxiliaresControlDecota;
var
  k: integer;
  aux_lst : TDAOFTauxialiarControlDeCota;
begin
  
  lstAuxiliaresControlDeCota := TList.Create;
  SetLength(aux_lst,Length( DAOfdelta_cva_ParaControlDeCota ));
  for k:=0 to Length( DAOfdelta_cva_ParaControlDeCota )-1 do
  begin
      aux_lst[k]:= TauxialiarControlDeCota.Create( DAOfhObjetivo[k], DAOfdelta_cva_ParaControlDeCota[k] );
      lstAuxiliaresControlDeCota.add(aux_lst[k]);
  end;

  lstAuxiliaresControlDeCota.Sort(@CompareCotas_ControlDeCota); //ordenado de menor a mayor

end;

procedure TFichaHidroConEmbalse.Destruir_lstAuxiliaresControlDecota;
var
  k: integer;
begin
  if lstAuxiliaresControlDeCota <> nil then
  for k:= 0 to lstAuxiliaresControlDeCota.count -1 do
     TauxialiarControlDeCota( lstAuxiliaresControlDeCota.items[k] ).Free;
  lstAuxiliaresControlDeCota.Free;
  lstAuxiliaresControlDeCota:= nil;
end;


procedure THidroConEmbalse_cambioFichaPD(Actor: TCosa);
begin
  (Actor as THidroConEmbalse).cambioFichaPD;
end;

procedure AlInicio;
begin
  registrarClaseDeCosa(THidroConEmbalse.ClassName, THidroConEmbalse);
  registrarClaseDeCosa(TFichaHidroConEmbalse.ClassName, TFichaHidroConEmbalse);

  {$IFDEF LOG_APORTES_OPT}
  assign( flogAportesOpt, 'logAportesOpt.xlt' );
  rewrite( flogAportesOpt );
  writeln( flogAportesOpt, 'Central', #9, 'kPaso_Opt', #9, 'kCronica', #9, 'cntIter', #9, 'Estrella', #9, 'QAp' );
   {$ENDIF}

end;

procedure AlFinal;
begin
  {$IFDEF LOG_APORTES_OPT}
  closefile( flogAportesOpt );
   {$ENDIF}
end;

begin
 {$IFDEF DBG_HIDRO_CON_EMBALSE}
  flg_flog_open := False;
{$ENDIF}

end.
