within Buildings.Fluid.HeatExchangers.RadiantSlabs;
model ParallelCircuitsSlab
  "Model of multiple parallel circuits of a radiant slab"
  extends Buildings.Fluid.Interfaces.PartialTwoPort(
    port_a(p(start=p_start,
             nominal=Medium.p_default)),
    port_b(p(start=p_start,
           nominal=Medium.p_default)));
  extends Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.Slab;
  extends Buildings.Fluid.Interfaces.LumpedVolumeDeclarations;
  extends Buildings.Fluid.Interfaces.TwoPortFlowResistanceParameters(
   dp_nominal = Modelica.Fluid.Pipes.BaseClasses.WallFriction.Detailed.pressureLoss_m_flow(
      m_flow=m_flow_nominal/nCir,
      rho_a=rho_default,
      rho_b=rho_default,
      mu_a=mu_default,
      mu_b=mu_default,
      length=length,
      diameter=pipe.dIn,
      roughness=pipe.roughness,
      m_flow_small=m_flow_small/nCir));

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

  parameter Integer nCir(min=1) = 1 "Number of parallel circuits";
  parameter Integer nSeg(min=1) = if heatTransfer==Types.HeatTransfer.EpsilonNTU then 1 else 5
    "Number of volume segments in each circuit (along flow path)";

  parameter Modelica.Units.SI.Area A
    "Surface area of radiant slab (all circuits combined)"
  parameter Modelica.Units.SI.Length length=A/disPip/nCir
    "Length of the pipe of a single circuit";

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Nominal mass flow rate of all circuits combined"
  parameter Modelica.Units.SI.MassFlowRate m_flow_small(min=0) = 1E-4*abs(
    m_flow_nominal)
    "Small mass flow rate of all circuits combined for regularization of zero flow"

  final parameter Modelica.Units.SI.Velocity v_nominal=4*m_flow_nominal/pipe.dIn
      ^2/Modelica.Constants.pi/rho_default/nCir "Velocity at m_flow_nominal";

  // Parameters used for the fluid model implementation

  parameter Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer
    heatTransfer=Types.HeatTransfer.EpsilonNTU
    "Model for heat transfer between fluid and slab";

  // Diagnostics
   parameter Boolean show_T = false
    "= true, if actual temperature at port is computed"

  Modelica.Units.SI.MassFlowRate m_flow(start=0) = port_a.m_flow
    "Mass flow rate from port_a to port_b (m_flow > 0 is design flow direction) for all circuits combined";
  Modelica.Units.SI.PressureDifference dp(
    start=0,
    displayUnit="Pa") = port_a.p - port_b.p
    "Pressure difference between port_a and port_b";

  Medium.ThermodynamicState sta_a=if homotopyInitialization then
      Medium.setState_phX(port_a.p,
                          homotopy(actual=noEvent(actualStream(port_a.h_outflow)),
                                   simplified=inStream(port_a.h_outflow)),
                          homotopy(actual=noEvent(actualStream(port_a.Xi_outflow)),
                                   simplified=inStream(port_a.Xi_outflow)))
    else
      Medium.setState_phX(port_a.p,
                          noEvent(actualStream(port_a.h_outflow)),
                          noEvent(actualStream(port_a.Xi_outflow)))
      if show_T "Medium properties in port_a";

  Medium.ThermodynamicState sta_b=if homotopyInitialization then
      Medium.setState_phX(port_b.p,
                          homotopy(actual=noEvent(actualStream(port_b.h_outflow)),
                                   simplified=port_b.h_outflow),
                          homotopy(actual=noEvent(actualStream(port_b.Xi_outflow)),
                            simplified=port_b.Xi_outflow))
    else
      Medium.setState_phX(port_b.p,
                          noEvent(actualStream(port_b.h_outflow)),
                          noEvent(actualStream(port_b.Xi_outflow)))
       if show_T "Medium properties in port_b";

  Buildings.Fluid.HeatExchangers.RadiantSlabs.SingleCircuitSlab sla(
    redeclare final package Medium = Medium,
    final heatTransfer=heatTransfer,
    final sysTyp=sysTyp,
    final A=A/nCir,
    final disPip=disPip,
    final pipe=pipe,
    final layers=layers,
    final steadyStateInitial=steadyStateInitial,
    final iLayPip=iLayPip,
    final T_a_start=T_a_start,
    final T_b_start=T_b_start,
    final energyDynamics=energyDynamics,
    final massDynamics=massDynamics,
    final p_start=p_start,
    final T_start=T_start,
    final X_start=X_start,
    final C_start=C_start,
    final C_nominal=C_nominal,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=m_flow_nominal/nCir,
    final m_flow_small=m_flow_small/nCir,
    final homotopyInitialization=homotopyInitialization,
    final from_dp=from_dp,
    final dp_nominal=dp_nominal,
    final linearizeFlowResistance=linearizeFlowResistance,
    final deltaM=deltaM,
    final nSeg=nSeg,
    final length=length,
    final ReC=4000,
    final stateAtSurface_a=stateAtSurface_a,
    final stateAtSurface_b=stateAtSurface_b) "Single parallel circuit of the radiant slab"
protected
  parameter Medium.ThermodynamicState state_default = Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default[1:Medium.nXi]) "Start state";
  parameter Modelica.Units.SI.Density rho_default=Medium.density(state_default);
  parameter Modelica.Units.SI.DynamicViscosity mu_default=
      Medium.dynamicViscosity(state_default)
    "Dynamic viscosity at nominal condition";

  Buildings.Fluid.BaseClasses.MassFlowRateMultiplier masFloMul_a(
      redeclare final package Medium = Medium,
      final k=nCir)
    "Mass flow multiplier, used to avoid having to instanciate multiple slab models"
  Buildings.Fluid.BaseClasses.MassFlowRateMultiplier masFloMul_b(
      redeclare final package Medium = Medium,
      final k=nCir)
    "Mass flow multiplier, used to avoid having to instanciate multiple slab models"
  Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.HeatFlowRateMultiplier heaFloMul_a(
      final k=nCir)
    "Heat flow rate multiplier, used to avoid having to instanciate multiple slab models"
  Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.HeatFlowRateMultiplier heaFloMul_b(
     final k=nCir)
    "Heat flow rate multiplier, used to avoid having to instanciate multiple slab models"

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(sla.port_b, masFloMul_b.port_a)

  connect(masFloMul_b.port_b, port_b)

  connect(port_a, masFloMul_a.port_b)

  connect(masFloMul_a.port_a, sla.port_a)

  connect(sla.surf_a,heaFloMul_a. port_a)
  connect(heaFloMul_a.port_b, surf_a)
  connect(sla.surf_b,heaFloMul_b. port_a)
  connect(heaFloMul_b.port_b, surf_b)
end ParallelCircuitsSlab;


within Buildings.Fluid.HeatExchangers.RadiantSlabs;
model SingleCircuitSlab "Model of a single circuit of a radiant slab"
  extends Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.Slab;
  extends Buildings.Fluid.FixedResistances.BaseClasses.Pipe(
     nSeg=if heatTransfer==Types.HeatTransfer.EpsilonNTU then 1 else 5,
     final diameter=pipe.dIn,
     length=A/disPip,
     final thicknessIns=0,
     final lambdaIns = 0.04,
     dp_nominal = Modelica.Fluid.Pipes.BaseClasses.WallFriction.Detailed.pressureLoss_m_flow(
      m_flow=m_flow_nominal,
      rho_a=rho_default,
      rho_b=rho_default,
      mu_a=mu_default,
      mu_b=mu_default,
      length=length,
      diameter=pipe.dIn,
      roughness=pipe.roughness,
      m_flow_small=m_flow_small),
      preDro(dp(nominal=200*length)));

  parameter Modelica.Units.SI.Area A "Surface area of radiant slab"

  parameter Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer
    heatTransfer=Types.HeatTransfer.EpsilonNTU
    "Model for heat transfer between fluid and slab";
  parameter Modelica.Units.SI.Temperature T_c_start=(T_a_start*con_b[1].layers.R
       + T_b_start*con_a[1].layers.R)/layers.R
    "Initial construction temperature in the layer that contains the pipes, used if steadyStateInitial = false"
  final parameter Modelica.Units.SI.Velocity v_nominal=4*m_flow_nominal/pipe.dIn
      ^2/Modelica.Constants.pi/rho_default "Velocity at m_flow_nominal";

  Buildings.HeatTransfer.Conduction.MultiLayer con_a[nSeg](
    each final A=A/nSeg,
    each final steadyStateInitial=steadyStateInitial,
    each layers(
      final nLay = iLayPip,
      final material={layers.material[i] for i in 1:iLayPip},
      final absIR_a=layers.absIR_a,
      final absIR_b=layers.absIR_b,
      final absSol_a=layers.absSol_a,
      final absSol_b=layers.absSol_b,
      final roughness_a=layers.roughness_a),
    each T_a_start=T_a_start,
    each T_b_start=T_c_start,
    each stateAtSurface_a=stateAtSurface_a,
    each stateAtSurface_b=true)
    "Construction near the surface port surf_a"

  Buildings.HeatTransfer.Conduction.MultiLayer con_b[nSeg](
      each final A=A/nSeg,
      each final steadyStateInitial=steadyStateInitial,
      each layers(
        final nLay = layers.nLay-iLayPip,
        final material={layers.material[i] for i in iLayPip + 1:layers.nLay},
        final absIR_a=layers.absIR_a,
        final absIR_b=layers.absIR_b,
        final absSol_a=layers.absSol_a,
        final absSol_b=layers.absSol_b,
        final roughness_a=layers.roughness_a),
      each T_a_start=T_c_start,
      each T_b_start=T_b_start,
    each stateAtSurface_a=false,
    each stateAtSurface_b=stateAtSurface_b)
    "Construction near the surface port surf_b"

protected
  Modelica.Thermal.HeatTransfer.Components.ThermalCollector colAllToOne(
     final m=nSeg) "Connector to assign multiple heat ports to one heat port"
  Modelica.Thermal.HeatTransfer.Components.ThermalCollector colAllToOne1(
     final m=nSeg) "Connector to assign multiple heat ports to one heat port"

  final parameter Modelica.Units.SI.ThermalInsulance Rx=
      Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.Functions.AverageResistance(
      disPip=disPip,
      dPipOut=pipe.dOut,
      k=layers.material[iLayPip].k,
      sysTyp=sysTyp,
      kIns=layers.material[iLayPip + 1].k,
      dIns=layers.material[iLayPip + 1].x)
    "Thermal insulance for average temperature in plane with pipes";

  BaseClasses.PipeToSlabConductance fluSlaCon[nSeg](
    redeclare each final package Medium = Medium,
    each final APip=Modelica.Constants.pi*pipe.dIn*length/nSeg,
    each final RWal=Modelica.Math.log(pipe.dOut/pipe.dIn)/(2*Modelica.Constants.pi*pipe.k*(
        length/nSeg)),
    each final RFic=nSeg*Rx/A,
    each final  m_flow_nominal=m_flow_nominal,
    each kc_IN_con=
        Modelica.Fluid.Dissipation.HeatTransfer.StraightPipe.kc_overall_IN_con(
        d_hyd=pipe.dIn,
        L=length/nSeg,
        K=pipe.roughness),
    each final heatTransfer=heatTransfer) "Conductance between fluid and the slab"

  Modelica.Units.SI.MassFraction Xi_in_a[Medium.nXi]=inStream(port_a.Xi_outflow)
    "Inflowing mass fraction at port_a";
  Modelica.Units.SI.MassFraction Xi_in_b[Medium.nXi]=inStream(port_b.Xi_outflow)
    "Inflowing mass fraction at port_a";
  Modelica.Blocks.Sources.RealExpression T_a(
    final y=Medium.temperature_phX(p=port_a.p,
                                   h=inStream(port_a.h_outflow),
                                   X=cat(1,Xi_in_a,{1-sum(Xi_in_a)})))
    "Fluid temperature at port a"
  Modelica.Blocks.Sources.RealExpression T_b(
    final y=Medium.temperature_phX(p=port_b.p,
                                   h=inStream(port_b.h_outflow),
                                   X=cat(1,Xi_in_b,{1-sum(Xi_in_b)})))
    "Fluid temperature at port b"

  Modelica.Blocks.Sources.RealExpression mFlu_flow[nSeg](each final y=m_flow)
    "Input signal for mass flow rate"

  Modelica.Blocks.Routing.Replicator T_a_rep(final nout=nSeg)
    "Signal replicator for T_a"
  Modelica.Blocks.Routing.Replicator T_b_rep(final nout=nSeg)
    "Signal replicator for T_b"
equation
  connect(colAllToOne1.port_b,surf_a)
  connect(colAllToOne.port_b,surf_b)
  connect(colAllToOne1.port_a, con_a.port_a)
  connect(colAllToOne.port_a, con_b.port_b)

  connect(fluSlaCon.fluid, vol.heatPort)
  connect(mFlu_flow.y, fluSlaCon.m_flow)
  connect(T_a.y, T_a_rep.u)
  connect(T_b.y, T_b_rep.u)
  connect(fluSlaCon.T_a, T_a_rep.y)
  connect(T_b_rep.y, fluSlaCon.T_b)
  connect(con_b.port_a, fluSlaCon.solid)

  connect(fluSlaCon.solid, con_a.port_b)
end SingleCircuitSlab;


Package with type definitions

within Buildings.Fluid.HeatExchangers.RadiantSlabs;
package Types "Package with type definitions"

  type HeatTransfer = enumeration(
      EpsilonNTU "Epsilon-NTU",
      FiniteDifference "Finite difference")
    "Model for the heat transfer along the fluid flow direction"

  type SystemType = enumeration(
      Ceiling_Wall_or_Capillary
        "Radiant heating or cooling system (ceiling or wall)",
      Floor "Floor heating system") "System type for radiant slab"
end Types;


User's Guide

within Buildings.Fluid.HeatExchangers.RadiantSlabs;
package UsersGuide "User's Guide"
  extends Modelica.Icons.Information;
end UsersGuide;


Multiplies the heat flow rate. This model multiplies the heat flow rate so that
0 = port_b.Q_flow + k * port_a.Q_flow.

within Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses;
model HeatFlowRateMultiplier "Multiplies the heat flow rate"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_a
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port_b
  parameter Real k "Gain for mass flow rate";
initial equation
  assert( k > Modelica.Constants.small or -k < -Modelica.Constants.small,
    "Gain must not be zero. Received k = " + String(k));
equation
  // Energy balance. (Energy is not conserved by this model!)
  port_b.Q_flow = -k*port_a.Q_flow;
  port_a.T = port_b.T;
end HeatFlowRateMultiplier;


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


within Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses;
model PipeToSlabConductance
  "Convective heat transfer in pipes and fictitious resistance to average slab temperature"
  replaceable package Medium =
    Modelica.Media.Interfaces.PartialMedium "Medium in the component"

  parameter Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer
    heatTransfer=
    Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.EpsilonNTU
    "Model for heat transfer between fluid and slab";
  parameter Modelica.Units.SI.Area APip "Pipe inside surface area";

  parameter
    kc_overall_IN_con kc_IN_con "Parameters for convective heat transfer calculation"

  Modelica.Fluid.Dissipation.HeatTransfer.StraightPipe.kc_overall_IN_var
    kc_IN_var(
    cp=Medium.specificHeatCapacityCp(fluSta),
    eta=Medium.dynamicViscosity(fluSta),
    lambda=Medium.thermalConductivity(fluSta),
    rho=Medium.density(fluSta),
    m_flow=m_flow) "Variables for convective heat transfer calculation"

  parameter Modelica.Units.SI.ThermalResistance RFic
    "Average fictitious thermal resistance between pipe surface and plane that contains pipe";
  parameter Modelica.Units.SI.ThermalResistance RWal
    "Thermal resistance through the pipe wall";

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

  Modelica.Blocks.Interfaces.RealInput m_flow(unit="kg/s")
    "Fluid mass flow rate from port_a to port_b"
  Modelica.Blocks.Interfaces.RealInput T_a(unit="K")
    "Temperature at fluid port_a"
  Modelica.Blocks.Interfaces.RealInput T_b(unit="K")
    "Temperature at fluid port_b"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a solid
    "Heat port at solid interface"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b fluid
    "Heat port at fluid interface"

  Modelica.Units.SI.TemperatureDifference dT "= solid.T - fluid.T";

  Modelica.Units.SI.CoefficientOfHeatTransfer hCon
    "Convective heat transfer coefficient";
  Modelica.Units.SI.ThermalResistance RTot
    "Thermal resistance between the fluid and the fictious plane of heat transfer";

  Modelica.Units.SI.HeatFlowRate Q_flow "Heat flow rate from solid -> fluid";

  // The records kc_overall_IN_con and kc_turbulent_IN_con are implemented
  // because in the Modelica Standard Library 3.2.2, they have a bug
  // that causes the pedantic model check in Dymola 2017 beta3 to fail.

record kc_overall_IN_con
  "Input record for function kc_overall and kc_overall_KC"

    //choices
  Modelica.Fluid.Dissipation.Utilities.Types.HeatTransferBoundary target=Modelica.Fluid.Dissipation.Utilities.Types.HeatTransferBoundary.UWTuDFF
    "Choice of heat transfer boundary condition"

  extends kc_turbulent_IN_con;
end kc_overall_IN_con;

protected
record kc_turbulent_IN_con
  "Input record for function kc_turbulent and kc_turbulent_KC"
  extends Modelica.Fluid.Dissipation.Utilities.Records.HeatTransfer.StraightPipe;

  Modelica.Fluid.Dissipation.Utilities.Types.Roughness roughness=Modelica.Fluid.Dissipation.Utilities.Types.Roughness.Considered
    "Choice of considering surface roughness"

    Modelica.Units.SI.Length K=0
      "Roughness (average height of surface asperities)"
end kc_turbulent_IN_con;

  Medium.ThermodynamicState fluSta = Medium.setState_pTX(p=Medium.p_default, T=fluid.T, X=Medium.X_default)
    "State of the medium";
  Modelica.Units.SI.SpecificHeatCapacity c_p=Medium.specificHeatCapacityCp(
      fluSta) "Specific heat capacity of the fluid";
equation
  hCon = Modelica.Fluid.Dissipation.HeatTransfer.StraightPipe.kc_overall_KC(
     IN_con=kc_IN_con, IN_var=kc_IN_var);
  RTot = 1/hCon/APip + RFic + RWal;

  if heatTransfer == Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.EpsilonNTU then
    Q_flow = Functions.heatFlowRate(T_a=T_a,
                          T_b=T_b,
                          T_s=solid.T,
                          T_f=fluid.T,
                          c_p=c_p,
                          UA=1/RTot,
                          m_flow=m_flow,
                          m_flow_nominal=m_flow_nominal);
  else
    Q_flow = dT/RTot;
  end if;

  dT = solid.T - fluid.T;
  solid.Q_flow = Q_flow;
  fluid.Q_flow = -Q_flow;
end PipeToSlabConductance;


Base class for radiant slab. This partial model is used to construct radiant slab models with one circuit or with multiple parallel circuits.

within Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses;
partial model Slab "Base class for radiant slab"
  parameter
    Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType
     sysTyp "Radiant system type";

  parameter Modelica.Units.SI.Distance disPip "Pipe distance";

  parameter Buildings.Fluid.Data.Pipes.Generic pipe
    "Record for pipe geometry and material"

  parameter HeatTransfer.Data.OpaqueConstructions.Generic layers(nLay(min=2))
    "Definition of the construction, which must have at least two material layers"
  parameter Boolean steadyStateInitial=false
    "=true initializes dT(0)/dt=0, false initializes T(0) at fixed temperature using T_a_start, T_c_start and T_b_start"

  parameter Integer iLayPip(min=1)
    "Number of the interface layer in which the pipes are located"

  parameter Modelica.Units.SI.Temperature T_a_start=293.15
    "Initial temperature at surf_a, used if steadyStateInitial = false"
  parameter Modelica.Units.SI.Temperature T_b_start=293.15
    "Initial temperature at surf_b, used if steadyStateInitial = false"

  parameter Boolean stateAtSurface_a=true
    "=true, a state will be at the surface a"
  parameter Boolean stateAtSurface_b=true
    "=true, a state will be at the surface b"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a surf_a
    "Heat port at construction surface"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a surf_b
    "Heat port at construction surface"
end Slab;


Average fictitious resistance for plane that contains the pipes. This function computes a fictitious thermal resistance between the pipe outer wall
and a fictitious, average temperature of the plane that contains the pipes.
The equation is the same as is implemented in TRNSYS 17 Type 56 active layer component, manual page 197-201.
Different equations are used for

within Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.Functions;
function AverageResistance
  "Average fictitious resistance for plane that contains the pipes"
  extends Modelica.Icons.Function;
  input Modelica.Units.SI.Distance disPip "pipe distance";
  input Modelica.Units.SI.Diameter dPipOut "pipe outside diameter";
  input Modelica.Units.SI.ThermalConductivity k
    "pipe level construction element thermal conductivity";
  input
    Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType
     sysTyp "Type of radiant system";
  input Modelica.Units.SI.ThermalConductivity kIns
    "floor slab insulation thermal conductivity";
  input Modelica.Units.SI.Thickness dIns "floor slab insulation thickness";
  output Modelica.Units.SI.ThermalInsulance Rx "Thermal insulance";
protected
  Real cri(unit="1")
    "Criteria used to select formula for computation of resistance";
  Real infSum
    "Approximation to infinite sum used to compute the thermal resistance";
  Real alpha(unit="W/(m2.K)", min=0)
    "Criteria used to select formula for computation of resistance";
  Real fac "Factor used for systems in wall or ceiling, or for capillary tubes";
algorithm

  if sysTyp == Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Floor then
    alpha := kIns/dIns;
    assert(alpha < 1.212,
           "Warning: In RadiantAverageResistance, require alpha = kIns/dIns <= 1.212 W/(m2.K).\n" +
                     "   Obtained alpha = " + String(alpha) + " W/(m2.K)\n" +
                     "            kIns = " + String(kIns) + " W/(m.K)\n" +
                     "            dIns = " + String(dIns) + " m\n" +
                     "            For these values, the radiant slab model is outside its valid range.\n",
                     level=AssertionLevel.warning);
    infSum := - sum(((alpha/k*disPip - 2*Modelica.Constants.pi*s)/
                    (alpha/k*disPip + 2*Modelica.Constants.pi*s))
                    *Modelica.Math.exp(-4*Modelica.Constants.pi*s*dIns/disPip)/s for s in 1:100);
    Rx := disPip*(Modelica.Math.log(disPip/Modelica.Constants.pi/dPipOut) + infSum)
          /(2*Modelica.Constants.pi*k);
    fac := 0; // not needed.
  elseif sysTyp == Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Ceiling_Wall_or_Capillary then
    // Branch for radiant ceilings, radiant walls, and systems with capillary heat exchangers
    cri := disPip/dPipOut;
    fac := if (cri >= 5.8) then Modelica.Math.log(cri/Modelica.Constants.pi) else (cri/Modelica.Constants.pi/3);
    Rx := disPip/2/Modelica.Constants.pi/k * fac;
  else
    assert(sysTyp == Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Floor or
           sysTyp == Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Ceiling_Wall_or_Capillary,
           "Invalid value for sysTyp in \"Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses.Functions.AverageResistance\"
    Check parameters of the radiant slab model.");
    cri := 0;
    fac := 0;
    Rx  := 1;
  end if;
end AverageResistance;


Functions for convective heat transfer

within Buildings.Fluid.HeatExchangers.RadiantSlabs.BaseClasses;
package Functions "Functions for convective heat transfer"
end Functions;


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


within Buildings.Fluid.HeatExchangers.RadiantSlabs.Examples;
model SingleCircuitMultipleCircuitEpsilonNTU
  "Model that tests the radiant slab with multiple parallel circuits and epsilon-NTU configuration"
  extends Modelica.Icons.Example;
 package Medium = Buildings.Media.Water;
  Sources.Boundary_ph sin(redeclare package Medium = Medium, nPorts=3,
    p(displayUnit="Pa") = 300000) "Sink"
  Modelica.Blocks.Sources.Pulse pulse(
    startTime=0,
    amplitude=50*400,
    offset=300000 - 50*200,
    width=50,
    period=86400/2)
  Buildings.Fluid.HeatExchangers.RadiantSlabs.SingleCircuitSlab sla1(
    m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium,
    layers=layers,
    iLayPip=1,
    pipe=pipe,
    sysTyp=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Floor,
    disPip=0.2,
    A=A,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=true) "Slabe with embedded pipes"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.167
    "Nominal mass flow rate for each circuit";
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TAbo(T=293.15)
    "Air temperature above the slab"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TBel(T=293.15)
    "Radiant temperature below the slab"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conAbo1(G=20*A)
    "Combined convection and radiation resistance above the slab"
  parameter Modelica.Units.SI.Area A=10 "Heat transfer area for each circuit";
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conBel1(G=20*A)
    "Combined convection and radiation resistance below the slab"
  parameter HeatTransfer.Data.OpaqueConstructions.Generic layers(nLay=3, material={
        Buildings.HeatTransfer.Data.Solids.Generic(
        x=0.08,
        k=1.13,
        c=1000,
        d=1400,
        nSta=5),Buildings.HeatTransfer.Data.Solids.Generic(
        x=0.05,
        k=0.04,
        c=1400,
        d=10),Buildings.HeatTransfer.Data.Solids.Generic(
        x=0.2,
        k=1.8,
        c=1100,
        d=2400)})
    "Material layers from surface a to b (8cm concrete, 5 cm insulation, 20 cm reinforced concrete)"
  parameter Data.Pipes.PEX_RADTEST pipe "Pipe material"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conAbo2(G=20*A)
    "Combined convection and radiation resistance above the slab"
  Buildings.Fluid.HeatExchangers.RadiantSlabs.SingleCircuitSlab sla2(
    m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium,
    layers=layers,
    iLayPip=1,
    pipe=pipe,
    sysTyp=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Floor,
    disPip=0.2,
    A=A,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=true) "Slabe with embedded pipes"

  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conBel2(G=20*A)
    "Combined convection and radiation resistance below the slab"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conBel3(G=nCir*20*A)
    "Combined convection and radiation resistance below the slab"
  ParallelCircuitsSlab sla3(
    redeclare package Medium = Medium,
    layers=layers,
    iLayPip=1,
    pipe=pipe,
    sysTyp=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Floor,
    disPip=0.2,
    nCir=nCir,
    A=nCir*A,
    m_flow_nominal=nCir*m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=true) "Slabe with embedded pipes"

  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conAbo3(G=nCir*20*A)
    "Combined convection and radiation resistance above the slab"
  Sensors.TemperatureTwoPort senTem1(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal/2) "Temperature sensor"
  Sensors.TemperatureTwoPort senTem2(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal/2) "Temperature sensor"
  Sensors.TemperatureTwoPort senTem3(redeclare package Medium = Medium,
      m_flow_nominal=nCir*m_flow_nominal) "Temperature sensor"
  Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    nPorts=3,
    use_p_in=true,
    T=313.15) "Source"
  parameter Integer nCir=2 "Number of parallel circuits for slab 3";
equation
  connect(TBel.port, conBel1.port_a)
  connect(conBel1.port_b, sla1.surf_b)
  connect(sla1.surf_a, conAbo1.port_a)
  connect(TAbo.port, conAbo1.port_b)
  connect(TAbo.port, conAbo2.port_b)
  connect(conAbo2.port_a, sla2.surf_a)
  connect(TBel.port, conBel2.port_a)
  connect(TBel.port, conBel3.port_a)
  connect(TAbo.port, conAbo3.port_b)
  connect(conAbo3.port_a, sla3.surf_a)
  connect(conBel3.port_b, sla3.surf_b)
  connect(sla1.port_b, senTem1.port_a)
  connect(sla2.port_b, senTem2.port_a)
  connect(sla3.port_b, senTem3.port_a)
  connect(senTem1.port_b, sin.ports[1])
  connect(senTem2.port_b, sin.ports[2])
  connect(senTem3.port_b, sin.ports[3])
  connect(conBel2.port_b, sla2.surf_b)
  connect(pulse.y, sou.p_in)
  connect(sou.ports[1], sla1.port_a)
  connect(sou.ports[2], sla2.port_a)
  connect(sou.ports[3], sla3.port_a)
end SingleCircuitMultipleCircuitEpsilonNTU;


Model that tests the radiant slab with multiple parallel circuits. This example compares the results of two models of a single circuit that are arranged in
parallel, versus a model that directly implements two parallel circuits.
Both configurations have the same mass flow rate and temperatures.
For simplicity, a combined convective and radiative resistance
which is independent of the temperature difference has been used.
The model is exposed to a step change in pressure, which causes forward and reverse
flow.

within Buildings.Fluid.HeatExchangers.RadiantSlabs.Examples;
model SingleCircuitMultipleCircuitFiniteDifference
  "Model that tests the radiant slab with multiple parallel circuits"
  extends
    Buildings.Fluid.HeatExchangers.RadiantSlabs.Examples.SingleCircuitMultipleCircuitEpsilonNTU(
    sla1(heatTransfer=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.FiniteDifference),
    sla2(heatTransfer=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.FiniteDifference),
    sla3(heatTransfer=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.FiniteDifference));
end SingleCircuitMultipleCircuitFiniteDifference;


within Buildings.Fluid.HeatExchangers.RadiantSlabs.Examples;
model StepResponseEpsilonNTU
  "Model that tests the radiant slab with epsilon-NTU configuration"
  extends Modelica.Icons.Example;
 package Medium = Buildings.Media.Water;
  Sources.Boundary_ph sin(redeclare package Medium = Medium, nPorts=1) "Sink"
  Sources.MassFlowSource_T sou(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=298.15,
    nPorts=1) "Source"
  Modelica.Blocks.Sources.Pulse pulse(
    period=86400,
    startTime=0,
    amplitude=-m_flow_nominal,
    offset=m_flow_nominal)
  Buildings.Fluid.HeatExchangers.RadiantSlabs.SingleCircuitSlab
       sla(
    m_flow_nominal=m_flow_nominal,
    redeclare package Medium = Medium,
    layers=layers,
    iLayPip=1,
    pipe=pipe,
    sysTyp=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.SystemType.Floor,
    disPip=0.2,
    A=A,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    heatTransfer=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.FiniteDifference)
    "Slabe with embedded pipes"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.167
    "Nominal mass flow rate";
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TAirAbo(T=293.15)
    "Air temperature above the slab"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TRadAbo(T=293.15)
    "Radiant temperature above the slab"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TAirBel(T=293.15)
    "Air temperature below the slab"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TRadBel(T=293.15)
    "Radiant temperature below the slab"
  HeatTransfer.Convection.Interior conAbo(
    A=A,
    conMod=Buildings.HeatTransfer.Types.InteriorConvection.Temperature,
    til=Buildings.Types.Tilt.Floor)
    "Convective heat transfer above the slab"
  parameter Modelica.Units.SI.Area A=10 "Heat transfer area";
  HeatTransfer.Convection.Interior conBel(
    A=A,
    conMod=Buildings.HeatTransfer.Types.InteriorConvection.Temperature,
    til=Buildings.Types.Tilt.Ceiling)
    "Convective heat transfer below the slab"
  Modelica.Thermal.HeatTransfer.Components.BodyRadiation hRadAbo(Gr=A/(1/0.7 + 1
        /0.7 - 1)) "Radiative heat transfer above the slab"
  Modelica.Thermal.HeatTransfer.Components.BodyRadiation hRadBel(Gr=A/(1/0.7 + 1
        /0.7 - 1)) "Radiative heat transfer below the slab"
  parameter HeatTransfer.Data.OpaqueConstructions.Generic layers(nLay=3, material={
        Buildings.HeatTransfer.Data.Solids.Generic(
        x=0.08,
        k=1.13,
        c=1000,
        d=1400,
        nSta=5),Buildings.HeatTransfer.Data.Solids.Generic(
        x=0.05,
        k=0.04,
        c=1400,
        d=10),Buildings.HeatTransfer.Data.Solids.Generic(
        x=0.2,
        k=1.8,
        c=1100,
        d=2400)})
    "Material layers from surface a to b (8cm concrete, 5 cm insulation, 20 cm reinforced concrete)"
  parameter Data.Pipes.PEX_RADTEST pipe "Pipe material"
  Sensors.TemperatureTwoPort TOut(redeclare package Medium = Medium,
      m_flow_nominal=m_flow_nominal) "Outlet temperature of the slab"
equation
  connect(pulse.y, sou.m_flow_in)
  connect(sou.ports[1], sla.port_a)
  connect(TAirAbo.port, conAbo.fluid)
  connect(TRadAbo.port, hRadAbo.port_a)
  connect(TAirBel.port, conBel.fluid)
  connect(TRadBel.port, hRadBel.port_a)
  connect(conAbo.solid, sla.surf_a)
  connect(hRadAbo.port_b, sla.surf_a)
  connect(conBel.solid, sla.surf_b)
  connect(hRadBel.port_b, sla.surf_b)
  connect(sla.port_b, TOut.port_a)
  connect(TOut.port_b, sin.ports[1])
end StepResponseEpsilonNTU;


Model that tests the radiant slab. This example models the step response of a radiant slab.

within Buildings.Fluid.HeatExchangers.RadiantSlabs.Examples;
model StepResponseFiniteDifference "Model that tests the radiant slab"
  extends
    Buildings.Fluid.HeatExchangers.RadiantSlabs.Examples.StepResponseEpsilonNTU(
    sla(heatTransfer=Buildings.Fluid.HeatExchangers.RadiantSlabs.Types.HeatTransfer.FiniteDifference));
end StepResponseFiniteDifference;


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


Dynamic radiator for space heating

within Buildings.Fluid.HeatExchangers.Radiators;
model RadiatorEN442_2 "Dynamic radiator for space heating"
   extends Buildings.Fluid.Interfaces.PartialTwoPortInterface(
   show_T=true,
   m_flow_nominal=abs(Q_flow_nominal/cp_nominal/(T_a_nominal-T_b_nominal)));
   extends Buildings.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"

  Buildings.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) *
        Buildings.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) *
        Buildings.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) *
        Buildings.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) *
        Buildings.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"

  Buildings.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 *
      Buildings.Utilities.Math.Functions.powerLinearized(
        x=k*TWat_nominal[i] - TRad_nominal,
        n=n,
        x0=0.1*k*(T_b_nominal-TRad_nominal)) + (1-fraRad) *
      Buildings.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;


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


Test model for radiator

within Buildings.Fluid.HeatExchangers.Radiators.Examples;
model RadiatorEN442_2 "Test model for radiator"
  extends Modelica.Icons.Example;
 package Medium = Buildings.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";

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

  Buildings.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"
  Buildings.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"
  Buildings.HeatTransfer.Sources.FixedTemperature TBCCon1(T=TRoo)
  Buildings.HeatTransfer.Sources.FixedTemperature TBCCon2(T=TRoo)
  Modelica.Blocks.Sources.Step step(
    startTime=3600,
    offset=300000 + dp_nominal,
    height=-dp_nominal)
  Buildings.HeatTransfer.Sources.FixedTemperature TBCRad2(T=TRoo)
  Buildings.HeatTransfer.Sources.FixedTemperature TBCRad1(T=TRoo)
  Buildings.Fluid.Sensors.TemperatureTwoPort senTemRad1In(
    redeclare final package Medium = Medium,
    m_flow_nominal=rad1.m_flow_nominal,
    tau=0) "Temperature sensor at inlet of radiator 1"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTemRad1Out(
    redeclare final package Medium = Medium,
    m_flow_nominal=rad1.m_flow_nominal,
    tau=0) "Temperature sensor at outlet of radiator 1"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTemRad2In(
    redeclare final package Medium = Medium,
    m_flow_nominal=rad2.m_flow_nominal,
    tau=0) "Temperature sensor at inlet of radiator 2"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTemRad2Out(
    redeclare final package Medium = Medium,
    m_flow_nominal=rad2.m_flow_nominal,
    tau=0) "Temperature sensor at outlet of radiator 2"
equation
  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)
  connect(sou.ports[1], senTemRad1In.port_a)
  connect(senTemRad1In.port_b, rad1.port_a)
  connect(rad1.port_b, senTemRad1Out.port_a)
  connect(senTemRad1Out.port_b, res1.port_a)
  connect(sou.ports[2], senTemRad2In.port_a)
  connect(senTemRad2In.port_b, rad2.port_a)
  connect(rad2.port_b, senTemRad2Out.port_a)
  connect(senTemRad2Out.port_b, res2.port_a)
end RadiatorEN442_2;


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

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

  Buildings.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"

  Buildings.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"

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

  Buildings.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"

  Buildings.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"
  Buildings.Fluid.Sensors.TemperatureTwoPort T_a1(
    redeclare final package Medium = Medium1,
    m_flow_nominal=hex.m1_flow_nominal,
    tau=0) "Temperature at port_a1"
  Buildings.Fluid.Sensors.TemperatureTwoPort T_b1(
    redeclare final package Medium = Medium1,
    m_flow_nominal=hex.m1_flow_nominal,
    tau=0) "Temperature at port_b1"
  Buildings.Fluid.Sensors.TemperatureTwoPort T_a2(
    redeclare final package Medium = Medium2,
    m_flow_nominal=hex.m2_flow_nominal,
    tau=0) "Temperature at port_a2"
  Buildings.Fluid.Sensors.TemperatureTwoPort T_b2(
    redeclare final package Medium = Medium2,
    m_flow_nominal=hex.m2_flow_nominal,
    tau=0) "Temperature at port_b2"
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], T_a1.port_a)
  connect(T_a1.port_b, hex.port_a1)
  connect(hex.port_b1, T_b1.port_a)
  connect(T_b1.port_b, sin_1.ports[1])
  connect(hex.port_a2, T_a2.port_b)
  connect(T_a2.port_a, sou_2.ports[1])
  connect(T_b2.port_a, hex.port_b2)
  connect(T_b2.port_b, sin_2.ports[1])
end ConstantEffectiveness;


within Buildings.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 = Buildings.Media.Water;
 package Medium2 = Buildings.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";

  Buildings.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"
  Buildings.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)
  Buildings.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    use_p_in=true,
    nPorts=5,
    p=300000,
    T=273.15 + 25)
    "Boundary condition"
  Buildings.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"
  Buildings.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=Buildings.Fluid.Types.HeatExchangerConfiguration.ParallelFlow,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"

  Buildings.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=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  Buildings.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=Buildings.Fluid.Types.HeatExchangerConfiguration.CrossFlowStream1MixedStream2Unmixed,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  Buildings.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=Buildings.Fluid.Types.HeatExchangerConfiguration.CrossFlowStream1UnmixedStream2Mixed,
    show_T=true,
    T_a1_nominal=303.15,
    T_a2_nominal=293.15)
    "Heat exchanger"
  Buildings.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=Buildings.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 Buildings.Fluid.HeatExchangers.Validation;
model EvaporatorCondenser "Test model for the evaporator or condenser model"
  extends Modelica.Icons.Example;

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

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

  Buildings.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"

  Buildings.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"
  Buildings.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;


within Buildings.Fluid.HeatExchangers.Validation;
model HeaterCooler_u "Model that demonstrates the ideal heater model"
  extends Modelica.Icons.Example;

  package Medium = Buildings.Media.Air;

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=3000/1000/20
    "Nominal mass flow rate";

  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    use_T_in=false,
    p(displayUnit="Pa"),
    T=293.15,
    nPorts=2)
    "Sink"
  Buildings.Fluid.HeatExchangers.HeaterCooler_u heaSte(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=6000,
    Q_flow_nominal=3000,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Steady-state model of the heater"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTem1(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Modelica.Blocks.Sources.TimeTable TSet(table=[0, 273.15 + 20; 120, 273.15
    +20; 120, 273.15 + 30; 1200, 273.15 + 30])
    "Setpoint"
  Buildings.Controls.Continuous.LimPID con1(
    Td=1,
    k=1,
    Ti=10)
    "Controller"
  Buildings.Fluid.HeatExchangers.HeaterCooler_u heaDyn(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=6000,
    Q_flow_nominal=3000,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial)
    "Dynamic model of the heater"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTem2(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"

  Buildings.Controls.Continuous.LimPID con2(
    Td=1,
    Ti=10,
    k=0.1)
    "Controller"

  Buildings.Fluid.Sources.MassFlowSource_T sou(
    redeclare package Medium = Medium,
    use_T_in=false,
    nPorts=2,
    m_flow=2*m_flow_nominal,
    T=293.15) "Source"
equation
  connect(senTem1.T, con1.u_m)
  connect(TSet.y, con1.u_s)
  connect(con1.y, heaSte.u)
  connect(heaSte.port_b, senTem1.port_a)
  connect(senTem2.T, con2.u_m)
  connect(TSet.y, con2.u_s)
  connect(con2.y, heaDyn.u)
  connect(heaDyn.port_b, senTem2.port_a)

  connect(heaSte.port_a, sou.ports[1])
  connect(sou.ports[2], heaDyn.port_a)
  connect(senTem2.port_b, sin.ports[1])
  connect(senTem1.port_b, sin.ports[2])
end HeaterCooler_u;


within Buildings.Fluid.HeatExchangers;
package Validation "Collection of models that validate the heat exchanger models"
extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.Fluid.HeatExchangers.Validation;
model PrescribedOutlet
  "Model that demonstrates the ideal heater/cooler model for a prescribed outlet temperature, configured as steady-state"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Water;
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.1
    "Nominal mass flow rate";
  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    use_T_in=false,
    p(displayUnit="Pa"),
    T=293.15,
    nPorts=3) "Sink"
  Buildings.Fluid.HeatExchangers.PrescribedOutlet heaHigPow(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=6000,
    QMax_flow=1e4,
    use_X_wSet=false)
    "Steady-state model of the heater with high capacity"
  Buildings.Fluid.Sensors.TemperatureTwoPort heaHigPowOut(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Modelica.Blocks.Sources.TimeTable TSetHeat(table=[0,273.15 + 20.0; 120,273.15
    + 20.0; 120,273.15 + 60.0; 500,273.15 + 60.0; 500,273.15 + 30.0; 1200,273.15 + 30.0])
    "Setpoint heating"
  Buildings.Fluid.Sensors.TemperatureTwoPort cooLimPowOut(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.HeatExchangers.PrescribedOutlet cooLimPow(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=6000,
    QMin_flow=-1000,
    use_X_wSet=false)
    "Steady-state model of the cooler with limited capacity"
  Modelica.Blocks.Sources.TimeTable TSetCool(table=[0,273.15 + 20.0; 120,273.15
    + 20.0; 120,273.15 + 15.0; 500,273.15 + 15.0; 500,273.15 + 10.0; 1200,273.15 + 10.0])
    "Setpoint cooling"
  Buildings.Fluid.HeatExchangers.PrescribedOutlet heaCooUnl(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=6000,
    use_X_wSet=false)
    "Steady-state model of the heater or cooler with unlimited capacity"
  Modelica.Blocks.Sources.TimeTable TSetCoolHeat(table=[0,273.15 + 20.0; 120,273.15
    + 20.0; 120,273.15 + 15.0; 500,273.15 + 15.0; 500,273.15 + 30.0; 1200,273.15
    + 30.0]) "Setpoint cooling"
  Buildings.Fluid.Sensors.TemperatureTwoPort heaCooUnlOut(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Modelica.Blocks.Sources.Ramp m_flow(
    height=-2*m_flow_nominal,
    duration=100,
    offset=m_flow_nominal,
    startTime=1000) "Mass flow rate"
  Buildings.Fluid.Sensors.TemperatureTwoPort heaHigPowIn(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort cooLimPowIn(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort heaCooUnlIn(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal) "Temperature sensor"
  Sources.MassFlowSource_T sou1(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    T=293.15) "Flow source"
  Sources.MassFlowSource_T sou2(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    T=293.15) "Flow source"
  Sources.MassFlowSource_T sou3(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1,
    T=293.15) "Flow source"
equation
  connect(heaHigPow.port_b, heaHigPowOut.port_a)
  connect(TSetHeat.y, heaHigPow.TSet)
  connect(cooLimPow.port_b, cooLimPowOut.port_a)
  connect(TSetCool.y, cooLimPow.TSet)
  connect(heaCooUnl.port_b, heaCooUnlOut.port_a)
  connect(TSetCoolHeat.y, heaCooUnl.TSet)
  connect(heaHigPowIn.port_b, heaHigPow.port_a)
  connect(cooLimPowIn.port_b, cooLimPow.port_a)
  connect(heaCooUnlIn.port_b, heaCooUnl.port_a)
  connect(heaCooUnlOut.port_b, sin.ports[1])
  connect(cooLimPowOut.port_b, sin.ports[2])
  connect(heaHigPowOut.port_b, sin.ports[3])
  connect(m_flow.y, sou1.m_flow_in)
  connect(sou1.ports[1], heaHigPowIn.port_a)
  connect(m_flow.y, sou2.m_flow_in)
  connect(m_flow.y, sou3.m_flow_in)
  connect(sou2.ports[1], cooLimPowIn.port_a)
  connect(sou3.ports[1], heaCooUnlIn.port_a)
end PrescribedOutlet;


Model that demonstrates the ideal heater/cooler model for a prescribed outlet temperature, configured as dynamic. Model that demonstrates the use of an ideal heater and an ideal cooler, configured as dynamic models.

within Buildings.Fluid.HeatExchangers.Validation;
model PrescribedOutlet_dynamic
  "Model that demonstrates the ideal heater/cooler model for a prescribed outlet temperature, configured as dynamic"
  extends Buildings.Fluid.HeatExchangers.Validation.PrescribedOutlet(
    heaHigPow(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial),
    cooLimPow(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial),
    heaCooUnl(energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial));
end PrescribedOutlet_dynamic;


within Buildings.Fluid.HeatExchangers.Validation;
model WetCoilCounterFlowLowWaterFlowRate
  "Model that tests a heat exchanger with prescribed boundary conditions, in terms of properties of inlet water and inlet air"
  extends Modelica.Icons.Example;
  package Medium1 = Buildings.Media.Water
   "Medium model for water";
  package Medium2 = Buildings.Media.Air
   "Medium model for air";

  parameter Modelica.Units.SI.MassFlowRate mWat_flow_nominal=0.44732114
    "Nominal mass flow rate";
  parameter Modelica.Units.SI.MassFlowRate mAir_flow_nominal=0.65844
    "Nominal mass flow rate";

  Buildings.Fluid.HeatExchangers.WetCoilCounterFlow
    hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=mWat_flow_nominal,
    m2_flow_nominal=mAir_flow_nominal,
    dp2_nominal(displayUnit="Pa") = 200,
    dp1_nominal(displayUnit="Pa") = 3000,
    UA_nominal=mWat_flow_nominal*4200*10/30,
    show_T=true,
    nEle=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Cooling coil"
  Buildings.Fluid.Sources.MassFlowSource_T sou_w(
    redeclare package Medium = Medium1,
    use_Xi_in=false,
    m_flow=1E-4*mWat_flow_nominal,
    use_T_in=false,
    T=282.15,
    nPorts=1,
    use_m_flow_in=true)
    "Source for water"
  Buildings.Fluid.Sources.Boundary_pT sin_w(
    redeclare package Medium = Medium1,
    use_p_in=false,
    T=293.15,
    nPorts=1)
    "sink for water"
  Buildings.Fluid.Sources.MassFlowSource_T sou_a(
    use_Xi_in=false,
    X={0.0086,1 - 0.0086},
    m_flow=mAir_flow_nominal,
    use_T_in=false,
    T=285.15,
    nPorts=1,
    redeclare package Medium = Medium2,
    use_m_flow_in=false)
    "Source for air"
  Buildings.Fluid.Sources.Boundary_pT sin_a(
    redeclare package Medium = Medium2,
    use_p_in=false,
    T=293.15,
    nPorts=1)
    "sink for air"
  Controls.OBC.CDL.Reals.Sources.Ramp ram(
    height=-mWat_flow_nominal,
    duration=1800,
    offset=mWat_flow_nominal,
    startTime=900)
  Sensors.TemperatureTwoPort senTemWatIn(
    redeclare package Medium = Medium1,
    allowFlowReversal=false,
    m_flow_nominal=mWat_flow_nominal,
    tau=0) "Temperature sensor"
  Sensors.TemperatureTwoPort senTemWatOut(
    redeclare package Medium = Medium1,
    allowFlowReversal=false,
    m_flow_nominal=mWat_flow_nominal,
    tau=0) "Temperature sensor"
  Sensors.TemperatureTwoPort senTemAirIn(
    redeclare package Medium = Medium2,
    allowFlowReversal=false,
    m_flow_nominal=mAir_flow_nominal,
    tau=0) "Temperature sensor"

  Sensors.TemperatureTwoPort senTemAirOut(
    redeclare package Medium = Medium2,
    allowFlowReversal=false,
    m_flow_nominal=mAir_flow_nominal,
    tau=0) "Temperature sensor"
equation
  connect(sou_w.m_flow_in, ram.y)
  connect(sou_w.ports[1], senTemWatIn.port_a)
  connect(senTemWatIn.port_b, hex.port_a1)
  connect(sin_w.ports[1], senTemWatOut.port_b)
  connect(senTemWatOut.port_a, hex.port_b1)
  connect(sou_a.ports[1], senTemAirIn.port_a)
  connect(senTemAirIn.port_b, hex.port_a2)
  connect(sin_a.ports[1], senTemAirOut.port_b)
  connect(senTemAirOut.port_a, hex.port_b2)
end WetCoilCounterFlowLowWaterFlowRate;


within Buildings.Fluid.HeatExchangers.Validation;
model WetCoilDiscretizedInitialization
  "Model that demonstrates use of a finite volume model of a heat exchanger with condensation"
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.WetCoilDiscretized(
   redeclare package Medium2 =
        Buildings.Media.Air);
  extends Modelica.Icons.Example;
end WetCoilDiscretizedInitialization;


within Buildings.Fluid.HeatExchangers.Validation;
model WetCoilDiscretizedInitializationPerfectGases
  "Model that demonstrates use of a finite volume model of a heat exchanger with condensation"
  extends
    Buildings.Fluid.HeatExchangers.Examples.BaseClasses.WetCoilDiscretized(
   redeclare package Medium2 =
        Buildings.Media.Air);
  extends Modelica.Icons.Example;
end WetCoilDiscretizedInitializationPerfectGases;


within Buildings.Fluid.HeatExchangers.Validation;
model WetCoilEffectivenessNTU
  "Model that validates the wet coil effectiveness-NTU model"
  extends Modelica.Icons.Example;

  package Medium_W = Buildings.Media.Water;
  package Medium_A = Buildings.Media.Air;

  constant Modelica.Units.SI.AbsolutePressure pAtm=101325
    "Atmospheric pressure";

  parameter Modelica.Units.SI.Temperature T_a1_nominal=
      Modelica.Units.Conversions.from_degF(42) "Inlet water temperature";
  parameter Modelica.Units.SI.Temperature T_a2_nominal=
      Modelica.Units.Conversions.from_degF(80) "Inlet air temperature";
  parameter Modelica.Units.SI.Temperature T_b1_nominal=273.15 + 11.0678
    "Outlet water temperature in fully wet conditions";
  parameter Modelica.Units.SI.Temperature T_b2_nominal=273.15 + 13.5805
    "Outlet air temperature in fully wet conditions";
  final parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal=m1_flow_nominal
      *4186*(T_a1_nominal - T_b1_nominal);
  parameter Real X_w_a2_nominal = 0.0173
    "Inlet water mass fraction in fully wet conditions";
  parameter Modelica.Units.SI.ThermalConductance UA_nominal=4748
    "Total thermal conductance at nominal flow, from textbook";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=3.78
    "Nominal mass flow rate of water";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=2.646
    "Nominal mass flow rate of air";
  parameter Types.HeatExchangerConfiguration hexCon=
    Types.HeatExchangerConfiguration.CounterFlow
    "Heat exchanger configuration";
  Buildings.Fluid.Sources.Boundary_pT sinAir(
    redeclare package Medium = Medium_A,
    use_p_in=false,
    nPorts=2)
    "Air sink"
  Sources.MassFlowSource_T souAir(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    T=T_a2_nominal,
    use_Xi_in=true,
    nPorts=1)
    "Air source"
  Buildings.Fluid.Sources.Boundary_pT sinWat(
    redeclare package Medium = Medium_W,
    nPorts=2)
    "Sink for water"
  Buildings.Utilities.Psychrometrics.ToTotalAir conversion
  Sensors.RelativeHumidityTwoPort relHumIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Inlet relative humidity"
  Sensors.TemperatureTwoPort TDryBulIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Inlet dry bulb temperature"
  Modelica.Blocks.Sources.RealExpression pAir(y=pAtm) "Air pressure"
  Buildings.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBulIn(redeclare package
              Medium = Medium_A) "Computation of wet bulb temperature"
  Sensors.MassFractionTwoPort senMasFraIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of entering air"
  Sensors.MassFractionTwoPort senMasFraOut(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of leaving air"
  Sensors.TemperatureTwoPort TDryBulOut(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Dry bulb temperature of leaving air"
  Buildings.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBulOut(redeclare package
              Medium = Medium_A) "Computation of wet bulb temperature"
  Modelica.Blocks.Sources.RealExpression pAir1(y=pAtm) "Air pressure"
  Buildings.Fluid.HeatExchangers.WetCoilEffectivenessNTU hexWetNTU(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    UA_nominal=UA_nominal,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    dp1_nominal=0,
    configuration=hexCon,
    show_T=true) "Effectiveness-NTU coil model (parameterized with nominal UA)"
  Sources.MassFlowSource_T souWat1(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1)
    "Source for water"
  Sensors.RelativeHumidityTwoPort relHumOut_eps(redeclare package Medium =
        Medium_A, m_flow_nominal=m2_flow_nominal) "Outlet relative humidity"
  Buildings.Fluid.HeatExchangers.WetCoilEffectivenessNTU hexWetNTU_TX(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    use_Q_flow_nominal=true,
    Q_flow_nominal=Q_flow_nominal,
    T_a2_nominal=T_a2_nominal,
    w_a2_nominal=X_w_a2_nominal/(1 - X_w_a2_nominal),
    T_a1_nominal=T_a1_nominal,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    dp1_nominal=0,
    configuration=hexCon,
    show_T=true)
    "Effectiveness-NTU coil model (parameterized with nominal T and X)"
  Sources.MassFlowSource_T souAir1(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    T=T_a2_nominal,
    use_Xi_in=true,
    nPorts=1)
    "Air source"
  Sources.MassFlowSource_T souWat2(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1)
    "Source for water"
  Modelica.Blocks.Sources.CombiTimeTable w_a2(table=[0,0.0035383; 1,0.01765],
      timeScale=1000)
                     "Absolute humidity of entering air"
equation
  connect(pAir.y, wetBulIn.p)
  connect(pAir1.y, wetBulOut.p)
  connect(senMasFraOut.port_b, sinAir.ports[1])
  connect(TDryBulOut.T, wetBulOut.TDryBul)
  connect(senMasFraOut.X, wetBulOut.Xi[1])
  connect(souAir.ports[1], senMasFraIn.port_a)
  connect(senMasFraIn.port_b, TDryBulIn.port_a)
  connect(senMasFraIn.X, wetBulIn.Xi[1])
  connect(TDryBulIn.T, wetBulIn.TDryBul)
  connect(TDryBulIn.port_b, relHumIn.port_a)
  connect(souWat1.ports[1], hexWetNTU.port_a1)
  connect(hexWetNTU.port_b1, sinWat.ports[1])
  connect(hexWetNTU.port_b2, TDryBulOut.port_a)
  connect(hexWetNTU.port_a2, relHumIn.port_b)
  connect(TDryBulOut.port_b, relHumOut_eps.port_a)
  connect(relHumOut_eps.port_b, senMasFraOut.port_a)
  connect(hexWetNTU_TX.port_b1, sinWat.ports[2])
  connect(souAir1.ports[1], hexWetNTU_TX.port_a2)
  connect(sinAir.ports[2], hexWetNTU_TX.port_b2)
  connect(souWat2.ports[1], hexWetNTU_TX.port_a1)
  connect(w_a2.y[1], conversion.XiDry)
  connect(conversion.XiTotalAir, souAir.Xi_in[1])
  connect(conversion.XiTotalAir, souAir1.Xi_in[1])
end WetCoilEffectivenessNTU;


within Buildings.Fluid.HeatExchangers.Validation;
model WetCoilEffectivenessNTUCounterFlow
  "Model that validates the wet coil effectiveness-NTU model"
  extends Modelica.Icons.Example;

  package Medium_W = Buildings.Media.Water;
  package Medium_A = Buildings.Media.Air;

  constant Modelica.Units.SI.AbsolutePressure pAtm=101325
    "Atmospheric pressure";

  parameter Modelica.Units.SI.Temperature T_a1_nominal=
      Modelica.Units.Conversions.from_degF(42) "Inlet water temperature";
  parameter Modelica.Units.SI.Temperature T_a2_nominal=
      Modelica.Units.Conversions.from_degF(80) "Inlet air temperature";
  parameter Modelica.Units.SI.Temperature T_b1_nominal=273.15 + 11.0678
    "Outlet water temperature in fully wet conditions";
  parameter Modelica.Units.SI.Temperature T_b2_nominal=273.15 + 13.5805
    "Outlet air temperature in fully wet conditions";
  final parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal=m1_flow_nominal
      *4186*(T_a1_nominal - T_b1_nominal);
  parameter Real X_w_a2_nominal = 0.0173
    "Inlet water mass fraction in fully wet conditions";
  parameter Modelica.Units.SI.ThermalConductance UA_nominal=4748
    "Total thermal conductance at nominal flow, from textbook";
  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=3.78
    "Nominal mass flow rate of water";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=2.646
    "Nominal mass flow rate of air";
  parameter Types.HeatExchangerConfiguration hexCon=
    Types.HeatExchangerConfiguration.CounterFlow
    "Heat exchanger configuration";
  Buildings.Fluid.Sources.Boundary_pT sinAir(
    redeclare package Medium = Medium_A,
    use_p_in=false,
    nPorts=3)
    "Air sink"
  Sources.MassFlowSource_T souAir(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    T=T_a2_nominal,
    use_Xi_in=true,
    nPorts=1)
    "Air source"
  Buildings.Fluid.Sources.Boundary_pT sinWat(
    redeclare package Medium = Medium_W,
    nPorts=3)
    "Sink for water"
  Buildings.Utilities.Psychrometrics.ToTotalAir conversion
  Sensors.RelativeHumidityTwoPort relHumIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Inlet relative humidity"
  Sensors.TemperatureTwoPort TDryBulIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Inlet dry bulb temperature"
  Modelica.Blocks.Sources.RealExpression pAir(y=pAtm) "Air pressure"
  Buildings.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBulIn(redeclare
      package Medium = Medium_A) "Computation of wet bulb temperature"
  Sensors.MassFractionTwoPort senMasFraIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of entering air"
  Sensors.MassFractionTwoPort senMasFraOut(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of leaving air"
  Sensors.TemperatureTwoPort TDryBulOut(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Dry bulb temperature of leaving air"
  Buildings.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBulOut(redeclare
      package Medium = Medium_A) "Computation of wet bulb temperature"
  Modelica.Blocks.Sources.RealExpression pAir1(y=pAtm) "Air pressure"
  Buildings.Fluid.HeatExchangers.WetCoilEffectivenessNTU hexWetNTU(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    UA_nominal=UA_nominal,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    dp1_nominal=0,
    configuration=hexCon,
    show_T=true) "Effectiveness-NTU coil model (parameterized with nominal UA)"
  Sources.MassFlowSource_T souWat1(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1)
    "Source for water"
  WetCoilCounterFlow hexDis(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    allowFlowReversal1=false,
    allowFlowReversal2=false,
    dp1_nominal=0,
    UA_nominal=UA_nominal,
    show_T=true,
    nEle=30,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau1=0.1,
    tau2=0.1,
    tau_m=0.1)
    "Discretized coil model"
  Sources.MassFlowSource_T souWat(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1) "Source for water"
  Sources.MassFlowSource_T souAir2(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    T=T_a2_nominal,
    use_Xi_in=true,
    nPorts=1)
    "Air source"
  Sensors.MassFractionTwoPort senMasFraOut1(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of leaving air"
  Sensors.TemperatureTwoPort TDryBulOut1(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Dry bulb temperature of leaving air"
  Sensors.RelativeHumidityTwoPort relHumOut_eps(redeclare package Medium =
        Medium_A, m_flow_nominal=m2_flow_nominal) "Outlet relative humidity"
  Sensors.RelativeHumidityTwoPort relHumOut_dis(redeclare package Medium =
        Medium_A, m_flow_nominal=m2_flow_nominal) "Outlet relative humidity"
  Buildings.Fluid.HeatExchangers.WetCoilEffectivenessNTU hexWetNTU_TX(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    use_Q_flow_nominal=true,
    Q_flow_nominal=Q_flow_nominal,
    T_a2_nominal=T_a2_nominal,
    w_a2_nominal=X_w_a2_nominal/(1 - X_w_a2_nominal),
    T_a1_nominal=T_a1_nominal,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    dp1_nominal=0,
    configuration=hexCon,
    show_T=true)
    "Effectiveness-NTU coil model (parameterized with nominal T and X)"
  Sources.MassFlowSource_T souAir1(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    T=T_a2_nominal,
    use_Xi_in=true,
    nPorts=1)
    "Air source"
  Sources.MassFlowSource_T souWat2(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1)
    "Source for water"
  Modelica.Blocks.Sources.CombiTimeTable w_a2(table=[0,0.0035383; 1,0.01765],
      timeScale=1000)
                     "Absolute humidity of entering air"
equation
  connect(pAir.y, wetBulIn.p)
  connect(pAir1.y, wetBulOut.p)
  connect(senMasFraOut.port_b, sinAir.ports[1])
  connect(TDryBulOut.T, wetBulOut.TDryBul)
  connect(senMasFraOut.X, wetBulOut.Xi[1])
  connect(souAir.ports[1], senMasFraIn.port_a)
  connect(senMasFraIn.port_b, TDryBulIn.port_a)
  connect(senMasFraIn.X, wetBulIn.Xi[1])
  connect(TDryBulIn.T, wetBulIn.TDryBul)
  connect(TDryBulIn.port_b, relHumIn.port_a)
  connect(souWat1.ports[1], hexWetNTU.port_a1)
  connect(hexWetNTU.port_b1, sinWat.ports[1])
  connect(souWat.ports[1], hexDis.port_a1)
  connect(hexDis.port_b1, sinWat.ports[2])
  connect(souAir2.ports[1], hexDis.port_a2)
  connect(hexWetNTU.port_b2, TDryBulOut.port_a)
  connect(hexWetNTU.port_a2, relHumIn.port_b)
  connect(hexDis.port_b2, TDryBulOut1.port_a)
  connect(senMasFraOut1.port_b, sinAir.ports[2])
  connect(TDryBulOut.port_b, relHumOut_eps.port_a)
  connect(relHumOut_eps.port_b, senMasFraOut.port_a)
  connect(TDryBulOut1.port_b, relHumOut_dis.port_a)
  connect(relHumOut_dis.port_b, senMasFraOut1.port_a)
  connect(hexWetNTU_TX.port_b1, sinWat.ports[3])
  connect(souAir1.ports[1], hexWetNTU_TX.port_a2)
  connect(sinAir.ports[3], hexWetNTU_TX.port_b2)
  connect(souWat2.ports[1], hexWetNTU_TX.port_a1)
  connect(w_a2.y[1], conversion.XiDry)
  connect(conversion.XiTotalAir, souAir.Xi_in[1])
  connect(conversion.XiTotalAir, souAir1.Xi_in[1])
  connect(conversion.XiTotalAir, souAir2.Xi_in[1])
end WetCoilEffectivenessNTUCounterFlow;


within Buildings.Fluid.HeatExchangers.Validation;
model WetCoilEffectivenessNTUHeating
  "Model that validates the wet coil effectiveness-NTU model in heating conditions"
  extends Modelica.Icons.Example;

  package Medium_W = Buildings.Media.Water;
  package Medium_A = Buildings.Media.Air;

  constant Modelica.Units.SI.AbsolutePressure pAtm=101325
    "Atmospheric pressure";

  parameter Modelica.Units.SI.Temperature T_a1_nominal=50 + 273.15
    "Inlet water temperature";

  parameter Modelica.Units.SI.Temperature T_b1_nominal=45 + 273.15
    "Outlet water temperature";

  parameter Modelica.Units.SI.Temperature T_a2_nominal=273.15
    "Inlet air temperature";

  final parameter Modelica.Units.SI.Temperature T_b2_nominal=T_a2_nominal +
      Q_flow_nominal/m2_flow_nominal/1010 "Outlet air temperature";

  final parameter Modelica.Units.SI.ThermalConductance CMin_flow_nominal=min(
      m1_flow_nominal*4186, m2_flow_nominal*1010)
    "Minimal capacity flow rate at nominal condition";

  final parameter Modelica.Units.SI.ThermalConductance CMax_flow_nominal=max(
      m1_flow_nominal*4186, m2_flow_nominal*1010)
    "Minimal capacity flow rate at nominal condition";

  final parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal=m1_flow_nominal
      *4186*(T_a1_nominal - T_b1_nominal);

  final parameter Real eps_nominal=
    abs(Q_flow_nominal/((T_a1_nominal - T_a2_nominal) * CMin_flow_nominal))
    "Nominal effectiveness";

  parameter Modelica.Units.SI.ThermalConductance UA_nominal=
      Buildings.Fluid.HeatExchangers.BaseClasses.ntu_epsilonZ(
      eps=eps_nominal,
      Z=CMin_flow_nominal/CMax_flow_nominal,
      flowRegime=Integer(hexCon))*CMin_flow_nominal
    "Total thermal conductance at nominal flow";

  parameter Modelica.Units.SI.MassFlowRate m1_flow_nominal=3.78
    "Nominal mass flow rate of water";
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal=2.646
    "Nominal mass flow rate of air";
  parameter Types.HeatExchangerConfiguration hexCon=
    Types.HeatExchangerConfiguration.CounterFlow
    "Heat exchanger configuration";
  Buildings.Fluid.Sources.Boundary_pT sinAir(
    redeclare package Medium = Medium_A,
    use_p_in=false,
    nPorts=3)
    "Air sink"
  Sources.MassFlowSource_T souAir(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    use_T_in=true,
    T=T_a2_nominal,
    nPorts=1)
    "Air source"
  Buildings.Fluid.Sources.Boundary_pT sinWat(
    redeclare package Medium = Medium_W,
    nPorts=3)
    "Sink for water"
  Sensors.RelativeHumidityTwoPort relHumIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Inlet relative humidity"
  Sensors.TemperatureTwoPort TDryBulIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Inlet dry bulb temperature"
  Sensors.MassFractionTwoPort senMasFraIn(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of entering air"
  Sensors.MassFractionTwoPort senMasFraOut(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of leaving air"
  Sensors.TemperatureTwoPort TDryBulOut(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Dry bulb temperature of leaving air"
  Sources.MassFlowSource_T souWat1(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1)
    "Source for water"
  DryCoilCounterFlow hexDis(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    allowFlowReversal1=false,
    allowFlowReversal2=false,
    dp1_nominal=0,
    UA_nominal=UA_nominal,
    show_T=true,
    nEle=30,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau1=0.1,
    tau2=0.1,
    tau_m=0.1)
    "Discretized coil model"
  Sources.MassFlowSource_T souWat(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1) "Source for water"
  Sources.MassFlowSource_T souAir2(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    use_T_in=true,
    T=T_a2_nominal,
    nPorts=1)
    "Air source"
  Sensors.MassFractionTwoPort senMasFraOut1(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Water mass fraction of leaving air"
  Sensors.TemperatureTwoPort TDryBulOut1(redeclare package Medium = Medium_A,
      m_flow_nominal=m2_flow_nominal) "Dry bulb temperature of leaving air"
  Sensors.RelativeHumidityTwoPort relHumOut_eps(redeclare package Medium =
        Medium_A, m_flow_nominal=m2_flow_nominal) "Outlet relative humidity"
  Sensors.RelativeHumidityTwoPort relHumOut_dis(redeclare package Medium =
        Medium_A, m_flow_nominal=m2_flow_nominal) "Outlet relative humidity"
  Buildings.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexDryNTU_T(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    Q_flow_nominal=Q_flow_nominal,
    T_a2_nominal=T_a2_nominal,
    T_a1_nominal=T_a1_nominal,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    dp1_nominal=0,
    configuration=hexCon,
    show_T=true)
    "Effectiveness-NTU coil model (parameterized with nominal T and X)"
  Sources.MassFlowSource_T souAir1(
    redeclare package Medium = Medium_A,
    m_flow=m2_flow_nominal,
    use_T_in=true,
    T=T_a2_nominal,
    nPorts=1)
    "Air source"
  Sources.MassFlowSource_T souWat2(
    redeclare package Medium = Medium_W,
    m_flow=m1_flow_nominal,
    T=T_a1_nominal,
    nPorts=1)
    "Source for water"
  Controls.OBC.CDL.Reals.Sources.Ramp T_a2(
    height=15,
    duration=1000,
    offset=273.15) "Air inlet temperature"
  Buildings.Fluid.HeatExchangers.WetCoilEffectivenessNTU hexWetNTU_TX(
    redeclare package Medium1 = Medium_W,
    redeclare package Medium2 = Medium_A,
    use_Q_flow_nominal=true,
    Q_flow_nominal=Q_flow_nominal,
    T_a2_nominal=T_a2_nominal,
    w_a2_nominal=0.001,
    T_a1_nominal=T_a1_nominal,
    m1_flow_nominal=m1_flow_nominal,
    m2_flow_nominal=m2_flow_nominal,
    dp2_nominal=0,
    dp1_nominal=0,
    configuration=hexCon,
    show_T=true)
    "Effectiveness-NTU coil model (parameterized with nominal T and X)"
equation
  connect(senMasFraOut.port_b, sinAir.ports[1])
  connect(souAir.ports[1], senMasFraIn.port_a)
  connect(senMasFraIn.port_b, TDryBulIn.port_a)
  connect(TDryBulIn.port_b, relHumIn.port_a)
  connect(souWat.ports[1], hexDis.port_a1)
  connect(hexDis.port_b1, sinWat.ports[1])
  connect(souAir2.ports[1], hexDis.port_a2)
  connect(hexDis.port_b2, TDryBulOut1.port_a)
  connect(senMasFraOut1.port_b, sinAir.ports[2])
  connect(TDryBulOut.port_b, relHumOut_eps.port_a)
  connect(relHumOut_eps.port_b, senMasFraOut.port_a)
  connect(TDryBulOut1.port_b, relHumOut_dis.port_a)
  connect(relHumOut_dis.port_b, senMasFraOut1.port_a)
  connect(hexDryNTU_T.port_b1, sinWat.ports[2])
  connect(souAir1.ports[1], hexDryNTU_T.port_a2)
  connect(sinAir.ports[3], hexDryNTU_T.port_b2)
  connect(souWat2.ports[1], hexDryNTU_T.port_a1)
  connect(T_a2.y, souAir2.T_in)
  connect(T_a2.y, souAir.T_in)
  connect(T_a2.y, souAir1.T_in)
  connect(souWat1.ports[1], hexWetNTU_TX.port_a1)
  connect(hexWetNTU_TX.port_b1, sinWat.ports[3])
  connect(relHumIn.port_b, hexWetNTU_TX.port_a2)
  connect(hexWetNTU_TX.port_b2, TDryBulOut.port_a)
end WetCoilEffectivenessNTUHeating;


Heat pump with prescribed condenser leaving temperature and performance curve adjusted based on Carnot efficiency. This is a model of a heat pump whose coefficient of performance COP changes
with temperatures in the same way as the Carnot efficiency changes.
The control input is the setpoint of the condenser leaving temperature, which
is met exactly at steady state if the heat pump has sufficient capacity.

within Buildings.Fluid.HeatPumps;
model Carnot_TCon
  "Heat pump with prescribed condenser leaving temperature and performance curve adjusted based on Carnot efficiency"
 extends Buildings.Fluid.Chillers.BaseClasses.PartialCarnot_T(
   final COP_is_for_cooling = false,
   final QEva_flow_nominal = -QCon_flow_nominal*(COP_nominal-1)/COP_nominal,
   PEle(y=QCon_flow/COP),
   redeclare HeatExchangers.Heater_T con(
    final from_dp=from_dp1,
    final dp_nominal=dp1_nominal,
    final linearizeFlowResistance=linearizeFlowResistance1,
    final deltaM=deltaM1,
    final QMax_flow=QCon_flow_max,
    final tau=tau1,
    final T_start=T1_start,
    final energyDynamics=energyDynamics,
    final homotopyInitialization=homotopyInitialization),
   redeclare HeatExchangers.HeaterCooler_u eva(
    final from_dp=from_dp2,
    final dp_nominal=dp2_nominal,
    final linearizeFlowResistance=linearizeFlowResistance2,
    final deltaM=deltaM2,
    final tau=tau2,
    final T_start=T2_start,
    final energyDynamics=energyDynamics,
    final homotopyInitialization=homotopyInitialization,
    final Q_flow_nominal=QEva_flow_nominal));

  parameter Modelica.Units.SI.HeatFlowRate QCon_flow_max(min=0) = Modelica.Constants.inf
    "Maximum heat flow rate for heating (positive)";

  Modelica.Blocks.Interfaces.RealInput TSet(unit="K")
    "Condenser leaving water temperature"

protected
  Modelica.Blocks.Math.Gain yEva(final k=1/QEva_flow_nominal)
    "Normalized evaporator heat flow rate"
  Modelica.Blocks.Math.Add QEva_flow_internal(final k1=-1)
    "Heat removed by evaporator"
initial equation
  assert(QCon_flow_nominal > 0, "Parameter QCon_flow_nominal must be positive.");
  assert(COP_nominal > 1, "The nominal COP of a heat pump must be bigger than one.");

equation
  connect(TSet, con.TSet)
  connect(con.Q_flow, QCon_flow)
  connect(QEva_flow_internal.u1, con.Q_flow)
  connect(QEva_flow_internal.u2, PEle.y)
  connect(QEva_flow_internal.y, yEva.u)
  connect(QEva_flow, QEva_flow_internal.y)
  connect(yEva.y, eva.u)
end Carnot_TCon;


Reversible heat pump with performance curve adjusted based on Carnot efficiency. This is model of a heat pump whose coefficient of performance COP changes
with temperatures in the same way as the Carnot efficiency changes.
The input signal <i>y</i> is the control signal for the compressor.

within Buildings.Fluid.HeatPumps;
model Carnot_y
  "Reversible heat pump with performance curve adjusted based on Carnot efficiency"
  extends Buildings.Fluid.Chillers.BaseClasses.PartialCarnot_y(
    final COP_is_for_cooling = false);

initial equation
  assert(COP_nominal > 1, "The nominal COP of a heat pump must be bigger than one.");
end Carnot_y;


Model for a reversable heat pump based on the equation fit method. Model for a reversable heat pump using the equation fit method and that takes as an
input the set point for the leaving fluid temperature.

within Buildings.Fluid.HeatPumps;
model EquationFitReversible
  "Model for a reversable heat pump based on the equation fit method"
  extends Buildings.Fluid.Interfaces.FourPortHeatMassExchanger(
          show_T=true,
          final m1_flow_nominal=per.hea.mLoa_flow*scaling_factor,
          final m2_flow_nominal=per.hea.mSou_flow*scaling_factor,
          final dp1_nominal = per.dpHeaLoa_nominal,
          final dp2_nominal = per.dpHeaSou_nominal,
       redeclare final Buildings.Fluid.MixingVolumes.MixingVolume
          vol1(final prescribedHeatFlowRate=true),
       redeclare final Buildings.Fluid.MixingVolumes.MixingVolume
          vol2(final prescribedHeatFlowRate=true));

  parameter Data.EquationFitReversible.Generic per
   "Performance data"
  parameter Real scaling_factor = 1
   "Scaling factor for heat pump capacity";
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_small=per.hea.Q_flow*
      scaling_factor*1E-9
    "Small value for heat flow rate or power, used to avoid division by zero"

  Modelica.Blocks.Interfaces.IntegerInput uMod
   "Control input signal, cooling mode=-1, off=0, heating mode=+1"
  Modelica.Blocks.Interfaces.RealInput TSet(
    final unit="K",
    displayUnit="degC")
   "Set point for leaving fluid temperature at port b1"

  Modelica.Blocks.Interfaces.RealOutput P(final unit="W")
   "Compressor power "
  Modelica.Blocks.Interfaces.RealOutput QSou_flow(final unit="W")
   "Heat flow rate at the source heat exchanger"
  Modelica.Blocks.Interfaces.RealOutput QLoa_flow(final unit="W")
   "Heat flow rate at the load heat exchanger"

  Modelica.Blocks.Interfaces.RealOutput COP(
    final min=0,
    final unit="1")
    "Coefficient of performance, assuming useful heat is at load side (at Medium 1)"

  output Real PLR(min=0, nominal=1, unit="1") = equFit.PLR
   "Part load ratio";

  Buildings.Controls.OBC.CDL.Utilities.Assert aleMes(
    message="uMod cannot be -1 if reverseCycle is false.")
      if not per.reverseCycle
    "Generate alert message if control input is not valid"

protected
  constant Modelica.Units.SI.SpecificEnergy h1_default=
      Medium1.specificEnthalpy_pTX(
      Medium1.p_default,
      Medium1.T_default,
      Medium1.X_default) "Default enthalpy for Medium 1";

  Modelica.Blocks.Sources.RealExpression mLoa_flow(y=port_a1.m_flow)
   "Load-side mass flow rate"
  Modelica.Blocks.Sources.RealExpression mSou_flow(y=port_a2.m_flow)
   "Source-side mass flow rate"
  Modelica.Units.SI.SpecificEnthalpy hSet=if uMod == 0 then h1_default else
      Medium1.specificEnthalpy_pTX(
      p=port_b1.p,
      T=TSet,
      X=cat(
        1,
        port_b1.Xi_outflow,
        {1 - sum(port_b1.Xi_outflow)})) "Enthalpy corresponding to set point";
  Modelica.Blocks.Sources.RealExpression TSouEnt(
    final y=Medium2.temperature(
      Medium2.setState_phX(port_a2.p,
                           inStream(port_a2.h_outflow),
                           inStream(port_a2.Xi_outflow))))
   "Source side entering fluid temperature"
  Modelica.Blocks.Sources.RealExpression TLoaEnt(
    final y=Medium1.temperature(
      Medium1.setState_phX(port_a1.p,
                          inStream(port_a1.h_outflow),
                          inStream(port_a1.Xi_outflow))))
   "Load side entering fluid temperature"
  Modelica.Blocks.Sources.RealExpression Q_flow_set(
    final y=if uMod == 1 then Buildings.Utilities.Math.Functions.smoothMax(
              x1=m1_flow * (hSet - inStream(port_a1.h_outflow)),
              x2=Q_flow_small,
              deltaX=Q_flow_small/100)
            elseif uMod == -1 then Buildings.Utilities.Math.Functions.smoothMin(
              x1=m1_flow * (hSet - inStream(port_a1.h_outflow)),
              x2=-Q_flow_small,
              deltaX=Q_flow_small/100)
            else 0)
    "Required heat flow rate to meet set point"

  BaseClasses.EquationFitReversible equFit(
    final per=per,
    final scaling_factor=scaling_factor,
    final Q_flow_small=Q_flow_small)
    "Performance model"

  Buildings.HeatTransfer.Sources.PrescribedHeatFlow preHeaFloLoa
   "Prescribed load side heat flow rate"
  Buildings.HeatTransfer.Sources.PrescribedHeatFlow preHeaFloSou
   "Prescribed source side heat flow rate"

  Controls.OBC.CDL.Integers.GreaterEqualThreshold greEqu(
    final t=0) if not per.reverseCycle
    "Indicator, outputs true if in cooling mode"

equation
  connect(equFit.QSou_flow,QSou_flow)
  connect(mSou_flow.y, equFit.mSou_flow)
  connect(mLoa_flow.y, equFit.mLoa_flow)
  connect(equFit.QLoa_flow,QLoa_flow)
  connect(equFit.QLoa_flow,preHeaFloLoa.Q_flow)
  connect(TSouEnt.y,equFit.TSouEnt)
  connect(TLoaEnt.y,equFit.TLoaEnt)
  connect(equFit.P, P)
  connect(uMod, equFit.uMod)
  connect(equFit.QSou_flow, preHeaFloSou.Q_flow)
  connect(vol1.heatPort, preHeaFloLoa.port)
  connect(vol2.heatPort, preHeaFloSou.port)
  connect(aleMes.u,greEqu.y)
  connect(greEqu.u, uMod)
  connect(equFit.Q_flow_set, Q_flow_set.y)
  connect(equFit.COP, COP)
end EquationFitReversible;