Partial model for heat exchanger with effectiveness - NTU relation and no moisture condensation. Partial model of a heat exchanger without humidity condensation.
This model transfers heat in the amount of

within AixLib.Fluid.HeatExchangers.BaseClasses;
model PartialEffectivenessNTU
  "Partial model for heat exchanger with effectiveness - NTU relation and no moisture condensation"
  extends AixLib.Fluid.HeatExchangers.BaseClasses.PartialEffectiveness(
      sensibleOnly1=true,
      sensibleOnly2=true,
      Q1_flow = eps*QMax_flow,
      Q2_flow = -Q1_flow,
      mWat1_flow = 0,
      mWat2_flow = 0);
  import con = AixLib.Fluid.Types.HeatExchangerConfiguration;
  import flo = AixLib.Fluid.Types.HeatExchangerFlowRegime;

  parameter con configuration "Heat exchanger configuration"

  constant Boolean use_dynamicFlowRegime = false
    "If true, flow regime is determined using actual flow rates";
  // This switch is declared as a constant instead of a parameter
  //   as users typically need not to change this setting,
  //   and setting it true may generate events.
  //   See discussions in https://github.com/ibpsa/modelica-ibpsa/pull/1683

  parameter Boolean use_Q_flow_nominal = true
    "Set to true to specify Q_flow_nominal and temperatures, or to false to specify effectiveness"

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal(
    fixed=use_Q_flow_nominal)
    "Nominal heat flow rate (positive for heat transfer from 1 to 2)"
  parameter Modelica.Units.SI.Temperature T_a1_nominal(fixed=use_Q_flow_nominal)
    "Nominal temperature at port a1"
  parameter Modelica.Units.SI.Temperature T_a2_nominal(fixed=use_Q_flow_nominal)
    "Nominal temperature at port a2"

  parameter Real eps_nominal(fixed=not use_Q_flow_nominal)
    "Nominal heat transfer effectiveness"

  input Modelica.Units.SI.ThermalConductance UA "UA value";

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

  // NTU has been removed as NTU goes to infinity as CMin goes to zero.
  // This quantity is not good for modeling.
  //  Real NTU(min=0) "Number of transfer units";
  final parameter Modelica.Units.SI.ThermalConductance UA_nominal(fixed=false)
    "Nominal UA value";
  final parameter Real NTU_nominal(min=0, fixed=false)
    "Nominal number of transfer units";

protected
  final parameter Medium1.ThermodynamicState sta1_default = Medium1.setState_pTX(
     T=Medium1.T_default,
     p=Medium1.p_default,
     X=Medium1.X_default[1:Medium1.nXi]) "Default state for medium 1";
  final parameter Medium2.ThermodynamicState sta2_default = Medium2.setState_pTX(
     T=Medium2.T_default,
     p=Medium2.p_default,
     X=Medium2.X_default[1:Medium2.nXi]) "Default state for medium 2";

  parameter Modelica.Units.SI.SpecificHeatCapacity cp1_nominal(fixed=false)
    "Specific heat capacity of medium 1 at nominal condition";
  parameter Modelica.Units.SI.SpecificHeatCapacity cp2_nominal(fixed=false)
    "Specific heat capacity of medium 2 at nominal condition";
  parameter Modelica.Units.SI.ThermalConductance C1_flow_nominal(fixed=false)
    "Nominal capacity flow rate of Medium 1";
  parameter Modelica.Units.SI.ThermalConductance C2_flow_nominal(fixed=false)
    "Nominal capacity flow rate of Medium 2";
  parameter Modelica.Units.SI.ThermalConductance CMin_flow_nominal(fixed=false)
    "Minimal capacity flow rate at nominal condition";
  parameter Modelica.Units.SI.ThermalConductance CMax_flow_nominal(fixed=false)
    "Maximum capacity flow rate at nominal condition";
  parameter Real Z_nominal(
    min=0,
    max=1,
    fixed=false) "Ratio of capacity flow rate at nominal condition";
  parameter Modelica.Units.SI.Temperature T_b1_nominal(fixed=false)
    "Nominal temperature at port b1";
  parameter Modelica.Units.SI.Temperature T_b2_nominal(fixed=false)
    "Nominal temperature at port b2";
  parameter flo flowRegime_nominal(fixed=false)
    "Heat exchanger flow regime at nominal flow rates";
  flo flowRegime(fixed=false, start=flowRegime_nominal)
    "Heat exchanger flow regime";
initial equation
  assert(m1_flow_nominal > Modelica.Constants.eps,
    "m1_flow_nominal must be positive, m1_flow_nominal = " + String(
    m1_flow_nominal));
  assert(m2_flow_nominal > Modelica.Constants.eps,
    "m2_flow_nominal must be positive, m2_flow_nominal = " + String(
    m2_flow_nominal));

  cp1_nominal = Medium1.specificHeatCapacityCp(sta1_default);
  cp2_nominal = Medium2.specificHeatCapacityCp(sta2_default);

  // Heat transferred from fluid 1 to 2 at nominal condition
  C1_flow_nominal = m1_flow_nominal*cp1_nominal;
  C2_flow_nominal = m2_flow_nominal*cp2_nominal;
  CMin_flow_nominal = min(C1_flow_nominal, C2_flow_nominal);
  CMax_flow_nominal = max(C1_flow_nominal, C2_flow_nominal);
  Z_nominal = CMin_flow_nominal/CMax_flow_nominal;
  Q_flow_nominal = m1_flow_nominal*cp1_nominal*(T_a1_nominal - T_b1_nominal);
  if use_Q_flow_nominal then
    Q_flow_nominal = -m2_flow_nominal*cp2_nominal*(T_a2_nominal - T_b2_nominal);
    eps_nominal = abs(Q_flow_nominal/((T_a1_nominal - T_a2_nominal)*
      CMin_flow_nominal));
    assert(Q_flow_nominal / (T_a1_nominal - T_a2_nominal) >= 0,
    "In " + getInstanceName() + ": Q_flow_nominal is defined with the wrong sign. " +
    "By convention, a positive value describes a heat flow from Medium1 to Medium2. " +
    "The parameter T_a1_nominal should then be larger than T_a2_nominal." +
    "Future version of this library might enforce this convention and throw an error.",
    level = AssertionLevel.warning);
  else
    T_a1_nominal = Medium1.T_default;
    T_a2_nominal = Medium2.T_default;
    T_b1_nominal = Medium1.T_default;
    T_b2_nominal = Medium2.T_default;
  end if;
  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 |T_a1_nominal-T_a2_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));
  // Assign the flow regime for the given heat exchanger configuration and capacity flow rates
  if (configuration == con.CrossFlowStream1MixedStream2Unmixed) then
    flowRegime_nominal = if (C1_flow_nominal < C2_flow_nominal) then flo.CrossFlowCMinMixedCMaxUnmixed
       else flo.CrossFlowCMinUnmixedCMaxMixed;
  elseif (configuration == con.CrossFlowStream1UnmixedStream2Mixed) then
    flowRegime_nominal = if (C1_flow_nominal < C2_flow_nominal) then flo.CrossFlowCMinUnmixedCMaxMixed
       else flo.CrossFlowCMinMixedCMaxUnmixed;
  elseif (configuration == con.ParallelFlow) then
    flowRegime_nominal = flo.ParallelFlow;
  elseif (configuration == con.CounterFlow) then
    flowRegime_nominal = flo.CounterFlow;
  elseif (configuration == con.CrossFlowUnmixed) then
    flowRegime_nominal = flo.CrossFlowUnmixed;
  else
    // Invalid flow regime. Assign a value to flowRegime_nominal, and stop with an assert
    flowRegime_nominal = flo.CrossFlowUnmixed;
    assert(configuration >= con.ParallelFlow and configuration <= con.CrossFlowStream1UnmixedStream2Mixed,
      "Invalid heat exchanger configuration.");
  end if;
  // The equation sorter of Dymola 7.3 does not guarantee that the above assert is tested prior to the
  // function call on the next line. Thus, we add the test on eps_nominal to avoid an error in ntu_epsilonZ
  // for invalid input arguments
  NTU_nominal = if (eps_nominal > 0 and eps_nominal < 1) then
    AixLib.Fluid.HeatExchangers.BaseClasses.ntu_epsilonZ(
    eps=eps_nominal,
    Z=Z_nominal,
    flowRegime=Integer(flowRegime_nominal)) else 0;
  UA_nominal = NTU_nominal*CMin_flow_nominal;
equation
  // Assign the flow regime for the given heat exchanger configuration and capacity flow rates
  if use_dynamicFlowRegime then
    if (configuration == con.ParallelFlow) then
      flowRegime = if (C1_flow*C2_flow >= 0) then flo.ParallelFlow else flo.CounterFlow;
    elseif (configuration == con.CounterFlow) then
      flowRegime = if (C1_flow*C2_flow >= 0) then flo.CounterFlow else flo.ParallelFlow;
    elseif (configuration == con.CrossFlowUnmixed) then
      flowRegime = flo.CrossFlowUnmixed;
    elseif (configuration == con.CrossFlowStream1MixedStream2Unmixed) then
      flowRegime = if (C1_flow < C2_flow) then flo.CrossFlowCMinMixedCMaxUnmixed
         else flo.CrossFlowCMinUnmixedCMaxMixed;
    else
      // have ( configuration == con.CrossFlowStream1UnmixedStream2Mixed)
      flowRegime = if (C1_flow < C2_flow) then flo.CrossFlowCMinUnmixedCMaxMixed
         else flo.CrossFlowCMinMixedCMaxUnmixed;
    end if;
  else
    flowRegime = flowRegime_nominal;
    assert(noEvent(m1_flow > -0.1 * m1_flow_nominal)
       and noEvent(m2_flow > -0.1 * m2_flow_nominal),
"*** Warning in " + getInstanceName() +
      ": The flow direction reversed.
      However, because the constant use_dynamicFlowRegime is set to false,
      the model does not change equations based on the actual flow regime.
      To switch equations based on the actual flow regime during the simulation,
      set the constant use_dynamicFlowRegime=true.
      Note that this can lead to slow simulation because of events.",
      level = AssertionLevel.warning);
  end if;

  // Effectiveness
  eps = AixLib.Fluid.HeatExchangers.BaseClasses.epsilon_C(
    UA=UA,
    C1_flow=C1_flow,
    C2_flow=C2_flow,
    flowRegime=Integer(flowRegime),
    CMin_flow_nominal=CMin_flow_nominal,
    CMax_flow_nominal=CMax_flow_nominal,
    delta=delta);
end PartialEffectivenessNTU;


within AixLib.Fluid.HeatExchangers.BaseClasses;
partial model PartialPrescribedOutlet
  "Ideal heater, cooler, humidifier or dehumidifier with prescribed outlet conditions"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface;
  extends AixLib.Fluid.Interfaces.TwoPortFlowResistanceParameters(
    final computeFlowResistance=(abs(dp_nominal) > Modelica.Constants.eps));

  constant Boolean homotopyInitialization = true "= true, use homotopy method"

  // Dynamics
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  parameter Modelica.Units.SI.Time tau(min=0) = 10
    "Time constant at nominal flow rate (used if energyDynamics not equal Modelica.Fluid.Types.Dynamics.SteadyState)"

protected
  AixLib.Fluid.FixedResistances.PressureDrop preDro(
    redeclare final package Medium = Medium,
    final m_flow_nominal=m_flow_nominal,
    final deltaM=deltaM,
    final allowFlowReversal=allowFlowReversal,
    final show_T=false,
    final from_dp=from_dp,
    final linearized=linearizeFlowResistance,
    final homotopyInitialization=homotopyInitialization,
    final dp_nominal=dp_nominal) "Flow resistance"

  AixLib.Fluid.Interfaces.PrescribedOutlet outCon(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_small=m_flow_small,
    final show_T=false,
    final m_flow_nominal=m_flow_nominal,
    final tau=tau) "Model to set outlet conditions"
initial equation
  assert(homotopyInitialization, "In " + getInstanceName() +
    ": The constant homotopyInitialization has been modified from its default value. This constant will be removed in future releases.",
    level = AssertionLevel.warning);

equation
  connect(port_a, preDro.port_a)
  connect(preDro.port_b,outCon. port_a)
  connect(outCon.port_b, port_b)
end PartialPrescribedOutlet;


Fully dry coil model. This model implements the calculation for a 100% dry coil.

within AixLib.Fluid.HeatExchangers.BaseClasses;
model WetCoilDryRegime
  "Fully dry coil model"

  // - water
  input Modelica.Units.SI.ThermalConductance UAWat "UA for water side";
  input Modelica.Units.SI.MassFlowRate mWat_flow "Mass flow rate for water";
  input Modelica.Units.SI.MassFlowRate mWatNonZer_flow(min=Modelica.Constants.eps)
    "Mass flow rate for water, bounded away from zero";

  input Modelica.Units.SI.SpecificHeatCapacity cpWat
    "Specific heat capacity of water";
  input Modelica.Units.SI.Temperature TWatIn "Water temperature at inlet";
  // -- air
  input Modelica.Units.SI.ThermalConductance UAAir "UA for air side";
  input Modelica.Units.SI.MassFlowRate mAir_flow(min=Modelica.Constants.eps)
    "Mass flow rate of air";
  input Modelica.Units.SI.MassFlowRate mAirNonZer_flow(min=Modelica.Constants.eps)
    "Mass flow rate for air, bounded away from zero";
  input Modelica.Units.SI.SpecificHeatCapacity cpAir
    "Specific heat capacity of moist air at constant pressure";
  input Modelica.Units.SI.Temperature TAirIn "Temperature of air at inlet";
  // -- misc.
  input AixLib.Fluid.Types.HeatExchangerFlowRegime cfg
    "Flow regime of the heat exchanger";
  input Modelica.Units.SI.MassFlowRate mAir_flow_nominal
    "Nominal mass flow rate for air";
  input Modelica.Units.SI.MassFlowRate mWat_flow_nominal
    "Nominal mass flow rate for water";

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

  output Modelica.Units.SI.HeatFlowRate QTot_flow
    "Heat transferred from water to air";
  output Modelica.Units.SI.Temperature TWatOut "Temperature of water at outlet";
  output Modelica.Units.SI.Temperature TAirOut
    "Temperature of air at the outlet";
  output Real eps(min=0, max=1, unit="1")
    "Effectiveness for heat exchanger";
  Modelica.Units.SI.ThermalConductance CWat_flow=mWat_flow*cpWat
    "Capacitance rate of water";
  Modelica.Units.SI.ThermalConductance CAir_flow=mAir_flow*cpAir
    "Capacitance rate of air";
  Modelica.Units.SI.ThermalConductance CMin_flow_nominal=min(mAir_flow_nominal*
      cpAir, mWat_flow_nominal*cpWat) "Minimum capacity rate";
  Modelica.Units.SI.ThermalConductance CMax_flow_nominal=max(mAir_flow_nominal*
      cpAir, mWat_flow_nominal*cpWat) "Maximum capacity rate";
  Modelica.Units.SI.ThermalConductance CMin_flow=
      AixLib.Utilities.Math.Functions.smoothMin(
      x1=CAir_flow,
      x2=CWat_flow,
      deltaX=1E-3*(CMax_flow_nominal - CMin_flow_nominal))
    "Minimum capacity rate";
  Modelica.Units.SI.ThermalConductance UA "Overall heat transfer coefficient";
  output Modelica.Units.SI.Temperature TSurAirOut
    "Surface Temperature at air outlet";
equation
  UA = 1/ (1 / UAAir + 1 / UAWat);

  eps=epsilon_C(
    UA=UA,
    C1_flow=CWat_flow,
    C2_flow=CAir_flow,
    flowRegime=Integer(cfg),
    CMin_flow_nominal= CMin_flow_nominal,
    CMax_flow_nominal=CMax_flow_nominal,
    delta= delta);

  QTot_flow = eps*CMin_flow*(TAirIn-TWatIn);
  TAirOut=TAirIn-QTot_flow/(mAirNonZer_flow*cpAir);
  TWatOut=TWatIn+QTot_flow/(mWatNonZer_flow*cpWat);
  TSurAirOut = (TAirOut * UAAir + TWatIn * UAWat) / (UAAir + UAWat);
end WetCoilDryRegime;


Model implementing the switching algorithm of the TK-fuzzy model for cooling coil application. This model implements the switching algorithm for the dry and wet regime.

within AixLib.Fluid.HeatExchangers.BaseClasses;
model WetCoilDryWetRegime
  "Model implementing the switching algorithm of the TK-fuzzy model for cooling coil application"

  parameter Modelica.Units.SI.MassFlowRate mWat_flow_nominal(min=0)
    "Nominal mass flow rate for water"
  parameter Modelica.Units.SI.MassFlowRate mAir_flow_nominal(min=0)
    "Nominal mass flow rate for air"

  input Real Qfac(final unit="1")
    "Smoothing factor to prevent division-by-zero";

  input AixLib.Fluid.Types.HeatExchangerFlowRegime cfg=
    AixLib.Fluid.Types.HeatExchangerFlowRegime.CounterFlow
    "Heat exchanger configuration";

  // -- Water
  Modelica.Blocks.Interfaces.RealInput UAWat(
    final quantity="ThermalConductance",
    final unit="W/K")
    "Product of heat transfer coefficient times area for water side"
  Modelica.Blocks.Interfaces.RealInput mWat_flow(
    quantity="MassFlowRate",
    min = 0,
    final unit="kg/s")
    "Mass flow rate for water"
  Modelica.Blocks.Interfaces.RealInput cpWat(
    final quantity="SpecificHeatCapacity",
    final unit="J/(kg.K)")
    "Inlet water temperature"
  Modelica.Blocks.Interfaces.RealInput TWatIn(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    min = 200,
    start = 288.15,
    nominal = 300,
    displayUnit="degC")
    "Inlet water temperature"
  // -- Air
  Modelica.Blocks.Interfaces.RealInput UAAir(
    final quantity="ThermalConductance",
    final unit="W/K")
    "Product of heat transfer coefficient times area for air side"
  Modelica.Blocks.Interfaces.RealInput mAir_flow(
    quantity="MassFlowRate",
    min = 0,
    final unit="kg/s")
    "Mass flow rate for air"
  Modelica.Blocks.Interfaces.RealInput cpAir(
    final quantity="SpecificHeatCapacity",
    final unit="J/(kg.K)")
    "Inlet specific heat capacity (at constant pressure)"
  Modelica.Blocks.Interfaces.RealInput TAirIn(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    min = 200,
    start = 288.15,
    nominal = 300,
    displayUnit="degC")
    "Inlet air temperature"
  Modelica.Blocks.Interfaces.RealInput hAirIn(
    final quantity="SpecificEnergy",
    final unit="J/kg")
    "Inlet air enthalpy"
  Modelica.Blocks.Interfaces.RealInput pAir(
    final quantity="Pressure",
    final unit="Pa",
    displayUnit="bar",
    min=70000,
    nominal = 1e5)
    "Inlet air absolute pressure"
  Modelica.Blocks.Interfaces.RealInput X_wAirIn(
    min=0,
    max=1,
    unit="1")
    "Mass fraction of water in inlet air (kg water/kg total air)"

  Modelica.Blocks.Interfaces.RealOutput QTot_flow(
    final quantity="Power",
    final unit="W")
    "Total heat transfer from water into air, negative for cooling"
  Modelica.Blocks.Interfaces.RealOutput QSen_flow(
    final quantity="Power",
    final unit="W")
    "Sensible heat transfer from water into air, negative for cooling"
  Modelica.Units.SI.HeatFlowRate QLat_flow "Latent heat transfer rate";

  Modelica.Blocks.Interfaces.RealOutput mCon_flow(
    quantity="MassFlowRate",
    final unit="kg/s")
    "Mass flow of the condensate, negative for dehumidification"
  AixLib.Fluid.HeatExchangers.BaseClasses.WetCoilDryRegime fullyDry(
    final UAWat=UAWat,
    final mWat_flow=mWat_flow,
    final cpWat=cpWat,
    final TWatIn=TWatIn,
    final UAAir=UAAir,
    final mAir_flow=mAir_flow,
    final mWatNonZer_flow=mWatNonZer_flow,
    final mAirNonZer_flow=mAirNonZer_flow,
    final cpAir=cpAir,
    final TAirIn=TAirIn,
    final cfg=cfg,
    final mAir_flow_nominal=mAir_flow_nominal,
    final mWat_flow_nominal=mWat_flow_nominal) "Fully-dry coil model";

  AixLib.Fluid.HeatExchangers.BaseClasses.WetCoilWetRegime fullyWet(
    final UAWat=UAWat,
    final mWat_flow=mWat_flow,
    final cpWat=cpWat,
    final TWatIn=TWatIn,
    final UAAir=UAAir,
    final mAir_flow=mAir_flow,
    final mWatNonZer_flow=mWatNonZer_flow,
    final mAirNonZer_flow=mAirNonZer_flow,
    final cpAir=cpAir,
    final TAirIn=TAirIn,
    final cfg=cfg,
    final mAir_flow_nominal=mAir_flow_nominal,
    final mWat_flow_nominal=mWat_flow_nominal,
    final pAir=pAir,
    final X_wAirIn=X_wAirIn) "Fully-wet coil model";

  Real dryFra(final unit="1", min=0, max=1)
    "Dry fraction, 0.3 means condensation occurs at 30% heat exchange length from air inlet";
protected
  Modelica.Units.SI.MassFlowRate mAirNonZer_flow(min=Modelica.Constants.eps) =
    AixLib.Utilities.Math.Functions.smoothMax(
    x1=mAir_flow,
    x2=1E-3*mAir_flow_nominal,
    deltaX=0.25E-3*mAir_flow_nominal) "Mass flow rate of air";
  Modelica.Units.SI.MassFlowRate mWatNonZer_flow(min=Modelica.Constants.eps) =
    AixLib.Utilities.Math.Functions.smoothMax(
    x1=mWat_flow,
    x2=1E-3*mWat_flow_nominal,
    deltaX=0.25E-3*mWat_flow_nominal) "Mass flow rate of water";

  Modelica.Units.SI.Temperature TAirInDewPoi
    "Dew point temperature of incoming air";

  AixLib.Utilities.Psychrometrics.pW_X pWIn(
    final X_w=X_wAirIn,
    final p_in=pAir);
  AixLib.Utilities.Psychrometrics.TDewPoi_pW TDewIn(
    final p_w=pWIn.p_w);

  //-- Values for fuzzy logics
  Real mu_FW(final unit="1", min=0, max=1), mu_FD(unit="1",min=0, max=1)
    "Membership functions for Fully-Wet and Fully-Dry conditions";
  Real w_FW(final unit="1", min=0, max=1),  w_FD(unit="1",min=0, max=1)
    "Normalized weight functions for Fully-Wet and Fully-Dry conditions";

equation

  TAirInDewPoi=TDewIn.T;

  mu_FW= AixLib.Utilities.Math.Functions.spliceFunction(
    pos=0,neg=1,x=fullyWet.TSurAirIn-TAirInDewPoi,
    deltax=AixLib.Utilities.Math.Functions.smoothMax(
      abs(fullyDry.TSurAirOut-fullyWet.TSurAirIn), 1e-2,1e-3));

  mu_FD= AixLib.Utilities.Math.Functions.spliceFunction(
    pos=1,neg=0,x=fullyDry.TSurAirOut-TAirInDewPoi,
    deltax=AixLib.Utilities.Math.Functions.smoothMax(
      abs(fullyDry.TSurAirOut-fullyWet.TSurAirIn), 1e-2,1e-3));

  w_FW=mu_FW/(mu_FW+mu_FD);
  w_FD=mu_FD/(mu_FW+mu_FD);

  QTot_flow= -(w_FW*fullyWet.QTot_flow+w_FD*fullyDry.QTot_flow)*Qfac;
  QSen_flow= -(w_FW*fullyWet.QSen_flow+w_FD*fullyDry.QTot_flow)*Qfac;
  dryFra= w_FD;

  QLat_flow=QTot_flow-QSen_flow;
  mCon_flow=QLat_flow/AixLib.Utilities.Psychrometrics.Constants.h_fg*Qfac;
end WetCoilDryWetRegime;


within AixLib.Fluid.HeatExchangers.BaseClasses;
model WetCoilUARated
  "Model that calculates the UA-value from cooling coil data at rated conditions."

  replaceable package MediumA=AixLib.Media.Air
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Air-side medium";
  replaceable package MediumW=AixLib.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Water-side medium";

  parameter Boolean use_Q_flow_nominal = false
    "Set to true to specify Q_flow_nominal and inlet conditions, or to false to specify UA_nominal"
  parameter Modelica.Units.SI.HeatFlowRate QTot_flow
    "Nominal heat flow rate (positive for heat transfer from 1 to 2)";
  parameter Modelica.Units.SI.Temperature TAirIn
    "Air inlet temperature at a rated condition";

  parameter Modelica.Units.SI.MassFraction X_wAirIn
    "Mass fraction of water in inlet air at a rated condition";
  parameter Modelica.Units.SI.Temperature TWatIn
    "Water inlet temperature at a rated condition";

  parameter Modelica.Units.SI.MassFlowRate mAir_flow
    "Air mass flow rate at a rated condition";
  parameter Modelica.Units.SI.MassFlowRate mWat_flow
    "Water mass flow rate at a rated condition";
  parameter Modelica.Units.SI.ThermalConductance UA
    "Overall heat transfer coefficient for a fully dry condition";
  parameter Real r_nominal(min=0, max=1)
    "Ratio between air-side and water-side convective heat transfer at nominal condition";

protected
  constant Modelica.Units.SI.SpecificEnthalpy hfg=AixLib.Utilities.Psychrometrics.Constants.h_fg
    "Enthapy of vaporization of water";
  constant Modelica.Units.SI.SpecificEnthalpy hUnit=1
    "Physical dimension of specific enthalpy used for a unit conversion";
  constant Modelica.Units.SI.Temperature TUnit=1
    "Physical dimension of temperature used for a unit conversion";
  constant Modelica.Units.SI.SpecificHeatCapacity cpUnit=1
    "Physical dimension of specific heat capacity used for a unit conversion";
  parameter Modelica.Units.SI.Temperature TAirOut(fixed=false)
    "Air outlet temperature  at a rated condition";
  parameter Modelica.Units.SI.Temperature TWatOut=TWatIn - QTot_flow/cpWat/
      mWat_flow "Water outlet temperature at a rated condition";
  parameter Modelica.Units.SI.SpecificEnthalpy hAirIn=
      MediumA.specificEnthalpy_pTX(
      p=MediumA.p_default,
      T=TAirIn,
      X={X_wAirIn,1 - X_wAirIn})
    "Enthalpy of incoming moist air at a rated condition";
  parameter MediumA.ThermodynamicState staAir=MediumA.setState_phX(
    p=MediumA.p_default, h=hAirIn, X={X_wAirIn, 1-X_wAirIn})
    "Inlet air thermodynamic state";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpAir=
      MediumA.specificHeatCapacityCp(staAir)
    "Isobaric specific heat capacity of air";
  parameter Modelica.Units.SI.SpecificEnthalpy hAirOut=hAirIn + QTot_flow/
      mAir_flow "Enthalpy of outgoing moist air at a rated condition";
  parameter Modelica.Units.SI.SpecificEnthalpy hWatIn=
      MediumW.specificEnthalpy_pTX(
      p=MediumW.p_default,
      T=TWatIn,
      X=MediumW.X_default)
    "Enthalpy of incoming moist air at a rated condition";
  parameter MediumW.ThermodynamicState staWat=MediumW.setState_phX(
    p=MediumW.p_default, h=hWatIn, X=MediumW.X_default)
    "Inlet water thermodynamic state";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpWat=
      MediumW.specificHeatCapacityCp(staWat)
    "Isobaric specific heat capacity of water";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpEff(fixed=false, min=0) "Effective specific heat: change in saturated moist air enthalpy with respect to
    temperature along the saturation line between inlet and outlet water temperatures";
  parameter Modelica.Units.SI.SpecificEnthalpy LMED(fixed=false)
    "Log mean enthalpy difference";
  parameter Modelica.Units.SI.MassFlowRate UASta(
    fixed=false,
    min=0,
    start=1/(1/10 + 1/20))
    "Overall heat transfer coefficient for enthalpy difference";
  parameter Modelica.Units.SI.ThermalConductance UAAir(
    min=0,
    start=10,
    fixed=false)
    "Air side convective heat transfer coefficient, including fin resistance";
  parameter Modelica.Units.SI.ThermalConductance UAWat(
    min=0,
    start=20,
    fixed=false) "Water side convective heat transfer coefficient";
  parameter Boolean isFulDry(fixed=false)
    "Indicator of the fully-dry coil regime";
  parameter Boolean isFulWet(fixed=false)
    "Indicator of the fully-wet coil regime";
  parameter Modelica.Units.SI.AbsolutePressure pSatTWatIn=
      AixLib.Utilities.Psychrometrics.Functions.saturationPressure(TWatIn)
    "Saturation pressure of water at the water inlet temperature";
  parameter Modelica.Units.SI.MassFraction X_wSatTWatIn=
      AixLib.Utilities.Psychrometrics.Functions.X_pSatpphi(
      pSat=pSatTWatIn,
      p=MediumA.p_default,
      phi=1)
    "Mass fraction of water in saturated moist air at the water inlet temperature";
  parameter Modelica.Units.SI.SpecificEnthalpy hSatTWatIn=
      AixLib.Media.Air.specificEnthalpy_pTX(
      p=MediumA.p_default,
      T=TWatIn,
      X={X_wSatTWatIn,1 - X_wSatTWatIn})
    "Enthalpy of saturated moist air at the water inlet temperature";
  parameter Modelica.Units.SI.AbsolutePressure pSatTWatOut=
      AixLib.Utilities.Psychrometrics.Functions.saturationPressure(TWatOut)
    "Saturation pressure of water at the water oulet temperature";
  parameter Modelica.Units.SI.MassFraction X_wSatTWatOut=
      AixLib.Utilities.Psychrometrics.Functions.X_pSatpphi(
      pSat=pSatTWatOut,
      p=MediumA.p_default,
      phi=1)
    "Mass fraction of water in saturated moist air at the water outlet temperature";
  parameter Modelica.Units.SI.SpecificEnthalpy hSatTWatOut=
      AixLib.Media.Air.specificEnthalpy_pTX(
      p=MediumA.p_default,
      T=TWatOut,
      X={X_wSatTWatOut,1 - X_wSatTWatOut})
    "Enthalpy of saturated moist air at the water oulet temperature";
initial equation
  isFulDry = if use_Q_flow_nominal then (X_wSatTWatIn >= X_wAirIn) else true;
  isFulWet = if use_Q_flow_nominal then (X_wSatTWatOut <= X_wAirIn) else true;
  assert(
    not use_Q_flow_nominal or
      hAirOut >= hSatTWatIn and hAirIn >= hSatTWatOut or
      hAirOut <= hSatTWatIn and hAirIn <= hSatTWatOut,
    "In " + getInstanceName() +
    ": The moist air enthalpy at the coil inlet or outlet is unrealistically low. " +
    "Check the rated conditions.");
  assert(
    isFulDry or isFulWet,
    "In " + getInstanceName() +
    ": The nominal conditions correspond to a partially-wet coil regime. " +
    "The modeling uncertainty under such conditions has not been assessed. " +
    "Rather specify nominal conditions in fully-dry or fully-wet regime.",
    level=AssertionLevel.warning);
  if use_Q_flow_nominal then
    if isFulDry then
      TAirOut = TAirIn + QTot_flow / mAir_flow / cpAir;
      LMED = (if abs(TWatIn - TAirOut - (TWatOut - TAirIn)) < Modelica.Constants.small then
        TWatIn - TAirOut else AixLib.Fluid.HeatExchangers.BaseClasses.lmtd(
          TWatIn,
          TWatOut,
          TAirIn,
          TAirOut)) / TUnit * hUnit;
      QTot_flow=LMED*UASta;
      cpEff = 0;
      UA = UASta*cpUnit;
    else //fully wet
      // calculation of overall UAsta based on log mean enthalpy difference
      LMED = (if abs(hSatTWatIn - hAirOut - (hSatTWatOut - hAirIn)) < Modelica.Constants.small then
        (hSatTWatIn - hAirOut)/hUnit*TUnit else
        AixLib.Fluid.HeatExchangers.BaseClasses.lmtd(
          hSatTWatIn/hUnit*TUnit,
          hSatTWatOut/hUnit*TUnit,
          hAirIn/hUnit*TUnit,
          hAirOut/hUnit*TUnit)) / TUnit * hUnit;
      QTot_flow=LMED*UASta;
      cpEff= (hSatTWatOut-hSatTWatIn)/(TWatOut-TWatIn);
      UASta = (UAAir/cpAir)/(1 + (cpEff*UAAir)/(cpAir*UAWat));
      // Dummy value.
      TAirOut=MediumA.T_default;
    end if;
  else
    // Dummy values.
    TAirIn=MediumA.T_default;
    TAirOut=MediumA.T_default;
    X_wAirIn=MediumA.X_default[1];
    TWatIn=MediumA.T_default;
    TWatOut=MediumA.T_default;
    hAirIn=MediumA.h_default;
    hAirOut=MediumA.h_default;
    LMED=hUnit;
    -QTot_flow=LMED*UASta;
    cpEff= 0;
  end if;

  UAWat = UAAir / r_nominal;
  UA = 1/ (1/UAAir  + 1/UAWat);
end WetCoilUARated;


Fully wet coil model using esilon_C.mo function. This model implements the calculation for a 100% wet coil.

within AixLib.Fluid.HeatExchangers.BaseClasses;
model WetCoilWetRegime
  "Fully wet coil model using esilon_C.mo function"
  constant Real cpEff0=2050 "Used for scaling";
  constant Real cpWat0=4200 "Used for scaling";
  parameter Real delta = 1E-3 "Small value used for smoothing";
  constant Modelica.Units.SI.SpecificHeatCapacity cpDum=1
    "Dummy cp to eliminate the warning message of the unit mismatch when using the eps-NTU model for the wet coil";
  constant Modelica.Units.SI.TemperatureDifference dTWat=0.1
    "Temperature differential used to compute the finite difference of the saturated specific enthalpy";
  parameter Real tau=6*60
    "Time constant for state estimation: introduced to avoid the algebraic loop of the wet coil equations";

  // - water
  input Modelica.Units.SI.ThermalConductance UAWat "UA for water side";
  input Modelica.Units.SI.MassFlowRate mWat_flow "Mass flow rate of water";
  input Modelica.Units.SI.MassFlowRate mWatNonZer_flow
    "Non-zero mass flow rate of water";
  input Modelica.Units.SI.SpecificHeatCapacity cpWat
    "Specific heat capacity of water";
  input Modelica.Units.SI.Temperature TWatIn "Water temperature at inlet";
  input Modelica.Units.SI.MassFlowRate mWat_flow_nominal
    "Mass flow rate of water at nominal conditions";
  // -- air
  input Modelica.Units.SI.Pressure pAir "Pressure on air-side of coil";
  input Modelica.Units.SI.ThermalConductance UAAir "UA for air side";
  input Modelica.Units.SI.MassFlowRate mAir_flow "Mass flow rate of air";
  input Modelica.Units.SI.MassFlowRate mAirNonZer_flow
    "Non-zero mass flow rate of water";
  input Modelica.Units.SI.SpecificHeatCapacity cpAir
    "Specific heat capacity of moist air at constant pressure";
  input Modelica.Units.SI.Temperature TAirIn "Temperature of air at inlet";
  input Modelica.Units.SI.MassFraction X_wAirIn
    "Mass fraction of water in moist air at inlet";
  input AixLib.Fluid.Types.HeatExchangerFlowRegime cfg
    "Configuration of the heat exchanger";
  input Modelica.Units.SI.MassFlowRate mAir_flow_nominal
    "Mass flow rate of air at nominal conditions";

  Modelica.Units.SI.SpecificEnthalpy hAirIn
    "Specific enthalpy of air at inlet conditions";
  AixLib.Utilities.Psychrometrics.hSat_pTSat hSatWatInM(p=pAir,TSat=TWatIn)
    "Model to calculate saturated specific enthalpy of air at water inlet temperature";
  Modelica.Units.SI.SpecificEnthalpy hSatWatIn
    "Saturated specific enthalpy of air at water inlet temperature";
  AixLib.Utilities.Psychrometrics.hSat_pTSat hSatWatIn_dT_M(p=pAir,TSat=TWatIn+dTWat)
    "Model to calculate derivative of saturated specific enthalpy of air at water inlet temperature";
  Modelica.Units.SI.SpecificHeatCapacity dhSatdTWatIn
    "Finite difference of saturated moist air enthalpy at water inlet temperature";
  Real NonZerDelWatTem
    "Regularization water temperature difference between inlet and outlet";

  Modelica.Units.SI.SpecificEnthalpy hAirOut
    "Specific enthalpy of moist air at the air outlet";
  AixLib.Utilities.Psychrometrics.hSat_pTSat hSatWatOutM(p=pAir,TSat=TWatOutEst)
    "Model to calculate saturated specific enthalpy of air at water outlet temperature";
  Modelica.Units.SI.SpecificEnthalpy hSatWatOut
    "Saturated specific enthalpy of air at water outlet temperature";

  Modelica.Units.SI.Temperature TSurEff
    "Effective surface temperature of the coil to split sensible and latent heat from total heat transfer rate";

  Modelica.Units.SI.SpecificEnthalpy hSatSurEff
    "Enthalpy of saturated moist air at the effective surface temperature";

  AixLib.Utilities.Psychrometrics.hSat_pTSat hSatSurEffM(p=pAir,TSat=TSurEff)
    "An object to calculate the saturated enthalpy of moist air at the coil surface temperature";
  AixLib.Utilities.Psychrometrics.hSat_pTSat hSatSurEffMinM(p=pAir,TSat=273.15+1)
    "An object to calculate a lower bound of the saturated enthalpy of moist
    air at the coil surface temperature";

  Modelica.Units.SI.SpecificHeatCapacity cpEff "Effective specific heat: change in enthalpy with respect to temperature
     along the saturation line at the local water temperature";

  Modelica.Units.SI.MassFlowRate UASta
    "Overall mass transfer coefficient for dry coil";

  // Set start value, otherwise OpenModelica has a division by zero in the expression
  // (1 - exp(-NTUAirSta)) of hSatSurEff
  Real NTUAirSta(
    start=1,
    unit="1")
    "Number of transfer units for air-side only (NTU_a*)";

  Real epsSta(start=0.66, unit="1")
    "Effectiveness for heat exchanger (e*)";

  Modelica.Units.SI.MassFlowRate CStaMin
    "Min of product of mass flow rates and specific heats; analogous to Cmin";

  Modelica.Units.SI.MassFlowRate CStaMin_flow_nominal=min(mAir_flow_nominal,
      mWat_flow_nominal*cpEff0/cpWat0)
    "Analogus to CMin_flow_nominal, only for a regularization";
  Modelica.Units.SI.MassFlowRate CStaMax_flow_nominal=max(mAir_flow_nominal,
      mWat_flow_nominal*cpEff0/cpWat0)
    "Analogus to CMax_flow_nominal, only for a regularization";
  Modelica.Units.SI.MassFlowRate deltaCStaMin=delta*min(mAir_flow_nominal,
      mWat_flow_nominal*cpEff0/cpWat0)
    "Min of product of mass flow rates and specific heats, analogous to Cmin";
  Modelica.Units.SI.Temperature TWatOutEst
    "State estimation of temperature of water at outlet";

  output Modelica.Units.SI.HeatFlowRate QTot_flow
    "Total heat flow from water to air stream";
  output Modelica.Units.SI.HeatFlowRate QSen_flow
    "Sensible heat flow from water to air stream";
  output Modelica.Units.SI.Temperature TWatOut
    "Temperature at the water outlet";
  output Modelica.Units.SI.Temperature TSurAirIn
    "Coil surface temperature at the air inlet";
  output Modelica.Units.SI.Temperature TAirOut "Temperature at the air outlet";
initial equation
  TWatOutEst=0.5*(TWatIn+ TAirIn);

equation

  hAirIn=AixLib.Media.Air.specificEnthalpy_pTX(
    p=pAir,T=TAirIn,X={X_wAirIn,1-X_wAirIn});
  hSatWatIn=hSatWatInM.hSat;
  dhSatdTWatIn=(hSatWatIn_dT_M.hSat-hSatWatInM.hSat)/dTWat;
  hSatWatOut= hSatWatOutM.hSat;
  NonZerDelWatTem=AixLib.Utilities.Math.Functions.regNonZeroPower(
    x=TWatOutEst-TWatIn,n=1,delta=0.1);
  cpEff = AixLib.Utilities.Math.Functions.smoothMax(
    (hSatWatOut - hSatWatIn)/NonZerDelWatTem,
    dhSatdTWatIn,
    cpEff0*delta);

  CStaMin=AixLib.Utilities.Math.Functions.smoothMin(
    mAir_flow,
    mWat_flow*cpWat/cpEff,
    deltaCStaMin/4);

  UASta = (UAAir/cpAir)/(1 + (cpEff*UAAir)/(cpAir*UAWat));

  epsSta=epsilon_C(
    UA=UASta*cpDum,
    C1_flow=mWat_flow*cpWat/cpEff*cpDum,
    C2_flow=mAir_flow*cpDum,
    flowRegime=Integer(cfg),
    CMin_flow_nominal=CStaMin_flow_nominal*cpDum,
    CMax_flow_nominal=CStaMax_flow_nominal*cpDum,
    delta=delta);

  QTot_flow = epsSta*CStaMin*(hAirIn  - hSatWatIn);

  QTot_flow = mAir_flow*(hAirIn- hAirOut);
  TWatOut=TWatIn+QTot_flow/(mWatNonZer_flow*cpWat);

  NTUAirSta = UAAir/(mAir_flow*cpAir);

  hSatSurEff = AixLib.Utilities.Math.Functions.smoothMax(
    x1 = hSatSurEffMinM.hSat,
    x2 = hAirIn  +(hAirOut - hAirIn) / (1 - exp(-NTUAirSta)),
    deltaX = delta*1E4); // NTUAirSta is bounded as long as UAAir>0 due to the regularization of mAir_flow

  hSatSurEffM.hSat=hSatSurEff;
  TAirOut = TSurEff +(TAirIn  - TSurEff)*exp(-NTUAirSta);
  QSen_flow= AixLib.Utilities.Math.Functions.smoothMin(
    x1 = mAir_flow*cpAir*(TAirIn-TAirOut),
    x2 = QTot_flow,
    deltaX = delta*mWatNonZer_flow*cpWat0*5); // the last term is only for regularization with DTWater=5oC

  TSurAirIn = (TAirIn * UAAir + TWatOut * UAWat) / (UAWat + UAAir);
  der(TWatOutEst)=-1/tau*TWatOutEst+1/tau*TWatOut;
end WetCoilWetRegime;


Test model for HACoilInside. Test model for
        AixLib.Fluid.HeatExchanger.BaseClassess.HACoilInside.

within AixLib.Fluid.HeatExchangers.BaseClasses.Examples;
model HACoilInside "Test model for HACoilInside"
  extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.Sine sine(
    f=0.1,
    amplitude=0.063,
    offset=0.063) "Mass flow rate"
  Modelica.Blocks.Sources.Sine sine1(
    amplitude=10,
    f=0.1,
    offset=273.15 + 50) "Temperature"
  AixLib.Fluid.HeatExchangers.BaseClasses.HACoilInside hASin(
    hA_nominal=13*(0.5+1)/0.5,
    m_flow_nominal=0.063) "Model for convection coefficient"
equation
  connect(sine1.y, hASin.T)
  connect(sine.y, hASin.m_flow)
end HACoilInside;


Test model for dry coil convection coefficient. Test model for
AixLib.Fluid.HeatExchangers.BaseClasses.HADryCoil.

within AixLib.Fluid.HeatExchangers.BaseClasses.Examples;
model HADryCoil "Test model for dry coil convection coefficient"
  extends Modelica.Icons.Example;
  AixLib.Fluid.HeatExchangers.BaseClasses.HADryCoil  hADryCoi(
    m_flow_nominal_w=0.1,
    UA_nominal=10000,
    m_flow_nominal_a=2.5) "Calculates an hA value for a dry coil"
  Modelica.Blocks.Sources.Ramp TWat(
    offset=293.15,
    duration=20,
    startTime=40,
    height=40) "Temperature of the water"
  Modelica.Blocks.Sources.Ramp TAir(
    height=-20,
    offset=293.15,
    duration=20,
    startTime=60) "Temperature of the air"
  Modelica.Blocks.Sources.Ramp mWat_flow(
    height=0.1,
    duration=20,
    offset=0) "Water mass flow rate"
  Modelica.Blocks.Sources.Ramp mAir_flow(
    duration=20,
    offset=0,
    height=2.5,
    startTime=20) "Air mass flow rate"
  AixLib.Fluid.HeatExchangers.BaseClasses.HADryCoil hADryCoiAir(
    m_flow_nominal_w=0.1,
    UA_nominal=10000,
    m_flow_nominal_a=2.5,
    waterSideFlowDependent=false,
    waterSideTemperatureDependent=false)
    "Calculates an hA value for a dry coil"
  AixLib.Fluid.HeatExchangers.BaseClasses.HADryCoil hADryCoiWat(
    m_flow_nominal_w=0.1,
    UA_nominal=10000,
    m_flow_nominal_a=2.5,
    airSideFlowDependent=false,
    airSideTemperatureDependent=false) "Calculates an hA value for a dry coil"
equation
  connect(TWat.y, hADryCoi.T_1)
  connect(hADryCoi.T_2, TAir.y)
  connect(mAir_flow.y, hADryCoi.m2_flow)
  connect(mWat_flow.y, hADryCoi.m1_flow)
  connect(TWat.y, hADryCoiAir.T_1)
  connect(hADryCoiAir.T_2, TAir.y)
  connect(mAir_flow.y, hADryCoiAir.m2_flow)
  connect(mWat_flow.y, hADryCoiAir.m1_flow)
  connect(TWat.y, hADryCoiWat.T_1)
  connect(hADryCoiWat.T_2, TAir.y)
  connect(mAir_flow.y, hADryCoiWat.m2_flow)
  connect(mWat_flow.y, hADryCoiWat.m1_flow)
end HADryCoil;


within AixLib.Fluid.HeatExchangers.BaseClasses.Examples;
model HANaturalCylinder "Test model for natural convection outside of a coil"
  extends Modelica.Icons.Example;
  AixLib.Fluid.HeatExchangers.BaseClasses.HANaturalCylinder hANatCyl(redeclare
      package Medium = AixLib.Media.Water,
      ChaLen=0.1,
    hA_nominal=10,
    TFlu_nominal=293.15,
    TSur_nominal=313.15)
    "Calculates an hA value for natural convection around a cylinder"
  Modelica.Blocks.Sources.Ramp TSur(
    duration=100,
    height=50,
    offset=293.15) "Temperature of the pipe surface"
  Modelica.Blocks.Sources.Ramp TFlu(
    duration=100,
    startTime=150,
    height=50,
    offset=293.15) "Temperature of the surrounding fluid"
equation
  connect(TSur.y, hANatCyl.TSur)
  connect(TFlu.y, hANatCyl.TFlu)
end HANaturalCylinder;


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


within AixLib.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 AixLib.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = AixLib.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 AixLib.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 AixLib.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = AixLib.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 AixLib.Fluid.HeatExchangers.Examples;
model DryCoilEffectivenessNTUMassFlow
  "Model of epsilon-NTU dry coil that tests variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    AixLib.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  AixLib.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=AixLib.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)

  AixLib.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 AixLib.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 = AixLib.Media.Water "Medium model for water";
 package Medium2 = AixLib.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";

  AixLib.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"
  AixLib.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"
  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=false,
    p=300000,
    T=293.15,
    nPorts=1) "Boundary condition"
  AixLib.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"
  AixLib.Fluid.Sensors.TemperatureTwoPort temSen(
    redeclare package Medium = Medium2,
    m_flow_nominal=m2_flow_nominal)
    "Temperature sensor"
  AixLib.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"
  AixLib.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"
  AixLib.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=AixLib.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 AixLib.Fluid.HeatExchangers.Examples;
model DynamicHX
  "Model that demonstrates use of a simple dynamic heat exchanger"
 package Medium1 = AixLib.Media.Water "Medium model";
  import AixLib;
  extends Modelica.Icons.Example;

 package Medium2 = AixLib.Media.Air "Medium model";

  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    use_p_in=true,
    T=273.15 + 10,
    X={0.001,0.999},
    nPorts=1)
    "Boundary condition"
    Modelica.Blocks.Sources.Ramp PIn(
    height=200,
    duration=60,
    offset=101325,
    startTime=50)
    "Ramp signal for pressure"

  AixLib.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2, T=273.15 + 5,
    use_p_in=true,
    use_T_in=true,
    nPorts=1)
    "Boundary condition"

    Modelica.Blocks.Sources.Ramp TWat(
    height=10,
    duration=60,
    offset=273.15 + 30,
    startTime=60) "Water temperature"
  Modelica.Blocks.Sources.Constant TDb(k=293.15) "Drybulb temperature"

  Modelica.Blocks.Sources.Constant POut(k=101325) "Pressure"

  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=true,
    p=300000,
    T=273.15 + 25,
    nPorts=1)
    "Boundary condition"

  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    T=273.15 + 50,
    use_T_in=true,
    nPorts=1)
    "Boundary condition"

  Modelica.Blocks.Sources.Trapezoid trapezoid(
    amplitude=5000,
    rising=10,
    width=100,
    falling=10,
    period=3600,
    offset=300000)
    "Signal for pressure boundary condition"
  AixLib.Fluid.HeatExchangers.DynamicHX dynamicHX(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=1,
    m2_flow_nominal=1,
    dp1_nominal=5000,
    dp2_nominal=1000,
    dT_nom=30,
    Q_nom=50000)
  AixLib.Fluid.Sensors.TemperatureTwoPort THeaOut1(
    redeclare package Medium = Medium1,
    m_flow_nominal=1,
    T_start=289.15) "Outlet temperature of the heater"
  AixLib.Fluid.Sensors.TemperatureTwoPort THeaOut2(
    redeclare package Medium = Medium2,
    m_flow_nominal=1,
    T_start=289.15) "Outlet temperature of the heater"
equation
  connect(PIn.y,sou_2. p_in)
  connect(TDb.y, sou_2.T_in)
  connect(TWat.y, sou_1.T_in)
  connect(POut.y, sin_2.p_in)
  connect(trapezoid.y, sin_1.p_in)
  connect(sou_1.ports[1], dynamicHX.port_a1)
  connect(sou_2.ports[1], dynamicHX.port_a2)
  connect(THeaOut1.port_a, dynamicHX.port_b1)
  connect(THeaOut1.port_b, sin_1.ports[1])
  connect(dynamicHX.port_b2, THeaOut2.port_a)
  connect(THeaOut2.port_b, sin_2.ports[1])
end DynamicHX;


within AixLib.Fluid.HeatExchangers.Examples;
model HeatingRod "Example for the usage of the heating rod model"
  extends Modelica.Icons.Example;
  extends AixLib.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = AixLib.Media.Water,
    m_flow_nominal=V*rhoWat/3600,
    Q_flow_nominal=100,
    conPI(k=10),
    vol(V=V/1000),
    mov(nominalValuesDefineDefaultPressureCurve=true));
  AixLib.Fluid.HeatExchangers.HeatingRod heatingRod(
    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,
    eta=0.97)
  Modelica.Blocks.Interfaces.IntegerOutput numSwiHR
    "Number of on switches of heating rod"
  Modelica.Blocks.Interfaces.RealOutput Pel
    "Electrical power used to provide current heat flow"

protected
  parameter Modelica.Units.SI.Density rhoWat=1000 "Density of water";

equation
  connect(mov.port_b, heatingRod.port_a)
  connect(heatingRod.port_b, THeaOut.port_a)

  connect(conPI.y, heatingRod.u)
  connect(heatingRod.numSwi, numSwiHR)
  connect(heatingRod.Pel, Pel)
end HeatingRod;


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


within AixLib.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 AixLib.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = AixLib.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 AixLib.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 AixLib.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = AixLib.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 AixLib.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 AixLib.Fluid.HeatExchangers.Examples.BaseClasses.Heater(
    redeclare package Medium = AixLib.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 AixLib.Fluid.HeatExchangers.Examples;
model WetCoilEffectivenessNTUMassFlow
  "Model that tests the wet coil effectiveness-NTU model with variable mass flow rates"
  extends Modelica.Icons.Example;
  extends
    AixLib.Fluid.HeatExchangers.Examples.BaseClasses.EffectivenessNTUMassFlow(
    sou_1(nPorts=1),
    sin_1(nPorts=1),
    sou_2(nPorts=1),
    sin_2(nPorts=1));

  AixLib.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/AixLib.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 AixLib.Fluid.HeatExchangers.Examples.BaseClasses;
partial model EffectivenessNTUMassFlow
  "Partial model of epsilon-NTU coil that tests variable mass flow rates"
  package Medium1 = AixLib.Media.Water "Medium model for water";
  package Medium2 = AixLib.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";
  AixLib.Fluid.Sources.MassFlowSource_T sin_2(
    redeclare package Medium = Medium2,
    T=T_a2_nominal,
    use_m_flow_in=true) "Sink for air"
  AixLib.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"
  AixLib.Fluid.Sources.MassFlowSource_T sin_1(
    redeclare package Medium = Medium1,
    T=T_a1_nominal,
    use_m_flow_in=true) "Sink for water"
  AixLib.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"
  AixLib.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 AixLib.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";

  AixLib.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"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature TBou
    "Fixed temperature boundary condition"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TVol
    "Sensor for volume temperature"
  AixLib.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"
  AixLib.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 AixLib.Fluid.HeatExchangers.Examples;
package BaseClasses "Package with base classes for AixLib.Fluid.HeatExchangers.Examples"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within AixLib.Fluid.HeatExchangers;
package Radiators "Package with radiators models for hydronic space heating systems"
  extends Modelica.Icons.VariantsPackage;
end Radiators;


Radiator multilayer model

within AixLib.Fluid.HeatExchangers.Radiators;
model Radiator "Radiator multilayer model"
  import SIunits =
         Modelica.Units.SI;
  import calcT =
    AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.CalcExcessTemp;
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface;
  extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations(each final C_nominal=fill(1E-2, Medium.nC), each final C_start=fill(0, Medium.nC));
  // parameter Real kv=.1;
  parameter Boolean selectable=false
    "Radiator record"
  parameter AixLib.DataBase.Radiators.RadiatorBaseDataDefinition radiatorType
    "Choose a radiator"
  parameter
    AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.RadiatorTypes.RadiatorType
    Type=(if selectable then
      radiatorType.Type else BaseClasses.RadiatorTypes.PanelRadiator10)
    "Type of radiator"
  parameter Real NominalPower=
    (if selectable then radiatorType.NominalPower else 1000)
    "Nominal power of radiator per meter at nominal temperatures in W/m"
  parameter Real Exponent=(if selectable then radiatorType.Exponent else 1.29)
    "Radiator exponent"
  parameter Real VolumeWater(unit="l/m")=
    (if selectable then radiatorType.VolumeWater else 20)
    "Water volume inside radiator per m, in l/m"
  parameter Real MassSteel(unit="kg/m")=
    (if selectable then radiatorType.MassSteel else 30)
    "Material mass of radiator per m, in kg/m"
  parameter SIunits.Density DensitySteel=
    (if selectable then radiatorType.DensitySteel else 7900)
    "Specific density of steel, in kg/m3"
  parameter SIunits.SpecificHeatCapacity CapacitySteel=
    (if selectable then radiatorType.CapacitySteel else 551)
    "Specific heat capacity of steel, in J/kgK"
  parameter SIunits.ThermalConductivity LambdaSteel=
    (if selectable then radiatorType.LambdaSteel else 60)
    "Thermal conductivity of steel, in W/mK"
  parameter SIunits.Length length=
    (if selectable then radiatorType.length else 1)
    "Length of radiator, in m"
  parameter SIunits.Length height=
    (if selectable then radiatorType.height else 0.6)
    "Height of raditor, in m"
  parameter Modelica.Units.SI.Area A=2*length*height "Radiator surface area"
  parameter Modelica.Units.SI.Length d=0.025 "Thickness of radiator wall"
  parameter Modelica.Units.SI.Emissivity eps=0.95 "Emissivity"

  parameter SIunits.Temperature RT_nom[3]=(if selectable then radiatorType.RT_nom
       else Modelica.Units.Conversions.from_degC({75,65,20}))
    "Nominal temperatures (TIn, TOut, TAir) according to DIN-EN 442."
  parameter Real PD = (if selectable then radiatorType.PressureDrop else 548208)
    "Pressure drop coefficient, delta_p[Pa] = PD*m_flow[kg/s]^2"
  parameter Boolean from_dp = false
    "= true, use m_flow = f(dp) else dp = f(m_flow)"
  constant Boolean homotopyInitialization = true "= true, use homotopy method"
  parameter Boolean linearized = false
    "= true, use linear relation between m_flow and dp for any flow rate"

  parameter Integer N=16
    "Number of discretisation layers";
  parameter AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.CalcExcessTemp.Temp
    calc_dT=AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.CalcExcessTemp.exp
    "Select calculation method";

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a ConvectiveHeat
    "Convective heat port to room"
  AixLib.Utilities.Interfaces.RadPort RadiativeHeat "Radiative heat port to room"
  Sensors.TemperatureTwoPort FlowTemperature(redeclare package Medium =
             Medium,
    m_flow_nominal=m_flow_nominal)
    "Flow temperature"
  Sensors.TemperatureTwoPort ReturnTemperature(redeclare package Medium =
             Medium,
    m_flow_nominal=m_flow_nominal)
    "Return temperature"
  FixedResistances.PressureDrop    res(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=m_flow_nominal,
    final show_T=show_T,
    final from_dp=from_dp,
    final dp_nominal=PD*m_flow_nominal^2,
    final homotopyInitialization=homotopyInitialization,
    final linearized=linearized,
    final deltaM=deltaM)
    "Base class of radiator"

  parameter Real deltaM=0.3 "Fraction of nominal mass flow rate where transition to turbulent occurs"
  parameter Modelica.Fluid.Types.Dynamics initDynamicsWall=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial "Like energyDynamics, but SteadyState leeds to same behavior as DynamicFreeInitial"
protected
  parameter SIunits.Volume Vol_Water=(length*VolumeWater/1000)/N
    "Volume of water";
  parameter SIunits.Volume Vol_Steel=(length*MassSteel) / DensitySteel /N
    "Volume of steel"
  parameter SIunits.Length d1=2*(Vol_Water/Modelica.Constants.pi/length)^0.5
    "Inner diameter of single layer";
  parameter SIunits.Length d2=
    2*((Vol_Water+Vol_Steel)/Modelica.Constants.pi/length)^0.5
    "Outer diameter of single layer";
  parameter Real dT_V_nom=RT_nom[1]-RT_nom[3];
  parameter Real dT_R_nom=RT_nom[2]-RT_nom[3];

// Calculation of convective excess temperature, according to the chosen calculation method

  parameter Real dT_nom=if calc_dT==calcT.ari then (dT_V_nom+dT_R_nom)/2 else
    if calc_dT==calcT.log then (dT_V_nom-dT_R_nom)/log(dT_V_nom/dT_R_nom) else
    ((Exponent-1)*(dT_V_nom-dT_R_nom)/(dT_R_nom^(1-Exponent)-dT_V_nom^
    (1-Exponent)))^(1/Exponent)
    "Nominal temperature difference";

// Calculation of nominal radiation excess temperature

  parameter Real delta_nom=(dT_nom+RT_nom[3])*(dT_nom+RT_nom[3])*
    (dT_nom+RT_nom[3])*(dT_nom+RT_nom[3])-RT_nom[3]*RT_nom[3]*RT_nom[3]*RT_nom[3];
  parameter SIunits.Power Q_dot_nom_i= length * NominalPower/N
    "Nominal heating power per layer";

  BaseClasses.MultiLayerThermalDelta multiLayer_HE[N](
    redeclare each package Medium = Medium,
    each final allowFlowReversal=allowFlowReversal,
    each final m_flow_small=m_flow_small,
    each final show_T=false,
    each final energyDynamics=energyDynamics,
    each final massDynamics=massDynamics,
    each final p_start=p_start,
    each final T_start=T_start,
    each final X_start=X_start,
    each final mSenFac=1,
    each M_Radiator=(length*MassSteel)/N,
    each calc_dT=calc_dT,
    each Type=Type,
    each n=Exponent,
    each DensitySteel=DensitySteel,
    each CapacitySteel=CapacitySteel,
    each length=length,
    each Vol_Water=Vol_Water,
    each s_eff=Type[1],
    each Q_dot_nom_i=Q_dot_nom_i,
    each dT_nom=dT_nom,
    each delta_nom=delta_nom,
    each LambdaSteel=LambdaSteel,
    each eps=eps,
    each A=A/N,
    each d=d,
    each m_flow_nominal=m_flow_nominal,
    each final initDynamicsWall=initDynamicsWall)
    "Multilayer base class"

equation

  for i in 1:N loop
    connect(multiLayer_HE[i].convective, ConvectiveHeat);
    connect(multiLayer_HE[i].radiative, RadiativeHeat);
  end for;

  for j in 1:(N-1) loop
    connect(multiLayer_HE[j].port_b, multiLayer_HE[j+1].port_a);
  end for;

  connect( FlowTemperature.port_b, multiLayer_HE[1].port_a);
  connect(res.port_a, multiLayer_HE[N].port_b);

  connect(res.port_b, ReturnTemperature.port_a)

  connect(ReturnTemperature.port_b, port_b)
  connect(FlowTemperature.port_a, port_a)
end Radiator;


Dynamic radiator for space heating

within AixLib.Fluid.HeatExchangers.Radiators;
model RadiatorEN442_2 "Dynamic radiator for space heating"
   extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
   show_T=true,
   m_flow_nominal=abs(Q_flow_nominal/cp_nominal/(T_a_nominal-T_b_nominal)));
   extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations(
     final X_start = Medium.X_default,
     final C_start = fill(0, Medium.nC),
     final C_nominal = fill(1E-2, Medium.nC),
     final mSenFac = 1 + 500*mDry/(VWat*cp_nominal*Medium.density(
        Medium.setState_pTX(Medium.p_default, Medium.T_default, Medium.X_default))),
     final massDynamics=energyDynamics);

  constant Boolean homotopyInitialization = true "= true, use homotopy method"

  parameter Integer nEle(min=1) = 5
    "Number of elements used in the discretization";
  parameter Real fraRad(min=0, max=1) = 0.35 "Fraction radiant heat transfer";
  // Assumptions

  parameter Modelica.Units.SI.Power Q_flow_nominal
    "Nominal heating power (positive for heating)"
  parameter Modelica.Units.SI.Temperature T_a_nominal
    "Water inlet temperature at nominal condition"
  parameter Modelica.Units.SI.Temperature T_b_nominal
    "Water outlet temperature at nominal condition"
  parameter Modelica.Units.SI.Temperature TAir_nominal=293.15
    "Air temperature at nominal condition"
  parameter Modelica.Units.SI.Temperature TRad_nominal=TAir_nominal
    "Radiative temperature at nominal condition"

  parameter Real n = 1.24 "Exponent for heat transfer";
  parameter Modelica.Units.SI.Volume VWat=5.8E-6*abs(Q_flow_nominal)
    "Water volume of radiator"
  parameter Modelica.Units.SI.Mass mDry=0.0263*abs(Q_flow_nominal)
    "Dry mass of radiator that will be lumped to water heat capacity"
  parameter Real deltaM(min=0.01) = 0.3
    "Fraction of nominal mass flow rate where transition to turbulent occurs"

  parameter Boolean from_dp = false
    "= true, use m_flow = f(dp) else dp = f(m_flow)"

  parameter Modelica.Units.SI.PressureDifference dp_nominal(displayUnit="Pa")=
       0 "Pressure drop at nominal mass flow rate"
  parameter Boolean linearized = false
    "= true, use linear relation between m_flow and dp for any flow rate"

  // Heat flow rates
  Modelica.Units.SI.HeatFlowRate QCon_flow=heatPortCon.Q_flow
    "Heat input into the water due to convective heat transfer with room air";
  Modelica.Units.SI.HeatFlowRate QRad_flow=heatPortRad.Q_flow
    "Heat input into the water due to radiative heat transfer with room";
  Modelica.Units.SI.HeatFlowRate Q_flow=QCon_flow + QRad_flow
    "Heat input into the water";

  // Heat ports
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPortCon
    "Heat port for convective heat transfer with room air temperature"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPortRad
    "Heat port for radiative heat transfer with room radiation temperature"

  AixLib.Fluid.MixingVolumes.MixingVolume[nEle] vol(
    redeclare each package Medium = Medium,
    each nPorts=2,
    each V=VWat/nEle,
    each final m_flow_nominal = m_flow_nominal,
    each final energyDynamics=energyDynamics,
    each final massDynamics=energyDynamics,
    each final p_start=p_start,
    each final T_start=T_start,
    each final X_start=X_start,
    each final C_start=C_start,
    each final mSenFac=mSenFac) "Volume for fluid stream"
protected
  parameter Modelica.Units.SI.SpecificHeatCapacity cp_nominal=
      Medium.specificHeatCapacityCp(Medium.setState_pTX(
      Medium.p_default,
      T_a_nominal,
      Medium.X_default)) "Specific heat capacity at nominal conditions";
  parameter Modelica.Units.SI.HeatFlowRate QEle_flow_nominal[nEle](each fixed=
        false, each start=Q_flow_nominal/nEle)
    "Nominal heating power of each element";
  parameter Modelica.Units.SI.Temperature TWat_nominal[nEle](each fixed=false,
      start={T_a_nominal - i/nEle*(T_a_nominal - T_b_nominal) for i in 1:nEle})
    "Water temperature in each element at nominal conditions";
  parameter Modelica.Units.SI.TemperatureDifference[nEle] dTRad_nominal(each
      fixed=false, start={T_a_nominal - i/nEle*(T_a_nominal - T_b_nominal) -
        TRad_nominal for i in 1:nEle})
    "Temperature difference for radiative heat transfer at nominal conditions";
  parameter Modelica.Units.SI.TemperatureDifference[nEle] dTCon_nominal(each
      fixed=false, start={T_a_nominal - i/nEle*(T_a_nominal - T_b_nominal) -
        TAir_nominal for i in 1:nEle})
    "Temperature difference for convective heat transfer at nominal conditions";

  parameter Modelica.Units.SI.ThermalConductance UAEle(
    fixed=false,
    min=0,
    start=Q_flow_nominal/((T_a_nominal + T_b_nominal)/2 - ((1 - fraRad)*
        TAir_nominal + fraRad*TRad_nominal))/nEle)
    "UA value at nominal condition for each element";

   final parameter Real k = if T_b_nominal > TAir_nominal then 1 else -1
    "Parameter that is used to compute QEle_flow_nominal for heating or cooling mode";

   Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow[nEle] preCon(
    each final alpha=0)
    "Heat input into radiator from convective heat transfer"
   Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow[nEle] preRad(
    each final alpha=0)
    "Heat input into radiator from radiative heat transfer"

  Modelica.Units.SI.TemperatureDifference dTCon[nEle]={heatPortCon.T - vol[i].T
      for i in 1:nEle} "Temperature difference for convective heat transfer";
  Modelica.Units.SI.TemperatureDifference dTRad[nEle]={heatPortRad.T - vol[i].T
      for i in 1:nEle} "Temperature difference for radiative heat transfer";

  Modelica.Blocks.Sources.RealExpression QCon[nEle](y={if homotopyInitialization
         then homotopy(actual=(1 - fraRad) * UAEle * (heatPortCon.T - vol[i].T) *
        AixLib.Utilities.Math.Functions.regNonZeroPower(
        x=(heatPortCon.T - vol[i].T),
        n=n - 1,
        delta=0.05), simplified=(1 - fraRad) * UAEle .* abs(dTCon_nominal[i]) ^ (
        n - 1) * (heatPortCon.T - vol[i].T)) else (1 - fraRad) * UAEle * (heatPortCon.T - vol[i].T) *
        AixLib.Utilities.Math.Functions.regNonZeroPower(
        x=(heatPortCon.T - vol[i].T),
        n=n - 1,
        delta=0.05) for i in 1:nEle}) "Convective heat flow rate"

  Modelica.Blocks.Sources.RealExpression QRad[nEle](y={if homotopyInitialization
         then homotopy(actual=fraRad * UAEle * (heatPortRad.T - vol[i].T) *
        AixLib.Utilities.Math.Functions.regNonZeroPower(
        x=(heatPortRad.T - vol[i].T),
        n=n - 1,
        delta=0.05), simplified=fraRad * UAEle * abs(dTRad_nominal[i]) ^ (n - 1)
         * (heatPortRad.T - vol[i].T)) else fraRad * UAEle * (heatPortRad.T - vol[i].T) *
        AixLib.Utilities.Math.Functions.regNonZeroPower(
        x=(heatPortRad.T - vol[i].T),
        n=n - 1,
        delta=0.05) for i in 1:nEle}) "Radiative heat flow rate"

  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preSumCon(
    final alpha=0)
    "Heat input into radiator from convective heat transfer"
  Modelica.Blocks.Math.Sum sumCon(nin=nEle, k=-ones(nEle))
    "Sum of convective heat flow rate"
  Modelica.Blocks.Math.Sum sumRad(nin=nEle, k=-ones(nEle))
    "Sum of radiative heat flow rate"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preSumRad(
    final alpha=0)
    "Heat input into radiator from radiative heat transfer"

  AixLib.Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=m_flow_nominal,
    final from_dp=from_dp,
    final dp_nominal=dp_nominal,
    final homotopyInitialization=homotopyInitialization,
    final linearized=linearized,
    final deltaM=deltaM,
    final show_T=false) "Pressure drop component"

initial equation
  if T_b_nominal > TAir_nominal then
     assert(T_a_nominal > T_b_nominal,
       "In RadiatorEN442_2, T_a_nominal must be higher than T_b_nominal.");
     assert(Q_flow_nominal > 0,
       "In RadiatorEN442_2, nominal power must be bigger than zero if T_b_nominal > TAir_nominal.");
  else
     assert(T_a_nominal < T_b_nominal,
       "In RadiatorEN442_2, T_a_nominal must be lower than T_b_nominal.");
     assert(Q_flow_nominal < 0,
       "In RadiatorEN442_2, nominal power must be smaller than zero if T_b_nominal < TAir_nominal.");
  end if;
  TWat_nominal[1] = T_a_nominal - QEle_flow_nominal[1]/m_flow_nominal/
  Medium.specificHeatCapacityCp(
        Medium.setState_pTX(Medium.p_default, T_a_nominal, Medium.X_default));
  for i in 2:nEle loop
    TWat_nominal[i] = TWat_nominal[i-1] - QEle_flow_nominal[i]/m_flow_nominal/
    Medium.specificHeatCapacityCp(
        Medium.setState_pTX(Medium.p_default, TWat_nominal[i-1], Medium.X_default));
  end for;
  dTRad_nominal = TWat_nominal .- TRad_nominal;
  dTCon_nominal = TWat_nominal .- TAir_nominal;
  Q_flow_nominal = sum(QEle_flow_nominal);

  for i in 1:nEle loop
    // Use difference, TWat_nominal[i] - TRad/Air_nominal, to avoid larger system of equations
    QEle_flow_nominal[i] = k * UAEle * (fraRad *
      AixLib.Utilities.Math.Functions.powerLinearized(
        x=k*TWat_nominal[i] - TRad_nominal,
        n=n,
        x0=0.1*k*(T_b_nominal-TRad_nominal)) + (1-fraRad) *
      AixLib.Utilities.Math.Functions.powerLinearized(
        x=k*TWat_nominal[i] - TAir_nominal,
        n=n,
        x0=0.1*k*(T_b_nominal-TAir_nominal)));
   end for;

  assert(homotopyInitialization, "In " + getInstanceName() +
    ": The constant homotopyInitialization has been modified from its default value. This constant will be removed in future releases.",
    level = AssertionLevel.warning);

equation
  connect(preCon.port, vol.heatPort)
  connect(preRad.port, vol.heatPort)
  connect(vol[nEle].ports[2], port_b)
  for i in 1:nEle-1 loop
    connect(vol[i].ports[2], vol[i+1].ports[1])
  end for;
  connect(QCon.y, preCon.Q_flow)
  connect(sumCon.u, QCon.y)
  connect(sumCon.y, preSumCon.Q_flow)
  connect(preSumCon.port, heatPortCon)
  connect(QRad.y, preRad.Q_flow)
  connect(QRad.y, sumRad.u)
  connect(sumRad.y, preSumRad.Q_flow)
  connect(preSumRad.port, heatPortRad)
  connect(res.port_a, port_a)
  connect(res.port_b, vol[1].ports[1])
end RadiatorEN442_2;


Radiator exponent.

within AixLib.Fluid.HeatExchangers.Radiators.BaseClasses;
model HeatConvRadiator

  parameter Real n "Radiator exponent";
  parameter Real NominalPower "Nominal power of radiator";
  parameter Real s_eff "Fraction of radiation power";
  parameter Real dT_nom "Nominal temperature difference";
  parameter Real kA=(1-s_eff)*NominalPower/dT_nom^n;
  Real alpha_t;
  Modelica.Units.NonSI.Temperature_degC posDiff=noEvent(abs(port_b.T - port_a.T))
    "Positive temperature difference";
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_a
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port_b

equation
  alpha_t = if noEvent(posDiff <= 5e-12) then 0 else (kA*noEvent(posDiff^(n-1)));
  port_a.Q_flow + port_b.Q_flow = 0;
  port_a.Q_flow = alpha_t*(port_a.T - port_b.T);
end HeatConvRadiator;


multi layers of heat exchanger

within AixLib.Fluid.HeatExchangers.Radiators.BaseClasses;
model MultiLayerThermalDelta "multi layers of heat exchanger"

  import calcT =
    AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.CalcExcessTemp;
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface;
  extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations(each final C_nominal=fill(1E-2, Medium.nC), each final C_start=fill(0, Medium.nC));

  parameter Modelica.Units.SI.Mass M_Radiator "Mass of radiator";
  parameter calcT.Temp calc_dT
    "Select calculation method of excess temperature";
  parameter
    AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.RadiatorTypes.RadiatorType
    Type
    "Type of radiator"
  parameter Real n
    "Radiator exponent"
  parameter Modelica.Units.SI.Density DensitySteel=DensitySteel
    "Specific density of steel, in kg/m3"
  parameter Modelica.Units.SI.SpecificHeatCapacity CapacitySteel=CapacitySteel
    "Specific heat capacity of steel, in J/kgK"
  parameter Modelica.Units.SI.ThermalConductivity LambdaSteel=LambdaSteel
    "Thermal conductivity of steel, in W/mK"
  parameter Modelica.Units.SI.Length length "Length of radiator, in m"

  parameter Modelica.Units.SI.Volume Vol_Water "Water volume inside layer";
  parameter Real s_eff=Type[1]
    "Radiative coefficient";
  parameter Real Q_dot_nom_i
    "Nominal power of single layer";
  parameter Real dT_nom
    "Nominal access temperature";
  parameter Real delta_nom
    "Nominal Radiation temperature";
  parameter Modelica.Units.SI.Emissivity eps "Emissivity";
  parameter Modelica.Units.SI.Area A "Area of radiator layer";
  parameter Modelica.Units.SI.Length d "Thickness of radiator wall";

  parameter Modelica.Fluid.Types.Dynamics initDynamicsWall=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
   "Like energyDynamics, but SteadyState leeds to same behavior as DynamicFreeInitial"

  AixLib.Utilities.Interfaces.RadPort radiative
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a convective
  Utilities.HeatTransfer.HeatToRad twoStar_RadEx(A=(s_eff*Q_dot_nom_i)/((delta_nom)*Modelica.Constants.sigma*eps), eps=1)
  AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.HeatConvRadiator
    heatConv_Radiator(
    final n=n,
    final NominalPower=Q_dot_nom_i,
    final s_eff=s_eff,
    final dT_nom=dT_nom)
  AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.RadiatorWall radiator_wall(
    final initDynamics=initDynamicsWall,
    final lambda=LambdaSteel,
    final c=CapacitySteel,
    final d=d,
    final T0=T_start,
    final A=A,
    final C=M_Radiator*CapacitySteel)
  AixLib.Fluid.MixingVolumes.MixingVolume Volume(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final massDynamics=massDynamics,
    final p_start=p_start,
    final T_start=T_start,
    each final X_start=X_start,
    each final C_start=C_start,
    each final C_nominal=C_nominal,
    final mSenFac=1,
    final m_flow_small=m_flow_small,
    final V=Vol_Water,
    final use_C_flow=false,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)

equation

  connect(heatConv_Radiator.port_b, convective)
  connect(radiator_wall.port_b, heatConv_Radiator.port_a)
  connect(radiator_wall.port_b, twoStar_RadEx.convPort)
  connect(twoStar_RadEx.radPort, radiative)
  connect(Volume.heatPort, radiator_wall.port_a)
  connect(port_a, Volume.ports[1])
  connect(Volume.ports[2], port_b)
end MultiLayerThermalDelta;


Calculates the pressure drop in a radiator according to manufacturer data.

within AixLib.Fluid.HeatExchangers.Radiators.BaseClasses;
model PressureDropRadiator
  "Calculates the pressure drop in a radiator according to manufacturer data"
  extends AixLib.Fluid.Interfaces.PartialTwoPortTransport;

  parameter Real PD(unit="1/(kg.m)")
    "Pressure drop coefficient, delta_p[Pa] = PD*m_flow[kg/s]^2";

equation
   // Isenthalpic state transformation (no storage and no loss of energy)
  port_a.h_outflow = inStream(port_b.h_outflow);
  port_b.h_outflow = inStream(port_a.h_outflow);

  //Hydraulic Part: pressure drop

   port_b.p = if noEvent(port_a.m_flow>=0) then port_a.p - PD*port_a.m_flow*
   port_a.m_flow else  port_a.p + PD*port_a.m_flow*port_a.m_flow;
end PressureDropRadiator;


Simple (vertical) sectional radiator

within AixLib.Fluid.HeatExchangers.Radiators.BaseClasses;
package RadiatorTypes
  extends Modelica.Icons.TypesPackage;

  // constants: ratio of radiative power as a fraction of total heat emission (taken from DIN EN 442-2, 2003),

  type RadiatorType = Real[2]
  constant Real[2] SectionalRadiator={0.30,1};
  constant Real[2] PanelRadiator10={0.50,1};
  constant Real[2] PanelRadiator11={0.35,1.9};
  constant Real[2] PanelRadiator12={0.25,2.8};
  constant Real[2] PanelRadiator20={0.35,2.1};
  constant Real[2] PanelRadiator21={0.20,3.3};
  constant Real[2] PanelRadiator22={0.15,4.5};
  constant Real[2] PanelRadiator30={0.20,3.7};
  constant Real[2] PanelRadiator31={0.15,4.8};
  constant Real[2] PanelRadiator32={0.10,6.7};
  constant Real[2] PanelRadiator33={0.10,7.9};
                                               // extrapolated convective surface ( used surface increase of 1.2 - Peter Mathes)
  // also more convection devices
  constant Real[2] ConvectorHeaterUncovered={0.05,1};
  constant Real[2] ConvectorHeaterCovered={0.00,1};
  constant Real[2] ThermX2Typ10={0.5,1};
  constant Real[2] ThermX2Typ11={0.35,1};
  constant Real[2] ThermX2Typ12={0.3,1};
  constant Real[2] ThermX2Typ22={0.3,1};
  constant Real[2] ThermX2Typ33={0.2,1};

// protected

end RadiatorTypes;


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


Example for EBC radiator

within AixLib.Fluid.HeatExchangers.Radiators.Examples;
model Radiator "Example for EBC radiator"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Water "Medium model";
  Sources.MassFlowSource_T source(redeclare package Medium = Medium,
    nPorts=1,
    m_flow=0.02761,
    T=328.15)
  Sources.Boundary_pT   sink(redeclare package Medium = Medium,
    nPorts=1)
    "Sink"
  AixLib.Fluid.HeatExchangers.Radiators.Radiator radiator(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    selectable=true,
    radiatorType=AixLib.DataBase.Radiators.RadiatorBaseDataDefinition(
        NominalPower=496,
        RT_nom=Modelica.Units.Conversions.from_degC({55,45,20}),
        PressureDrop=1017878,
        Exponent=1.2776,
        VolumeWater=3.6,
        MassSteel=17.01,
        DensitySteel=7900,
        CapacitySteel=551,
        LambdaSteel=60,
        Type=BaseClasses.RadiatorTypes.PanelRadiator10,
        length=2.6,
        height=0.3),
    calc_dT=AixLib.Fluid.HeatExchangers.Radiators.BaseClasses.CalcExcessTemp.exp)
    "Radiator"
  FixedResistances.PressureDrop       res(redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=100000)
    "Pipe"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature convTemp(T=293.15)
    "Convetive heat"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature radTemp(T=293.15)
    "Radiative heat"
equation
  connect(radiator.port_b, res.port_a)
  connect(res.port_b, sink.ports[1])
  connect(radTemp.port, radiator.RadiativeHeat)
  connect(convTemp.port, radiator.ConvectiveHeat)
  connect(source.ports[1], radiator.port_a)
end Radiator;


Test model for radiator

within AixLib.Fluid.HeatExchangers.Radiators.Examples;
model RadiatorEN442_2 "Test model for radiator"
  extends Modelica.Icons.Example;
 package Medium = AixLib.Media.Water "Medium model";
  parameter Modelica.Units.SI.Temperature TRoo=20 + 273.15 "Room temperature"
  parameter Modelica.Units.SI.Power Q_flow_nominal=500 "Nominal power";
  parameter Modelica.Units.SI.Temperature T_a_nominal=313.15
    "Radiator inlet temperature at nominal condition";
  parameter Modelica.Units.SI.Temperature T_b_nominal=303.15
    "Radiator outlet temperature at nominal condition";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=Q_flow_nominal/(
      T_a_nominal - T_b_nominal)/Medium.cp_const "Nominal mass flow rate";
  parameter Modelica.Units.SI.PressureDifference dp_nominal=3000
    "Pressure drop at m_flow_nominal";

  AixLib.Fluid.Sources.Boundary_pT sou(
    nPorts=2,
    redeclare package Medium = Medium,
    use_p_in=true,
    T=T_a_nominal)
  FixedResistances.PressureDrop res2(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=dp_nominal)
  FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=dp_nominal)
  AixLib.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    nPorts=2,
    p(displayUnit="Pa") = 300000,
    T=T_b_nominal) "Sink"

  AixLib.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad1(
    redeclare package Medium = Medium,
    T_a_nominal=T_a_nominal,
    T_b_nominal=T_b_nominal,
    Q_flow_nominal=Q_flow_nominal,
    TAir_nominal=TRoo,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Radiator"
  AixLib.Fluid.HeatExchangers.Radiators.RadiatorEN442_2 rad2(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_a_nominal=T_a_nominal,
    T_b_nominal=T_b_nominal,
    Q_flow_nominal=Q_flow_nominal,
    TAir_nominal=TRoo) "Radiator"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TBCCon1(T=TRoo)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TBCCon2(T=TRoo)
  Modelica.Blocks.Sources.Step step(
    startTime=3600,
    offset=300000 + dp_nominal,
    height=-dp_nominal)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TBCRad2(T=TRoo)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TBCRad1(T=TRoo)
equation
  connect(sou.ports[1], rad1.port_a)
  connect(sou.ports[2], rad2.port_a)
  connect(rad1.port_b, res1.port_a)
  connect(rad2.port_b, res2.port_a)
  connect(res1.port_b, sin.ports[1])
  connect(res2.port_b, sin.ports[2])
  connect(step.y, sou.p_in)
  connect(TBCRad2.port, rad2.heatPortRad)
  connect(TBCRad1.port, rad1.heatPortRad)
  connect(TBCCon2.port, rad2.heatPortCon)
  connect(TBCCon1.port, rad1.heatPortCon)
end RadiatorEN442_2;


within AixLib.Fluid.HeatExchangers.Validation;
model ConstantEffectiveness
  "Model that demonstrates use of a heat exchanger with constant effectiveness"
  extends Modelica.Icons.Example;

 package Medium1 = AixLib.Media.Water "Medium model";
 package Medium2 = AixLib.Media.Air "Medium model";

  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    use_p_in=true,
    nPorts=1,
    T=273.15 + 10,
    X={0.001,0.999})
    "Boundary condition"
    Modelica.Blocks.Sources.Ramp PIn(
    height=200,
    duration=60,
    offset=101325,
    startTime=50)
    "Ramp signal for pressure"

  AixLib.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2, T=273.15 + 5,
    use_p_in=true,
    use_T_in=true,
    nPorts=1)
    "Boundary condition"

    Modelica.Blocks.Sources.Ramp TWat(
    height=10,
    duration=60,
    offset=273.15 + 30,
    startTime=60) "Water temperature"
  Modelica.Blocks.Sources.Constant TDb(k=293.15) "Drybulb temperature"

  Modelica.Blocks.Sources.Constant POut(k=101325) "Pressure"

  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=true,
    nPorts=1,
    p=300000,
    T=273.15 + 25)
    "Boundary condition"

  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    T=273.15 + 50,
    use_T_in=true,
    nPorts=1)
    "Boundary condition"

  AixLib.Fluid.HeatExchangers.ConstantEffectiveness hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    show_T=true,
    m1_flow_nominal=5,
    m2_flow_nominal=5,
    dp1_nominal=500,
    dp2_nominal=10)
    "Heat exchanger"

  Modelica.Blocks.Sources.Trapezoid trapezoid(
    amplitude=5000,
    rising=10,
    width=100,
    falling=10,
    period=3600,
    offset=300000)
    "Signal for pressure boundary condition"
equation
  connect(PIn.y,sou_2. p_in)
  connect(TDb.y, sou_2.T_in)
  connect(TWat.y, sou_1.T_in)
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_a2, sou_2.ports[1])
  connect(POut.y, sin_2.p_in)
  connect(hex.port_b1, sin_1.ports[1])
  connect(sin_2.ports[1], hex.port_b2)
  connect(trapezoid.y, sin_1.p_in)
end ConstantEffectiveness;


within AixLib.Fluid.HeatExchangers.Validation;
model DryCoilEffectivenessNTU
  "Model that demonstrates use of a heat exchanger without condensation that uses the epsilon-NTU relation"
  extends Modelica.Icons.Example;

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

  parameter Modelica.Units.SI.SpecificHeatCapacity cp1=
      Medium1.specificHeatCapacityCp(Medium1.setState_pTX(
      Medium1.p_default,
      Medium1.T_default,
      Medium1.X_default)) "Specific heat capacity of medium 2";
  parameter Modelica.Units.SI.SpecificHeatCapacity cp2=
      Medium2.specificHeatCapacityCp(Medium2.setState_pTX(
      Medium2.p_default,
      Medium2.T_default,
      Medium2.X_default)) "Specific heat capacity of medium 2";
  parameter Modelica.Units.SI.MassFlowRate m1_flow=5
    "Nominal mass flow rate medium 1";
  parameter Modelica.Units.SI.MassFlowRate m2_flow=m1_flow*cp1/cp2
    "Nominal mass flow rate medium 2";

  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2,
    use_p_in=true,
    nPorts=5,
    T=273.15 + 10) "Boundary condition"
    Modelica.Blocks.Sources.Ramp PIn(
    height=200,
    duration=60,
    offset=101325,
    startTime=100) "Pressure boundary condition"
  AixLib.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2,
    T=273.15 + 5,
    use_p_in=true,
    use_T_in=true,
    nPorts=5) "Boundary condition"
    Modelica.Blocks.Sources.Ramp TWat(
    height=10,
    duration=60,
    offset=273.15 + 30,
    startTime=60) "Water temperature"
  Modelica.Blocks.Sources.Constant TDb(k=293.15) "Drybulb temperature"
    Modelica.Blocks.Sources.Constant POut(k=101325)
  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=true,
    nPorts=5,
    p=300000,
    T=273.15 + 25)
    "Boundary condition"
  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    p=300000 + 5000,
    T=273.15 + 50,
    use_T_in=true,
    nPorts=5)
    "Boundary condition"
  AixLib.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexPar(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    dp1_nominal=500,
    dp2_nominal=10,
    m1_flow_nominal=m1_flow,
    m2_flow_nominal=m2_flow,
    Q_flow_nominal=m2_flow*cp2*(24 - 20),
    configuration=AixLib.Fluid.Types.HeatExchangerConfiguration.ParallelFlow,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"

  AixLib.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexCou(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    dp1_nominal=500,
    dp2_nominal=10,
    m1_flow_nominal=m1_flow,
    m2_flow_nominal=m2_flow,
    Q_flow_nominal=m2_flow*cp2*(24 - 20),
    configuration=AixLib.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  AixLib.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexCroC1Mix(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    dp1_nominal=500,
    dp2_nominal=10,
    m1_flow_nominal=m1_flow,
    m2_flow_nominal=m2_flow,
    Q_flow_nominal=m2_flow*cp2*(24 - 20),
    configuration=AixLib.Fluid.Types.HeatExchangerConfiguration.CrossFlowStream1MixedStream2Unmixed,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  AixLib.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexCroC1Unm(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    dp1_nominal=500,
    dp2_nominal=10,
    m1_flow_nominal=m1_flow,
    m2_flow_nominal=m2_flow,
    Q_flow_nominal=m2_flow*cp2*(24 - 20),
    configuration=AixLib.Fluid.Types.HeatExchangerConfiguration.CrossFlowStream1UnmixedStream2Mixed,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  AixLib.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexCroUnm(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    dp1_nominal=500,
    dp2_nominal=10,
    m1_flow_nominal=m1_flow,
    m2_flow_nominal=m2_flow,
    Q_flow_nominal=m2_flow*cp2*(24 - 20),
    configuration=AixLib.Fluid.Types.HeatExchangerConfiguration.CrossFlowUnmixed,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  Modelica.Blocks.Sources.Trapezoid trapezoid(
    amplitude=5000,
    rising=10,
    width=100,
    falling=10,
    period=3600,
    offset=300000)
    "Pressure boundary condition"
equation
  connect(PIn.y,sou_2. p_in)
  connect(TDb.y, sou_2.T_in)
  connect(TWat.y, sou_1.T_in)
  connect(sou_1.ports[1], hexPar.port_a1)
  connect(hexPar.port_a2, sou_2.ports[1])
  connect(POut.y, sin_2.p_in)
  connect(hexPar.port_b1, sin_1.ports[1])
  connect(sin_2.ports[1], hexPar.port_b2)
  connect(hexCou.port_a1, sou_1.ports[2])
  connect(hexCroC1Mix.port_a1, sou_1.ports[3])
  connect(hexCroC1Unm.port_a1, sou_1.ports[4])
  connect(hexCou.port_b2, sin_2.ports[2])
  connect(hexCroC1Mix.port_b2, sin_2.ports[3])
  connect(hexCroC1Unm.port_b2, sin_2.ports[4])
  connect(hexCou.port_b1, sin_1.ports[2])
  connect(hexCroC1Mix.port_b1, sin_1.ports[3])
  connect(hexCroC1Unm.port_b1, sin_1.ports[4])
  connect(hexCou.port_a2, sou_2.ports[2])
  connect(hexCroC1Mix.port_a2, sou_2.ports[3])
  connect(hexCroC1Unm.port_a2, sou_2.ports[4])
  connect(hexCroUnm.port_a1, sou_1.ports[5])
  connect(hexCroUnm.port_b2, sin_2.ports[5])
  connect(hexCroUnm.port_b1, sin_1.ports[5])
  connect(hexCroUnm.port_a2, sou_2.ports[5])
  connect(trapezoid.y, sin_1.p_in)
end DryCoilEffectivenessNTU;


within AixLib.Fluid.HeatExchangers.Validation;
model EvaporatorCondenser "Test model for the evaporator or condenser model"
  extends Modelica.Icons.Example;

  package Medium = AixLib.Media.Water "Medium model";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.01
    "Nominal mass flow rate";

  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature ref(T=283.15)
    "Refrigerant temperature"

  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heaFlo
    "Heat flow rate sensor"
  Modelica.Fluid.Sources.MassFlowSource_T sou(
    nPorts=1,
    redeclare package Medium = Medium,
    m_flow=0.1,
    use_m_flow_in=true,
    T=323.15) "Flow source"

  Modelica.Fluid.Sources.FixedBoundary sin(
    redeclare package Medium = Medium,
    p=0,
    nPorts=1) "Sink"

  AixLib.Fluid.HeatExchangers.EvaporatorCondenser eva(
    redeclare package Medium = Medium,
    m_flow(start=0.1),
    dp(start=10),
    UA=100,
    dp_nominal=0,
    tau=5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    m_flow_nominal=m_flow_nominal) "Evaporator"

  Modelica.Blocks.Sources.Ramp m_flow(
    duration=100,
    height=9*m_flow_nominal,
    offset=m_flow_nominal) "Mass flow rate"
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem(
    m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium,
    tau=0.01,
    initType=Modelica.Blocks.Types.Init.SteadyState) "Temperature sensor"
equation
  connect(ref.port, heaFlo.port_a)
  connect(heaFlo.port_b, eva.port_ref)
  connect(sou.ports[1], eva.port_a)
  connect(m_flow.y, sou.m_flow_in)
  connect(eva.port_b, senTem.port_a)
  connect(senTem.port_b, sin.ports[1])
end EvaporatorCondenser;