within Buildings.Fluid.HeatExchangers.BaseClasses.Examples;
model HexElementSensible
  "Model that tests the basic element that is used to built heat exchanger models"
  extends Modelica.Icons.Example;
 package Medium_W = Buildings.Media.Water;
 package Medium_A = Buildings.Media.Air;
  Buildings.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium_A,
    use_p_in=true,
    use_T_in=true,
    T=288.15,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp PIn(
    height=20,
    duration=300,
    startTime=300,
    offset=101325)
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium_A,
    use_p_in=true,
    use_T_in=true,
    T=283.15,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp TWat(
    startTime=1,
    height=4,
    duration=300,
    offset=303.15) "Water temperature"
  Modelica.Blocks.Sources.Constant TDb(k=278.15) "Drybulb temperature"
    Modelica.Blocks.Sources.Constant POut(k=101325)
  Buildings.Fluid.Sources.Boundary_pT sin_1(
   redeclare package Medium = Medium_W,
    use_p_in=true,
    T=288.15,
    nPorts=1)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium_W,
    use_T_in=true,
    nPorts=1,
    p=101340,
    T=293.15)
  Buildings.Fluid.FixedResistances.PressureDrop res_22(
    m_flow_nominal=5,
    dp_nominal=5,
    redeclare package Medium = Medium_A)
  Buildings.Fluid.FixedResistances.PressureDrop res_12(
    m_flow_nominal=5,
    dp_nominal=5,
    redeclare package Medium = Medium_W)
  Buildings.Fluid.HeatExchangers.BaseClasses.HexElementSensible hex(
    m1_flow_nominal=5,
    m2_flow_nominal=5,
    UA_nominal=9999,
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    dp1_nominal=5,
    dp2_nominal=5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Sources.Constant TDb1(k=303.15) "Drybulb temperature"
  Buildings.Fluid.FixedResistances.PressureDrop res_11(
    m_flow_nominal=5,
    dp_nominal=5,
    redeclare package Medium = Medium_W)
  Buildings.Fluid.FixedResistances.PressureDrop res_21(
    m_flow_nominal=5,
    dp_nominal=5,
    redeclare package Medium = Medium_A)
  Modelica.Blocks.Sources.Constant hACon(k=10000) "Convective heat transfer"
equation
  connect(TDb.y, sou_1.T_in)
  connect(POut.y, sin_1.p_in)
  connect(PIn.y, sou_2.p_in)
  connect(TWat.y, sou_2.T_in)
  connect(POut.y, sin_2.p_in)
  connect(hex.port_b1, res_12.port_a)
  connect(res_22.port_a, hex.port_b2)
  connect(TDb1.y, sin_2.T_in)
  connect(res_11.port_b, hex.port_a1)
  connect(hex.port_a2, res_21.port_b)
  connect(hACon.y, hex.Gc_1)
  connect(hACon.y, hex.Gc_2)
  connect(sou_2.ports[1], res_21.port_a)
  connect(sin_1.ports[1], res_12.port_b)
  connect(sou_1.ports[1], res_11.port_a)
  connect(sin_2.ports[1], res_22.port_b)
end HexElementSensible;


Test model for latent heat exchange

within Buildings.Fluid.HeatExchangers.BaseClasses.Examples;
model MassExchange "Test model for latent heat exchange"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  Buildings.Fluid.HeatExchangers.BaseClasses.MassExchange masExc(redeclare
      package Medium =
               Medium) "Model for mass exchange"
  Modelica.Blocks.Sources.Ramp TSur(
    duration=1,
    height=20,
    offset=273.15 + 5) "Surface temperature"
    Modelica.Blocks.Sources.Constant X_w(k=0.01)
    "Humidity mass fraction in medium"
    Modelica.Blocks.Sources.Constant Gc(k=1)
    "Sensible convective thermal conductance"
equation
  connect(TSur.y, masExc.TSur)
  connect(Gc.y, masExc.Gc)
  connect(X_w.y, masExc.XInf)
end MassExchange;


within Buildings.Fluid.HeatExchangers.BaseClasses;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for RayleighNumber

within Buildings.Fluid.HeatExchangers.BaseClasses.Examples;
model RayleighNumber "Test model for RayleighNumber"
  extends Modelica.Icons.Example;
  Buildings.Fluid.HeatExchangers.BaseClasses.RayleighNumber rayleighNumber(ChaLen=
        0.1, redeclare package Medium =
        Buildings.Media.Water)
  Modelica.Blocks.Sources.Sine TSur(
    amplitude=50,
    f=1/50,
    offset=273.15 + 50) "Temperature of the hot surface"
  Modelica.Blocks.Sources.Sine TFlu(
    amplitude=50,
    f=1/25,
    offset=273.15 + 50) "Temperature of the surrounding fluid"
equation
  connect(TSur.y, rayleighNumber.TSur)
  connect(TFlu.y, rayleighNumber.TFlu)
end RayleighNumber;


Cooling tower with constant approach temperature. Model for a steady-state or dynamic cooling tower with constant approach temperature.
The approach temperature is the difference between the leaving water temperature and
the entering air temperature.
The entering air temperature is used from the signal TAir. If
connected to the a dry-bulb temperature, then a dry cooling tower is modeled.
If connected to a wet-bulb temperature, then a wet cooling tower is modeled.

within Buildings.Fluid.HeatExchangers.CoolingTowers;
model FixedApproach "Cooling tower with constant approach temperature"
  extends Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.CoolingTower;

  parameter Modelica.Units.SI.TemperatureDifference TApp(
    min=0,
    displayUnit="K") = 2 "Approach temperature difference";
  Modelica.Blocks.Interfaces.RealInput TAir(min=0, unit="K")
    "Entering air dry or wet bulb temperature"

protected
  Modelica.Blocks.Sources.RealExpression QWat_flow(
    y = m_flow*(
      Medium.specificEnthalpy(Medium.setState_pTX(
      p=port_b.p,
      T=TAir + TApp,
      X=inStream(port_b.Xi_outflow))) - inStream(port_a.h_outflow)))
    "Heat input into water"
equation
  connect(QWat_flow.y, preHea.Q_flow)
end FixedApproach;


within Buildings.Fluid.HeatExchangers.CoolingTowers;
model Merkel "Cooling tower model based on Merkel's theory"
  extends
    Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.CoolingTowerVariableSpeed(
  final fanRelPowDer=
    Buildings.Utilities.Math.Functions.splineDerivatives(
      x=fanRelPow.r_V,
      y=fanRelPow.r_P,
      ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic(
        x=fanRelPow.r_P,
        strict=false)));

  final parameter Modelica.Units.SI.MassFlowRate mAir_flow_nominal=
      m_flow_nominal/ratWatAir_nominal "Nominal mass flow rate of air"

  parameter Real ratWatAir_nominal(min=0, unit="1") = 1.2
    "Water-to-air mass flow rate ratio at design condition"

  replaceable parameter Buildings.Fluid.HeatExchangers.CoolingTowers.Data.UAMerkel UACor
    constrainedby Buildings.Fluid.HeatExchangers.CoolingTowers.Data.UAMerkel
    "Coefficients for UA correction"

  final parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal(max=0) = per.Q_flow_nominal
    "Nominal heat transfer, (negative)";
  final parameter Modelica.Units.SI.ThermalConductance UA_nominal=per.UA_nominal
    "Thermal conductance at nominal flow, used to compute heat capacity";
  final parameter Real eps_nominal=per.eps_nominal
    "Nominal heat transfer effectiveness";
  final parameter Real NTU_nominal(min=0)=per.NTU_nominal
    "Nominal number of transfer units";

protected
  Modelica.Blocks.Sources.RealExpression TWatIn(
    final y=Medium.temperature(
      Medium.setState_phX(
        p=port_a.p,
        h=inStream(port_a.h_outflow),
        X=inStream(port_a.Xi_outflow))))
    "Water inlet temperature"
  Modelica.Blocks.Sources.RealExpression mWat_flow(final y=port_a.m_flow)
    "Water mass flow rate"

  Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Merkel per(
    redeclare final package Medium = Medium,
    final m_flow_nominal=m_flow_nominal,
    final ratWatAir_nominal=ratWatAir_nominal,
    final TAirInWB_nominal=TAirInWB_nominal,
    final TWatIn_nominal=TWatIn_nominal,
    final TWatOut_nominal=TWatOut_nominal,
    final fraFreCon=fraFreCon,
    final UACor = UACor,
    final yMin=yMin) "Model for thermal performance"

equation
  connect(per.y, y)
  connect(per.TAir, TAir)
  connect(per.Q_flow, preHea.Q_flow)
  connect(per.m_flow, mWat_flow.y)
  connect(TWatIn.y, per.TWatIn)
end Merkel;


Package with cooling tower models

within Buildings.Fluid.HeatExchangers;
package CoolingTowers "Package with cooling tower models"
  extends Modelica.Icons.VariantsPackage;
end CoolingTowers;


within Buildings.Fluid.HeatExchangers.CoolingTowers;
model YorkCalc
  "Cooling tower with variable speed using the York calculation for the approach temperature"
  extends
    Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.CoolingTowerVariableSpeed(
    TWatIn_nominal(fixed=false),
    TWatOut_nominal(fixed=false),
    fanRelPowDer(each fixed=false));

  parameter Modelica.Units.SI.TemperatureDifference TApp_nominal(displayUnit=
        "K") = 3.89 "Design approach temperature"
  parameter Modelica.Units.SI.TemperatureDifference TRan_nominal(displayUnit=
        "K") = 5.56 "Design range temperature (water in - water out)"

  Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.BoundsYorkCalc bou
    "Bounds for correlation";

  Modelica.Units.SI.TemperatureDifference TRan(displayUnit="K") = T_a - T_b
    "Range temperature";
  Modelica.Units.SI.TemperatureDifference TAppAct(displayUnit="K")=
    Buildings.Utilities.Math.Functions.spliceFunction(
    pos=TAppCor,
    neg=TAppFreCon,
    x=y - yMin + yMin/20,
    deltax=yMin/20) "Approach temperature difference";
  Modelica.Units.SI.MassFraction FRWat=m_flow/mWat_flow_nominal
    "Ratio actual over design water mass flow ratio";
  Modelica.Units.SI.MassFraction FRAir=y
    "Ratio actual over design air mass flow ratio";

protected
  package Water =  Buildings.Media.Water "Medium package for water";
  parameter Real FRWat0(min=0, start=1, fixed=false)
    "Ratio actual over design water mass flow ratio at nominal condition";
  parameter Modelica.Units.SI.MassFlowRate mWat_flow_nominal(
    min=0,
    start=m_flow_nominal,
    fixed=false) "Nominal water mass flow rate";

  Modelica.Units.SI.TemperatureDifference dTMax(displayUnit="K") = T_a - TAir
    "Maximum possible temperature difference";
  Modelica.Units.SI.TemperatureDifference TAppCor(
    min=0,
    displayUnit="K")=
    Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.yorkCalc(
    TRan=TRan,
    TWetBul=TAir,
    FRWat=FRWat,
    FRAir=Buildings.Utilities.Math.Functions.smoothMax(
      x1=FRWat/bou.liqGasRat_max,
      x2=FRAir,
      deltaX=0.01)) "Approach temperature for forced convection";
  Modelica.Units.SI.TemperatureDifference TAppFreCon(
    min=0,
    displayUnit="K") = (1 - fraFreCon)*dTMax + fraFreCon*
    Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.yorkCalc(
    TRan=TRan,
    TWetBul=TAir,
    FRWat=FRWat,
    FRAir=1) "Approach temperature for free convection";

  Modelica.Units.SI.Temperature T_a "Temperature in port_a";
  Modelica.Units.SI.Temperature T_b "Temperature in port_b";

  Modelica.Blocks.Sources.RealExpression QWat_flow(
    y = m_flow*(
      Medium.specificEnthalpy(Medium.setState_pTX(
        p=port_b.p,
        T=TAir + TAppAct,
        X=inStream(port_b.Xi_outflow))) -
      inStream(port_a.h_outflow)))
    "Heat input into water"
initial equation
  TWatOut_nominal = TAirInWB_nominal + TApp_nominal;
  TRan_nominal = TWatIn_nominal - TWatOut_nominal; // by definition of the range temp.
  TApp_nominal = Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.yorkCalc(
                   TRan=TRan_nominal, TWetBul=TAirInWB_nominal,
                   FRWat=FRWat0, FRAir=1); // this will be solved for FRWat0
  mWat_flow_nominal = m_flow_nominal/FRWat0;

  // Derivatives for spline that interpolates the fan relative power
  fanRelPowDer = Buildings.Utilities.Math.Functions.splineDerivatives(
            x=fanRelPow.r_V,
            y=fanRelPow.r_P,
            ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic(x=fanRelPow.r_P,
                                                                              strict=false));

  // Check that a medium is used that has the same definition of enthalpy vs. temperature.
  // This is needed because below, T_a=Water.temperature needed to be hard-coded to use
  // Water.* instead of Medium.* in the function calls due to a bug in OpenModelica.
  assert(abs(Medium.specificEnthalpy_pTX(p=101325, T=273.15, X=Medium.X_default) -
             Water.specificEnthalpy_pTX(p=101325, T=273.15, X=Medium.X_default)) < 1E-5 and
         abs(Medium.specificEnthalpy_pTX(p=101325, T=293.15, X=Medium.X_default) -
             Water.specificEnthalpy_pTX(p=101325, T=293.15, X=Medium.X_default)) < 1E-5,
         "The selected medium has an enthalpy computation that is not consistent
  with the one in Buildings.Media.Water
  Use a different medium, such as Buildings.Media.Water.");
equation
  // States at the inlet and outlet

  if allowFlowReversal then
    if homotopyInitialization then
      T_a=Water.temperature(Water.setState_phX(p=port_a.p,
                                 h=homotopy(actual=actualStream(port_a.h_outflow),
                                            simplified=inStream(port_a.h_outflow)),
                                 X=homotopy(actual=actualStream(port_a.Xi_outflow),
                                            simplified=inStream(port_a.Xi_outflow))));
      T_b=Water.temperature(Water.setState_phX(p=port_b.p,
                                 h=homotopy(actual=actualStream(port_b.h_outflow),
                                            simplified=port_b.h_outflow),
                                 X=homotopy(actual=actualStream(port_b.Xi_outflow),
                                            simplified=port_b.Xi_outflow)));

    else
      T_a=Water.temperature(Water.setState_phX(p=port_a.p,
                                 h=actualStream(port_a.h_outflow),
                                 X=actualStream(port_a.Xi_outflow)));
      T_b=Water.temperature(Water.setState_phX(p=port_b.p,
                                 h=actualStream(port_b.h_outflow),
                                 X=actualStream(port_b.Xi_outflow)));
    end if; // homotopyInitialization

  else // reverse flow not allowed
    T_a=Water.temperature(Water.setState_phX(p=port_a.p,
                               h=inStream(port_a.h_outflow),
                               X=inStream(port_a.Xi_outflow)));
    T_b=Water.temperature(Water.setState_phX(p=port_b.p,
                               h=inStream(port_b.h_outflow),
                               X=inStream(port_b.Xi_outflow)));
  end if;

  connect(QWat_flow.y, preHea.Q_flow)
end YorkCalc;


Base class for cooling towers. Base class for a steady-state cooling tower.
The variable TAirHT is used to compute the heat transfer with the water side of the cooling tower.
For a dry cooling tower, this is equal to the dry-bulb temperature.
For a wet cooling tower, this is equal to the wet-bulb temperature.

within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses;
partial model CoolingTower "Base class for cooling towers"
  extends Buildings.Fluid.Interfaces.TwoPortHeatMassExchanger(
    redeclare final Buildings.Fluid.MixingVolumes.MixingVolume vol);

  Modelica.Blocks.Interfaces.RealOutput TLvg(
    final unit="K",
    displayUnit="degC") "Leaving water temperature"
  Modelica.Units.SI.HeatFlowRate Q_flow=preHea.Q_flow
    "Heat input into water circuit";

protected
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea
    "Prescribed heat flow"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TVol
    "Water temperature in volume, leaving at port_b"

equation
  connect(preHea.port, vol.heatPort)
  connect(TVol.port, vol.heatPort)
  connect(TVol.T, TLvg)
end CoolingTower;


Base class for cooling towers with variable speed fan. Base model for a steady-state or dynamic cooling tower with a variable speed fan.
This base model is used for both the Merkel and York calculation.

within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses;
model CoolingTowerVariableSpeed "Base class for cooling towers with variable speed fan"
  extends Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.CoolingTower;

  import cha =
    Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Characteristics;

  parameter Modelica.Units.SI.Temperature TAirInWB_nominal=273.15 + 25.55
    "Nominal outdoor (air inlet) wetbulb temperature"
  parameter Modelica.Units.SI.Temperature TWatIn_nominal
    "Nominal water inlet temperature"
  parameter Modelica.Units.SI.Temperature TWatOut_nominal
    "Nominal water outlet temperature"

  parameter Real fraFreCon(min=0, max=1, final unit="1") = 0.125
    "Fraction of tower capacity in free convection regime"

  parameter Real fraPFan_nominal(unit="W/(kg/s)") = 275/0.15
    "Fan power divided by water mass flow rate at design condition"
  parameter Modelica.Units.SI.Power PFan_nominal=fraPFan_nominal*m_flow_nominal
    "Fan power"

  parameter Real yMin(min=0.01, max=1, final unit="1") = 0.3
    "Minimum control signal until fan is switched off (used for smoothing
    between forced and free convection regime)"

  replaceable parameter cha.fan fanRelPow(
       r_V = {0, 0.1,   0.3,   0.6,   1},
       r_P = {0, 0.1^3, 0.3^3, 0.6^3, 1})
    constrainedby cha.fan
    "Fan relative power consumption as a function of control signal, fanRelPow=P(y)/P(y=1)"

  Modelica.Blocks.Interfaces.RealInput TAir(
    final min=0,
    final unit="K",
    displayUnit="degC")
    "Entering air wet bulb temperature"

  Modelica.Blocks.Interfaces.RealInput y(unit="1") "Fan control signal"

  Modelica.Blocks.Interfaces.RealOutput PFan(
    final quantity="Power",
    final unit="W")=
    Buildings.Utilities.Math.Functions.spliceFunction(
        pos=cha.normalizedPower(per=fanRelPow, r_V=y, d=fanRelPowDer) * PFan_nominal,
        neg=0,
        x=y-yMin+yMin/20,
        deltax=yMin/20)
    "Electric power consumed by fan"

protected
  parameter Real fanRelPowDer[size(fanRelPow.r_V,1)]
    "Coefficients for fan relative power consumption as a function
    of control signal";

initial equation
  // Check validity of relative fan power consumption at y=yMin and y=1
  assert(cha.normalizedPower(per=fanRelPow, r_V=yMin, d=fanRelPowDer) > -1E-4,
    "The fan relative power consumption must be non-negative for y=0."
  + "\n   Obtained fanRelPow(0) = "
  + String(cha.normalizedPower(per=fanRelPow, r_V=yMin, d=fanRelPowDer))
  + "\n   You need to choose different values for the parameter fanRelPow.");
  assert(abs(1-cha.normalizedPower(per=fanRelPow, r_V=1, d=fanRelPowDer))<1E-4,
  "The fan relative power consumption must be one for y=1."
  + "\n   Obtained fanRelPow(1) = "
  + String(cha.normalizedPower(per=fanRelPow, r_V=1, d=fanRelPowDer))
  + "\n   You need to choose different values for the parameter fanRelPow."
  + "\n   To increase the fan power, change fraPFan_nominal or PFan_nominal.");
end CoolingTowerVariableSpeed;


within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses;
block Merkel "Model for thermal performance of Merkel cooling tower"
  extends Modelica.Blocks.Icons.Block;

  replaceable package Medium =
    Modelica.Media.Interfaces.PartialMedium "Medium in the component"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Nominal mass flow rate of water"

  final parameter Modelica.Units.SI.MassFlowRate mAir_flow_nominal=
      m_flow_nominal/ratWatAir_nominal "Nominal mass flow rate of air"

  parameter Real ratWatAir_nominal(min=0, unit="1")
    "Water-to-air mass flow rate ratio at design condition"

  parameter Modelica.Units.SI.Temperature TAirInWB_nominal
    "Nominal outdoor (air inlet) wetbulb temperature"
  parameter Modelica.Units.SI.Temperature TWatIn_nominal
    "Nominal water inlet temperature"
  parameter Modelica.Units.SI.Temperature TWatOut_nominal
    "Nominal water outlet temperature"

  parameter Real fraFreCon(min=0, max=1, final unit="1")
    "Fraction of tower capacity in free convection regime"

  replaceable parameter Buildings.Fluid.HeatExchangers.CoolingTowers.Data.UAMerkel UACor
    constrainedby Buildings.Fluid.HeatExchangers.CoolingTowers.Data.UAMerkel
    "Coefficients for UA correction"

  parameter Real yMin(min=0.01, max=1, final unit="1")
    "Minimum control signal until fan is switched off (used for smoothing
    between forced and free convection regime)"

  final parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal(max=0) = -
    m_flow_nominal*cpWat_nominal*(TWatIn_nominal - TWatOut_nominal)
    "Nominal heat transfer, (negative)";
  final parameter Modelica.Units.SI.ThermalConductance UA_nominal=NTU_nominal*
      CMin_flow_nominal
    "Thermal conductance at nominal flow, used to compute heat capacity";
  final parameter Real eps_nominal=
    Q_flow_nominal/((TAirInWB_nominal - TWatIn_nominal) * CMin_flow_nominal)
    "Nominal heat transfer effectiveness";
  final parameter Real NTU_nominal(min=0)=
      Buildings.Fluid.HeatExchangers.BaseClasses.ntu_epsilonZ(
      eps=min(1, max(0, eps_nominal)),
      Z=Z_nominal,
      flowRegime=Integer(Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow))
    "Nominal number of transfer units";

  Modelica.Blocks.Interfaces.RealInput y(unit="1") "Fan control signal"

  Modelica.Blocks.Interfaces.RealInput m_flow(final unit="kg/s")
   "Water mass flow rate"
  Modelica.Blocks.Interfaces.RealInput TWatIn(
    final min=0,
    final unit="K",
    displayUnit="degC")
    "Inlet water temperature"

  Modelica.Blocks.Interfaces.RealInput TAir(
    final min=0,
    final unit="K",
    displayUnit="degC")
    "Entering air wet bulb temperature"
  Modelica.Units.SI.Temperature TAirOut(displayUnit="degC")
    "Outlet air temperature";

  Modelica.Units.SI.MassFlowRate mAir_flow "Air mass flow rate";

  Modelica.Units.SI.MassFraction FRWat
    "Ratio actual over design water mass flow ratio";
  Modelica.Units.SI.MassFraction FRAir
    "Ratio actual over design air mass flow ratio";

  Real eps(min=0, max=1, unit="1") "Heat exchanger effectiveness";

  Modelica.Units.SI.SpecificHeatCapacity cpWat "Heat capacity of water";

  Modelica.Units.SI.ThermalConductance CAir_flow
    "Heat capacity flow rate of air";
  Modelica.Units.SI.ThermalConductance CWat_flow
    "Heat capacity flow rate of water";
  Modelica.Units.SI.ThermalConductance CMin_flow(min=0)
    "Minimum heat capacity flow rate";

  Modelica.Units.SI.HeatFlowRate QMax_flow "Maximum heat flow rate into air";

  Modelica.Units.SI.ThermalConductance UAe(min=0)
    "Thermal conductance for equivalent fluid";
  Modelica.Units.SI.ThermalConductance UA "Thermal conductance";

  Modelica.Blocks.Interfaces.RealOutput Q_flow "Heat removed from water"
protected
  final package Air = Buildings.Media.Air "Package of medium air";

  final parameter Air.ThermodynamicState staAir_default=Air.setState_pTX(
      T=TAirInWB_nominal,
      p=Air.p_default,
      X=Air.X_default[1:Air.nXi]) "Default state for air";
  final parameter Medium.ThermodynamicState
    staWat_default=Medium.setState_pTX(
      T=TWatIn_nominal,
      p=Medium.p_default,
      X=Medium.X_default[1:Medium.nXi]) "Default state for water";

  parameter Real delta=1E-3 "Parameter used for smoothing";

  parameter Modelica.Units.SI.SpecificHeatCapacity cpe_nominal=
      Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
      TIn=TAirInWB_nominal, TOut=TAirOutWB_nominal)
    "Specific heat capacity of the equivalent medium on medium 1 side";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpAir_nominal=
      Air.specificHeatCapacityCp(staAir_default)
    "Specific heat capacity of air at nominal condition";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpWat_nominal=
      Medium.specificHeatCapacityCp(staWat_default)
    "Specific heat capacity of water at nominal condition";

  parameter Modelica.Units.SI.ThermalConductance CAir_flow_nominal=
      mAir_flow_nominal*cpe_nominal "Nominal capacity flow rate of air";
  parameter Modelica.Units.SI.ThermalConductance CWat_flow_nominal=
      m_flow_nominal*cpWat_nominal "Nominal capacity flow rate of water";
  parameter Modelica.Units.SI.ThermalConductance CMin_flow_nominal=min(
      CAir_flow_nominal, CWat_flow_nominal)
    "Minimal capacity flow rate at nominal condition";
  parameter Modelica.Units.SI.ThermalConductance CMax_flow_nominal=max(
      CAir_flow_nominal, CWat_flow_nominal)
    "Maximum capacity flow rate at nominal condition";
  parameter Real Z_nominal(
    min=0,
    max=1) = CMin_flow_nominal/CMax_flow_nominal
    "Ratio of capacity flow rate at nominal condition";

  parameter Modelica.Units.SI.Temperature TAirOutWB_nominal(fixed=false)
    "Nominal leaving air wetbulb temperature";

  Real UA_FAir "UA correction factor as function of air flow ratio";
  Real UA_FWat "UA correction factor as function of water flow ratio";
  Real UA_DifWB
    "UA correction factor as function of differential wetbulb temperature";
  Real corFac_FAir "Smooth factor as function of air flow ratio";
  Real corFac_FWat "Smooth factor as function of water flow ratio";
  Modelica.Units.SI.SpecificHeatCapacity cpEqu
    "Specific heat capacity of the equivalent fluid";

initial equation
  // Heat transferred from air to water at nominal condition
  Q_flow_nominal = mAir_flow_nominal*cpe_nominal*(TAirInWB_nominal - TAirOutWB_nominal);

  assert(eps_nominal > 0 and eps_nominal < 1,
    "eps_nominal out of bounds, eps_nominal = " + String(eps_nominal) +
    "\n  To achieve the required heat transfer rate at epsilon=0.8, set |TAirInWB_nominal-TWatIn_nominal| = "
     + String(abs(Q_flow_nominal/0.8*CMin_flow_nominal)) +
    "\n  or increase flow rates. The current parameters result in " +
    "\n  CMin_flow_nominal = " + String(CMin_flow_nominal) +
    "\n  CMax_flow_nominal = " + String(CMax_flow_nominal));

equation
   // For cp water, we use the inlet temperatures because the effect is small
   // for actual water temperature differences, and in case of Buildings.Media.Water,
   // cp is constant.
  cpWat = Medium.specificHeatCapacityCp(Medium.setState_pTX(
    p=Medium.p_default,
    T=TWatIn,
    X=Medium.X_default));

  // Determine the airflow based on fan speed signal
  mAir_flow = Buildings.Utilities.Math.Functions.spliceFunction(
    pos=y*mAir_flow_nominal,
    neg=fraFreCon*mAir_flow_nominal,
    x=y - yMin + yMin/20,
    deltax=yMin/20);
  FRAir = mAir_flow/mAir_flow_nominal;
  FRWat = m_flow/m_flow_nominal;

  // UA for equivalent fluid
  // Adjust UA
  UA_FAir =Buildings.Fluid.Utilities.extendedPolynomial(
    x=FRAir,
    c=UACor.cAirFra,
    xMin=UACor.FRAirMin,
    xMax=UACor.FRAirMax)
    "UA correction factor as function of air flow fraction";
  UA_FWat =Buildings.Fluid.Utilities.extendedPolynomial(
    x=FRWat,
    c=UACor.cWatFra,
    xMin=UACor.FRWatMin,
    xMax=UACor.FRWatMax)
    "UA correction factor as function of water flow fraction";
  UA_DifWB =Buildings.Fluid.Utilities.extendedPolynomial(
    x=TAirInWB_nominal - TAir,
    c=UACor.cDifWB,
    xMin=UACor.TDiffWBMin,
    xMax=UACor.TDiffWBMax)
    "UA correction factor as function of differential wet bulb temperature";
  corFac_FAir =Buildings.Utilities.Math.Functions.smoothHeaviside(
    x=FRAir - UACor.FRAirMin/4,
    delta=UACor.FRAirMin/4);
  corFac_FWat =Buildings.Utilities.Math.Functions.smoothHeaviside(
    x=FRWat - UACor.FRWatMin/4,
    delta=UACor.FRWatMin/4);

  UA = UA_nominal*UA_FAir*UA_FWat*UA_DifWB*corFac_FAir*corFac_FWat;

  UAe = UA*cpEqu/Buildings.Utilities.Psychrometrics.Constants.cpAir;

  // Capacity for air and water
  CAir_flow =abs(mAir_flow)*cpEqu;
  CWat_flow =abs(m_flow)*cpWat;
  CMin_flow =Buildings.Utilities.Math.Functions.smoothMin(
    CAir_flow,
    CWat_flow,
    delta*CMin_flow_nominal);

  // Calculate epsilon
  eps = Buildings.Fluid.HeatExchangers.BaseClasses.epsilon_C(
    UA=UAe,
    C1_flow=CAir_flow,
    C2_flow=CWat_flow,
    flowRegime=Integer(Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow),
    CMin_flow_nominal=CMin_flow_nominal,
    CMax_flow_nominal=CMax_flow_nominal,
    delta=delta);
  // QMax_flow is maximum heat transfer into medium air: positive means heating
  QMax_flow = CMin_flow*(TWatIn - TAir);
  eps*QMax_flow =CAir_flow*(TAirOut - TAir);

  cpEqu =
    Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
      TIn=TAir,
      TOut=TAirOut);

  Q_flow = -eps * QMax_flow;
end Merkel;


within Buildings.Fluid.HeatExchangers.CoolingTowers;
package BaseClasses "Package with base classes for Buildings.Fluid.HeatExchangers.CoolingTowers"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Functions for fan characteristics

within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses;
package Characteristics "Functions for fan characteristics"
end Characteristics;


Validation model for the normalized power calculation. This model validates the computation of the normalized power
for a varying fan control signal.

within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Characteristics.Validation;
model NormalizedPower "Validation model for the normalized power calculation"
  extends Modelica.Icons.Example;
  parameter Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Characteristics.fan fanRelPow(
       r_V = {0, 0.1,   0.3,   0.6,   1},
       r_P = {0, 0.1^3, 0.3^3, 0.6^3, 1})
    "Fan data";
  final parameter Real fanRelPowDer[size(fanRelPow.r_V,1)](each fixed=false)
    "Coefficients for fan relative power consumption as a function of control signal";

  Real y "Control signal";
  Modelica.Units.SI.Efficiency r_P(max=1) "Normalized power consumption";

initial equation
  // Derivatives for spline that interpolates the fan relative power
  fanRelPowDer = Buildings.Utilities.Math.Functions.splineDerivatives(
            x=fanRelPow.r_V,
            y=fanRelPow.r_P,
            ensureMonotonicity=Buildings.Utilities.Math.Functions.isMonotonic(x=fanRelPow.r_P,
                                                                              strict=false));
equation
  y = time;
  r_P = Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Characteristics.normalizedPower(
    per=fanRelPow,
    r_V=y,
    d=fanRelPowDer);
end NormalizedPower;


within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Characteristics;
package Validation "Collection of models that validate the cooling tower models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


<html>
<p>
This package contains functions for calculations used in the cooling tower models.
</p>
</html>

within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses;
package Functions
end Functions;


Validation model for the equivalent heat capacity calculation. This model validates the computation of the equivalent heat capacity for five inlet temperature conditions and
variable changes in temperature between inlet and outlet airflows.

within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.Validation;
model EquivalentHeatCapacity
  "Validation model for the equivalent heat capacity calculation"
  extends Modelica.Icons.Example;

  Modelica.Units.SI.TemperatureDifference deltaT
    "Change in temperature of the air entering and leaving the cooling tower";

  Modelica.Units.SI.Temperature TIn[1,5]=[283.15,288.15,293.15,298.15,303.15]
    "Inlet temperatures";

  Modelica.Units.SI.Temperature TOut[1,5]=[TIn[1, 1] + deltaT,TIn[1, 2] +
      deltaT,TIn[1, 3] + deltaT,TIn[1, 4] + deltaT,TIn[1, 5] + deltaT]
    "Outlet temperatures";

  Modelica.Units.SI.SpecificHeatCapacity cpe10
    "Equivalent specific heat capacity with 10 degC inlet temperature";
  Modelica.Units.SI.SpecificHeatCapacity cpe15
    "Equivalent specific heat capacity with 15 degC inlet temperature";
  Modelica.Units.SI.SpecificHeatCapacity cpe20
    "Equivalent specific heat capacity with 20 degC inlet temperature";
  Modelica.Units.SI.SpecificHeatCapacity cpe25
    "Equivalent specific heat capacity with 25 degC inlet temperature";
  Modelica.Units.SI.SpecificHeatCapacity cpe30
    "Equivalent specific heat capacity with 30 degC inlet temperature";

protected
  constant Real con = 1 "Conversion factor to avoid warning because of unit missmatch";
equation
  deltaT = con*time;
  cpe10 = Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
    TIn = TIn[1,1], TOut = TOut[1,1]);
  cpe15 = Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
    TIn = TIn[1,2], TOut = TOut[1,2]);
  cpe20 = Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
    TIn = TIn[1,3], TOut = TOut[1,3]);
  cpe25 = Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
    TIn = TIn[1,4], TOut = TOut[1,4]);
  cpe30 = Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions.equivalentHeatCapacity(
    TIn = TIn[1,5], TOut = TOut[1,5]);
end EquivalentHeatCapacity;


within Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.Functions;
package Validation "Collection of models that validate the cooling tower base functions"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.Fluid.HeatExchangers.CoolingTowers;
package Correlations "Package with correlations for cooling tower performance"
  extends Modelica.Icons.MaterialProperty;
end Correlations;


within Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations;
package BaseClasses "Package with base classes for Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Example for yorkCalc correlation. Validation model that plots the approach temperature based on the York model for different
ratios of water and air flow rates.

within Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.Examples;
model YorkCalc "Example for yorkCalc correlation"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.TemperatureDifference TRan=5.56
    "Range temperature (water in - water out)";
  parameter Modelica.Units.SI.Temperature TAirInWB=25.55 + 273.15
    "Inlet air wet bulb temperature";
  Modelica.Units.SI.MassFraction x "Independent variable";
  Modelica.Units.SI.TemperatureDifference TApp_Wat
    "Approach temperature as a function of FRWat";
  Modelica.Units.SI.TemperatureDifference TApp_Air
    "Approach temperature as a function of FRAir";

equation
  x = 0.25+time;
  TApp_Wat=Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.yorkCalc(TRan=TRan,
                                                                    TWetBul=TAirInWB,
                                                                    FRWat=x,
                                                                    FRAir=1);
  TApp_Air=Buildings.Fluid.HeatExchangers.CoolingTowers.Correlations.yorkCalc(TRan=TRan,
                                                                    TWetBul=TAirInWB,
                                                                    FRWat=1,
                                                                    FRAir=x);
end YorkCalc;


Cooling tower performance data

within Buildings.Fluid.HeatExchangers.CoolingTowers;
package Data "Cooling tower performance data"
  extends Modelica.Icons.MaterialPropertiesPackage;
end Data;


UA correction factors for Merkel cooling towers. This data record contains the cooling tower performance data for

Buildings.Fluid.HeatExchangers.CoolingTowers.Merkel.
Similar to the CoolingTower:VariableSpeed:Merkel model in EnergyPlus,
Merkel's theory is modified to include Scheier's adjustment factors that
adjust UA values at off-design conditions. The three factors are:

within Buildings.Fluid.HeatExchangers.CoolingTowers.Data;
record UAMerkel "UA correction factors for Merkel cooling towers"
  extends Modelica.Icons.Record;

  parameter Real cDifWB[3]={1,0.0081,0}
    "Polynomial coefficients for correction of design wet bulb minus actual wet bulb temperature"
  parameter Real cAirFra[3]={0,1.3,-0.3}
    "Polynomial coefficients for correction for fractional air flow rate"
  parameter Real cWatFra[3]={0.1082,1.667,-0.7713}
    "Polynomial coefficients for correction for fractional water flow rate"

  parameter Real FRAirMin(min=0) = 0.2 "Minimum value for air flow fraction"
  parameter Real FRAirMax(min=0)= 1.0 "Maximum value for air flow fraction"
  parameter Real FRWatMin(min=0) = 0.3 "Minimum value for water flow fraction"
  parameter Real FRWatMax(min=0) = 1.0 "Maximum value for water flow fraction"

  // Range for the curves
  parameter Modelica.Units.SI.TemperatureDifference TDiffWBMin(
    max=0,
    displayUnit="K") = -10
    "Minimum value for leaving evaporator temperature difference"
  parameter Modelica.Units.SI.TemperatureDifference TDiffWBMax(
    min=0,
    displayUnit="K") = 25
    "Maximum value for leaving evaporator temperature difference"
end UAMerkel;


Test model for cooling tower with fixed approach temperature using the dry-bulb temperature. This example illustrates the use of the cooling tower model

Buildings.Fluid.HeatExchangers.CoolingTowers.FixedApproach, using
the outdoor dry-bulb temperature as the potential for heat transfer.
Heat is injected into the volume vol. An on/off controller
switches the cooling loop water pump on or off based on the temperature of
this volume.
The cooling tower outlet temperature has a fixed approach temperature to the
outdoor dry-bulb temperature.

within Buildings.Fluid.HeatExchangers.CoolingTowers.Examples;
model FixedApproachDryBulb
  "Test model for cooling tower with fixed approach temperature using the dry-bulb temperature"
  extends Modelica.Icons.Example;
  extends BaseClasses.PartialStaticTwoPortCoolingTower(
    redeclare CoolingTowers.FixedApproach tow(
        m_flow_nominal=m_flow_nominal),
    vol(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial));
equation
  connect(weaBus.TDryBul, tow.TAir)
end FixedApproachDryBulb;


Test model for cooling tower with fixed approach temperature using the wet-bulb temperature. This example illustrates the use of the cooling tower model

Buildings.Fluid.HeatExchangers.CoolingTowers.FixedApproach, using
the outdoor wet-bulb temperature as the potential for heat transfer.
Heat is injected into the volume vol. An on/off controller
switches the cooling loop water pump on or off based on the temperature of
this volume.
The cooling tower outlet temperature has a fixed approach temperature to the
outdoor wet-bulb temperature.

within Buildings.Fluid.HeatExchangers.CoolingTowers.Examples;
model FixedApproachWetBulb
  "Test model for cooling tower with fixed approach temperature using the wet-bulb temperature"
  extends Modelica.Icons.Example;
  extends BaseClasses.PartialStaticTwoPortCoolingTower(
    redeclare CoolingTowers.FixedApproach tow(
      m_flow_nominal=m_flow_nominal),
    weaDat(
      final computeWetBulbTemperature=true));
equation
  connect(weaBus.TWetBul, tow.TAir)
end FixedApproachWetBulb;


Test model for cooling tower using the Merkel theory. This example illustrates the use of the cooling tower model

Buildings.Fluid.HeatExchangers.CoolingTowers.Merkel.
Heat is injected into the volume vol. An on/off controller
switches the cooling loop water pump on or off based on the temperature of
this volume.
The cooling tower outlet temperature is controlled to track a fixed temperature.

within Buildings.Fluid.HeatExchangers.CoolingTowers.Examples;
model Merkel "Test model for cooling tower using the Merkel theory"
  extends Modelica.Icons.Example;
  extends BaseClasses.PartialStaticTwoPortCoolingTower(
    redeclare Buildings.Fluid.HeatExchangers.CoolingTowers.Merkel tow(
      ratWatAir_nominal=ratWatAir_nominal,
      TAirInWB_nominal=273.15 + 25.55,
      TWatIn_nominal=273.15 + 35,
      TWatOut_nominal=273.15 + 35 - 5.56,
      PFan_nominal=4800),
    weaDat(final computeWetBulbTemperature=true));

  parameter Real ratWatAir_nominal = 0.625
    "Design water-to-air ratio"

  Modelica.Blocks.Sources.Constant TSetLea(k=273.15 + 18)
    "Setpoint for leaving temperature"

  Buildings.Controls.OBC.CDL.Reals.PID conFan(
    k=1,
    Ti=60,
    Td=10,
    reverseActing=false,
    u_s(unit="K", displayUnit="degC"),
    u_m(unit="K", displayUnit="degC")) "Controller for tower fan"

equation
  connect(TSetLea.y, conFan.u_s)
  connect(conFan.y, tow.y)
  connect(tow.TLvg, conFan.u_m)
  connect(weaBus.TWetBul, tow.TAir)
end Merkel;


within Buildings.Fluid.HeatExchangers.CoolingTowers;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for cooling tower using the York performance correlation. This example illustrates the use of the cooling tower model

Buildings.Fluid.HeatExchangers.CoolingTowers.YorkCalc.
Heat is injected into the volume vol. An on/off controller
switches the cooling loop water pump on or off based on the temperature of
this volume.
The cooling tower outlet temperature is controlled to track a fixed temperature.

within Buildings.Fluid.HeatExchangers.CoolingTowers.Examples;
model YorkCalc
  "Test model for cooling tower using the York performance correlation"
  extends Modelica.Icons.Example;
  extends BaseClasses.PartialStaticTwoPortCoolingTower(
    redeclare CoolingTowers.YorkCalc tow,
    weaDat(
      final computeWetBulbTemperature=true));

  Modelica.Blocks.Sources.Constant TSetLea(k=273.15 + 18)
    "Setpoint for leaving temperature"
  Controls.Continuous.LimPID conFan(
    k=1,
    Ti=60,
    Td=10,
    reverseActing=false,
    initType=Modelica.Blocks.Types.Init.InitialState)
    "Controller for tower fan"
equation
  connect(TSetLea.y, conFan.u_s)
  connect(conFan.y, tow.y)
  connect(tow.TLvg, conFan.u_m)
  connect(weaBus.TWetBul, tow.TAir)
end YorkCalc;


within Buildings.Fluid.HeatExchangers.CoolingTowers.Examples;
package BaseClasses "Package with base classes for Buildings.Fluid.HeatExchangers.CoolingTowers.Examples"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.Fluid.HeatExchangers.CoolingTowers.Examples.BaseClasses;
partial model PartialStaticTwoPortCoolingTower
  "Base class for test models of cooling towers"

  package Medium_W = Buildings.Media.Water "Medium model for water";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.5
    "Design water flow rate"

  replaceable
    Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.CoolingTower tow
     constrainedby
    Buildings.Fluid.HeatExchangers.CoolingTowers.BaseClasses.CoolingTower(
    redeclare package Medium = Medium_W,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=6000,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    show_T=true) "Cooling tower"

  Buildings.Fluid.Movers.FlowControlled_m_flow pum(
    redeclare package Medium = Medium_W,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nominalValuesDefineDefaultPressureCurve=true)
    "Pump for condenser water loop"

  Buildings.BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
    Modelica.Utilities.Files.loadResource(
      "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))

  Buildings.BoundaryConditions.WeatherData.Bus weaBus "Weather data bus"

  Modelica.Blocks.Logical.OnOffController onOffCon(
    bandwidth=2,
    reference(
      unit="K",
      displayUnit="degC"),
    u(unit="K",
      displayUnit="degC"))
    "On/off controller"

  Modelica.Blocks.Logical.Switch swi "Control switch for chilled water pump"

  Modelica.Blocks.Sources.Constant TSwi(k=273.15 + 22)
    "Switch temperature for switching tower pump on"

  Modelica.Blocks.Sources.Constant zer(k=0) "Zero flow rate"

  Modelica.Blocks.Sources.Constant m_flow(k=m_flow_nominal)
    "Water flow rate"

  Buildings.Fluid.MixingVolumes.MixingVolume vol(nPorts=3,
    redeclare package Medium = Medium_W,
    m_flow_nominal=m_flow_nominal,
    V=0.5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)

  Buildings.Fluid.Sources.Boundary_pT exp(
    redeclare package Medium = Medium_W,
    nPorts=1) "Expansion vessel"

  Modelica.Thermal.HeatTransfer.Sources.FixedHeatFlow fixHeaFlo(
    Q_flow=0.5*m_flow_nominal*4200*5) "Fixed heat flow rate"

  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TVol
    "Water temperature"

  Buildings.Fluid.Sensors.TemperatureTwoPort TEnt(
    redeclare package Medium = Medium_W,
    m_flow_nominal=m_flow_nominal)
    "Water entering temperature"
equation
  connect(weaDat.weaBus, weaBus)
  connect(onOffCon.y, swi.u2)
  connect(zer.y, swi.u3)
  connect(m_flow.y, swi.u1)
  connect(vol.ports[1], pum.port_a)
  connect(fixHeaFlo.port, vol.heatPort)
  connect(vol.heatPort, TVol.port)
  connect(tow.port_b, vol.ports[2])
  connect(onOffCon.u, TSwi.y)
  connect(TVol.T, onOffCon.reference)
  connect(swi.y, pum.m_flow_in)
  connect(exp.ports[1], vol.ports[3])

  connect(pum.port_b, TEnt.port_a)
  connect(TEnt.port_b, tow.port_a)
end PartialStaticTwoPortCoolingTower;


within Buildings.Fluid.HeatExchangers.CoolingTowers.Validation;
model MerkelEnergyPlus
  "Validation with EnergyPlus model for Merkel's cooling tower"
  extends Modelica.Icons.Example;

  package MediumAir = Buildings.Media.Air "Air medium model";
  package MediumWat = Buildings.Media.Water "Water medium model";

  parameter Modelica.Units.SI.Density denWat=MediumWat.density(
      MediumWat.setState_pTX(
      MediumWat.p_default,
      MediumWat.T_default,
      MediumWat.X_default)) "Default density of water";

  // Cooling tower parameters
  parameter Modelica.Units.SI.PressureDifference dp_nominal=6000
    "Nominal pressure difference of cooling tower";
  parameter Modelica.Units.SI.VolumeFlowRate VWat_flow_nominal=0.00109181
    "Nominal volumetric flow rate of water (medium 2)";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=VWat_flow_nominal*
      denWat "Nominal mass flow rate of water (medium 2)";
  parameter Real ratWatAir_nominal = 1.61599
    "Nominal water-to-air ratio";
  parameter Modelica.Units.SI.Temperature TAirInWB_nominal=18.85 + 273.15
    "Nominal outdoor wetbulb temperature";
  parameter Modelica.Units.SI.Temperature TWatIn_nominal=34.16 + 273.15
    "Nominal water inlet temperature";
  parameter Modelica.Units.SI.Temperature TWatOut_initial=33.019 + 273.15
    "Nominal water inlet temperature";
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal=-20286.37455
    "Nominal heat transfer, positive";
  parameter Modelica.Units.SI.ThermalConductance UA_nominal_EP=2011.28668
    "Nominal heat transfer, positive";
  parameter Modelica.Units.SI.Power PFan_nominal=213.00693 "Nominal fan power";

  parameter Real r_VEnePlu[:] = {0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1}
    "Fan control signal";
  parameter Real r_PEnePlu[:] = {0,0.020982275,0.027843038,0.046465108,
    0.082729139,0.142515786,0.231705701,0.356179538,0.521817952,0.734501596,1}
    "Fan power output as a function of the signal";

  Modelica.Blocks.Sources.CombiTimeTable datRea(
    tableOnFile=true,
    fileName=ModelicaServices.ExternalReferences.loadResource(
      "modelica://Buildings//Resources/Data/Fluid/HeatExchangers/CoolingTowers/Validation/MerkelEnergyPlus/CoolingTower_VariableSpeed_Merkel.dat"),
    verboseRead=false,
    columns=2:10,
    tableName="EnergyPlus",
    smoothness=Modelica.Blocks.Types.Smoothness.ConstantSegments)
    "Reader for \"CoolingTower_VariableSpeed_Merkel.idf\" energy plus example results"

  Buildings.Fluid.HeatExchangers.CoolingTowers.Merkel tow(
    redeclare package Medium = MediumWat,
    dp_nominal=dp_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=TWatOut_initial,
    m_flow_nominal=m_flow_nominal,
    ratWatAir_nominal=ratWatAir_nominal,
    TAirInWB_nominal=TAirInWB_nominal,
    TWatIn_nominal=TWatIn_nominal,
    TWatOut_nominal=TWatIn_nominal+Q_flow_nominal/(m_flow_nominal*Buildings.Utilities.Psychrometrics.Constants.cpWatLiq),
    PFan_nominal=PFan_nominal,
    yMin=0.1,
    fraFreCon=0.1,
    fanRelPow(r_V=r_VEnePlu, r_P=r_PEnePlu),
    UACor(FRAirMin=0.2)) "Merkel-theory based cooling tower"

  Sources.MassFlowSource_T souWat(
    redeclare package Medium = MediumWat,
    use_m_flow_in=true,
    T=328.15,
    nPorts=1,
    use_T_in=true)
    "Water source to the cooling tower"

  Sources.Boundary_pT sinWat(redeclare package Medium = MediumWat,nPorts=1)
    "Water sink from the cooling tower"

  Controls.OBC.UnitConversions.From_degC TEntWat
    "Block that converts entering water temperature"

  Controls.OBC.UnitConversions.From_degC TAirWB
    "Block that converts entering air wetbulb temperature"

  Modelica.Blocks.Sources.RealExpression TLvg_EP(y=datRea.y[4])
    "EnergyPlus results: cooling tower leaving water temperature"

  Modelica.Blocks.Sources.RealExpression Q_flow_EP(y=-1*datRea.y[6])
    "EnergyPlus results: cooling tower heat flow rate"

  Modelica.Blocks.Sources.RealExpression PFan_EP(y=datRea.y[7])
    "EnergyPlus results: fan power consumption"

equation
  connect(tow.TAir, TAirWB.y)
  connect(souWat.ports[1], tow.port_a)
  connect(tow.port_b, sinWat.ports[1])
  connect(TEntWat.y, souWat.T_in)
  connect(datRea.y[2], TAirWB.u)
  connect(TEntWat.u, datRea.y[3])
  connect(souWat.m_flow_in, datRea.y[5])
  connect(tow.y, datRea.y[9])
end MerkelEnergyPlus;


Collection of validation models

within Buildings.Fluid.HeatExchangers.CoolingTowers;
package Validation "Collection of validation models"
    extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.Fluid.HeatExchangers.Examples;
model AirHeater_T
  "Example model for the heater with prescribed outlet temperature and air as the medium"
  extends Modelica.Icons.Example;
  extends Buildings.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = Buildings.Media.Air,
    m_flow_nominal=V*1.2*6/3600,
    Q_flow_nominal=30*6*6,
    mov(dp_nominal=1200, nominalValuesDefineDefaultPressureCurve=true));

  Heater_T hea(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=1000,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    QMax_flow=Q_flow_nominal) "Heater"

  Controls.SetPoints.Table tab(table=[0,273.15 + 15; 1,273.15 + 30])
    "Temperature set point"
equation
  connect(hea.port_b, THeaOut.port_a)
  connect(conPI.y, tab.u)
  connect(tab.y, hea.TSet)
  connect(mov.port_b, hea.port_a)
end AirHeater_T;


within Buildings.Fluid.HeatExchangers.Examples;
model AirHeater_u
  "Example model for the heater with prescribed heat input and air as the medium"
  extends Modelica.Icons.Example;
  extends Buildings.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = Buildings.Media.Air,
    m_flow_nominal=V*1.2*6/3600,
    Q_flow_nominal=30*6*6,
    mov(nominalValuesDefineDefaultPressureCurve=true, dp_nominal=1200));

  HeaterCooler_u hea(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=1000,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=Q_flow_nominal) "Heater"
equation
  connect(hea.port_b, THeaOut.port_a)
  connect(conPI.y, hea.u)
  connect(mov.port_b, hea.port_a)
end AirHeater_u;


within Buildings.Fluid.HeatExchangers.Examples;
model DryCoilCounterFlowMassFlow
  "Model of a cooling coil that tests variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  DryCoilCounterFlow hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    show_T=true,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=Q_flow_nominal/Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)

  Sensors.RelativeHumidityTwoPort senRelHum(         redeclare package Medium =
        Medium2, m_flow_nominal=m2_flow_nominal)
equation
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_b1, sin_1.ports[1])
  connect(hex.port_a2, sou_2.ports[1])
  connect(senRelHum.port_a, hex.port_b2)
  connect(senRelHum.port_b, sin_2.ports[1])
end DryCoilCounterFlowMassFlow;


within Buildings.Fluid.HeatExchangers.Examples;
model DryCoilCounterFlowPControl
  "Model that demonstrates use of a heat exchanger without condensation and with feedback control"
  extends Modelica.Icons.Example;
  package Medium1 = Buildings.Media.Water;
  package Medium2 = Buildings.Media.Air;

  parameter Modelica.Units.SI.Temperature T_a1_nominal=5 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b1_nominal=10 + 273.15;
  parameter Modelica.Units.SI.Temperature T_a2_nominal=30 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b2_nominal=15 + 273.15;
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=0.1
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";
  Buildings.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    T=303.15)
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    T=T_a2_nominal,
    X={0.02,1 - 0.02},
    use_T_in=true,
    use_X_in=true,
    p(displayUnit="Pa") = 101325 + 300)
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_p_in=false,
    p=300000,
    T=293.15)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_T_in=true,
    p=300000 + 12000)
  Buildings.Fluid.FixedResistances.PressureDrop res_2(
    from_dp=true,
    redeclare package Medium = Medium2,
    dp_nominal=100,
    m_flow_nominal=m2_flow_nominal)
  Buildings.Fluid.FixedResistances.PressureDrop res_1(
    from_dp=true,
    redeclare package Medium = Medium1,
    dp_nominal=3000,
    m_flow_nominal=m1_flow_nominal)
  Buildings.Fluid.Sensors.TemperatureTwoPort temSen(redeclare package Medium =
               Medium2, m_flow_nominal=m2_flow_nominal)
  Buildings.Fluid.Actuators.Valves.TwoWayEqualPercentage val(
    redeclare package Medium = Medium1,
    m_flow_nominal=m1_flow_nominal,
    dpValve_nominal=6000) "Valve model"
  Modelica.Blocks.Sources.TimeTable TSet(table=[0,288.15; 600,288.15; 600,
        298.15; 1200,298.15; 1800,283.15; 2400,283.15; 2400,288.15])
    "Setpoint temperature"
  Buildings.Fluid.HeatExchangers.DryCoilCounterFlow hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal - T_b1_nominal)/
       Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Sources.Constant const(k=0.8)
  Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi(use_p_in=false)
  Modelica.Blocks.Sources.Constant const1(k=T_a2_nominal)
  Buildings.Controls.Continuous.LimPID con(
    Td=1,
    reverseActing=false,
    yMin=0,
    k=0.1,
    Ti=60) "Controller"
  Modelica.Blocks.Sources.Ramp TWat(
    height=30,
    offset=T_a1_nominal,
    startTime=300,
    duration=2000) "Water temperature, raised to high value at t=3000 s"
equation
  connect(hex.port_b1, res_1.port_a)
  connect(val.port_b, hex.port_a1)
  connect(sou_1.ports[1], val.port_a)
  connect(sin_1.ports[1], res_1.port_b)
  connect(sin_2.ports[1], res_2.port_b)
  connect(sou_2.ports[1], hex.port_a2)
  connect(temSen.port_b, res_2.port_a)
  connect(x_pTphi.X, sou_2.X_in)
  connect(const.y, x_pTphi.phi)
  connect(const1.y, x_pTphi.T)
  connect(const1.y, sou_2.T_in)
  connect(TSet.y, con.u_s)
  connect(temSen.T, con.u_m)
  connect(TWat.y, sou_1.T_in)
  connect(con.y, val.y)
  connect(temSen.port_a, hex.port_b2)
end DryCoilCounterFlowPControl;


within Buildings.Fluid.HeatExchangers.Examples;
model DryCoilDiscretized
  "Model that demonstrates use of a finite volume model of a heat exchanger without condensation"
  extends Modelica.Icons.Example;

  package Medium1 = Buildings.Media.Water;
  package Medium2 = Buildings.Media.Air;

  parameter Modelica.Units.SI.Temperature T_a1_nominal=60 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b1_nominal=40 + 273.15;
  parameter Modelica.Units.SI.Temperature T_a2_nominal=5 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b2_nominal=20 + 273.15;
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=5
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";

  Buildings.Fluid.HeatExchangers.DryCoilDiscretized hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    nPipPar=1,
    nPipSeg=3,
    nReg=2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal-T_b1_nominal)/
      Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    dp2_nominal=200,
    dp1_nominal=5000,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp1=true,
    from_dp2=true)
  Sources.MassFlowSource_T            sin_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_m_flow_in=true,
    T=303.15)
    Modelica.Blocks.Sources.Ramp PIn(
    offset=101525,
    height=-199,
    duration=60,
    startTime=120)
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    use_p_in=true,
    use_T_in=true,
    T=283.15,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp TWat(
    duration=60,
    startTime=60,
    height=5,
    offset=273.15 + 60) "Water temperature"
  Modelica.Blocks.Sources.Constant TDb(k=273.15 + 5) "Drybulb temperature"
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    p=300000,
    T=293.15,
    use_p_in=true,
    nPorts=1)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    use_T_in=true,
    T=293.15,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp PSin_1(
    startTime=240,
    offset=300000,
    height=4990,
    duration=60)
    Modelica.Blocks.Sources.Ramp m_flow_2(
    duration=60,
    startTime=120,
    height=28 - 0.124,
    offset=-28) "Mass flow rate on air side"
equation
  connect(PIn.y,sou_2. p_in)
  connect(TDb.y, sou_2.T_in)
  connect(TWat.y, sou_1.T_in)
  connect(PSin_1.y, sin_1.p_in)
  connect(sou_1.ports[1], hex.port_a1)
  connect(sou_2.ports[1], hex.port_a2)
  connect(sin_2.ports[1], hex.port_b2)
  connect(hex.port_b1, sin_1.ports[1])
  connect(m_flow_2.y, sin_2.m_flow_in)
end DryCoilDiscretized;


within Buildings.Fluid.HeatExchangers.Examples;
model DryCoilDiscretizedPControl
  "Model that demonstrates use of a finite volume model of a heat exchanger without condensation and with feedback control"
  extends Modelica.Icons.Example;

  package Medium1 = Buildings.Media.Water "Medium model for water";
  package Medium2 = Buildings.Media.Air "Medium model for air";
  parameter Modelica.Units.SI.Temperature T_a1_nominal=60 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b1_nominal=50 + 273.15;
  parameter Modelica.Units.SI.Temperature T_a2_nominal=20 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b2_nominal=40 + 273.15;
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=5
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";

  Sources.MassFlowSource_T            sin_2(                       redeclare
      package Medium = Medium2,
    nPorts=1,
    m_flow=-10.5,
    T=303.15)
  Buildings.Fluid.Sources.Boundary_pT sou_2(                       redeclare
      package Medium = Medium2,
    nPorts=1,
    use_p_in=false,
    use_T_in=false,
    p(displayUnit="Pa") = 101625,
    T=T_a2_nominal)
  Buildings.Fluid.Sources.Boundary_pT sin_1(                       redeclare
      package Medium = Medium1,
    p=300000,
    T=293.15,
    use_p_in=true,
    nPorts=1)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 9000,
    nPorts=1,
    use_T_in=false,
    T=T_a1_nominal)
    Modelica.Blocks.Sources.Ramp PSin_1(
    duration=60,
    height=5000,
    startTime=240,
    offset=300000)
  Buildings.Fluid.Sensors.TemperatureTwoPort temSen(redeclare package Medium =
        Medium2, m_flow_nominal=m2_flow_nominal)
  Buildings.Fluid.Actuators.Valves.TwoWayEqualPercentage val(
    redeclare package Medium = Medium1,
    l=0.005,
    m_flow_nominal=m1_flow_nominal,
    use_strokeTime=false,
    dpFixed_nominal=2000 + 3000,
    dpValve_nominal=6000) "Valve model"
  Modelica.Blocks.Sources.TimeTable TSet(table=[0,298.15; 600,298.15; 600,
        303.15; 1200,303.15; 1800,298.15; 2400,298.15; 2400,304.15])
    "Setpoint temperature"
  Buildings.Fluid.HeatExchangers.DryCoilDiscretized hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    show_T=true,
    nPipPar=1,
    nPipSeg=3,
    nReg=4,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal-T_b1_nominal)/
      Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    dp1_nominal(displayUnit="Pa") = 0,
    dp2_nominal(displayUnit="Pa") = 300,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp1=true,
    from_dp2=true)
  Buildings.Fluid.Actuators.Motors.IdealMotor mot(tOpe=60) "Motor model"
  Buildings.Controls.Continuous.LimPID con(
    k=1,
    Ti=60,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    Td=60) "Controller"
equation
  connect(PSin_1.y, sin_1.p_in)
  connect(val.port_b, hex.port_a1)
  connect(sou_1.ports[1], val.port_a)
  connect(sou_2.ports[1], hex.port_a2)
  connect(mot.y, val.y)
  connect(hex.port_b2, temSen.port_a)
  connect(TSet.y, con.u_s)
  connect(temSen.T, con.u_m)
  connect(con.y, mot.u)
  connect(hex.port_b1, sin_1.ports[1])
  connect(temSen.port_b, sin_2.ports[1])
end DryCoilDiscretizedPControl;


within Buildings.Fluid.HeatExchangers.Examples;
model DryCoilEffectivenessNTUMassFlow
  "Model of epsilon-NTU dry coil that tests variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  Buildings.Fluid.HeatExchangers.DryCoilEffectivenessNTU hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal(displayUnit="Pa") = 3000,
    Q_flow_nominal=Q_flow_nominal,
    T_a1_nominal=T_a1_nominal,
    T_a2_nominal=T_a2_nominal,
    show_T=true)

  Buildings.Fluid.Sensors.RelativeHumidityTwoPort senRelHum(
                                                     redeclare package Medium =
        Medium2, m_flow_nominal=m2_flow_nominal,
    initType=Modelica.Blocks.Types.Init.InitialState)
equation
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_b1, sin_1.ports[1])
  connect(hex.port_a2, sou_2.ports[1])
  connect(senRelHum.port_a, hex.port_b2)
  connect(senRelHum.port_b, sin_2.ports[1])
end DryCoilEffectivenessNTUMassFlow;


within Buildings.Fluid.HeatExchangers.Examples;
model DryCoilEffectivenessNTUPControl
  "Model that demonstrates use of a heat exchanger without condensation that uses the epsilon-NTU relation with feedback control"
  extends Modelica.Icons.Example;

 package Medium1 = Buildings.Media.Water "Medium model for water";
 package Medium2 = Buildings.Media.Air "Medium model for air";
  parameter Modelica.Units.SI.Temperature T_a1_nominal=60 + 273.15
    "Temperature at nominal conditions as port a1";
  parameter Modelica.Units.SI.Temperature T_b1_nominal=50 + 273.15
    "Temperature at nominal conditions as port b1";
  parameter Modelica.Units.SI.Temperature T_a2_nominal=20 + 273.15
    "Temperature at nominal conditions as port a2";
  parameter Modelica.Units.SI.Temperature T_b2_nominal=40 + 273.15
    "Temperature at nominal conditions as port b2";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=5
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";

  Buildings.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    T=303.15,
    nPorts=1) "Boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_p_in=false,
    use_T_in=false,
    p(displayUnit="Pa") = 101625,
    T=T_a2_nominal) "Boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=false,
    p=300000,
    T=293.15,
    nPorts=1) "Boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 9000,
    nPorts=1,
    use_T_in=false,
    T=T_a1_nominal)
    "Boundary condition"
  Buildings.Fluid.Sensors.TemperatureTwoPort temSen(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal)
    "Temperature sensor"
  Buildings.Fluid.Actuators.Valves.TwoWayEqualPercentage val(
    redeclare package Medium = Medium1,
    l=0.005,
    m_flow_nominal=m1_flow_nominal,
    dpFixed_nominal=2000 + 3000,
    dpValve_nominal=6000) "Valve"
  Buildings.Controls.Continuous.LimPID P(
    Ti=30,
    k=0.1,
    Td=1)
    "Controller"
  Modelica.Blocks.Sources.Pulse TSet(
    amplitude=5,
    period=3600,
    offset=273.15 + 22) "Temperature setpoint"
  Buildings.Fluid.HeatExchangers.DryCoilEffectivenessNTU hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    show_T=true,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    Q_flow_nominal=m1_flow_nominal*4200*(T_a1_nominal-T_b1_nominal),
    configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    T_a1_nominal=T_a1_nominal,
    T_a2_nominal=T_a2_nominal,
    dp1_nominal(displayUnit="Pa") = 0,
    dp2_nominal(displayUnit="Pa") = 200 + 100)
    "Heat exchanger"

equation
  connect(val.port_b, hex.port_a1)
  connect(sou_1.ports[1], val.port_a)
  connect(sou_2.ports[1], hex.port_a2)
  connect(hex.port_b2, temSen.port_a)
  connect(TSet.y, P.u_s)
  connect(temSen.T, P.u_m)
  connect(P.y, val.y)
  connect(hex.port_b1, sin_1.ports[1])
  connect(temSen.port_b, sin_2.ports[1])
end DryCoilEffectivenessNTUPControl;


within Buildings.Fluid.HeatExchangers;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within Buildings.Fluid.HeatExchangers.Examples;
model PlateHeatExchangerEffectivenessNTUPControl
  "Model that demonstrates use of a plate heat exchanger without condensation that uses the epsilon-NTU relation with feedback control"
  extends Modelica.Icons.Example;

 package Medium1 = Buildings.Media.Water "Medium model for water";
 package Medium2 = Buildings.Media.Water "Medium model for water";
  parameter Modelica.Units.SI.Temperature T_a1_nominal=60 + 273.15
    "Temperature at nominal conditions as port a1";
  parameter Modelica.Units.SI.Temperature T_b1_nominal=50 + 273.15
    "Temperature at nominal conditions as port b1";
  parameter Modelica.Units.SI.Temperature T_a2_nominal=20 + 273.15
    "Temperature at nominal conditions as port a2";
  parameter Modelica.Units.SI.Temperature T_b2_nominal=40 + 273.15
    "Temperature at nominal conditions as port b2";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=0.01
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*(
      T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";

  Buildings.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    use_p_in=false,
    p(displayUnit="Pa") = 300000,
    T=303.15,
    nPorts=1) "Boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_p_in=false,
    use_T_in=false,
    p(displayUnit="Pa") = 305000,
    T=T_a2_nominal) "Boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=false,
    p=300000,
    T=293.15,
    nPorts=1) "Boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 9000,
    nPorts=1,
    use_T_in=false,
    T=T_a1_nominal)
    "Boundary condition"
  Buildings.Fluid.Sensors.TemperatureTwoPort temSen(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal)
    "Temperature sensor"
  Buildings.Fluid.Actuators.Valves.TwoWayEqualPercentage val(
    redeclare package Medium = Medium1,
    l=0.005,
    m_flow_nominal=m1_flow_nominal,
    dpFixed_nominal=2000 + 3000,
    dpValve_nominal=6000) "Valve"
  Buildings.Controls.Continuous.LimPID P(
    Ti=30,
    k=0.1,
    Td=1)
    "Controller"
  Modelica.Blocks.Sources.Pulse TSet(
    amplitude=5,
    period=3600,
    offset=273.15 + 22) "Temperature setpoint"
  Buildings.Fluid.HeatExchangers.PlateHeatExchangerEffectivenessNTU hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    show_T=true,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    dp1_nominal(displayUnit="Pa") = 0,
    dp2_nominal(displayUnit="Pa") = 3000,
    use_Q_flow_nominal=false,
    eps_nominal=0.5)
    "Heat exchanger"

equation
  connect(val.port_b, hex.port_a1)
  connect(sou_1.ports[1], val.port_a)
  connect(sou_2.ports[1], hex.port_a2)
  connect(hex.port_b2, temSen.port_a)
  connect(TSet.y, P.u_s)
  connect(temSen.T, P.u_m)
  connect(P.y, val.y)
  connect(hex.port_b1, sin_1.ports[1])
  connect(temSen.port_b, sin_2.ports[1])
end PlateHeatExchangerEffectivenessNTUPControl;


within Buildings.Fluid.HeatExchangers.Examples;
model WaterCooler_T
  "Example model for the sensible cooler with prescribed outlet temperature and water as the medium"
  extends Modelica.Icons.Example;
  extends Buildings.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = Buildings.Media.Water,
    m_flow_nominal=V*1000/3600,
    Q_flow_nominal=1000,
    vol(V=V/1000),
    mov(nominalValuesDefineDefaultPressureCurve=true),
    TOut(y=273.15 + 22 - 5*cos(time/86400*2*Modelica.Constants.pi)));

  SensibleCooler_T coo(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=1000,
    T_start=289.15,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    QMin_flow=-Q_flow_nominal) "Cooler"

  Controls.SetPoints.Table tab(table=[
    0, 273.15 + 10;
    1, 273.15 + 30])
    "Table to compute temperature set points"
equation
  connect(coo.port_b, THeaOut.port_a)
  connect(conPI.y, tab.u)
  connect(tab.y,coo. TSet)
  connect(mov.port_b,coo. port_a)
end WaterCooler_T;


within Buildings.Fluid.HeatExchangers.Examples;
model WaterHeater_T
  "Example model for the heater with prescribed outlet temperature and water as the medium"
  extends Modelica.Icons.Example;
  extends Buildings.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = Buildings.Media.Water,
    m_flow_nominal=V*1000/3600,
    Q_flow_nominal=100,
    vol(V=V/1000),
    mov(nominalValuesDefineDefaultPressureCurve=true));

  Heater_T hea(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=1000,
    T_start=289.15,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    QMax_flow=Q_flow_nominal) "Heater"
  Controls.SetPoints.Table tab(table=[0,273.15 + 10; 1,273.15 + 30])
equation
  connect(hea.port_b, THeaOut.port_a)
  connect(conPI.y, tab.u)
  connect(tab.y, hea.TSet)
  connect(mov.port_b, hea.port_a)
end WaterHeater_T;


within Buildings.Fluid.HeatExchangers.Examples;
model WaterHeater_u
  "Example model for the heater with prescribed heat input and water as the medium"
  extends Modelica.Icons.Example;
  extends Buildings.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = Buildings.Media.Water,
    m_flow_nominal=V*1000/3600,
    Q_flow_nominal=100,
    conPI(k=10),
    vol(V=V/1000),
    mov(nominalValuesDefineDefaultPressureCurve=true));

  HeaterCooler_u hea(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=1000,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=289.15,
    Q_flow_nominal=10*Q_flow_nominal) "Heater"
equation
  connect(hea.port_b, THeaOut.port_a)
  connect(conPI.y, hea.u)
  connect(mov.port_b, hea.port_a)
end WaterHeater_u;


within Buildings.Fluid.HeatExchangers.Examples;
model WetCoilCounterFlowMassFlow
  "Model of a cooling coil that tests variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  WetCoilCounterFlow hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=Q_flow_nominal/Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)

  Sensors.RelativeHumidityTwoPort senRelHum(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal)
equation
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_b1, sin_1.ports[1])
  connect(hex.port_a2, sou_2.ports[1])
  connect(hex.port_b2, senRelHum.port_a)
  connect(senRelHum.port_b, sin_2.ports[1])
end WetCoilCounterFlowMassFlow;


within Buildings.Fluid.HeatExchangers.Examples;
model WetCoilCounterFlowPControl
  "Model that demonstrates use of a heat exchanger with condensation and with feedback control"
  extends Modelica.Icons.Example;
  package Medium1 = Buildings.Media.Water;
  package Medium2 = Buildings.Media.Air;
  parameter Modelica.Units.SI.Temperature T_a1_nominal=5 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b1_nominal=10 + 273.15;
  parameter Modelica.Units.SI.Temperature T_a2_nominal=30 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b2_nominal=15 + 273.15;
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=0.1
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=0.2*m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";
  Buildings.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_p_in=false,
    p(displayUnit="Pa") = 101325,
    T=303.15)
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    T=T_a2_nominal,
    X={0.02,1 - 0.02},
    use_T_in=true,
    use_X_in=true,
    p(displayUnit="Pa") = 101325 + 300)
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_p_in=false,
    p=300000,
    T=293.15)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_T_in=true,
    p=300000 + 12000)
  Buildings.Fluid.FixedResistances.PressureDrop res_2(
    from_dp=true,
    redeclare package Medium = Medium2,
    dp_nominal=100,
    m_flow_nominal=m2_flow_nominal)
  Buildings.Fluid.FixedResistances.PressureDrop res_1(
    from_dp=true,
    redeclare package Medium = Medium1,
    dp_nominal=3000,
    m_flow_nominal=m1_flow_nominal)
  Buildings.Fluid.Sensors.TemperatureTwoPort temSen(redeclare package Medium =
               Medium2, m_flow_nominal=m2_flow_nominal)
  Buildings.Fluid.Actuators.Valves.TwoWayEqualPercentage val(
    redeclare package Medium = Medium1,
    m_flow_nominal=m1_flow_nominal,
    dpValve_nominal=6000) "Valve model"
  Modelica.Blocks.Sources.TimeTable TSet(table=[0,288.15; 600,288.15; 600,
        298.15; 1200,298.15; 1800,283.15; 2400,283.15; 2400,288.15])
    "Setpoint temperature"
  Buildings.Fluid.HeatExchangers.WetCoilCounterFlow hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=2*m1_flow_nominal*4200*(T_a1_nominal - T_b1_nominal)/
      Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Sources.Constant const(k=0.8)
  Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi(use_p_in=false)
  Modelica.Blocks.Sources.Constant const1(k=T_a2_nominal)
  Buildings.Controls.Continuous.LimPID con(
    Td=1,
    reverseActing=false,
    yMin=0,
    k=0.1,
    Ti=60) "Controller"
  Modelica.Blocks.Sources.Ramp TWat(
    height=5,
    offset=T_a1_nominal,
    startTime=300,
    duration=2000) "Water temperature, raised to high value at t=3000 s"
equation
  connect(hex.port_b1, res_1.port_a)
  connect(val.port_b, hex.port_a1)
  connect(sou_1.ports[1], val.port_a)
  connect(sin_1.ports[1], res_1.port_b)
  connect(sin_2.ports[1], res_2.port_b)
  connect(sou_2.ports[1], hex.port_a2)
  connect(hex.port_b2, temSen.port_a)
  connect(temSen.port_b, res_2.port_a)
  connect(x_pTphi.X, sou_2.X_in)
  connect(const.y, x_pTphi.phi)
  connect(const1.y, x_pTphi.T)
  connect(const1.y, sou_2.T_in)
  connect(TSet.y, con.u_s)
  connect(temSen.T, con.u_m)
  connect(TWat.y, sou_1.T_in)
  connect(con.y, val.y)
end WetCoilCounterFlowPControl;


within Buildings.Fluid.HeatExchangers.Examples;
model WetCoilDiscretizedMassFlow
  "Model of a cooling coil that tests variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  WetCoilDiscretized hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    allowFlowReversal1=true,
    allowFlowReversal2=true,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=Q_flow_nominal/Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)

  Sensors.RelativeHumidityTwoPort senRelHum(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal,
    initType=Modelica.Blocks.Types.Init.SteadyState)

equation
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_b1, sin_1.ports[1])
  connect(hex.port_a2, sou_2.ports[1])
  connect(hex.port_b2, senRelHum.port_a)
  connect(senRelHum.port_b, sin_2.ports[1])
end WetCoilDiscretizedMassFlow;


within Buildings.Fluid.HeatExchangers.Examples;
model WetCoilDiscretizedPControl
  "Model that demonstrates use of a finite volume model of a heat exchanger with condensation and feedback control"
  extends Modelica.Icons.Example;

  package Medium1 = Buildings.Media.Water;
  package Medium2 = Buildings.Media.Air;

  parameter Modelica.Units.SI.Temperature T_a1_nominal=5 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b1_nominal=10 + 273.15;
  parameter Modelica.Units.SI.Temperature T_a2_nominal=30 + 273.15;
  parameter Modelica.Units.SI.Temperature T_b2_nominal=10 + 273.15;
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=5
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";

 Buildings.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    use_p_in=false,
    p=101325,
    T=303.15,
    nPorts=1)
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_p_in=false,
    use_T_in=true,
    p(displayUnit="Pa") = 101525,
    T=293.15)
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    p=300000,
    T=293.15,
    use_p_in=true,
    nPorts=1)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_T_in=true,
    p=300000 + 7000,
    T=278.15)
    Modelica.Blocks.Sources.Ramp PSin(
    duration=60,
    height=5000,
    startTime=240,
    offset=300000)
  Buildings.Fluid.Sensors.TemperatureTwoPort temSen(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal)
  Buildings.Fluid.Actuators.Valves.TwoWayLinear val(
    redeclare package Medium = Medium1,
    m_flow_nominal=m1_flow_nominal,
    use_strokeTime=false,
    dpFixed_nominal=2000,
    dpValve_nominal=5000)
  Modelica.Blocks.Sources.TimeTable TSet(table=[0,293.15; 600,293.15; 600,
        288.15; 1200,288.15; 1800,288.15; 2400,295.15; 2400,295.15])
    "Setpoint temperature"
  Buildings.Fluid.HeatExchangers.WetCoilDiscretized hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    show_T=true,
    nPipPar=1,
    nPipSeg=3,
    nReg=4,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal-T_b1_nominal)/
     Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    dp2_nominal(displayUnit="Pa") = 200,
    dp1_nominal(displayUnit="Pa") = 0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Sources.Step TSou_2(
    startTime=3000,
    offset=T_a2_nominal,
    height=-3)
  Modelica.Blocks.Sources.Step TSou_1(
    startTime=3000,
    height=10,
    offset=T_a1_nominal)
  Buildings.Controls.Continuous.LimPID con(
    k=1,
    Ti=60,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    Td=60,
    reverseActing=false) "Controller"
  Buildings.Fluid.Actuators.Motors.IdealMotor mot(tOpe=60) "Motor model"
equation
  connect(PSin.y, sin_1.p_in)
  connect(sou_2.ports[1], hex.port_a2)
  connect(hex.port_b2, temSen.port_a)
  connect(val.port_b, hex.port_a1)
  connect(sou_1.ports[1], val.port_a)
  connect(TSou_2.y, sou_2.T_in)
  connect(TSou_1.y, sou_1.T_in)
  connect(TSet.y, con.u_s)
  connect(temSen.T, con.u_m)
  connect(con.y, mot.u)
  connect(mot.y, val.y)
  connect(sin_2.ports[1], temSen.port_b)
  connect(hex.port_b1, sin_1.ports[1])
end WetCoilDiscretizedPControl;


within Buildings.Fluid.HeatExchangers.Examples;
model WetCoilEffectivenessNTUMassFlow
  "Model that tests the wet coil effectiveness-NTU model with variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  Buildings.Fluid.HeatExchangers.WetCoilEffectivenessNTU hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=Q_flow_nominal/Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
      T_a1_nominal,
      T_b1_nominal,
      T_a2_nominal,
      T_b2_nominal),
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Heat exchanger"

  Sensors.RelativeHumidityTwoPort senRelHum(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal)
    "Relative humidity sensor"

equation
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_b1, sin_1.ports[1])
  connect(hex.port_a2, sou_2.ports[1])
  connect(hex.port_b2, senRelHum.port_a)
  connect(senRelHum.port_b, sin_2.ports[1])
end WetCoilEffectivenessNTUMassFlow;


within Buildings.Fluid.HeatExchangers.Examples.BaseClasses;
partial model EffectivenessNTUMassFlow
  "Partial model of epsilon-NTU coil that tests variable mass flow rates"
  package Medium1 = Buildings.Media.Water "Medium model for water";
  package Medium2 = Buildings.Media.Air
    "Medium model for air";
  parameter Modelica.Units.SI.Temperature T_a1_nominal=5 + 273.15
    "Nominal water inlet temperature";
  parameter Modelica.Units.SI.Temperature T_b1_nominal=10 + 273.15
    "Nominal water outlet temperature";
  parameter Modelica.Units.SI.Temperature T_a2_nominal=30 + 273.15
    "Nominal air inlet temperature";
  parameter Modelica.Units.SI.Temperature T_b2_nominal=15 + 273.15
    "Nominal air outlet temperature";
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal=m1_flow_nominal*4200*
      (T_a1_nominal - T_b1_nominal) "Nominal heat transfer";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=0.1
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate medium 2";
  Buildings.Fluid.Sources.MassFlowSource_T sin_2(
    redeclare package Medium = Medium2,
    T=T_a2_nominal,
    use_m_flow_in=true) "Sink for air"
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    T=T_a2_nominal,
    X={0.02,1 - 0.02},
    use_T_in=true,
    use_X_in=true) "Source for air"
  Buildings.Fluid.Sources.MassFlowSource_T sin_1(
    redeclare package Medium = Medium1,
    T=T_a1_nominal,
    use_m_flow_in=true) "Sink for water"
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    use_T_in=false,
    T=T_a1_nominal) "Source for water"

  Modelica.Blocks.Sources.Constant relHum(k=0.8) "Relative humidity"
  Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi(use_p_in=false)
  Modelica.Blocks.Sources.Constant temSou_2(k=T_a2_nominal)
    "Temperature boundary condition"
  Modelica.Blocks.Math.Gain mWat_flow(k=-m1_flow_nominal)
    "Water mass flow rate"
  Modelica.Blocks.Sources.TimeTable mWatGai(
    table=[0,1; 0.1,1; 0.2,0.01; 0.3,0.01],
    timeScale=3600)
    "Gain for water mass flow rate"
  Modelica.Blocks.Sources.TimeTable mAirGai(
    table=[0,1; 0.5,1; 0.6,-1; 0.7,0; 1,0],
    timeScale=3600)
    "Gain for air mass flow rate"
  Modelica.Blocks.Math.Gain mAir_flow(k=-m2_flow_nominal) "Air mass flow rate"
equation
  connect(x_pTphi.X, sou_2.X_in)
  connect(relHum.y, x_pTphi.phi)
  connect(temSou_2.y, x_pTphi.T)
  connect(temSou_2.y, sou_2.T_in)
  connect(mWatGai.y, mWat_flow.u)
  connect(mWat_flow.y, sin_1.m_flow_in)
  connect(mAirGai.y, mAir_flow.u)
  connect(mAir_flow.y, sin_2.m_flow_in)
end EffectivenessNTUMassFlow;


within Buildings.Fluid.HeatExchangers.Examples.BaseClasses;
partial model Heater "Base class for example model for the heater and cooler"

  replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium model";

  parameter Modelica.Units.SI.Volume V=6*6*2.7 "Volume";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=V*1.2*6/3600
    "Nominal mass flow rate";
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal=30*6*6
    "Nominal heat loss of the room";

  Buildings.Fluid.MixingVolumes.MixingVolume vol(
    redeclare package Medium = Medium,
    T_start=289.15,
    V=V,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=m_flow_nominal,
    mSenFac=2,
    nPorts=3)
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(
    G=Q_flow_nominal/20) "Thermal conductance to the outside"
  Buildings.HeatTransfer.Sources.PrescribedTemperature TBou
    "Fixed temperature boundary condition"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TVol
    "Sensor for volume temperature"
  Buildings.Fluid.Movers.FlowControlled_m_flow mov(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState) "Fan or pump"
  Modelica.Blocks.Sources.RealExpression TOut(
    y(final unit="K", displayUnit="degC")=
      273.15 + 16 - 5*cos(time/86400*2*Modelica.Constants.pi))
    "Outdoor temperature"
  Modelica.Blocks.Sources.Pulse TSet(
    amplitude=4,
    period=86400,
    offset=273.15 + 16,
    startTime=7*3600,
    y(final unit="K", displayUnit="degC")) "Setpoint for room temperature"
  Controls.Continuous.LimPID conPI(
    k=1,
    yMax=1,
    yMin=0,
    Ti=120) "Controller"
  Modelica.Blocks.Sources.Constant mFan_flow(k=m_flow_nominal)
    "Mass flow rate of the fan"
  Buildings.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium,
    nPorts=1)
    "Fixed pressure boundary condition, required to set a reference pressure"
  Sensors.TemperatureTwoPort THeaOut(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    T_start=289.15) "Outlet temperature of the heater"
  FixedResistances.PressureDrop res(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=100,
    linearized=true) "Flow resistance to decouple pressure state from boundary"
equation
  connect(theCon.port_a, TBou.port)
  connect(vol.heatPort, theCon.port_b)
  connect(vol.heatPort, TVol.port)
  connect(TOut.y, TBou.T)
  connect(TVol.T, conPI.u_m)
  connect(TSet.y, conPI.u_s)
  connect(mFan_flow.y,mov. m_flow_in)
  connect(THeaOut.port_b, vol.ports[1])
  connect(vol.ports[2],mov. port_a)
  connect(res.port_b, bou.ports[1])
  connect(res.port_a, vol.ports[3])
end Heater;


within Buildings.Fluid.HeatExchangers.Examples;
package BaseClasses "Package with base classes for Buildings.Fluid.HeatExchangers.Examples"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.Fluid.HeatExchangers.Examples.BaseClasses;
partial model WetCoilDiscretized
  "Model that demonstrates use of a finite volume model of a heat exchanger with condensation"

  package Medium1 = Buildings.Media.Water "Medium for water-side";
  replaceable package Medium2 = Modelica.Media.Interfaces.PartialMedium
    "Medium for air-side"

  parameter Modelica.Units.SI.Temperature T_a1_nominal=5 + 273.15
    "Water inlet temperature";
  parameter Modelica.Units.SI.Temperature T_b1_nominal=10 + 273.15
    "Water outlet temperature";
  parameter Modelica.Units.SI.Temperature T_a2_nominal=30 + 273.15
    "Air inlet temperature";
  parameter Modelica.Units.SI.Temperature T_b2_nominal=10 + 273.15
    "Air inlet temperature";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=5
    "Nominal mass flow rate water-side";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=m1_flow_nominal*4200
      /1000*(T_a1_nominal - T_b1_nominal)/(T_b2_nominal - T_a2_nominal)
    "Nominal mass flow rate air-side";

  Buildings.Fluid.HeatExchangers.WetCoilDiscretized hexFixIni(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    nPipPar=1,
    nPipSeg=3,
    nReg=2,
    dp1_nominal(displayUnit="Pa") = 5000,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal - T_b1_nominal)/
        Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    show_T=true) "Coil with fixed initial conditions"
  Sources.MassFlowSource_T            sin_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_m_flow_in=true,
    T=303.15)
  Buildings.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    nPorts=1,
    T=293.15)
    Modelica.Blocks.Sources.Ramp TWat(
    duration=60,
    height=15,
    offset=273.15 + 5,
    startTime=0) "Water temperature"
  Sources.MassFlowSource_T            sin_1(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_m_flow_in=true,
    T=293.15)
  Buildings.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    use_T_in=true,
    T=293.15,
    nPorts=1)
  Buildings.Fluid.HeatExchangers.WetCoilDiscretized hexSteStaIni(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    nPipPar=1,
    nPipSeg=3,
    nReg=2,
    dp1_nominal(displayUnit="Pa") = 5000,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal - T_b1_nominal)/
        Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial,
    show_T=true) "Coil with fixed initial conditions"
  Sources.MassFlowSource_T            sin_3(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_m_flow_in=true,
    T=303.15)
  Buildings.Fluid.Sources.Boundary_pT sou_3(
    redeclare package Medium = Medium2,
    nPorts=1,
    T=293.15)
  Sources.MassFlowSource_T            sin_4(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_m_flow_in=true,
    T=293.15)
  Buildings.Fluid.Sources.Boundary_pT sou_4(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    use_T_in=true,
    T=293.15,
    nPorts=1)
  Buildings.Fluid.HeatExchangers.WetCoilDiscretized hexSteSta(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    nPipPar=1,
    nPipSeg=3,
    nReg=2,
    dp1_nominal(displayUnit="Pa") = 5000,
    UA_nominal=m1_flow_nominal*4200*(T_a1_nominal - T_b1_nominal)/
        Buildings.Fluid.HeatExchangers.BaseClasses.lmtd(
        T_a1_nominal,
        T_b1_nominal,
        T_a2_nominal,
        T_b2_nominal),
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    show_T=true) "Coil with fixed initial conditions"
  Sources.MassFlowSource_T            sin_5(
    redeclare package Medium = Medium2,
    nPorts=1,
    use_m_flow_in=true,
    T=303.15)
  Buildings.Fluid.Sources.Boundary_pT sou_5(
    redeclare package Medium = Medium2,
    nPorts=1,
    T=293.15)
  Sources.MassFlowSource_T            sin_6(
    redeclare package Medium = Medium1,
    nPorts=1,
    use_m_flow_in=true,
    T=293.15)
  Buildings.Fluid.Sources.Boundary_pT sou_6(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    use_T_in=true,
    T=293.15,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp m2_flow(
    duration=60,
    startTime=60,
    height=1.1*m2_flow_nominal,
    offset=-m2_flow_nominal) "Air mass flow rate"
    Modelica.Blocks.Sources.Ramp m1_flow(
    duration=60,
    startTime=180,
    height=1.1*m1_flow_nominal,
    offset=-m1_flow_nominal) "Water mass flow rate"
    Modelica.Blocks.Sources.Ramp m1_flow1(
    duration=60,
    startTime=180,
    height=1.1*m1_flow_nominal,
    offset=-m1_flow_nominal) "Water mass flow rate"
    Modelica.Blocks.Sources.Ramp m1_flow2(
    duration=60,
    startTime=180,
    height=1.1*m1_flow_nominal,
    offset=-m1_flow_nominal) "Water mass flow rate"
equation
  connect(TWat.y, sou_1.T_in)
  connect(sou_1.ports[1], hexFixIni.port_a1)
  connect(sou_2.ports[1], hexFixIni.port_a2)
  connect(hexFixIni.port_b1, sin_1.ports[1])
  connect(hexFixIni.port_b2, sin_2.ports[1])
  connect(TWat.y,sou_4. T_in)
  connect(sou_4.ports[1], hexSteStaIni.port_a1)
  connect(sou_3.ports[1], hexSteStaIni.port_a2)
  connect(hexSteStaIni.port_b1, sin_4.ports[1])
  connect(TWat.y,sou_6. T_in)
  connect(sou_6.ports[1], hexSteSta.port_a1)
  connect(sou_5.ports[1], hexSteSta.port_a2)
  connect(hexSteSta.port_b1, sin_6.ports[1])
  connect(hexSteSta.port_b2, sin_5.ports[1])
  connect(hexSteStaIni.port_b2, sin_3.ports[1])
  connect(m2_flow.y, sin_2.m_flow_in)
  connect(m2_flow.y, sin_3.m_flow_in)
  connect(m2_flow.y, sin_5.m_flow_in)
  connect(m1_flow.y, sin_1.m_flow_in)
  connect(m1_flow1.y, sin_4.m_flow_in)
  connect(m1_flow2.y, sin_6.m_flow_in)
end WetCoilDiscretized;


Package with radiant slab models

within Buildings.Fluid.HeatExchangers;
package RadiantSlabs "Package with radiant slab models"
  extends Modelica.Icons.VariantsPackage;
end RadiantSlabs;