Evaporator or condenser with refrigerant experiencing constant temperature phase change. Model for a constant temperature evaporator or condenser based on a ε-NTU
heat exchanger model.

within AixLib.Fluid.HeatExchangers;
model EvaporatorCondenser
  "Evaporator or condenser with refrigerant experiencing constant temperature phase change"
  extends AixLib.Fluid.Interfaces.TwoPortHeatMassExchanger(redeclare final
      AixLib.Fluid.MixingVolumes.MixingVolume vol(final
        prescribedHeatFlowRate=false));

  parameter Modelica.Units.SI.ThermalConductance UA
    "Thermal conductance of heat exchanger";
  parameter Modelica.Units.SI.ThermalConductance UA_small=UA/10
    "Small thermal conductance for regularisation of heat transfer "

  Modelica.Blocks.Interfaces.RealOutput Q_flow(unit="W")
    "Heat added to the fluid"
  Modelica.Blocks.Interfaces.RealOutput T(unit="K") "Medium temperature"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_ref
    "Temperature and heat flow from the refrigerant"

  Modelica.Units.SI.Efficiency NTU=UA/(AixLib.Utilities.Math.Functions.smoothMax(
      abs(port_a.m_flow),
      m_flow_small,
      m_flow_small)*cp_default) "Number of transfer units of heat exchanger";

  Modelica.Units.SI.Efficiency eps=AixLib.Utilities.Math.Functions.smoothMin(
      AixLib.Fluid.HeatExchangers.BaseClasses.epsilon_ntuZ(
        NTU,
        0,
        Integer(AixLib.Fluid.Types.HeatExchangerFlowRegime.ConstantTemperaturePhaseChange)),
      0.999,
      1.0e-4) "Effectiveness of heat exchanger";

  Modelica.Blocks.Sources.RealExpression UAeff(
    final y=AixLib.Utilities.Math.Functions.smoothMax(
      x1=UA,
      x2=eps*cp_default*abs(port_a.m_flow)/(1 - eps),
      deltaX=UA_small))
    "Effective heat transfer coefficient"

protected
  parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity";

  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heaFlo
    "Heat flow sensor"
  Modelica.Thermal.HeatTransfer.Components.Convection con
    "Convective heat transfer"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTem
    "Temperature sensor"
equation
  connect(heaFlo.port_b, vol.heatPort)
  connect(heaFlo.Q_flow, Q_flow)
  connect(port_ref, con.solid)
  connect(con.fluid, heaFlo.port_a)
  connect(UAeff.y, con.Gc)
  connect(senTem.port, vol.heatPort)
  connect(senTem.T, T)
end EvaporatorCondenser;


Heater or cooler with prescribed heat flow rate. Model for an ideal heater or cooler with prescribed heat flow rate to the medium.

within AixLib.Fluid.HeatExchangers;
model HeaterCooler_u "Heater or cooler with prescribed heat flow rate"
  extends AixLib.Fluid.Interfaces.TwoPortHeatMassExchanger(
    redeclare final AixLib.Fluid.MixingVolumes.MixingVolume vol(
    final prescribedHeatFlowRate=true));

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Heat flow rate at u=1, positive for heating";
  Modelica.Blocks.Interfaces.RealInput u(unit="1") "Control input"
  Modelica.Blocks.Interfaces.RealOutput Q_flow(unit="W")
    "Heat added to the fluid"
protected
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea(
    final alpha=0)
    "Prescribed heat flow"
  Modelica.Blocks.Math.Gain gai(
    k(final unit="W")=Q_flow_nominal,
    y(final unit="W"))
    "Gain"
equation
  connect(u, gai.u)
  connect(gai.y, preHea.Q_flow)
  connect(preHea.port, vol.heatPort)
  connect(gai.y, Q_flow)
end HeaterCooler_u;


Heater with prescribed outlet temperature. Model for an ideal heater that controls its outlet temperature to
a prescribed outlet temperature.

within AixLib.Fluid.HeatExchangers;
model Heater_T "Heater with prescribed outlet temperature"
  extends AixLib.Fluid.HeatExchangers.BaseClasses.PartialPrescribedOutlet(
    outCon(
      final QMin_flow = 0,
      final QMax_flow = QMax_flow,
      final mWatMax_flow = 0,
      final mWatMin_flow = 0,
      final use_TSet = true,
      final use_X_wSet = false,
      final T_start=T_start,
      final X_start=Medium.X_default));

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

  parameter Modelica.Units.SI.Temperature T_start=Medium.T_default
    "Start value of temperature"

  Modelica.Blocks.Interfaces.RealInput TSet(
    unit="K",
    displayUnit="degC")
    "Set point temperature of the fluid that leaves port_b"

  Modelica.Blocks.Interfaces.RealOutput Q_flow(unit="W")
    "Heat flow rate added to the fluid (if flow is from port_a to port_b)"

equation
  connect(TSet, outCon.TSet)
  connect(outCon.Q_flow, Q_flow)
end Heater_T;


Heating rod which converts electrical energy into heat with a given efficiency. Model for a heating rod.

within AixLib.Fluid.HeatExchangers;
model HeatingRod
  "Heating rod which converts electrical energy into heat with a given efficiency"
  extends AixLib.Fluid.Interfaces.TwoPortHeatMassExchanger(
    redeclare final AixLib.Fluid.MixingVolumes.MixingVolume vol(
      final m_flow_small=m_flow_small,
      final V=V,
    final prescribedHeatFlowRate=true));

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Heat flow rate at u=1, positive for heating";
  parameter Modelica.Units.SI.Volume V=m_flow_nominal*tau/rho_default
    "Volume of heat exchanger";
  parameter Real eta      "Efficiency of the heating rod";

  // Count switches
  parameter Boolean use_countNumSwi=true
    "Turn the counting of the number of heating rod uses on or off."
  Modelica.Blocks.Interfaces.RealInput u(unit="1",
    min=0,
    max=1)                                         "Control input"
  Modelica.Blocks.Interfaces.RealOutput Pel(unit="W")
    "Electrical power used to provide current heat flow"
  Modelica.Blocks.Math.Gain gai_eta(final k=1/eta) "Divide efficiency"

  Modelica.Blocks.MathInteger.TriggeredAdd triggeredAdd(final use_reset=false,
      final y_start=0) if use_countNumSwi
    "To count on-off cycles"
  Modelica.Blocks.Sources.IntegerConstant integerConstant(final k=1)
 if use_countNumSwi
  Modelica.Blocks.Interfaces.IntegerOutput numSwi if use_countNumSwi
    "Number of on switches "
  Modelica.Blocks.Logical.GreaterThreshold greaterThreshold(final threshold=
        Modelica.Constants.eps) if use_countNumSwi
protected
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea(
    final alpha=0)
    "Prescribed heat flow"
  Modelica.Blocks.Math.Gain gai(k=Q_flow_nominal) "Gain"
equation
  connect(u, gai.u)
  connect(gai.y, preHea.Q_flow)
  connect(preHea.port, vol.heatPort)
  connect(gai.y, gai_eta.u)
  connect(gai_eta.y, Pel)
  connect(triggeredAdd.y,numSwi)
  connect(integerConstant.y,triggeredAdd. u)
  connect(greaterThreshold.y, triggeredAdd.trigger)
  connect(u, greaterThreshold.u)
end HeatingRod;


Package with heat exchanger models

within AixLib.Fluid;
package HeatExchangers "Package with heat exchanger models"
  extends Modelica.Icons.VariantsPackage;
end HeatExchangers;


Ideal heater, cooler, humidifier or dehumidifier with prescribed outlet conditions. Model that allows specifying the temperature and mass fraction of the fluid
that leaves the model from port_b.

within AixLib.Fluid.HeatExchangers;
model PrescribedOutlet
  "Ideal heater, cooler, humidifier or dehumidifier with prescribed outlet conditions"
  extends AixLib.Fluid.HeatExchangers.BaseClasses.PartialPrescribedOutlet(
    outCon(
      final T_start=T_start,
      final X_start=X_start,
      final use_TSet = use_TSet,
      final use_X_wSet = use_X_wSet,
      final QMax_flow = QMax_flow,
      final QMin_flow = QMin_flow,
      final mWatMax_flow = mWatMax_flow,
      final mWatMin_flow = mWatMin_flow));

  parameter Modelica.Units.SI.HeatFlowRate QMax_flow(min=0) = Modelica.Constants.inf
    "Maximum heat flow rate for heating (positive)"
  parameter Modelica.Units.SI.HeatFlowRate QMin_flow(max=0) = -Modelica.Constants.inf
    "Maximum heat flow rate for cooling (negative)"

  parameter Modelica.Units.SI.MassFlowRate mWatMax_flow(min=0) = Modelica.Constants.inf
    "Maximum water mass flow rate addition (positive)"
  parameter Modelica.Units.SI.MassFlowRate mWatMin_flow(max=0) = -Modelica.Constants.inf
    "Maximum water mass flow rate removal (negative)"

  parameter Modelica.Units.SI.Temperature T_start=Medium.T_default
    "Start value of temperature"
  parameter Modelica.Units.SI.MassFraction X_start[Medium.nX]=Medium.X_default
    "Start value of mass fractions m_i/m"

  parameter Boolean use_TSet = true
    "Set to false to disable temperature set point"

  parameter Boolean use_X_wSet = true
    "Set to false to disable water vapor set point"

  Modelica.Blocks.Interfaces.RealInput TSet(
    unit="K",
    displayUnit="degC") if use_TSet
    "Set point temperature of the fluid that leaves port_b"

  Modelica.Blocks.Interfaces.RealInput X_wSet(unit="1") if use_X_wSet
    "Set point for water vapor mass fraction of the fluid that leaves port_b"

  Modelica.Blocks.Interfaces.RealOutput Q_flow(unit="W")
    "Heat flow rate added to the fluid (if flow is from port_a to port_b)"

  Modelica.Blocks.Interfaces.RealOutput mWat_flow(unit="kg/s")
    "Water vapor mass flow rate added to the fluid (if flow is from port_a to port_b)"

equation
  connect(outCon.X_wSet, X_wSet)
  connect(outCon.mWat_flow, mWat_flow)
  connect(outCon.TSet, TSet)
  connect(outCon.Q_flow, Q_flow)
end PrescribedOutlet;


Sensible cooling device with prescribed outlet temperature. Model for an ideal sensible-only cooler that controls its outlet temperature to
a prescribed outlet temperature.

within AixLib.Fluid.HeatExchangers;
model SensibleCooler_T
  "Sensible cooling device with prescribed outlet temperature"
  extends AixLib.Fluid.HeatExchangers.BaseClasses.PartialPrescribedOutlet(
    outCon(
      final QMin_flow = QMin_flow,
      final QMax_flow = 0,
      final mWatMax_flow = 0,
      final mWatMin_flow = 0,
      final use_TSet = true,
      final use_X_wSet = false,
      final T_start=T_start,
      final X_start=Medium.X_default));

  parameter Modelica.Units.SI.HeatFlowRate QMin_flow(max=0) = -Modelica.Constants.inf
    "Maximum heat flow rate for cooling (negative)"

  parameter Modelica.Units.SI.Temperature T_start=Medium.T_default
    "Start value of temperature"

  Modelica.Blocks.Interfaces.RealInput TSet(
    unit="K",
    displayUnit="degC")
    "Set point temperature of the fluid that leaves port_b"

  Modelica.Blocks.Interfaces.RealOutput Q_flow(unit="W")
    "Heat flow rate added to the fluid (if flow is from port_a to port_b)"

equation
  connect(TSet, outCon.TSet)
  connect(outCon.Q_flow, Q_flow)
end SensibleCooler_T;


within AixLib.Fluid.HeatExchangers;
model WetCoilEffectivenessNTU
  "Heat exchanger with effectiveness - NTU relation and with moisture condensation"
  extends AixLib.Fluid.Interfaces.PartialFourPortInterface(
    redeclare replaceable package Medium2 = AixLib.Media.Air);
  extends AixLib.Fluid.Interfaces.FourPortFlowResistanceParameters(
    final computeFlowResistance1=true,
    final computeFlowResistance2=true);

  import con = AixLib.Fluid.Types.HeatExchangerConfiguration;
  import flo = AixLib.Fluid.Types.HeatExchangerFlowRegime;

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

  parameter AixLib.Fluid.Types.HeatExchangerConfiguration configuration=
    con.CounterFlow
    "Heat exchanger configuration";
  parameter Real r_nominal=2/3
    "Ratio between air-side and water-side convective heat transfer coefficient";

  parameter Boolean use_Q_flow_nominal = false
    "Set to true to specify Q_flow_nominal and inlet conditions, or to false to specify UA_nominal"

  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal(fixed=
        use_Q_flow_nominal)
    "Nominal heat flow rate (positive for heat transfer from 1 to 2)"
  parameter Modelica.Units.SI.Temperature T_a1_nominal(fixed=use_Q_flow_nominal)
    "Water inlet temperature at a rated condition"
  parameter Modelica.Units.SI.Temperature T_a2_nominal(fixed=use_Q_flow_nominal)
    "Air inlet temperature at a rated condition"
  parameter Modelica.Units.SI.MassFraction w_a2_nominal(start=0.01, fixed=
        use_Q_flow_nominal)
    "Humidity ratio of inlet air at a rated condition (in kg/kg dry air)"

  parameter Modelica.Units.SI.ThermalConductance UA_nominal(
    fixed=not use_Q_flow_nominal,
    min=0,
    start=1/(1/10 + 1/20))
    "Thermal conductance at nominal flow, used to compute heat capacity"

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

  Modelica.Units.SI.HeatFlowRate Q1_flow=-dryWetCalcs.QTot_flow
    "Heat input into water stream (positive if air is cooled)";
  Modelica.Units.SI.HeatFlowRate Q2_flow=dryWetCalcs.QTot_flow
    "Total heat input into air stream (negative if air is cooled)";
  Modelica.Units.SI.HeatFlowRate QSen2_flow=dryWetCalcs.QSen_flow
    "Sensible heat input into air stream (negative if air is cooled)";
  Modelica.Units.SI.HeatFlowRate QLat2_flow=AixLib.Utilities.Psychrometrics.Constants.h_fg
      *mWat_flow "Latent heat input into air (negative if air is dehumidified)";
  Real SHR(
    min=0,
    max=1,
    unit="1") = QSen2_flow /
      noEvent(if (Q2_flow > 1E-6 or Q2_flow < -1E-6) then Q2_flow else 1)
    "Sensible to total heat ratio";
  Modelica.Units.SI.MassFlowRate mWat_flow=dryWetCalcs.mCon_flow
    "Water flow rate of condensate removed from the air stream";

  Real dryFra(final unit="1", min=0, max=1) = dryWetCalcs.dryFra
    "Dry fraction, 0.3 means condensation occurs at 30% heat exchange length from air inlet";

protected
  final parameter Modelica.Units.SI.MassFraction X_w_a2_nominal=w_a2_nominal/(1
       + w_a2_nominal)
    "Water mass fraction of inlet air at a rated condition (in kg/kg total air)";

  parameter Boolean waterSideFlowDependent=true
    "Set to false to make water-side hA independent of mass flow rate"
  parameter Boolean airSideFlowDependent=true
    "Set to false to make air-side hA independent of mass flow rate"
  parameter Boolean waterSideTemperatureDependent=false
    "Set to false to make water-side hA independent of temperature"
  parameter Boolean airSideTemperatureDependent=false
    "Set to false to make air-side hA independent of temperature"

  Real delta=1E-2
    "Parameter for normalization";
  Real delta1=1E-1
    "Parameter for normalization";
  Real fac1 = AixLib.Utilities.Math.Functions.smoothMin(
    (1/delta * m1_flow/m1_flow_nominal)^2,1,delta1);
  Real fac2 = AixLib.Utilities.Math.Functions.smoothMin(
    (1/delta * m2_flow/m2_flow_nominal)^2,1,delta1);
  Real Qfac = fac1*fac2;

  AixLib.Fluid.HeatExchangers.BaseClasses.WetCoilUARated UAFroRated(
    final use_Q_flow_nominal=use_Q_flow_nominal,
    final QTot_flow=Q_flow_nominal,
    final UA=UA_nominal,
    final r_nominal=r_nominal,
    final TAirIn=T_a2_nominal,
    final X_wAirIn=X_w_a2_nominal,
    final TWatIn=T_a1_nominal,
    final mAir_flow=m2_flow_nominal,
    final mWat_flow=m1_flow_nominal)
    "Model that computes UA_nominal";

  AixLib.Fluid.HeatExchangers.HeaterCooler_u heaCoo(
    redeclare final package Medium = Medium1,
    final dp_nominal = dp1_nominal,
    final m_flow_nominal = m1_flow_nominal,
    final energyDynamics = energyDynamics,
    final Q_flow_nominal=-1,
    u(final unit="W"))
    "Heat exchange with water stream"

  AixLib.Fluid.Humidifiers.Humidifier_u heaCooHum_u(
    redeclare final package Medium = Medium2,
    final mWat_flow_nominal = 1,
    final dp_nominal = dp2_nominal,
    final m_flow_nominal = m2_flow_nominal,
    final energyDynamics = energyDynamics,
    u(final unit="kg/s"))
    "Heat and moisture exchange with air stream"
  AixLib.Fluid.HeatExchangers.BaseClasses.HADryCoil hA(
    final UA_nominal = UA_nominal,
    final m_flow_nominal_a = m2_flow_nominal,
    final m_flow_nominal_w = m1_flow_nominal,
    final waterSideTemperatureDependent = waterSideTemperatureDependent,
    final waterSideFlowDependent = waterSideFlowDependent,
    final airSideTemperatureDependent = airSideTemperatureDependent,
    final airSideFlowDependent = airSideFlowDependent,
    r_nominal = r_nominal)
    "Model for convective heat transfer coefficient"
  AixLib.Fluid.HeatExchangers.BaseClasses.WetCoilDryWetRegime dryWetCalcs(
    fullyWet(hAirOut(start=Medium2.h_default)),
    final cfg=flowRegime,
    final mWat_flow_nominal=m1_flow_nominal,
    final mAir_flow_nominal=m2_flow_nominal,
    final Qfac=Qfac)
    "Dry/wet calculations block"

  Modelica.Blocks.Sources.RealExpression cp_a1Exp(
    final y=Medium1.specificHeatCapacityCp(state_a1_inflow))
    "Expression for cp of air"
  Modelica.Blocks.Sources.RealExpression XWat_a2Exp(
    final y = if allowFlowReversal2
    then
      fra_a2 * state_a2_inflow.X[nWat] + fra_b2 * state_b2_inflow.X[nWat]
    else
      state_a2_inflow.X[nWat])
    "Expression for XWat"
  Modelica.Blocks.Sources.RealExpression p_a2Exp(
    final y = port_a2.p)
    "Pressure at port a2"
  Modelica.Blocks.Sources.RealExpression h_a2Exp(
    final y = if allowFlowReversal2
    then
      fra_a2 * Medium2.specificEnthalpy(state_a2_inflow)
      + fra_b2 * Medium2.specificEnthalpy(state_b2_inflow)
    else
      Medium2.specificEnthalpy(state_a2_inflow))
    "Specific enthalpy at port a2"
  Modelica.Blocks.Sources.RealExpression cp_a2Exp(final y=
        Medium2.specificHeatCapacityCp(state_a2_inflow))
    "Specific heat capacity at port a2"
  Modelica.Blocks.Sources.RealExpression TIn_a1Exp(
    final y = if allowFlowReversal1
    then
      fra_a1 * Medium1.temperature(state_a1_inflow)
      + fra_b1 * Medium1.temperature(state_b1_inflow)
    else
      Medium1.temperature(state_a1_inflow))
    "Temperature at port a1"
  Modelica.Blocks.Sources.RealExpression TIn_a2Exp(
    final y = if allowFlowReversal2
    then
      fra_a2 * Medium2.temperature(state_a2_inflow)
      + fra_b2 * Medium2.temperature(state_b2_inflow)
    else
      Medium2.temperature(state_a2_inflow))
    "Temperature at port a2"
  Modelica.Blocks.Sources.RealExpression m_flow_a1Exp(
    final y=AixLib.Utilities.Math.Functions.regNonZeroPower(
      x=port_a1.m_flow,n=1,delta=delta*m1_flow_nominal))
    "Absolute value of mass flow rate on water side"
  Modelica.Blocks.Sources.RealExpression m_flow_a2Exp(
    final y=AixLib.Utilities.Math.Functions.regNonZeroPower(
      x=port_a2.m_flow,n=1,delta=delta*m2_flow_nominal))
    "Absolute value of mass flow rate on air side"
  final parameter Integer nWat=
    AixLib.Fluid.HeatExchangers.BaseClasses.determineWaterIndex(
      Medium2.substanceNames)
    "Index of water";
  parameter flo flowRegime_nominal(fixed=false)
    "Heat exchanger flow regime at nominal flow rates";
  flo flowRegime(fixed=false, start=flowRegime_nominal)
    "Heat exchanger flow regime";

  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea
    "Prescribed heat flow"
  Real fra_a1(min=0, max=1) = if allowFlowReversal1
    then Modelica.Fluid.Utilities.regStep(
      m1_flow,
      1,
      0,
      m1_flow_small)
    else 1
    "Fraction of incoming state taken from port a2
    (used to avoid excessive calls to regStep)";
  Real fra_b1(min=0, max=1) = if allowFlowReversal1
    then 1-fra_a1
    else 0
    "Fraction of incoming state taken from port b2
    (used to avoid excessive calls to regStep)";
  Real fra_a2(min=0, max=1) = if allowFlowReversal2
    then Modelica.Fluid.Utilities.regStep(
      m2_flow,
      1,
      0,
      m2_flow_small)
    else 1
    "Fraction of incoming state taken from port a2
    (used to avoid excessive calls to regStep)";
  Real fra_b2(min=0, max=1) = if allowFlowReversal2
    then 1-fra_a2
    else 0
    "Fraction of incoming state taken from port b2
    (used to avoid excessive calls to regStep)";

  Modelica.Units.SI.ThermalConductance C1_flow=abs(m1_flow)*(if
      allowFlowReversal1 then fra_a1*Medium1.specificHeatCapacityCp(
      state_a1_inflow) + fra_b1*Medium1.specificHeatCapacityCp(state_b1_inflow)
       else Medium1.specificHeatCapacityCp(state_a1_inflow))
    "Heat capacity flow rate medium 1";
  Modelica.Units.SI.ThermalConductance C2_flow=abs(m2_flow)*(if
      allowFlowReversal2 then fra_a2*Medium2.specificHeatCapacityCp(
      state_a2_inflow) + fra_b2*Medium2.specificHeatCapacityCp(state_b2_inflow)
       else Medium2.specificHeatCapacityCp(state_a2_inflow))
    "Heat capacity flow rate medium 2";
  parameter Modelica.Units.SI.SpecificHeatCapacity cp1_nominal(fixed=false)
    "Specific heat capacity of medium 1 at nominal condition";
  parameter Modelica.Units.SI.SpecificHeatCapacity cp2_nominal(fixed=false)
    "Specific heat capacity of medium 2 at nominal condition";
  parameter Modelica.Units.SI.ThermalConductance C1_flow_nominal(fixed=false)
    "Nominal capacity flow rate of Medium 1";
  parameter Modelica.Units.SI.ThermalConductance C2_flow_nominal(fixed=false)
    "Nominal capacity flow rate of Medium 2";
  final parameter Medium1.ThermodynamicState sta1_default = Medium1.setState_phX(
     h=Medium1.h_default,
     p=Medium1.p_default,
     X=Medium1.X_default[1:Medium1.nXi]) "Default state for medium 1";
  final parameter Medium2.ThermodynamicState sta2_default = Medium2.setState_phX(
     h=Medium2.h_default,
     p=Medium2.p_default,
     X=Medium2.X_default[1:Medium2.nXi]) "Default state for medium 2";

initial equation
  assert(m1_flow_nominal > Modelica.Constants.eps,
    "m1_flow_nominal must be positive, m1_flow_nominal = " + String(
    m1_flow_nominal));
  assert(m2_flow_nominal > Modelica.Constants.eps,
    "m2_flow_nominal must be positive, m2_flow_nominal = " + String(
    m2_flow_nominal));

  cp1_nominal = Medium1.specificHeatCapacityCp(sta1_default);
  cp2_nominal = Medium2.specificHeatCapacityCp(sta2_default);
  C1_flow_nominal = m1_flow_nominal*cp1_nominal;
  C2_flow_nominal = m2_flow_nominal*cp2_nominal;
  if (configuration == con.CrossFlowStream1MixedStream2Unmixed) then
    flowRegime_nominal = if (C1_flow_nominal < C2_flow_nominal)
      then
        flo.CrossFlowCMinMixedCMaxUnmixed
      else
        flo.CrossFlowCMinUnmixedCMaxMixed;
  elseif (configuration == con.CrossFlowStream1UnmixedStream2Mixed) then
    flowRegime_nominal = if (C1_flow_nominal < C2_flow_nominal)
      then
        flo.CrossFlowCMinUnmixedCMaxMixed
      else
        flo.CrossFlowCMinMixedCMaxUnmixed;
  elseif (configuration == con.ParallelFlow) then
    flowRegime_nominal = flo.ParallelFlow;
  elseif (configuration == con.CounterFlow) then
    flowRegime_nominal = flo.CounterFlow;
  elseif (configuration == con.CrossFlowUnmixed) then
    flowRegime_nominal = flo.CrossFlowUnmixed;
  else
    // Invalid flow regime. Assign a value to flowRegime_nominal, and stop with an assert
    flowRegime_nominal = flo.CrossFlowUnmixed;
    assert(configuration >= con.ParallelFlow and
      configuration <= con.CrossFlowStream1UnmixedStream2Mixed,
      "Invalid heat exchanger configuration.");
  end if;

equation
  // Assign the flow regime for the given heat exchanger configuration and
  // mass flow rates
  if use_dynamicFlowRegime then
    if (configuration == con.ParallelFlow) then
      flowRegime = if (C1_flow*C2_flow >= 0)
        then
          flo.ParallelFlow
        else
          flo.CounterFlow;
    elseif (configuration == con.CounterFlow) then
      flowRegime = if (C1_flow*C2_flow >= 0)
        then
          flo.CounterFlow
        else
          flo.ParallelFlow;
    elseif (configuration == con.CrossFlowUnmixed) then
      flowRegime = flo.CrossFlowUnmixed;
    elseif (configuration == con.CrossFlowStream1MixedStream2Unmixed) then
      flowRegime = if (C1_flow < C2_flow)
        then
          flo.CrossFlowCMinMixedCMaxUnmixed
        else
          flo.CrossFlowCMinUnmixedCMaxMixed;
    else
      // have ( configuration == con.CrossFlowStream1UnmixedStream2Mixed)
      flowRegime = if (C1_flow < C2_flow)
        then
          flo.CrossFlowCMinUnmixedCMaxMixed
        else
          flo.CrossFlowCMinMixedCMaxUnmixed;
    end if;
  else
    flowRegime = flowRegime_nominal;
    assert(noEvent(m1_flow > -0.1 * m1_flow_nominal)
       and noEvent(m2_flow > -0.1 * m2_flow_nominal),
"*** Warning in " + getInstanceName() +
      ": The flow direction reversed.
      However, because the constant use_dynamicFlowRegime is set to false,
      the model does not change equations based on the actual flow regime.
      To switch equations based on the actual flow regime during the simulation,
      set the constant use_dynamicFlowRegime=true.
      Note that this can lead to slow simulation because of events.",
      level = AssertionLevel.warning);
  end if;

  connect(heaCoo.port_b, port_b1)
  connect(heaCooHum_u.port_b, port_b2)
  connect(hA.hA_1, dryWetCalcs.UAWat)
  connect(hA.hA_2, dryWetCalcs.UAAir)
  connect(cp_a1Exp.y, dryWetCalcs.cpWat)
  connect(XWat_a2Exp.y, dryWetCalcs.X_wAirIn)
  connect(p_a2Exp.y, dryWetCalcs.pAir)
  connect(h_a2Exp.y, dryWetCalcs.hAirIn)
  connect(cp_a2Exp.y, dryWetCalcs.cpAir)
  connect(TIn_a1Exp.y, hA.T_1)
  connect(TIn_a1Exp.y, dryWetCalcs.TWatIn)
  connect(TIn_a2Exp.y, hA.T_2)
  connect(TIn_a2Exp.y, dryWetCalcs.TAirIn)
  connect(m_flow_a1Exp.y, hA.m1_flow)
  connect(m_flow_a1Exp.y, dryWetCalcs.mWat_flow)
  connect(port_a1, heaCoo.port_a)
  connect(m_flow_a2Exp.y, hA.m2_flow)
  connect(m_flow_a2Exp.y, dryWetCalcs.mAir_flow)
  connect(port_a2, heaCooHum_u.port_a)
  connect(preHea.port, heaCooHum_u.heatPort)
  connect(dryWetCalcs.QTot_flow, heaCoo.u)
  connect(dryWetCalcs.mCon_flow, heaCooHum_u.u)
  connect(preHea.Q_flow, dryWetCalcs.QTot_flow)
end WetCoilEffectivenessNTU;


Active beam unit for cooling

within AixLib.Fluid.HeatExchangers.ActiveBeams;
model Cooling "Active beam unit for cooling"

  replaceable package MediumWat =
    Modelica.Media.Interfaces.PartialMedium "Medium 1 in the component"
  replaceable package MediumAir =
    Modelica.Media.Interfaces.PartialMedium "Medium 2 in the component"

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

  replaceable parameter Data.Generic perCoo "Performance data for cooling"

  parameter Integer nBeams(min=1)=1 "Number of beams in parallel";

  parameter Boolean allowFlowReversalWat=true
    "= true to allow flow reversal in water circuit, false restricts to design direction (port_a -> port_b)"
  parameter Boolean allowFlowReversalAir=true
    "= true to allow flow reversal in air circuit, false restricts to design direction (port_a -> port_b)"

  parameter Modelica.Units.SI.Time tau=30
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"

  // Flow resistance
  parameter Boolean from_dpWat = false
    "= true, use m_flow = f(dp) else dp = f(m_flow)"
  parameter Boolean linearizeFlowResistanceWat = false
    "= true, use linear relation between m_flow and dp for any flow rate"
  parameter Real deltaMWat = 0.1
    "Fraction of nominal flow rate where flow transitions to laminar"

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

  // Initialization
  parameter MediumWat.AbsolutePressure pWatCoo_start = MediumWat.p_default
    "Start value of pressure"
  parameter MediumWat.Temperature TWatCoo_start = MediumWat.T_default
    "Start value of temperature"

  parameter MediumWat.MassFlowRate mWat_flow_small(min=0) = 1E-4*abs(perCoo.mWat_flow_nominal)
    "Small mass flow rate for regularization of zero flow"
  parameter MediumAir.MassFlowRate mAir_flow_small(min=0) = 1E-4*abs(perCoo.mAir_flow_nominal)
    "Small mass flow rate for regularization of zero flow"

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

  // Ports
  Modelica.Fluid.Interfaces.FluidPort_a watCoo_a(
    redeclare final package Medium = MediumWat,
    m_flow(min=if allowFlowReversalWat then -Modelica.Constants.inf else 0),
    h_outflow(start=MediumWat.h_default))
    "Fluid connector watCoo_a (positive design flow direction is from watCoo_a to watCoo_b)"
  Modelica.Fluid.Interfaces.FluidPort_b watCoo_b(
    redeclare final package Medium = MediumWat,
    m_flow(max=if allowFlowReversalWat then +Modelica.Constants.inf else 0),
    h_outflow(start=MediumWat.h_default))
    "Fluid connector watCoo_b (positive design flow direction is from watCoo_a to watCoo_b)"

  Modelica.Fluid.Interfaces.FluidPort_a air_a(
    redeclare final package Medium = MediumAir,
    m_flow(min=if allowFlowReversalAir then -Modelica.Constants.inf else 0),
    h_outflow(start=MediumAir.h_default))
    "Fluid connector air_a (positive design flow direction is from air_a to air_b)"
  Modelica.Fluid.Interfaces.FluidPort_b air_b(
    redeclare final package Medium = MediumAir,
    m_flow(max=if allowFlowReversalAir then +Modelica.Constants.inf else 0),
    h_outflow(start=MediumAir.h_default))
    "Fluid connector air_b (positive design flow direction is from air_a to air_b)"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heaPor
    "Heat port, to be connected to room air"

  MediumWat.ThermodynamicState staWatCoo_a=
      MediumWat.setState_phX(watCoo_a.p,
                           noEvent(actualStream(watCoo_a.h_outflow)),
                           noEvent(actualStream(watCoo_a.Xi_outflow)))
      if show_T "Medium properties in port watCoo_a";
  MediumWat.ThermodynamicState staWatCoo_b=
      MediumWat.setState_phX(watCoo_b.p,
                           noEvent(actualStream(watCoo_b.h_outflow)),
                           noEvent(actualStream(watCoo_b.Xi_outflow)))
      if show_T "Medium properties in port watCoo_b";
  MediumAir.ThermodynamicState staAir_a=
      MediumAir.setState_phX(air_a.p,
                           noEvent(actualStream(air_a.h_outflow)),
                           noEvent(actualStream(air_a.Xi_outflow)))
      if show_T "Medium properties in port air_a";
  MediumAir.ThermodynamicState staAir_b=
      MediumAir.setState_phX(air_b.p,
                           noEvent(actualStream(air_b.h_outflow)),
                           noEvent(actualStream(air_b.Xi_outflow)))
      if show_T "Medium properties in port air_b";

  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heaToRoo(
    final alpha=0)
    "Heat tranferred to the room (in addition to heat from supply air)"

  // Pressure drop
  Modelica.Units.SI.PressureDifference dpWatCoo(displayUnit="Pa") = watCoo_a.p
     - watCoo_b.p "Pressure difference watCoo_a minus watCoo_b";

  Modelica.Units.SI.PressureDifference dpAir(displayUnit="Pa") = air_a.p -
    air_b.p "Pressure difference air_a minus air_b";

  FixedResistances.PressureDrop res(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=perCoo.mAir_flow_nominal*nBeams,
    final dp_nominal=perCoo.dpAir_nominal)

protected
  BaseClasses.Convector conCoo(
    redeclare final package Medium = MediumWat,
    final per=perCoo,
    final allowFlowReversal=allowFlowReversalWat,
    final m_flow_small=mWat_flow_small,
    final show_T=false,
    final homotopyInitialization=homotopyInitialization,
    final from_dp=from_dpWat,
    final linearizeFlowResistance=linearizeFlowResistanceWat,
    final deltaM=deltaMWat,
    final tau=tau,
    final energyDynamics=energyDynamics,
    final p_start=pWatCoo_start,
    final T_start=TWatCoo_start,
    final nBeams=nBeams) "Cooling beam"

  Modelica.Blocks.Math.Sum sum "Connector for heating and cooling mode"

  Modelica.Blocks.Math.Gain gaiSig(
    final k=-1,
    u(final unit="W"),
    y(final unit="W")) "Gain to reverse the sign"

  Sensors.MassFlowRate senFloAir(
    redeclare final package Medium = MediumAir) "Mass flow rate sensor"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTemRooAir
    "Temperature sensor for room air"

initial equation
  assert(perCoo.primaryAir.r_V[1]<=0.000001 and perCoo.primaryAir.f[1]<=0.00001,
    "Performance curve perCoo.primaryAir must pass through (0,0).");
  assert(perCoo.water.r_V[1]<=0.000001      and perCoo.water.f[1]<=0.00001,
    "Performance curve perCoo.water must pass through (0,0).");
  assert(perCoo.dT.r_dT[1]<=0.000001      and perCoo.dT.f[1]<=0.00001,
    "Performance curve perCoo.dT must pass through (0,0).");
  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(heaToRoo.port, heaPor)
  connect(sum.y, gaiSig.u)
  connect(gaiSig.y, heaToRoo.Q_flow)
  connect(senTemRooAir.port, heaPor)
  connect(air_b, senFloAir.port_b)
  connect(conCoo.port_b, watCoo_b)
  connect(conCoo.Q_flow, sum.u[1])
  connect(senTemRooAir.T, conCoo.TRoo)

  connect(air_a, res.port_a)
  connect(senFloAir.port_a, res.port_b)
  connect(watCoo_a, conCoo.port_a)
  connect(senFloAir.m_flow, conCoo.mAir_flow)
end Cooling;


within AixLib.Fluid.HeatExchangers.ActiveBeams;
model CoolingAndHeating "Active beam unit for heating and cooling"
  extends AixLib.Fluid.HeatExchangers.ActiveBeams.Cooling(sum(nin=2));

  replaceable parameter Data.Generic perHea "Performance data for heating"

  // Initialization
  parameter MediumWat.AbsolutePressure pWatHea_start = pWatCoo_start
    "Start value of pressure"

  parameter MediumWat.Temperature TWatHea_start = TWatCoo_start
    "Start value of temperature"

  Modelica.Fluid.Interfaces.FluidPort_a watHea_a(
    redeclare final package Medium = MediumWat,
    m_flow(min=if allowFlowReversalWat then -Modelica.Constants.inf else 0),
    h_outflow(start=MediumWat.h_default))
    "Fluid connector a (positive design flow direction is from watHea_a to watHea_b)"
  Modelica.Fluid.Interfaces.FluidPort_b watHea_b(
    redeclare final package Medium = MediumWat,
    m_flow(max=if allowFlowReversalWat then +Modelica.Constants.inf else 0),
    h_outflow(start=MediumWat.h_default))
    "Fluid connector b (positive design flow direction is from watHea_a to watHea_b)"

  MediumWat.ThermodynamicState staHea_a=
      MediumWat.setState_phX(watHea_a.p,
                          noEvent(actualStream(watHea_a.h_outflow)),
                          noEvent(actualStream(watHea_a.Xi_outflow)))
      if show_T "Medium properties in port watHea_a";

  MediumWat.ThermodynamicState staHea_b=
      MediumWat.setState_phX(watHea_b.p,
                          noEvent(actualStream(watHea_b.h_outflow)),
                          noEvent(actualStream(watHea_b.Xi_outflow)))
       if show_T "Medium properties in port watHea_b";

  Modelica.Units.SI.PressureDifference dpWatHea(displayUnit="Pa") = watHea_a.p
     - watHea_b.p "Pressure difference between watHea_a and watHea_b";

protected
  BaseClasses.Convector conHea(
    redeclare final package Medium = MediumWat,
    final per=perHea,
    final allowFlowReversal=allowFlowReversalWat,
    final m_flow_small=mWat_flow_small,
    final show_T=false,
    final homotopyInitialization=homotopyInitialization,
    final from_dp=from_dpWat,
    final linearizeFlowResistance=linearizeFlowResistanceWat,
    final deltaM=deltaMWat,
    final tau=tau,
    final energyDynamics=energyDynamics,
    final p_start=pWatHea_start,
    final T_start=TWatHea_start,
    final nBeams=nBeams) "Heating beam"

initial equation
  assert(perHea.primaryAir.r_V[1]<=0.000001 and perHea.primaryAir.f[1]<=0.00001,
    "Performance curve perHea.primaryAir must pass through (0,0).");
  assert(perHea.water.r_V[1]<=0.000001      and perHea.water.f[1]<=0.00001,
    "Performance curve perHea.water must pass through (0,0).");
  assert(perHea.dT.r_dT[1]<=0.000001        and perHea.dT.f[1]<=0.00001,
    "Performance curve perHea.dT must pass through (0,0).");

equation
  connect(conHea.port_b, watHea_b)
  connect(conHea.Q_flow, sum.u[2])
  connect(conHea.TRoo, senTemRooAir.T)
  connect(watHea_a, conHea.port_a)
  connect(conHea.mAir_flow, senFloAir.m_flow)
end CoolingAndHeating;


Package with active beams

within AixLib.Fluid.HeatExchangers;
package ActiveBeams "Package with active beams"
  extends Modelica.Icons.VariantsPackage;
end ActiveBeams;


User's Guide

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


Heat exchanger for the water stream

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses;
model Convector "Heat exchanger for the water stream"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow_nominal = per.mWat_flow_nominal*nBeams);
  extends AixLib.Fluid.Interfaces.TwoPortFlowResistanceParameters(
    final computeFlowResistance=true,
    final dp_nominal = per.dpWat_nominal "Don't multiply with nBeams, as the beams are in parallel");

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

  parameter Data.Generic per "Performance data"

  parameter Integer nBeams(min=1) "Number of beams in parallel";

  parameter Modelica.Units.SI.Time tau=30
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"

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

  // Initialization
  parameter Medium.AbsolutePressure p_start = Medium.p_default
    "Start value of pressure"
  parameter Medium.Temperature T_start = Medium.T_default
    "Start value of temperature"
  parameter Medium.MassFraction X_start[Medium.nX](
    final quantity=Medium.substanceNames) = Medium.X_default
    "Start value of mass fractions m_i/m"
  parameter Medium.ExtraProperty C_start[Medium.nC](
    final quantity=Medium.extraPropertiesNames)=fill(0, Medium.nC)
    "Start value of trace substances"

  Modelica.Blocks.Interfaces.RealInput mAir_flow(
    final unit="kg/s") "Air mass flow rate of a single beam"
  Modelica.Blocks.Interfaces.RealInput TRoo(
    final unit="K",
    displayUnit="degC") "Room air temperature"
  Modelica.Blocks.Interfaces.RealOutput Q_flow(final unit="W")
    "Actual capacity of a single beam"

protected
  HeaterCooler_u hex(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=m_flow_nominal,
    final m_flow_small=m_flow_small,
    final show_T=false,
    final from_dp=from_dp,
    final dp_nominal=dp_nominal,
    final linearizeFlowResistance=linearizeFlowResistance,
    final deltaM=deltaM,
    final tau=tau,
    final homotopyInitialization=homotopyInitialization,
    final energyDynamics=energyDynamics,
    final p_start=p_start,
    final T_start=T_start,
    final X_start=X_start,
    final C_start=C_start,
    final Q_flow_nominal=-nBeams * per.Q_flow_nominal)
    "Heat exchanger for the water stream"

  ModificationFactor mod(
    final nBeams=nBeams,
    final per=per) "Performance modification for part load"

  Modelica.Blocks.Sources.RealExpression senTem(final y=Medium.temperature(port_a_inflow))
    "Actual water temperature entering the beam"

  Medium.ThermodynamicState port_a_inflow=
    Medium.setState_phX(port_a.p, inStream(port_a.h_outflow), inStream(port_a.Xi_outflow))
    "state for medium inflowing through port_a";

  Sensors.MassFlowRate senFloWatCoo(
    redeclare final package Medium = Medium) "Mass flow rate sensor"

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(hex.Q_flow, Q_flow)
  connect(hex.port_b, port_b)
  connect(mod.y, hex.u)
  connect(senTem.y, mod.TWat)
  connect(TRoo, mod.TRoo)
  connect(mAir_flow, mod.mAir_flow)
  connect(senFloWatCoo.port_a, port_a)
  connect(senFloWatCoo.port_b, hex.port_a)
  connect(senFloWatCoo.m_flow, mod.mWat_flow)
end Convector;


Cubic spline for interpolation. This model calculates the output based on the cubic hermite interpolation
and linear extrapolation of predefined values. The predefined values must create a monotone curve.

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses;
model DerivativesCubicSpline "Cubic spline for interpolation"
  extends Modelica.Blocks.Icons.Block;
  parameter Real[:] xd={0,0.5,1};
  parameter Real[size(xd, 1)] yd={0,0.75,1};

  Modelica.Blocks.Interfaces.RealInput u
    "Independent variable for interpolation"
  Modelica.Blocks.Interfaces.RealOutput y "Interpolated value"
protected
  parameter Real[size(xd, 1)] dMonotone(each fixed=false) "Derivatives";
  Integer i "Counter to pick the interpolation interval";

initial algorithm
  // Get the derivative values at the support points

  dMonotone := AixLib.Utilities.Math.Functions.splineDerivatives(
    x=xd,
    y=yd,
    ensureMonotonicity=true);

algorithm
  i := 1;
  for j in 1:size(xd, 1) - 1 loop
    if u > xd[j] then
      i := j;
    end if;
  end for;
  // Extrapolate or interpolate the data
  y :=
    AixLib.Utilities.Math.Functions.cubicHermiteLinearExtrapolation(
    x=u,
    x1=xd[i],
    x2=xd[i + 1],
    y1=yd[i],
    y2=yd[i + 1],
    y1d=dMonotone[i],
    y2d=dMonotone[i + 1]);
end DerivativesCubicSpline;


Factor to modify nominal capacity. This model determines the three modification factors described in

AixLib.Fluid.HeatExchangers.ActiveBeams.UsersGuide
by comparing the actual values of air mass flow rate,
water mass flow rate and room-water temperature difference with the nominal values.
The three modification factors are then multiplied.
Input to this model are the total mass flow rates of all parallel beams combined.

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses;
model ModificationFactor "Factor to modify nominal capacity"
  extends Modelica.Blocks.Icons.Block;

  parameter Integer nBeams(min=1) "Number of beams in parallel";

  parameter Data.Generic per "Performance data"

  Modelica.Blocks.Interfaces.RealInput TWat(
    final unit="K",
    displayUnit="degC") "Temperature of the water entering the beams"
  Modelica.Blocks.Interfaces.RealInput mWat_flow(
    final unit="kg/s") "Mass flow rate of the water entering the beams"
  Modelica.Blocks.Interfaces.RealInput mAir_flow(
    final unit="kg/s") "Mass flow rate of the primary air entering the beams"

  Modelica.Blocks.Interfaces.RealInput TRoo(
    final unit="K",
    displayUnit="degC") "Room air temperature"

  Modelica.Blocks.Interfaces.RealOutput y(final unit="1")
    "Total modification factor"

protected
  Modelica.Blocks.Sources.Constant temDif_nom(
    final k=1/per.dT_nominal)
    "Nominal temperature difference between water and room air"
  Modelica.Blocks.Sources.Constant watFlo_nom(final k=1/(nBeams*per.mWat_flow_nominal))
                                     "Nominal water mass flow rate"
  Modelica.Blocks.Sources.Constant airFlo_nom(final k=1/(nBeams*per.mAir_flow_nominal))
                                     "Nominal water mass flow rate"

  DerivativesCubicSpline temDif_mod(
    final xd=per.dT.r_dT,
    final yd=per.dT.f)
    "Derivatives of the cubic spline for the temperature difference between room and water"
  DerivativesCubicSpline watFlo_mod(
    final xd=per.water.r_V,
    final yd=per.water.f) "Derivatives of the cubic spline for the water flow"
  DerivativesCubicSpline airFlo_mod(
    final xd=per.primaryAir.r_V,
    final yd=per.primaryAir.f)
    "Derivatives of the cubic spline for the air flow"

  Modelica.Blocks.Math.Product pro_3
    "Ratio of actual/nominal temperature difference"
  Modelica.Blocks.Math.Product pro_2 "Ratio of actual/nominal water flow rate"
  Modelica.Blocks.Math.Product pro_1 "Ratio of actual/nominal air flow rate"

  Modelica.Blocks.Math.MultiProduct mulPro(final nu=3)
    "Product of the three modification factors"

  Modelica.Blocks.Math.Add add(final k1=+1, final k2=-1)
    "Temperature difference between water and room air"

equation
  connect(mAir_flow, pro_1.u1)
  connect(airFlo_nom.y, pro_1.u2)
  connect(pro_1.y, airFlo_mod.u)
  connect(mulPro.y, y)
  connect(mWat_flow, pro_2.u1)
  connect(pro_2.y, watFlo_mod.u)
  connect(watFlo_nom.y, pro_2.u2)
  connect(TWat, add.u1)
  connect(add.u2, TRoo)
  connect(temDif_nom.y, pro_3.u2)
  connect(add.y, pro_3.u1)
  connect(pro_3.y, temDif_mod.u)
  connect(watFlo_mod.y, mulPro.u[1])
  connect(airFlo_mod.y, mulPro.u[2])
  connect(temDif_mod.y, mulPro.u[3])
end ModificationFactor;


Base classes for active beam models

within AixLib.Fluid.HeatExchangers.ActiveBeams;
package BaseClasses "Base classes for active beam models"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


Water model

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.Examples;
model Convector
  extends Modelica.Icons.Example;

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

  AixLib.Fluid.Sources.MassFlowSource_T wat(
    redeclare package Medium = Medium,
    m_flow=0.094,
    T=288.15,
    nPorts=1)
  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium, nPorts=1) "Pressure boundary condition"
  Modelica.Blocks.Sources.Ramp airFlo(height=0.0792, duration=4)
    "Air mass flow rate"
  Modelica.Blocks.Sources.Constant rooTem(k=273.15 + 25) "Room air temperature"
  AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.Convector con(
    redeclare package Medium = Medium,
    nBeams=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    per(
      mAir_flow_nominal=0.0792,
      mWat_flow_nominal=0.094,
      dT_nominal=-10,
      Q_flow_nominal=1092,
      dpWat_nominal=10000,
      dpAir_nominal=100)) "Convector model"
  AixLib.Fluid.Sensors.TemperatureTwoPort senTem(
    redeclare package Medium = Medium,
    m_flow_nominal=0.094) "Temperature sensor"
equation
  connect(airFlo.y, con.mAir_flow)
  connect(rooTem.y, con.TRoo)
  connect(con.port_b, senTem.port_a)
  connect(senTem.port_b, bou.ports[1])
  connect(wat.ports[1], con.port_a)
end Convector;


Clock. The example tests the implementation of

AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.DerivativesCubicSpline.
Default vectors are: x=[0,0.5,1] and y=[0,0.75,1].
Input to the model is the simulation time.

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.Examples;
model DerivateCubicSpline
  extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.ContinuousClock clock "Clock"
  AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.DerivativesCubicSpline
    cubSpl "Derivatives of cubic spline"
equation
  connect(clock.y, cubSpl.u)
end DerivateCubicSpline;


Constant input signal. This example tests the implementation of

AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.ModificationFactor.

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.Examples;
model ModificationFactor
   extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.Constant const1(k=20) "Constant input signal"
  Modelica.Blocks.Sources.Ramp ramp(height=0.0792, duration=1)
    "Ramp input signal"
  Modelica.Blocks.Sources.Ramp ramp1(height=0.094, duration=1)
    "Ramp input signal"
  Modelica.Blocks.Sources.Ramp ramp2(
    height=27.8,
    duration=1,
    offset=20) "Ramp input signal"
  AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses.ModificationFactor mod(
    nBeams=1,
    per(
      Q_flow_nominal=0.094*2*4200,
      mAir_flow_nominal=0.0792,
      mWat_flow_nominal=0.094,
      dT_nominal=27.8,
      dpWat_nominal=10000,
      dpAir_nominal=100)) "Modification factor"
equation
  connect(ramp.y, mod.mAir_flow)
  connect(ramp1.y, mod.mWat_flow)
  connect(ramp2.y, mod.TWat)
  connect(const1.y, mod.TRoo)
end ModificationFactor;


This package contains examples for the use of models that can be found in
<a href=\

within AixLib.Fluid.HeatExchangers.ActiveBeams.BaseClasses;
package Examples
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Package with performance data

within AixLib.Fluid.HeatExchangers.ActiveBeams;
package Data "Package with performance data"
  extends Modelica.Icons.MaterialPropertiesPackage;
end Data;


Performance data for Trox

within AixLib.Fluid.HeatExchangers.ActiveBeams.Data;
package Trox "Performance data for Trox"
  record DID632A_nozzleH_length6ft_cooling =
    AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Generic (
      primaryAir(
        r_V = {0,0.714286, 1,1.2857},
        f =   {0,0.823403, 1,1.1256}),
      dT(
        f = {0,0.5,1},
        r_dT=
            {0,0.5,1}),
      water(
        r_V = {0,0.33333,0.5,0.666667,0.833333,1,1.333333},
        f =   {0,0.71,0.85,0.92,0.97,1,1.04}),
      mAir_flow_nominal=0.0792,
      mWat_flow_nominal =   0.094,
      dpWat_nominal = 10000,
      dpAir_nominal = 100,
      dT_nominal =          -10,
      Q_flow_nominal =   -1092)
  "Performance data for Trox DID 632A for cooling mode"

  record DID632A_nozzleH_length6ft_heating =
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Generic (
      dT(
        f = {0,0.5,1},
        r_dT=
            {0,0.5,1}),
      primaryAir(
        r_V = {0,0.714286, 1, 1.2857},
        f =   {0,0.8554, 1, 1.0778}),
      water(
        r_V = {0,0.33333,0.5,0.666667,0.833333,1,1.333333},
        f =   {0,0.71,0.85,0.92,0.97,1,1.04}),
      mAir_flow_nominal=0.0792,
      mWat_flow_nominal =   0.094,
      dpWat_nominal = 10000,
      dpAir_nominal = 100,
      dT_nominal =          27.8,
      Q_flow_nominal =   2832)
  "Performance data for Trox DID 632A for heating mode"
end Trox;


Base classes for performance data

within AixLib.Fluid.HeatExchangers.ActiveBeams.Data;
package BaseClasses "Base classes for performance data"
end BaseClasses;


Medium model for air

within AixLib.Fluid.HeatExchangers.ActiveBeams.Examples;
model CoolingAndHeating
  extends Modelica.Icons.Example;

  package MediumA = AixLib.Media.Air "Medium model for air";

  package MediumW = AixLib.Media.Water "Medium model for water";

  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = MediumW,
    nPorts=1) "Sink chilled water"
  AixLib.Fluid.Sources.MassFlowSource_T souAir(
    redeclare package Medium = MediumA,
    m_flow=0.0792,
    use_m_flow_in=false,
    nPorts=1,
    T=285.85) "Source air"
  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = MediumA,
    nPorts=1) "Sink air"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor theConWal(G=200)
    "Thermal conductor for wall"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heaFlo
    "Thermal loads"
  Modelica.Blocks.Sources.Constant TSetHea(k=273.15 + 22)
    "Heating set-point temperature"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=301.15)
    "Outdoor air temperature"
  AixLib.Controls.Continuous.LimPID conHea(
    yMax=0.094,
    Td=0,
    Ti=100,
    k=0.1)
    "Controller for heating"
  Sources.MassFlowSource_T pumCoo(
    redeclare package Medium = MediumW,
    use_m_flow_in=true,
    nPorts=1,
    T=288.15) "Source chilled water"
  Modelica.Blocks.Math.Gain gain(k=1200) "Gain for thermal loads"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTem
    "Room air temperature sensor"
  Sources.MassFlowSource_T pumHea(
    redeclare package Medium = MediumW,
    use_m_flow_in=true,
    nPorts=1,
    T=320.95) "Source hot water"
  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = MediumW,
    nPorts=1) "Sink hot water"
  Modelica.Blocks.Sources.Sine sine(
    f=1/86400,
    amplitude=1,
    phase=-1.5707963267949) "Source for thermal loads"
  AixLib.Fluid.MixingVolumes.MixingVolume vol(nPorts=2,
    redeclare package Medium = MediumA,
    m_flow_nominal=0.1,
    V=30,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Air volume for room"
  Modelica.Blocks.Sources.Constant TSetCoo(k=273.15 + 25)
    "Cooling set-point temperature"
  AixLib.Controls.Continuous.LimPID conCoo(
    yMax=0.094,
    reverseActing=false,
    Td=0,
    k=0.5,
    Ti=70)
    "Controller for cooling"

  AixLib.Fluid.HeatExchangers.ActiveBeams.CoolingAndHeating beaCooHea(
    redeclare package MediumWat = MediumW,
    redeclare package MediumAir = MediumA,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_cooling perCoo,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_heating perHea,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial)
    "Active Beam"
equation
  connect(TOut.port, theConWal.port_a)
  connect(gain.y, heaFlo.Q_flow)
  connect(senTem.T,conHea. u_m)
  connect(sine.y, gain.u)
  connect(bou.ports[1], vol.ports[1])
  connect(theConWal.port_b, vol.heatPort)
  connect(heaFlo.port, vol.heatPort)
  connect(senTem.port, vol.heatPort)
  connect(TSetHea.y, conHea.u_s)
  connect(TSetCoo.y, conCoo.u_s)
  connect(conCoo.u_m, senTem.T)
  connect(beaCooHea.watCoo_b, sin_1.ports[1])
  connect(sin_2.ports[1], beaCooHea.watHea_b)
  connect(souAir.ports[1], beaCooHea.air_a)
  connect(beaCooHea.air_b, vol.ports[2])
  connect(beaCooHea.heaPor, vol.heatPort)
  connect(conCoo.y, pumCoo.m_flow_in)
  connect(conHea.y, pumHea.m_flow_in)
  connect(pumCoo.ports[1], beaCooHea.watCoo_a)
  connect(pumHea.ports[1], beaCooHea.watHea_a)
end CoolingAndHeating;


Medium model for air

within AixLib.Fluid.HeatExchangers.ActiveBeams.Examples;
model CoolingOnly
  extends Modelica.Icons.Example;

  package MediumA = AixLib.Media.Air "Medium model for air";

  package MediumW = AixLib.Media.Water "Medium model for water";

  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = MediumW,
    nPorts=1) "Sink for water"
  AixLib.Fluid.Sources.MassFlowSource_T souAir(
    redeclare package Medium = MediumA,
    use_m_flow_in=false,
    m_flow=0.0792,
    nPorts=1,
    T=285.85) "Source for air"
  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = MediumA,
    nPorts=1) "Sink for air"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor theConWal(G=200)
    "Thermal conductor for wall"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heaFlo
    "Thermal loads"
  Modelica.Blocks.Sources.Constant TSetCoo(k=273.15 + 25)
    "Set-point temperature"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=301.15)
    "Outdoor air temperature"
  AixLib.Controls.Continuous.LimPID conPID(
    reverseActing=false,
    Td=0,
    k=0.5,
    Ti=70,
    yMax=0.094) "Controller"
  Sources.MassFlowSource_T pum(
    redeclare package Medium = MediumW,
    use_m_flow_in=true,
    nPorts=1,
    T=288.15) "Source for water"
  Modelica.Blocks.Math.Gain gain(k=1200) "Gain thermal loads"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTem
    "Room air temperature sensor"
  Modelica.Blocks.Sources.Sine sine(
    f=1/86400,
    amplitude=1,
    phase=-1.5707963267949) "Source for thermal loads"
  AixLib.Fluid.MixingVolumes.MixingVolume vol(
    nPorts=2,
    redeclare package Medium = MediumA,
    m_flow_nominal=0.1,
    V=30,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=293.15) "Air volume for room"
  AixLib.Fluid.HeatExchangers.ActiveBeams.Cooling beaCoo(
    redeclare package MediumWat = MediumW,
    redeclare package MediumAir = MediumA,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_cooling perCoo,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Active beam"
equation
  connect(TOut.port, theConWal.port_a)
  connect(gain.y, heaFlo.Q_flow)
  connect(TSetCoo.y, conPID.u_s)
  connect(senTem.T, conPID.u_m)
  connect(vol.ports[1], bou.ports[1])
  connect(heaFlo.port, vol.heatPort)
  connect(theConWal.port_b, vol.heatPort)
  connect(senTem.port, vol.heatPort)
  connect(sine.y, gain.u)
  connect(beaCoo.watCoo_b, sin_1.ports[1])
  connect(beaCoo.heaPor, vol.heatPort)
  connect(souAir.ports[1], beaCoo.air_a)
  connect(beaCoo.air_b, vol.ports[2])
  connect(pum.ports[1], beaCoo.watCoo_a)
  connect(pum.m_flow_in, conPID.y)
end CoolingOnly;


Medium model for air

within AixLib.Fluid.HeatExchangers.ActiveBeams.Examples;
model HeatingOnly
  extends Modelica.Icons.Example;

  package MediumA = AixLib.Media.Air "Medium model for air";

  package MediumW = AixLib.Media.Water "Medium model for water";

  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = MediumW,
    nPorts=1) "Sink for chilled water"
  AixLib.Fluid.Sources.MassFlowSource_T souAir(
    redeclare package Medium = MediumA,
    m_flow=0.0792,
    use_m_flow_in=false,
    nPorts=1,
    T=285.85) "Source for air"
  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = MediumA,
    nPorts=1) "Sink for air"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor theConWal(G=200)
    "Thermal conductor for wall"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow heaFlo
    "Thermal loads"
  Modelica.Blocks.Sources.Constant TSetHea(k=273.15 + 22)
    "Heating set-point temperature"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TOut(T=301.15)
    "Outdoor air temperature"
  AixLib.Controls.Continuous.LimPID conPID(
    yMax=0.094,
    Td=0,
    Ti=100,
    k=0.1) "Controller"
  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = MediumW,
    T=288.15,
    nPorts=1) "Soure chilled water"
  Modelica.Blocks.Math.Gain gain(k=1200)
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTem
    "Room air temperature sensor"
  Sources.MassFlowSource_T pumHea(
    redeclare package Medium = MediumW,
    use_m_flow_in=true,
    nPorts=1,
    T=320.95) "Source for heating"
  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = MediumW,
    nPorts=1) "Sink for hot water"
  Modelica.Blocks.Sources.Sine sine(
    f=1/86400,
    amplitude=1,
    phase=-1.5707963267949) "Source for thermal loads"
  AixLib.Fluid.MixingVolumes.MixingVolume vol(nPorts=2,
    redeclare package Medium = MediumA,
    m_flow_nominal=0.1,
    V=30,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=293.15) "Air volume for room"

  AixLib.Fluid.HeatExchangers.ActiveBeams.CoolingAndHeating beaCooHea(
    redeclare package MediumWat = MediumW,
    redeclare package MediumAir = MediumA,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_cooling perCoo,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_heating perHea,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Active beam"
equation
  connect(TOut.port, theConWal.port_a)
  connect(gain.y, heaFlo.Q_flow)
  connect(TSetHea.y, conPID.u_s)
  connect(senTem.T, conPID.u_m)
  connect(sine.y, gain.u)
  connect(bou.ports[1], vol.ports[1])
  connect(theConWal.port_b, vol.heatPort)
  connect(heaFlo.port, vol.heatPort)
  connect(senTem.port, vol.heatPort)
  connect(beaCooHea.watHea_b, sin_2.ports[1])
  connect(beaCooHea.heaPor, vol.heatPort)
  connect(souAir.ports[1], beaCooHea.air_a)
  connect(sin_1.ports[1], beaCooHea.watCoo_b)
  connect(sou_1.ports[1], beaCooHea.watCoo_a)
  connect(beaCooHea.air_b, vol.ports[2])
  connect(pumHea.ports[1], beaCooHea.watHea_a)
  connect(pumHea.m_flow_in, conPID.y)
end HeatingOnly;


within AixLib.Fluid.HeatExchangers.ActiveBeams;
package Examples "Package with examples of active beam models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Medium model for air

within AixLib.Fluid.HeatExchangers.ActiveBeams.Validation;
model NumberOfBeams
  extends Modelica.Icons.Example;

  package MediumA = AixLib.Media.Air "Medium model for air";

  package MediumW = AixLib.Media.Water "Medium model for water";

  parameter Integer nBeams(min=1) = 10 "Number of beams";

  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = MediumW,
    nPorts=2) "Sink for chilled water"
  AixLib.Fluid.Sources.MassFlowSource_T souAir(
    redeclare package Medium = MediumA,
    use_m_flow_in=false,
    nPorts=1,
    m_flow=0.0792,
    T=285.85) "Source for air"
  AixLib.Fluid.Sources.Boundary_pT sin_3(
    redeclare package Medium = MediumA,
    nPorts=2)
  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = MediumW,
    nPorts=2,
    T=288.15) "Source for chilled water"
  AixLib.Fluid.Movers.FlowControlled_m_flow pumHotWat(
    redeclare package Medium = MediumW,
    m_flow_nominal=0.094,
    addPowerToMedium=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    use_inputFilter=false,
    nominalValuesDefineDefaultPressureCurve=true) "Pump for hot water"
  AixLib.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = MediumW,
    nPorts=2,
    T=320.95) "Source for hot water"
  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = MediumW,
    nPorts=2) "Sink for hot water"
  AixLib.Fluid.Movers.FlowControlled_m_flow pumChiWat(
    redeclare package Medium = MediumW,
    m_flow_nominal=0.094,
    addPowerToMedium=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    use_inputFilter=false,
    nominalValuesDefineDefaultPressureCurve=true) "Pump for chilled water"
  AixLib.Fluid.HeatExchangers.ActiveBeams.CoolingAndHeating beaCooHea(
    redeclare package MediumWat = MediumW,
    redeclare package MediumAir = MediumA,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_cooling perCoo,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_heating perHea,
    nBeams=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Active beam"

  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature
    prescribedTemperature "Room temperature"

  AixLib.Fluid.Sources.MassFlowSource_T souAir10(
    redeclare package Medium = MediumA,
    use_m_flow_in=false,
    nPorts=1,
    m_flow=0.0792*nBeams,
    T=285.85) "Source for air"

  AixLib.Fluid.Movers.FlowControlled_m_flow pumHotWat10(
    redeclare package Medium = MediumW,
    addPowerToMedium=false,
    m_flow_nominal=0.094*nBeams,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    use_inputFilter=false,
    nominalValuesDefineDefaultPressureCurve=true) "Pump for hot water"

  AixLib.Fluid.Movers.FlowControlled_m_flow pumChiWat10(
    redeclare package Medium = MediumW,
    addPowerToMedium=false,
    m_flow_nominal=0.094*nBeams,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    use_inputFilter=false,
    nominalValuesDefineDefaultPressureCurve=true) "Pump for chilled water"

  AixLib.Fluid.HeatExchangers.ActiveBeams.CoolingAndHeating beaCooHea10(
    redeclare package MediumWat = MediumW,
    redeclare package MediumAir = MediumA,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_cooling
      perCoo,
    redeclare
      AixLib.Fluid.HeatExchangers.ActiveBeams.Data.Trox.DID632A_nozzleH_length6ft_heating
      perHea,
    nBeams=nBeams,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Active beam"
  Modelica.Blocks.Sources.Step step(
    height=-0.094,
    offset=0.094,
    startTime=2000) "Chilled water mass flow rate"
  Modelica.Blocks.Sources.Step step1(
    height=0.094,
    startTime=3000)
    "Hot water mass flow rate"
  Modelica.Blocks.Sources.Step step2(
    height=0.094*nBeams,
    startTime=3000) "Hot water mass flow rate"
  Modelica.Blocks.Sources.Step step3(
    height=-0.094*nBeams,
    offset=0.094*nBeams,
    startTime=2000) "Chilled water mass flow rate"
  Modelica.Blocks.Sources.Step step4(
    offset=273.15 + 25,
    height=-5,
    startTime=2500) "Room air temperature variation"
equation
  connect(sou_2.ports[1], pumHotWat.port_a)
  connect(pumChiWat.port_a, sou_1.ports[1])
  connect(pumChiWat.port_b, beaCooHea.watCoo_a)
  connect(beaCooHea.watCoo_b, sin_1.ports[1])
  connect(sin_2.ports[1], beaCooHea.watHea_b)
  connect(beaCooHea.watHea_a, pumHotWat.port_b)
  connect(souAir.ports[1], beaCooHea.air_a)
  connect(sin_3.ports[1], beaCooHea.air_b)
  connect(pumChiWat10.port_b, beaCooHea10.watCoo_a)
  connect(beaCooHea10.watHea_a, pumHotWat10.port_b)
  connect(souAir10.ports[1], beaCooHea10.air_a)
  connect(pumChiWat10.port_a, sou_1.ports[2])
  connect(pumHotWat10.port_a, sou_2.ports[2])
  connect(beaCooHea10.air_b, sin_3.ports[2])
  connect(beaCooHea10.watCoo_b, sin_1.ports[2])
  connect(beaCooHea10.watHea_b, sin_2.ports[2])
  connect(step.y, pumChiWat.m_flow_in)
  connect(step1.y, pumHotWat.m_flow_in)
  connect(step3.y, pumChiWat10.m_flow_in)
  connect(step2.y, pumHotWat10.m_flow_in)
  connect(step4.y, prescribedTemperature.T)
  connect(prescribedTemperature.port, beaCooHea10.heaPor)
  connect(beaCooHea.heaPor, prescribedTemperature.port)
end NumberOfBeams;


Validation model for the dynamic response for one and multiple beams. This model validates whether the transient response is indeed
independent of the number of beams.
The model is similar to

AixLib.Fluid.HeatExchangers.ActiveBeams.Validation.NumberOfBeams,
except that it is configured with a dynamic balance and non-default initial conditions.

within AixLib.Fluid.HeatExchangers.ActiveBeams.Validation;
model NumberOfBeamsDynamics
  "Validation model for the dynamic response for one and multiple beams"
  extends NumberOfBeams(
    nBeams = 2,
    beaCooHea(
      energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
      show_T=true,
      tau=120,
      TWatCoo_start=278.15,
      TWatHea_start=303.15),
    beaCooHea10(
      energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
      show_T=true,
      tau=120,
      TWatCoo_start=278.15,
      TWatHea_start=303.15),
    step(startTime=200),
    step1(startTime=300),
    step3(startTime=200),
    step2(startTime=300));
end NumberOfBeamsDynamics;


Collection of validation models

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


within AixLib.Fluid.HeatExchangers.ActiveWalls;
model Distributor "Heating circuit distributor for underfloor heating systems"
  extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations;

  //General
  parameter Integer n(min=1) "Number of underfloor heating circuits / registers"

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

  parameter Modelica.Units.SI.Time tau=10
    "Time constant at nominal flow (if energyDynamics <> SteadyState)"

  // Assumptions
  parameter Boolean allowFlowReversal=true
    "= false to simplify equations, assuming, but not enforcing, no flow reversal"

  Modelica.Fluid.Interfaces.FluidPort_a mainFlow(redeclare final package Medium =
               Medium)

  Modelica.Fluid.Interfaces.FluidPort_b mainReturn(redeclare final package Medium =
               Medium)
  MixingVolumes.MixingVolume vol_flow(
    final nPorts=n + 1,
    final m_flow_nominal=m_flow_nominal,
    final V=m_flow_nominal*tau/rho_default,
    redeclare final package Medium = Medium,
    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 mSenFac=mSenFac,
    each final C_nominal=C_nominal,
    final allowFlowReversal=allowFlowReversal)
  MixingVolumes.MixingVolume vol_return(
    final nPorts=n + 1,
    final m_flow_nominal=m_flow_nominal,
    final V=m_flow_nominal*tau/rho_default,
    redeclare final package Medium = Medium,
    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 mSenFac=mSenFac,
    each final C_nominal=C_nominal,
    final allowFlowReversal=allowFlowReversal)
  Modelica.Fluid.Interfaces.FluidPorts_b flowPorts[n](redeclare each final
      package                                                                      Medium =
                       Medium)
  Modelica.Fluid.Interfaces.FluidPorts_a returnPorts[n](redeclare each final
      package                                                                        Medium =
                       Medium)

protected
  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default);
  parameter Modelica.Units.SI.Density rho_default=Medium.density(sta_default)
    "Density, used to compute fluid volume";
equation
  connect(mainFlow, vol_flow.ports[1])
  connect(mainReturn, vol_return.ports[1])

  for k in 1:n loop
    connect(vol_flow.ports[k + 1], flowPorts[k])
    connect(vol_return.ports[k + 1], returnPorts[k])
  end for;
end Distributor;


within AixLib.Fluid.HeatExchangers.ActiveWalls;
model PanelHeating
  "A panel heating for e.g. floor heating with discretization"

  extends Modelica.Fluid.Interfaces.PartialTwoPort;

     parameter AixLib.DataBase.ActiveWalls.ActiveWallBaseDataDefinition floorHeatingType=
      DataBase.ActiveWalls.JocoKlimaBodenTOP2000_Parkett()

  parameter Boolean isFloor =  true "Floor or Ceiling heating"

  parameter Integer dis(min=1) = 5 "Number of Discreatisation Layers";

  parameter Modelica.Units.SI.Area A "Area of floor / heating panel part";

  parameter Modelica.Units.SI.Temperature T0=
      Modelica.Units.Conversions.from_degC(20)
    "Initial temperature, in degrees Celsius";

  parameter Integer calcMethod=2 "Calculation method for convective heat transfer coefficient at surface"

  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hCon_const=2.5
    "Custom convective heat transfer coefficient"

  final parameter Modelica.Units.SI.Emissivity eps=floorHeatingType.eps
    "Emissivity";

  final parameter Real cTopRatio(min=0,max=1)= floorHeatingType.c_top_ratio;

  final parameter BaseClasses.HeatCapacityPerArea
    cFloorHeating=floorHeatingType.C_ActivatedElement;

  final parameter BaseClasses.HeatCapacityPerArea
    cTop=cFloorHeating * cTopRatio;

  final parameter BaseClasses.HeatCapacityPerArea
    cDown=cFloorHeating * (1-cTopRatio);

  final parameter Modelica.Units.SI.Length tubeLength=A/floorHeatingType.Spacing;

  final parameter Modelica.Units.SI.Volume VWater=
      Modelica.Units.Conversions.from_litre(floorHeatingType.VolumeWaterPerMeter
      *tubeLength) "Volume of Water";

  // ACCORDING TO GLUECK, Bauteilaktivierung 1999

  // According to equations 7.91 (for heat flow up) and 7.93 (for heat flow down) from page 41
  //   final parameter Modelica.SIunits.Temperature T_Floor_nom= if Floor then
  //     (floorHeatingType.q_dot_nom/8.92)^(1/1.1) + floorHeatingType.Temp_nom[3]
  //     else floorHeatingType.q_dot_nom/6.7 + floorHeatingType.Temp_nom[3];

  final parameter Modelica.Units.SI.CoefficientOfHeatTransfer kTop_nominal=
      floorHeatingType.k_top;

  final parameter Modelica.Units.SI.CoefficientOfHeatTransfer kDown_nominal=
      floorHeatingType.k_down;

  Modelica.Fluid.Sensors.TemperatureTwoPort TFlow(redeclare package Medium =
        Medium)
  Modelica.Fluid.Sensors.TemperatureTwoPort TReturn(redeclare package Medium =
        Medium)
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a ThermDown
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a thermConv
  AixLib.Utilities.Interfaces.RadPort starRad
  BaseClasses.PanelHeatingSegment panelHeatingSegment[dis](
    redeclare package Medium = Medium,
    each final A=A/dis,
    each final eps=eps,
    each final T0=T0,
    each final VWater=VWater/dis,
    each final kTop=kTop_nominal,
    each final kDown=kDown_nominal,
    each final cTop=cTop,
    each final cDown=cDown,
    each final isFloor=isFloor,
    each final calcMethod=calcMethod,
    each final hCon_const=hCon_const)

  BaseClasses.PressureDropPH pressureDrop(
    redeclare package Medium = Medium,
    final tubeLength=tubeLength,
    final n=floorHeatingType.PressureDropExponent,
    final m=floorHeatingType.PressureDropCoefficient)
equation

  // HEAT CONNECTIONS
  for i in 1:dis loop
    connect(panelHeatingSegment[i].thermConvWall, ThermDown);
    connect(panelHeatingSegment[i].thermConvRoom, thermConv);
    connect(panelHeatingSegment[i].starRad, starRad);
  end for;

  // FLOW CONNECTIONS

  //OUTER CONNECTIONS

  connect(TFlow.port_b, panelHeatingSegment[1].port_a);
  connect(pressureDrop.port_a, panelHeatingSegment[dis].port_b);

  //INNER CONNECTIONS

  if dis > 1 then
    for i in 1:(dis-1) loop
      connect(panelHeatingSegment[i].port_b, panelHeatingSegment[i + 1].port_a);
    end for;
  end if;

  connect(port_a, TFlow.port_a)

  connect(TReturn.port_b, port_b)
  connect(pressureDrop.port_b, TReturn.port_a)
end PanelHeating;


Constant thermal conductance of material.

within AixLib.Fluid.HeatExchangers.ActiveWalls.BaseClasses;
model HeatConductionSegment

  parameter Modelica.Units.SI.ThermalConductance kA
    "Constant thermal conductance of material";
  parameter Modelica.Units.SI.HeatCapacity mc_p
    "Heat capacity of element (= cp*m)";
  parameter Modelica.Units.SI.Temperature T0 "Initial Temperature of element";

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a port_a
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b port_b
    Modelica.Thermal.HeatTransfer.Components.ThermalConductor thermalConductor1(G=2*kA)
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor
    thermalConductor2(                                                        G=
       2*kA)
  Modelica.Thermal.HeatTransfer.Components.HeatCapacitor
    heatCapacitor(                                                     T(start=
          T0), C=mc_p)
equation
  connect(port_a, thermalConductor1.port_a)
  connect(thermalConductor1.port_b, heatCapacitor.port)
  connect(thermalConductor2.port_a, heatCapacitor.port)
  connect(thermalConductor2.port_b, port_b)
end HeatConductionSegment;


within AixLib.Fluid.HeatExchangers.ActiveWalls.BaseClasses;
model PanelHeatingSegment
  "One segment of the discretized panel heating"

extends Modelica.Fluid.Interfaces.PartialTwoPort;

parameter Boolean isFloor = true;

  parameter Modelica.Units.SI.Area A "Area of Floor part";

  parameter Modelica.Units.SI.Emissivity eps=0.95 "Emissivity";

  parameter Modelica.Units.SI.Temperature T0=
      Modelica.Units.Conversions.from_degC(20)
    "Initial temperature, in degrees Celsius";

  parameter Modelica.Units.SI.Volume VWater "Volume of Water in m^3";

  parameter Modelica.Units.SI.CoefficientOfHeatTransfer kTop;
  parameter Modelica.Units.SI.CoefficientOfHeatTransfer kDown;

parameter HeatCapacityPerArea cTop;
parameter HeatCapacityPerArea cDown;

  parameter Integer calcMethod=2 "Calculation method for convective heat transfer coefficient at surface"

  parameter Modelica.Units.SI.CoefficientOfHeatTransfer hCon_const=2.5
    "Constant heat transfer coefficient"

  Modelica.Fluid.Vessels.ClosedVolume vol(
    redeclare package Medium = Medium,
    energyDynamics=system.energyDynamics,
    use_HeatTransfer=true,
    T_start=T0,
    redeclare model HeatTransfer =
        Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer,
    use_portsData=false,
    V=VWater,
    nPorts=2)

  Modelica.Fluid.Sensors.TemperatureTwoPort TFlow(redeclare package Medium =
        Medium)
  Modelica.Fluid.Sensors.TemperatureTwoPort TReturn(redeclare package Medium =
        Medium)
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a thermConvWall
  Utilities.HeatTransfer.HeatToRad twoStar_RadEx(A=A, eps=eps)
  Utilities.HeatTransfer.HeatConvInside HeatConv(
    final A=A,
    final calcMethod=calcMethod,
    final hCon_const=hCon_const,
    surfaceOrientation=if isFloor then 2 else 1)
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a thermConvRoom
  AixLib.Utilities.Interfaces.RadPort starRad
  HeatConductionSegment panel_Segment1(
    kA=kTop*A,
    mc_p=cTop*A,
    T0=T0)
  HeatConductionSegment panel_Segment2(
    T0=T0,
    kA=kDown*A,
    mc_p=cDown*A)
equation

  connect(port_a, TFlow.port_a)

  connect(TFlow.port_b, vol.ports[1])
  connect(vol.ports[2], TReturn.port_a)
  connect(TReturn.port_b, port_b)
  connect(HeatConv.port_a, thermConvRoom)
  connect(twoStar_RadEx.radPort, starRad)
  connect(thermConvWall, thermConvWall)
  connect(panel_Segment1.port_b, twoStar_RadEx.convPort)
  connect(panel_Segment1.port_b, HeatConv.port_b)
  connect(panel_Segment1.port_a, vol.heatPort)
  connect(panel_Segment2.port_b, thermConvWall)
  connect(panel_Segment2.port_a, vol.heatPort)
end PanelHeatingSegment;


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

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

  parameter Real m = 2131
    "Pressure drop coefficient, delta_p[Pa] = tubeLength*m*m_flow[kg/s]^n";
  parameter Real n = 1.7
    "Pressure drop exponent, delta_p[Pa] = tubeLength*m*m_flow[kg/s]^n";
  parameter Modelica.Units.SI.Length tubeLength=10 "total length of tube";

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

  //Hydraulic Part: pressure drop works in both directions now

port_b.p = if noEvent(port_a.m_flow>=0) then port_a.p - tubeLength*m*(port_a.m_flow)^n else  port_a.p + tubeLength*m*(port_b.m_flow)^n;
end PressureDropPH;


Medium in the system

within AixLib.Fluid.HeatExchangers.ActiveWalls.Examples;
model PanelHeatingMultiple
  extends Modelica.Icons.Example;
      replaceable package Medium =
      Modelica.Media.Water.ConstantPropertyLiquidWater "Medium in the system"

  parameter Modelica.Units.SI.Area panelHeatingArea=10 "Area of heating panels";

  Distributor distributor(redeclare package Medium = Medium, m_flow_nominal=0.5, n=6)
  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panelheating_1D_Dis1(redeclare
      package                                                                                Medium = Medium, A=
        panelHeatingArea)
  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panelheating_1D_Dis2(redeclare
      package                                                                                Medium = Medium, A=
        panelHeatingArea)
  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panelheating_1D_Dis3(redeclare
      package                                                                                Medium = Medium, A=
        panelHeatingArea)
  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panelheating_1D_Dis4(redeclare
      package                                                                                Medium = Medium, A=
        panelHeatingArea)
  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panelheating_1D_Dis5(redeclare
      package                                                                                Medium = Medium, A=
        panelHeatingArea)
  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panelheating_1D_Dis6(redeclare
      package                                                                                Medium = Medium, A=
        panelHeatingArea)
  Modelica.Fluid.Sources.MassFlowSource_T boundary(
    nPorts=1,
    use_T_in=false,
    redeclare package Medium = Medium,
    m_flow=0.5,
    T=313.15)
  Modelica.Fluid.Sources.Boundary_pT boundary1(                  nPorts=1,
      redeclare package Medium = Medium)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature FixedTemp(T=293.15)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature FixedTemp1(
                                                                   T=293.15)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature FixedTemp2(
                                                                   T=293.15)
equation
  connect(boundary.ports[1], distributor.mainFlow)
  connect(boundary1.ports[1], distributor.mainReturn)
  connect(panelheating_1D_Dis2.thermConv, FixedTemp.port)
  connect(panelheating_1D_Dis1.thermConv, FixedTemp.port)
  connect(panelheating_1D_Dis3.thermConv, FixedTemp.port)
  connect(panelheating_1D_Dis4.thermConv, FixedTemp.port)
  connect(panelheating_1D_Dis5.thermConv, FixedTemp.port)
  connect(panelheating_1D_Dis6.thermConv, FixedTemp.port)
  connect(panelheating_1D_Dis1.starRad, FixedTemp1.port)
  connect(panelheating_1D_Dis2.starRad, FixedTemp1.port)
  connect(panelheating_1D_Dis3.starRad, FixedTemp1.port)
  connect(panelheating_1D_Dis4.starRad, FixedTemp1.port)
  connect(panelheating_1D_Dis5.starRad, FixedTemp1.port)
  connect(panelheating_1D_Dis6.starRad, FixedTemp1.port)
  connect(panelheating_1D_Dis2.ThermDown, FixedTemp2.port)
  connect(panelheating_1D_Dis1.ThermDown, FixedTemp2.port)
  connect(panelheating_1D_Dis3.ThermDown, FixedTemp2.port)
  connect(panelheating_1D_Dis4.ThermDown, FixedTemp2.port)
  connect(panelheating_1D_Dis5.ThermDown, FixedTemp2.port)
  connect(panelheating_1D_Dis6.ThermDown, FixedTemp2.port)
  connect(distributor.flowPorts[1], panelheating_1D_Dis1.port_a)
  connect(panelheating_1D_Dis2.port_a, distributor.flowPorts[2])
  connect(panelheating_1D_Dis3.port_a, distributor.flowPorts[3])
  connect(panelheating_1D_Dis4.port_a, distributor.flowPorts[4])
  connect(panelheating_1D_Dis5.port_a, distributor.flowPorts[5])
  connect(panelheating_1D_Dis6.port_a, distributor.flowPorts[6])
  connect(panelheating_1D_Dis1.port_b, distributor.returnPorts[1])
  connect(panelheating_1D_Dis2.port_b, distributor.returnPorts[2])
  connect(panelheating_1D_Dis3.port_b, distributor.returnPorts[3])
  connect(panelheating_1D_Dis4.port_b, distributor.returnPorts[4])
  connect(panelheating_1D_Dis5.port_b, distributor.returnPorts[5])
  connect(panelheating_1D_Dis6.port_b, distributor.returnPorts[6])
end PanelHeatingMultiple;


Medium in the system

within AixLib.Fluid.HeatExchangers.ActiveWalls.Examples;
model PanelHeatingSingle
  extends Modelica.Icons.Example;
     replaceable package Medium =
      Modelica.Media.Water.ConstantPropertyLiquidWater "Medium in the system"

  AixLib.Fluid.HeatExchangers.ActiveWalls.PanelHeating panel_Dis1D(
    redeclare package Medium = Medium,
    dis=2,
    A=2,
    isFloor=true,
    T0=292.15)
  Modelica.Fluid.Sources.MassFlowSource_T Source(
    nPorts=1,
    m_flow=0.01,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true,
    T=343.15)
  Modelica.Fluid.Pipes.StaticPipe pipe1(
    diameter=0.02,
    redeclare package Medium = Medium,
    length=0.5)
  Modelica.Fluid.Pipes.StaticPipe pipe2(
    length=10,
    diameter=0.02,
    redeclare package Medium = Medium)
  Modelica.Fluid.Sources.FixedBoundary
                                  tank(
    redeclare package Medium = Medium, nPorts=1)
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature fixedTemperature
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature fixedTemperature1
  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature fixedTemperature2
  Modelica.Fluid.Sensors.TemperatureTwoPort temperature(redeclare package Medium =
               Medium)
  Modelica.Blocks.Sources.Step     const(
    height=-6,
    offset=299.15,
    startTime=42300)
  Modelica.Blocks.Sources.Step     const1(
    height=24,
    offset=289.15,
    startTime=42300)
  Modelica.Blocks.Sources.Constant const2(k=0.005)
  inner Modelica.Fluid.System system(p_start=system.p_ambient,
      p_ambient(displayUnit="Pa"))
  Modelica.Blocks.Interfaces.RealOutput Power
  Modelica.Blocks.Interfaces.RealOutput Treturn
    "Temperature of the passing fluid"
  Modelica.Blocks.Interfaces.RealOutput Tflow "Connector of Real output signal"
equation
  Power =abs(panel_Dis1D.thermConv.Q_flow + panel_Dis1D.starRad.Q_flow);
  connect(Source.ports[1],pipe1. port_a)
  connect(pipe1.port_b, panel_Dis1D.port_a)
  connect(fixedTemperature.port, panel_Dis1D.ThermDown)
  connect(fixedTemperature1.port,panel_Dis1D.starRad)
  connect(fixedTemperature2.port, panel_Dis1D.thermConv)
  connect(pipe2.port_b, tank.ports[1])
  connect(panel_Dis1D.port_b, temperature.port_a)
  connect(pipe2.port_a, temperature.port_b)
  connect(fixedTemperature1.T, const.y)
  connect(const.y, fixedTemperature2.T)
  connect(const.y, fixedTemperature.T)
  connect(const1.y, Source.T_in)
  connect(const2.y, Source.m_flow_in)
  connect(temperature.T, Treturn)
  connect(const1.y, Tflow)
end PanelHeatingSingle;


Calculates the hA value for water inside a coil. Model for convective heat transfer coefficients inside a coil.
Optionally, the convective heat transfer coefficient can
be computed as a function of temperature and mass flow rate.

within AixLib.Fluid.HeatExchangers.BaseClasses;
model HACoilInside "Calculates the hA value for water inside a coil"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Water mass flow rate"

  Modelica.Blocks.Interfaces.RealInput m_flow(unit="kg/s") "Mass flow rate"
  Modelica.Blocks.Interfaces.RealInput T(unit="K") "Temperature"

  Modelica.Blocks.Interfaces.RealOutput hA(unit="W/K")
    "Inside convective heat transfer"

  parameter Modelica.Units.SI.ThermalConductance hA_nominal(min=0)
    "Convective heat transfer coefficient"
  parameter Real n(min=0, max=1)=0.85
    "Water-side exponent for convective heat transfer coefficient, h proportional to m_flow^n";
  parameter Modelica.Units.SI.Temperature T_nominal=
      Modelica.Units.Conversions.from_degC(20) "Nominal water temperature"
  parameter Boolean flowDependent=true
    "Set to false to make hA independent of mass flow rate"
  parameter Boolean temperatureDependent = true
    "Set to false to make hA independent of temperature"

protected
  Real x(min=0)
    "Factor for temperature dependent variation of heat transfer coefficient";
  parameter Real s(min=0, fixed=false)
    "Coefficient for temperature dependence of heat transfer coefficient";
  Real fm "Fraction of actual to nominal mass flow rate";

initial equation
  s =if temperatureDependent then 0.014/(1 + 0.014*
    Modelica.Units.Conversions.to_degC(T_nominal)) else 1;
equation
  fm = if flowDependent then m_flow / m_flow_nominal else 1;
  x = if temperatureDependent then 1 + s * (T-T_nominal) else 1;
  if flowDependent and temperatureDependent then
    hA = x * hA_nominal * AixLib.Utilities.Math.Functions.regNonZeroPower(fm, n, 0.1);
  elseif flowDependent then
    hA = hA_nominal * AixLib.Utilities.Math.Functions.regNonZeroPower(fm, n, 0.1);
  elseif temperatureDependent then
    hA = x * hA_nominal;
  else
    hA = hA_nominal;
  end if;
end HACoilInside;


Sensible convective heat transfer model for air to water coil. Model for sensible convective heat transfer coefficients for an air to water coil.

within AixLib.Fluid.HeatExchangers.BaseClasses;
model HADryCoil
  "Sensible convective heat transfer model for air to water coil"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.ThermalConductance UA_nominal(min=0)
    "Thermal conductance at nominal flow"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal_w
    "Water mass flow rate"
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal_a
    "Air mass flow rate"

  Modelica.Blocks.Interfaces.RealInput m1_flow(final unit="kg/s") "Mass flow rate medium 1"
  Modelica.Blocks.Interfaces.RealInput m2_flow(final unit="kg/s") "Mass flow rate medium 2"
  Modelica.Blocks.Interfaces.RealInput T_1(final unit="K") "Temperature medium 1"
  Modelica.Blocks.Interfaces.RealInput T_2(final unit="K") "Temperature medium 2"

  Modelica.Blocks.Interfaces.RealOutput hA_1(final unit="W/K")
    "Convective heat transfer medium 1"
  Modelica.Blocks.Interfaces.RealOutput hA_2(final unit="W/K")
    "Convective heat transfer medium 2"

  parameter Real r_nominal(min=0)=0.5
    "Ratio between air-side and water-side convective heat transfer coefficient"
  parameter Modelica.Units.SI.ThermalConductance hA_nominal_w(min=0) =
    UA_nominal*(r_nominal + 1)/r_nominal
    "Water side convective heat transfer coefficient"
  parameter Modelica.Units.SI.ThermalConductance hA_nominal_a(min=0) =
    r_nominal*hA_nominal_w
    "Air side convective heat transfer coefficient, including fin resistance"
  parameter Real n_w(min=0, max=1)=0.85
    "Water-side exponent for convective heat transfer coefficient, h~m_flow^n";
  parameter Real n_a(min=0, max=1)=0.8
    "Air-side exponent for convective heat transfer coefficient, h~m_flow^n";
  parameter Modelica.Units.SI.Temperature T0_w=
      Modelica.Units.Conversions.from_degC(20) "Water temperature"
  parameter Modelica.Units.SI.Temperature T0_a=
      Modelica.Units.Conversions.from_degC(20) "Air temperature"
  parameter Boolean waterSideFlowDependent=true
    "Set to false to make water-side hA independent of mass flow rate"
  parameter Boolean airSideFlowDependent = true
    "Set to false to make air-side hA independent of mass flow rate"
  parameter Boolean waterSideTemperatureDependent = true
    "Set to false to make water-side hA independent of temperature"
  parameter Boolean airSideTemperatureDependent = true
    "Set to false to make air-side hA independent of temperature"
protected
  Real x_a(min=0)
    "Factor for air side temperature dependent variation of heat transfer coefficient";
  Real x_w(min=0)
    "Factor for water side temperature dependent variation of heat transfer coefficient";
  parameter Real s_w(min=0, fixed=false)
    "Coefficient for temperature dependence of water side heat transfer coefficient";
  Real fm_w "Fraction of actual to nominal mass flow rate";
  Real fm_a "Fraction of actual to nominal mass flow rate";
initial equation
  s_w =if waterSideTemperatureDependent then 0.014/(1 + 0.014*
    Modelica.Units.Conversions.to_degC(T0_w)) else 1;
equation
  fm_w = if waterSideFlowDependent then
              m1_flow / m_flow_nominal_w else 1;
  fm_a = if airSideFlowDependent then
              m2_flow / m_flow_nominal_a else 1;
  x_w = if waterSideTemperatureDependent then
         1 + s_w * (T_1-T0_w) else
              1;
  x_a = if airSideTemperatureDependent then
         1 + 7.8532E-4 * (T_2-T0_a) else
              1;
  if waterSideFlowDependent then
    hA_1 = x_w * hA_nominal_w
               * AixLib.Utilities.Math.Functions.regNonZeroPower(fm_w, n_w, 0.1);
  else
    hA_1 = x_w * hA_nominal_w;
  end if;

  if airSideFlowDependent then
    hA_2 = x_a * hA_nominal_a
               * AixLib.Utilities.Math.Functions.regNonZeroPower(fm_a, n_a, 0.1);
  else
    hA_2 = x_a * hA_nominal_a;
  end if;
end HADryCoil;


within AixLib.Fluid.HeatExchangers.BaseClasses;
model HANaturalCylinder
  "Calculates an hA value for natural convection around a cylinder"
  extends Modelica.Blocks.Icons.Block;
  replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium inside the tank";
  parameter Modelica.Units.SI.Diameter ChaLen
    "Characteristic length of the cylinder";

  parameter Modelica.Units.SI.ThermalConductance hA_nominal(min=0)
    "Convective heat transfer coefficient"
  parameter Modelica.Units.SI.Temperature TFlu_nominal
    "Fluid temperature at hA_nominal"
  parameter Modelica.Units.SI.Temperature TSur_nominal
    "Surface temperature at hA_nominal"

  Modelica.Blocks.Interfaces.RealInput TSur(unit = "K")
    "Temperature of the external surface of the heat exchanger"
  Modelica.Blocks.Interfaces.RealInput TFlu(unit = "K")
    "Temperature of the fluid in the heat exchanger"
  Modelica.Blocks.Interfaces.RealOutput hA(unit = "W/K")
    "hA-value of the heat exchanger"
  Real h(unit="W/(m2.K)") "Convection coefficient";
protected
  parameter Real Gr_nominal(fixed=false) "Grashof number";
  parameter Real B_nominal(unit="1/K", fixed=false)
    "isobaricExpansionCoefficient";
  parameter Real nu_nominal(unit = "m2/s", fixed=false)
    "Kinematic viscosity of the medium";
  parameter Modelica.Units.SI.DynamicViscosity mu_nominal(fixed=false)
    "Dynamic viscosity of the medium";
  parameter Modelica.Units.SI.Density rho_nominal(fixed=false)
    "Density of the medium";

  parameter Modelica.Units.SI.ThermalConductivity k_nominal(fixed=false)
    "Thermal conductivity of the fluid";

  parameter Real Ra_nominal(fixed=false) "Rayleigh number";
  parameter Real Pr_nominal(fixed=false) "Prandlt number";
  parameter Real Nusselt_nominal(fixed=false) "Nusselt number";

  parameter Real h_nominal(unit="W/(m2.K)", fixed=false)
    "Convection coefficient";
  parameter Modelica.Units.SI.Area A(fixed=false)
    "Surface area, deduced from hA_nominal, fluid temperatures and characteristic length";

  Modelica.Units.SI.ThermalConductivity k "Thermal conductivity of the fluid";
  Real Gr "Grashof number";
  Real B(unit="1/K") "isobaricExpansionCoefficient";
  Real nu(unit = "m2/s") "Kinematic viscosity of the medium";
  Modelica.Units.SI.DynamicViscosity mu "Dynamic viscosity of the medium";
  Modelica.Units.SI.Density rho "Density of the medium";
  constant Modelica.Units.SI.Acceleration g=Modelica.Constants.g_n
    "Acceleration due to gravity";

  Medium.ThermodynamicState state
    "Thermodynamic state of the fluid around the cylinder";
  Real Ra "Rayleigh number";
  Real Pr "Prandlt number";
  Real Nusselt "Nusselt number";

function nusselt
    input Modelica.Units.SI.ThermalConductivity k "Thermal conductivity";
  input Real Pr "Prandlt number";
  input Real Ra "Rayleigh number";
  output Real Nu(min=0) "Nusselt number";
  protected
  Real num "Numerator";
  Real den "Denominator";
algorithm
  num := (0.387*AixLib.Utilities.Math.Functions.smoothMax(Ra,1,0.1)^(1/6));
  den := ((1+(0.559/Pr)^(9/16))^(8/27));
  Nu := (0.6+num/den)^2;
end nusselt;

initial equation

  // Fluid properties
  mu_nominal = AixLib.Fluid.HeatExchangers.BaseClasses.dynamicViscosityWater(
        T = 0.5 * (TSur_nominal+TFlu_nominal));
  rho_nominal = Medium.density(
        Medium.setState_pTX(
          p = Medium.p_default,
          T = 0.5*(TSur_nominal+TFlu_nominal),
          X = Medium.X_default));
  Pr_nominal = AixLib.Fluid.HeatExchangers.BaseClasses.prandtlNumberWater(
          T = 0.5*(TSur_nominal+TFlu_nominal));

  B_nominal = AixLib.Fluid.HeatExchangers.BaseClasses.isobaricExpansionCoefficientWater(
          T = 0.5*(TSur_nominal+TFlu_nominal));
  nu_nominal = mu_nominal/rho_nominal;

  Gr_nominal = Modelica.Constants.g_n * B_nominal * (TSur_nominal -
  TFlu_nominal)*ChaLen^3/nu_nominal^2;
  Ra_nominal = Gr_nominal*Pr_nominal;
  // Convection coefficient
  k_nominal = Medium.thermalConductivity(
    Medium.setState_pTX(
    p = Medium.p_default,
    T = 0.5*(TFlu_nominal+TSur_nominal),
    X = Medium.X_default));
  Nusselt_nominal = nusselt(k=k_nominal, Pr=Pr_nominal, Ra=Ra_nominal);
  h_nominal = Nusselt_nominal * k_nominal/ChaLen;
  A = hA_nominal / h_nominal;
equation
  // Fluid properties
  state = Medium.setState_pTX(
             p = Medium.p_default,
             T = 0.5*(TSur+TFlu),
             X = Medium.X_default);
  mu = AixLib.Fluid.HeatExchangers.BaseClasses.dynamicViscosityWater(
        T = 0.5 * (TSur+TFlu));
  rho = Medium.density(state);
  Pr = AixLib.Fluid.HeatExchangers.BaseClasses.prandtlNumberWater(
          T = 0.5*(TSur+TFlu));

  B = AixLib.Fluid.HeatExchangers.BaseClasses.isobaricExpansionCoefficientWater(
          T = 0.5*(TSur+TFlu));
  nu = mu/rho;

  Gr = Modelica.Constants.g_n * B * (TSur - TFlu)*ChaLen^3/nu^2;
  Ra = Gr*Pr;
  // Convection coefficient
  k = Medium.thermalConductivity(state);
  Nusselt = nusselt(k=k, Pr=Pr, Ra=Ra);
  h = Nusselt * k/ChaLen;
  hA = h*A;

            where NuD is the Nusselt number, RaD is the
            Rayleigh number and
            Pr is the Prandtl number.

            This correclation is accurate for RaD less than 1012.

            h is then calculated from the Nusselt number. The equation is

            h = NuD k/D

            where k is the thermal conductivity of the fluid and D is the diameter
            of the submerged cylinder.

References

            Fundamentals of Heat and Mass Transfer (Fourth Edition), Frank Incropera and David
            DeWitt, John Wiley and Sons, 1996

            ", revisions="

August 29, 2014 by Michael Wetter:

Refactored function calls for medium properties.

May 10, 2013 by Michael Wetter:

Revised implementation to use hA_nominal as a parameter, and compute the
associated surface area A. This revision was required to have a consistent
computation of the hA values inside and outside of the coil in the
heat exchanger model of the water tank.

February 26, 2013 by Peter Grant:

First implementation.

"),
    Icon(graphics={                       Text(
          extent={{-66,88},{60,-2}},
          textColor={0,0,0},
          fillColor={255,255,255},
          fillPattern=FillPattern.Solid,
          textString="hA"),
        Rectangle(
          extent={{-62,-26},{64,-72}},
          lineColor={0,0,0},
          fillColor={0,0,0},
          fillPattern=FillPattern.Solid),
        Ellipse(
          extent={{-56,-72},{-66,-26}},
          lineColor={0,0,0},
          fillColor={255,255,255},
          fillPattern=FillPattern.Solid),
        Ellipse(
          extent={{70,-72},{60,-26}},
          lineColor={0,0,0},
          fillColor={0,0,0},
          fillPattern=FillPattern.Solid),
        Polygon(
          points={{-38,-4},{-44,-18},{-32,-18},{-38,-4}},
          lineColor={175,175,175},
          fillColor={175,175,175},
          fillPattern=FillPattern.Solid),
        Polygon(
          points={{-12,-4},{-18,-18},{-6,-18},{-12,-4}},
          lineColor={175,175,175},
          fillColor={175,175,175},
          fillPattern=FillPattern.Solid),
        Polygon(
          points={{16,-4},{10,-18},{22,-18},{16,-4}},
          lineColor={175,175,175},
          fillColor={175,175,175},
          fillPattern=FillPattern.Solid),
        Polygon(
          points={{42,-4},{36,-18},{48,-18},{42,-4}},
          lineColor={175,175,175},
          fillColor={175,175,175},
          fillPattern=FillPattern.Solid),
        Line(
          points={{-38,-18},{-34,-38},{-44,-52},{-32,-72},{-40,-86}},
          color={175,175,175},
          smooth=Smooth.Bezier),
        Line(
          points={{-12,-18},{-8,-38},{-18,-52},{-6,-72},{-14,-86}},
          color={175,175,175},
          smooth=Smooth.Bezier),
        Line(
          points={{16,-18},{20,-38},{10,-52},{22,-72},{14,-86}},
          color={175,175,175},
          smooth=Smooth.Bezier),
        Line(
          points={{42,-18},{46,-38},{36,-52},{48,-72},{40,-86}},
          color={175,175,175},
          smooth=Smooth.Bezier)}),
   __Dymola_LockedEditing="Model from IBPSA");
end HANaturalCylinder;