within AixLib.Fluid.Interfaces;
model StaticFourPortHeatMassExchanger
  "Partial model transporting two fluid streams between four ports without storing mass or energy"
  extends AixLib.Fluid.Interfaces.PartialFourPortInterface;
  extends AixLib.Fluid.Interfaces.FourPortFlowResistanceParameters(
   final computeFlowResistance1=(dp1_nominal > Modelica.Constants.eps),
   final computeFlowResistance2=(dp2_nominal > Modelica.Constants.eps));

  constant Boolean prescribedHeatFlowRate1 = false
    "Set to true if the heat flow rate into fluid 1 is not a function of the component temperature";
  constant Boolean prescribedHeatFlowRate2 = false
    "Set to true if the heat flow rate into fluid 2 is not a function of the component temperature";

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

  // Q1_flow is sensible plus latent heat flow rate
  input Modelica.Units.SI.HeatFlowRate Q1_flow
    "Heat transferred into the medium 1";
  input Medium1.MassFlowRate mWat1_flow
    "Moisture mass flow rate added to the medium 1";
  // Q2_flow is sensible plus latent heat flow rate
  input Modelica.Units.SI.HeatFlowRate Q2_flow
    "Heat transferred into the medium 2";
  input Medium2.MassFlowRate mWat2_flow
    "Moisture mass flow rate added to the medium 2";
  constant Boolean sensibleOnly1
    "Set to true if sensible exchange only for medium 1";
  constant Boolean sensibleOnly2
    "Set to true if sensible exchange only for medium 2";

protected
  AixLib.Fluid.Interfaces.StaticTwoPortHeatMassExchanger bal1(
    redeclare final package Medium=Medium1,
    final sensibleOnly = sensibleOnly1,
    final prescribedHeatFlowRate=prescribedHeatFlowRate1,
    final m_flow_nominal = m1_flow_nominal,
    final dp_nominal = dp1_nominal,
    final allowFlowReversal = allowFlowReversal1,
    final m_flow_small = m1_flow_small,
    final homotopyInitialization = homotopyInitialization,
    final from_dp = from_dp1,
    final linearizeFlowResistance = linearizeFlowResistance1,
    final deltaM = deltaM1,
    final Q_flow = Q1_flow,
    final mWat_flow = mWat1_flow)
    "Model for heat, mass, species, trace substance and pressure balance of stream 1";
  AixLib.Fluid.Interfaces.StaticTwoPortHeatMassExchanger bal2(
    redeclare final package Medium=Medium2,
    final sensibleOnly = sensibleOnly2,
    final prescribedHeatFlowRate=prescribedHeatFlowRate2,
    final m_flow_nominal = m2_flow_nominal,
    final dp_nominal = dp2_nominal,
    final allowFlowReversal = allowFlowReversal2,
    final m_flow_small = m2_flow_small,
    final homotopyInitialization = homotopyInitialization,
    final from_dp = from_dp2,
    final linearizeFlowResistance = linearizeFlowResistance2,
    final deltaM = deltaM2,
    final Q_flow = Q2_flow,
    final mWat_flow = mWat2_flow)
    "Model for heat, mass, species, trace substance and pressure balance of stream 2";

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(bal1.port_a, port_a1);
  connect(bal1.port_b, port_b1);
  connect(bal2.port_a, port_a2);
  connect(bal2.port_b, port_b2);
end StaticFourPortHeatMassExchanger;


Partial model for static energy and mass conservation equations. This model transports fluid between its two ports, without storing mass or energy.
It implements a steady-state conservation equation for energy and mass fractions.
The model has zero pressure drop between its ports.

within AixLib.Fluid.Interfaces;
model StaticTwoPortConservationEquation
  "Partial model for static energy and mass conservation equations"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface;

  constant Boolean simplify_mWat_flow = true
    "Set to true to cause port_a.m_flow + port_b.m_flow = 0 even if mWat_flow is non-zero";

  constant Boolean prescribedHeatFlowRate = false
    "Set to true if the heat flow rate is not a function of a temperature difference to the fluid temperature";

  parameter Boolean use_mWat_flow = false
    "Set to true to enable input connector for moisture mass flow rate"

  parameter Boolean use_C_flow = false
    "Set to true to enable input connector for trace substance"

  Modelica.Blocks.Interfaces.RealInput Q_flow(unit="W")
    "Sensible plus latent heat flow rate transferred into the medium"
  Modelica.Blocks.Interfaces.RealInput mWat_flow(final quantity="MassFlowRate",
                                                 unit="kg/s")
    if use_mWat_flow "Moisture mass flow rate added to the medium"
  Modelica.Blocks.Interfaces.RealInput[Medium.nC] C_flow
    if use_C_flow "Trace substance mass flow rate added to the medium"

  // Outputs that are needed in models that extend this model
  Modelica.Blocks.Interfaces.RealOutput hOut(final unit="J/kg")
    "Leaving specific enthalpy of the component"

  Modelica.Blocks.Interfaces.RealOutput XiOut[Medium.nXi](each unit="1",
                                                          each min=0,
                                                          each max=1,
                                                          nominal=0.01*ones(Medium.nXi))
    "Leaving species concentration of the component"
  Modelica.Blocks.Interfaces.RealOutput COut[Medium.nC](each min=0)
    "Leaving trace substances of the component"

protected
  final parameter Boolean use_m_flowInv=
    (prescribedHeatFlowRate or use_mWat_flow or use_C_flow)
    "Flag, true if m_flowInv is used in the model"
  final parameter Real s[Medium.nXi] = {if Modelica.Utilities.Strings.isEqual(string1=Medium.substanceNames[i],
                                            string2="Water",
                                            caseSensitive=false)
                                            then 1 else 0 for i in 1:Medium.nXi}
    "Vector with zero everywhere except where species is";

  Real m_flowInv(unit="s/kg") "Regularization of 1/m_flow of port_a";

  Modelica.Units.SI.MassFlowRate mXi_flow[Medium.nXi]
    "Mass flow rates of independent substances added to the medium";

  // Parameters for inverseXRegularized.
  // These are assigned here for efficiency reason.
  // Otherwise, they would need to be computed each time
  // the function is invocated.
  final parameter Real deltaReg = m_flow_small/1E3
    "Smoothing region for inverseXRegularized";

  final parameter Real deltaInvReg = 1/deltaReg
    "Inverse value of delta for inverseXRegularized";

  final parameter Real aReg = -15*deltaInvReg
    "Polynomial coefficient for inverseXRegularized";
  final parameter Real bReg = 119*deltaInvReg^2
    "Polynomial coefficient for inverseXRegularized";
  final parameter Real cReg = -361*deltaInvReg^3
    "Polynomial coefficient for inverseXRegularized";
  final parameter Real dReg = 534*deltaInvReg^4
    "Polynomial coefficient for inverseXRegularized";
  final parameter Real eReg = -380*deltaInvReg^5
    "Polynomial coefficient for inverseXRegularized";
  final parameter Real fReg = 104*deltaInvReg^6
    "Polynomial coefficient for inverseXRegularized";

  final parameter Medium.ThermodynamicState state_default = Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default[1:Medium.nXi]) "Medium state at default values";
  // Density at medium default values, used to compute the size of control volumes
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(state=state_default)
    "Specific heat capacity, used to verify energy conservation";
  constant Modelica.Units.SI.TemperatureDifference dTMax(min=1) = 200
    "Maximum temperature difference across the StaticTwoPortConservationEquation";
  // Conditional connectors
  Modelica.Blocks.Interfaces.RealInput mWat_flow_internal(unit="kg/s")
    "Needed to connect to conditional connector";
  Modelica.Blocks.Interfaces.RealInput C_flow_internal[Medium.nC]
    "Needed to connect to conditional connector";
initial equation
  // Assert that the substance with name 'water' has been found.
  if use_mWat_flow then
    assert(Medium.nXi == 0 or abs(sum(s)-1) < 1e-5,
      "If Medium.nXi > 1, then substance 'water' must be present for one component.'"
         + Medium.mediumName + "'.\n"
         + "Check medium model.");
  end if;
equation
  // Conditional connectors
  connect(mWat_flow, mWat_flow_internal);
  if not use_mWat_flow then
    mWat_flow_internal = 0;
  end if;

  connect(C_flow, C_flow_internal);
  if not use_C_flow then
    C_flow_internal = zeros(Medium.nC);
  end if;

  // Species flow rate from connector mWat_flow
  mXi_flow = mWat_flow_internal * s;

  // Regularization of m_flow around the origin to avoid a division by zero
  // m_flowInv is only used if prescribedHeatFlowRate == true, or
  // if the input connectors mWat_flow or C_flow are enabled.
  if use_m_flowInv then
    m_flowInv = AixLib.Utilities.Math.Functions.inverseXRegularized(
                       x=port_a.m_flow,
                       delta=deltaReg, deltaInv=deltaInvReg,
                       a=aReg, b=bReg, c=cReg, d=dReg, e=eReg, f=fReg);
  else
    // m_flowInv is not used.
    m_flowInv = 0;
  end if;

  if prescribedHeatFlowRate then
    assert(noEvent( abs(Q_flow) < dTMax*cp_default*max(m_flow_small/1E3, abs(m_flow))),
   "In " + getInstanceName() + ":
   The heat flow rate equals " + String(Q_flow) +
   " W and the mass flow rate equals " + String(m_flow) + " kg/s,
   which results in a temperature difference " +
   String(abs(Q_flow)/ (cp_default*max(m_flow_small/1E3, abs(m_flow)))) +
   " K > dTMax=" +String(dTMax) + " K.
   This may indicate that energy is not conserved for small mass flow rates.
   The implementation may require prescribedHeatFlowRate = false.");
  end if;

  if allowFlowReversal then
    // Formulate hOut using spliceFunction. This avoids an event iteration.
    // The introduced error is small because deltax=m_flow_small/1e3
    hOut = AixLib.Utilities.Math.Functions.regStep(y1=port_b.h_outflow,
                                                    y2=port_a.h_outflow,
                                                    x=port_a.m_flow,
                                                    x_small=m_flow_small/1E3);
    XiOut = AixLib.Utilities.Math.Functions.regStep(y1=port_b.Xi_outflow,
                                                     y2=port_a.Xi_outflow,
                                                     x=port_a.m_flow,
                                                     x_small=m_flow_small/1E3);
    COut = AixLib.Utilities.Math.Functions.regStep(y1=port_b.C_outflow,
                                                    y2=port_a.C_outflow,
                                                    x=port_a.m_flow,
                                                    x_small=m_flow_small/1E3);
  else
    hOut =  port_b.h_outflow;
    XiOut = port_b.Xi_outflow;
    COut =  port_b.C_outflow;
  end if;

  //////////////////////////////////////////////////////////////////////////////////////////
  // Energy balance and mass balance

    // Mass balance (no storage)
    port_a.m_flow + port_b.m_flow = if simplify_mWat_flow then 0 else -mWat_flow_internal;

    // Substance balance
    // a) forward flow
    if use_m_flowInv then
      port_b.Xi_outflow = inStream(port_a.Xi_outflow) + mXi_flow * m_flowInv;
    else // no water is added
      assert(use_mWat_flow == false, "In " + getInstanceName() + ": Wrong implementation for forward flow.");
      port_b.Xi_outflow = inStream(port_a.Xi_outflow);
    end if;

    // b) backward flow
    if allowFlowReversal then
      if use_m_flowInv then
        port_a.Xi_outflow = inStream(port_b.Xi_outflow) - mXi_flow * m_flowInv;
      else // no water added
        assert(use_mWat_flow == false, "In " + getInstanceName() + ": Wrong implementation for reverse flow.");
        port_a.Xi_outflow = inStream(port_b.Xi_outflow);
      end if;
    else // no  flow reversal
      port_a.Xi_outflow = Medium.X_default[1:Medium.nXi];
    end if;

    // Energy balance.
    // This equation is approximate since m_flow = port_a.m_flow is used for the mass flow rate
    // at both ports. Since mWat_flow_internal << m_flow, the error is small.
    if prescribedHeatFlowRate then
      port_b.h_outflow = inStream(port_a.h_outflow) + Q_flow * m_flowInv;
      if allowFlowReversal then
        port_a.h_outflow = inStream(port_b.h_outflow) - Q_flow * m_flowInv;
      else
        port_a.h_outflow = Medium.h_default;
      end if;
    else
      // Case with prescribedHeatFlowRate == false.
      // port_b.h_outflow is known and the equation needs to be solved for Q_flow.
      // Hence, we cannot use m_flowInv as for m_flow=0, any Q_flow would satisfiy
      // Q_flow * m_flowInv = 0.
      // The same applies for port_b.Xi_outflow and mXi_flow.
      port_a.m_flow * (inStream(port_a.h_outflow) - port_b.h_outflow)     = -Q_flow;
      if allowFlowReversal then
        port_a.m_flow * (inStream(port_b.h_outflow)  - port_a.h_outflow)  = +Q_flow;
      else
        // When allowFlowReversal = false, the downstream enthalpy does not matter.
        // Therefore a dummy value is used to avoid algebraic loops
        port_a.h_outflow = Medium.h_default;
      end if;
    end if;

  // Transport of trace substances
  if use_m_flowInv and use_C_flow then
    port_b.C_outflow =  inStream(port_a.C_outflow) + C_flow_internal * m_flowInv;
  else // no trace substance added.
    assert(not use_C_flow, "In " + getInstanceName() + ": Wrong implementation of trace substance balance for forward flow.");
    port_b.C_outflow =  inStream(port_a.C_outflow);
  end if;

  if allowFlowReversal then
    if use_C_flow then
      port_a.C_outflow = inStream(port_b.C_outflow) - C_flow_internal * m_flowInv;
    else
      port_a.C_outflow = inStream(port_b.C_outflow);
    end if;
  else
    port_a.C_outflow = zeros(Medium.nC);
  end if;

  ////////////////////////////////////////////////////////////////////////////
  // No pressure drop in this model
  port_a.p = port_b.p;
end StaticTwoPortConservationEquation;


within AixLib.Fluid.Interfaces;
model StaticTwoPortHeatMassExchanger
  "Partial model transporting fluid between two ports without storing mass or energy"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface;
  extends AixLib.Fluid.Interfaces.TwoPortFlowResistanceParameters(
    final computeFlowResistance=(abs(dp_nominal) > Modelica.Constants.eps));

  constant Boolean sensibleOnly "Set to true if sensible exchange only";
  constant Boolean prescribedHeatFlowRate
    "Set to true if the heat flow rate is not a function of the component temperature";

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

  // Model inputs
  // Q_flow is the sensible plus latent heat flow rate
  input Modelica.Units.SI.HeatFlowRate Q_flow
    "Heat transferred into the medium";
  input Modelica.Units.SI.MassFlowRate mWat_flow
    "Moisture mass flow rate added to the medium";

  // Models for conservation equations and pressure drop
  AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation vol(
    redeclare final package Medium = Medium,
    final use_mWat_flow = not sensibleOnly,
    final prescribedHeatFlowRate = prescribedHeatFlowRate,
    final m_flow_nominal = m_flow_nominal,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_small=m_flow_small)
    "Control volume for steady-state energy and mass balance"

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

  // Outputs that are needed in models that extend this model
  Modelica.Blocks.Interfaces.RealOutput hOut(unit="J/kg")
    "Leaving temperature of the component";

  Modelica.Blocks.Interfaces.RealOutput XiOut[Medium.nXi](each unit="1",
                                                          each min=0,
                                                          each max=1)
    "Leaving species concentration of the component";
  Modelica.Blocks.Interfaces.RealOutput COut[Medium.nC](each min=0)
    "Leaving trace substances of the component";

protected
  Modelica.Blocks.Sources.RealExpression heaInp(y=Q_flow)
    "Block to set heat input into volume"
  Modelica.Blocks.Sources.RealExpression
    masExc(final y=mWat_flow) "Block to set moisture exchange in volume"

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(vol.hOut, hOut);
  connect(vol.XiOut, XiOut);
  connect(vol.COut, COut);
  connect(port_a,preDro. port_a)
  connect(preDro.port_b, vol.port_a)

  connect(vol.port_b, port_b)

  connect(heaInp.y, vol.Q_flow)
  connect(masExc.y, vol.mWat_flow)
end StaticTwoPortHeatMassExchanger;


within AixLib.Fluid.Interfaces;
model TwoPortHeatMassExchanger
  "Partial model transporting one fluid stream with storing mass or energy"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    port_a(h_outflow(start=h_outflow_start)),
    port_b(h_outflow(start=h_outflow_start)));
  extends AixLib.Fluid.Interfaces.TwoPortFlowResistanceParameters(
    final computeFlowResistance=true);

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

  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"

  replaceable AixLib.Fluid.MixingVolumes.MixingVolume vol
  constrainedby AixLib.Fluid.MixingVolumes.BaseClasses.PartialMixingVolume(
    redeclare final package Medium = Medium,
    nPorts = 2,
    V=m_flow_nominal*tau/rho_default,
    final allowFlowReversal=allowFlowReversal,
    final mSenFac=1,
    final m_flow_nominal = m_flow_nominal,
    final energyDynamics=energyDynamics,
    final massDynamics=energyDynamics,
    final p_start=p_start,
    final T_start=T_start,
    final X_start=X_start,
    final C_start=C_start) "Volume for fluid stream"

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

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";
  parameter Medium.ThermodynamicState sta_start=Medium.setState_pTX(
      T=T_start, p=p_start, X=X_start);
  parameter Modelica.Units.SI.SpecificEnthalpy h_outflow_start=
      Medium.specificEnthalpy(sta_start) "Start value for outflowing enthalpy";

initial algorithm
  assert((energyDynamics == Modelica.Fluid.Types.Dynamics.SteadyState) or
          tau > Modelica.Constants.eps,
"The parameter tau, or the volume of the model from which tau may be derived, is unreasonably small.
 You need to set energyDynamics == Modelica.Fluid.Types.Dynamics.SteadyState to model steady-state.
 Received tau = " + String(tau) + "\n");

  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(vol.ports[2], port_b)
  connect(port_a, preDro.port_a)
  connect(preDro.port_b, vol.ports[1])
end TwoPortHeatMassExchanger;


within AixLib.Fluid.Interfaces.Examples;
model ConservationEquation "Model that tests the conservation equation"
extends Modelica.Icons.Example;
 package Medium = AixLib.Media.Water "Medium model";
  AixLib.Fluid.Interfaces.ConservationEquation dyn(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPorts=2,
    fluidVolume=0.01,
    use_mWat_flow=true) "Dynamic conservation equation"

  AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation ste(
    redeclare package Medium = Medium,
    m_flow_nominal=0.01,
    show_T=true,
    prescribedHeatFlowRate=true,
    use_mWat_flow=true) "Steady-state conservation equation"

  Modelica.Blocks.Sources.Constant mWat_flow(k=0)
    "Water mass flow rate added to the control volume"
  Modelica.Blocks.Sources.TimeTable QSen_flow(startTime=0, table=[
                                0,-100;
                                900,-100;
                                900,0;
                                1800,0;
                                1800,100])
    "Sensible heat flow rate added to the control volume"
  AixLib.Fluid.Sources.Boundary_pT sin(
    nPorts=2,
    use_p_in=false,
    redeclare package Medium = Medium,
    p=101325,
    T=283.15)
  AixLib.Fluid.FixedResistances.PressureDrop res1(
    from_dp=true,
    redeclare package Medium = Medium,
    m_flow_nominal=0.01,
    dp_nominal=100) "Flow resistance"
  AixLib.Fluid.Sources.MassFlowSource_T bou(
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow=0.01) "Boundary condition for mass flow rate"
  AixLib.Fluid.FixedResistances.PressureDrop res2(
    from_dp=true,
    redeclare package Medium = Medium,
    m_flow_nominal=0.01,
    dp_nominal=100) "Flow resistance"

equation
  connect(QSen_flow.y, dyn.Q_flow)
  connect(mWat_flow.y, dyn.mWat_flow)

  connect(bou.ports[1], dyn.ports[1])
  connect(res1.port_b, sin.ports[1])
  connect(QSen_flow.y, ste.Q_flow)
  connect(mWat_flow.y, ste.mWat_flow)
  connect(res2.port_b, sin.ports[2])
  connect(ste.port_a, bou.ports[2])
  connect(ste.port_b, res2.port_a)
  connect(dyn.ports[2], res1.port_a)
end ConservationEquation;


within AixLib.Fluid.Interfaces.Examples;
model EightPortHeatMassExchanger
  "EightPortHeatMassExchanger example model"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Water;
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=1
    "Nominal mass flow rate";

  Sources.Boundary_pT sin(          redeclare package Medium = Medium, nPorts=4)
    "Mass flow sink"
  Sources.MassFlowSource_T sou2(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true,
    nPorts=1) "Mass flow source"
  Sources.MassFlowSource_T sou1(
    redeclare package Medium = Medium,
    m_flow=1,
    nPorts=1,
    T=283.15) "Mass flow source"
  Modelica.Blocks.Sources.Ramp ram_T2(
    height=10,
    offset=273.15,
    duration=5) "Temperature ramp"
  Modelica.Blocks.Sources.Ramp ram_m2_flow(
    height=-2,
    offset=1,
    duration=5) "Mass flow rate ramp"
  AixLib.Fluid.Interfaces.EightPortHeatMassExchanger eigPor(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    redeclare package Medium3 = Medium,
    redeclare package Medium4 = Medium,
    m1_flow_nominal=m_flow_nominal,
    m2_flow_nominal=m_flow_nominal,
    m3_flow_nominal=m_flow_nominal,
    m4_flow_nominal=m_flow_nominal,
    dp1_nominal=0,
    dp2_nominal=0,
    dp3_nominal=0,
    dp4_nominal=0,
    tau1=1,
    tau2=1,
    tau3=1,
    tau4=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Eight port heat and mass exchanger"
  Sources.MassFlowSource_T sou4(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true,
    nPorts=1) "Mass flow source"
  Modelica.Blocks.Sources.Ramp ram_T4(
    duration=5,
    height=-10,
    offset=283.15) "Temperature ramp"
  Modelica.Blocks.Sources.Ramp ram_m4_flow(
    duration=5,
    height=2,
    offset=-1) "Mass flow rate ramp"
  Sources.MassFlowSource_T sou3(
    redeclare package Medium = Medium,
    m_flow=1,
    nPorts=1,
    T=303.15) "Mass flow source"
equation
  connect(ram_m2_flow.y, sou2.m_flow_in)
  connect(ram_T2.y, sou2.T_in)
  connect(ram_m4_flow.y, sou4.m_flow_in)
  connect(ram_T4.y, sou4.T_in)
  connect(sou2.ports[1], eigPor.port_b2)
  connect(sou4.ports[1], eigPor.port_b4)
  connect(sou3.ports[1], eigPor.port_b3)
  connect(sou1.ports[1], eigPor.port_b1)
  connect(eigPor.port_a1, sin.ports[1])
  connect(eigPor.port_a3, sin.ports[2])
  connect(eigPor.port_a2, sin.ports[3])
  connect(eigPor.port_a4, sin.ports[4])
end EightPortHeatMassExchanger;


FourPortHeatMassExchanger example model

within AixLib.Fluid.Interfaces.Examples;
model FourPortHeatMassExchanger
  "FourPortHeatMassExchanger example model"
  extends Modelica.Icons.Example;
  package Medium = AixLib.Media.Water;
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=1
    "Nominal mass flow rate";

  AixLib.Fluid.Interfaces.FourPortHeatMassExchanger fouPor(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    m1_flow_nominal=m_flow_nominal,
    m2_flow_nominal=m_flow_nominal,
    dp1_nominal=0,
    dp2_nominal=0,
    tau1=1,
    tau2=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
                   "Four port heat mass exchanger"

  Sources.Boundary_pT sin(nPorts=2, redeclare package Medium = Medium)
    "Mass flow sink"
  Sources.MassFlowSource_T sou1(
    nPorts=1,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    use_T_in=true) "Mass flow source"
  Sources.MassFlowSource_T sou2(
    nPorts=1,
    redeclare package Medium = Medium,
    m_flow=1,
    T=283.15) "Mass flow source"
  Modelica.Blocks.Sources.Ramp ram_T(
    height=10,
    offset=273.15,
    duration=5) "Temperature ramp"
  Modelica.Blocks.Sources.Ramp ram_m_flow(
    height=-2,
    offset=1,
    duration=5) "Mass flow rate ramp"
equation
  connect(sin.ports[1], fouPor.port_b2)
  connect(fouPor.port_b1, sin.ports[2])
  connect(sou1.ports[1], fouPor.port_a1)
  connect(sou2.ports[1], fouPor.port_a2)
  connect(ram_m_flow.y, sou1.m_flow_in)
  connect(ram_T.y, sou1.T_in)
end FourPortHeatMassExchanger;


within AixLib.Fluid.Interfaces.Examples;
model HeaterCooler_u
  "Model that tests a heat exchanger model with reverse flow"
  extends Modelica.Icons.Example;

 package Medium = AixLib.Media.Water;

  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea1(
    redeclare package Medium = Medium,
    Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  Modelica.Blocks.Sources.Constant TDb(k=293.15) "Drybulb temperature"
  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=4,
    p(displayUnit="Pa") = 101735,
    T=293.15)
  AixLib.Fluid.FixedResistances.PressureDrop res_11(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_12(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.Sources.Boundary_pT sin_1(                       redeclare
      package Medium = Medium,
    use_p_in=true,
    T=288.15,
    nPorts=4)
    Modelica.Blocks.Sources.Constant POut(k=101325)
    Modelica.Blocks.Sources.Ramp u(
    height=2,
    duration=3600,
    offset=-1,
    startTime=0) "Control signal"
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea2(
    redeclare package Medium = Medium,
    Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  Modelica.Blocks.Math.Gain gain(k=-1)
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea3(
    redeclare package Medium = Medium,
    Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_2(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_3(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea4(
    redeclare package Medium = Medium, Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_4(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.MixingVolumes.MixingVolume mix1(
                                           redeclare package Medium = Medium, V=
       0.000001,
    nPorts=2,
    m_flow_nominal=0.5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Math.Add che1(k2=-1)
  Modelica.Blocks.Math.Add che2(k2=-1)
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea5(
    redeclare package Medium = Medium,
    Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_1(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_5(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea6(
    redeclare package Medium =
        Medium, Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea7(
    redeclare package Medium = Medium,
    Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_6(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_7(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.HeatExchangers.HeaterCooler_u hea8(
    redeclare package Medium = Medium, Q_flow_nominal=5000,
    m_flow_nominal=0.5,
    dp_nominal=200,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_8(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.MixingVolumes.MixingVolume mix2(
    redeclare package Medium = Medium,
    V=0.000001,
    nPorts=2,
    m_flow_nominal=0.5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Math.Add che9(k2=-1)
  Modelica.Blocks.Math.Add che10(k2=-1)

  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem2a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem2b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem1a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem1b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem3a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem3b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem4a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem4b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  Modelica.Blocks.Math.Add che3(k2=-1)
  Modelica.Blocks.Math.Add che4(k2=-1)
  Modelica.Blocks.Math.Add che5(k2=-1)
  Modelica.Blocks.Math.Add che6(k2=-1)
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem6b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem6a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem5b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem5a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  Modelica.Blocks.Math.Add che7(k2=-1)
  Modelica.Blocks.Math.Add che8(k2=-1)
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem8b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem8a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem7b(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                      senTem7a(redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    tau=0) "Temperature sensor"
equation
  connect(POut.y,sin_1. p_in)
  connect(TDb.y,sou_1. T_in)
  connect(u.y, hea1.u)
  connect(gain.y, hea2.u)
  connect(u.y, gain.u)
  connect(u.y, hea3.u)
  connect(gain.y, hea4.u)
  connect(u.y, hea6.u)
  connect(u.y, hea8.u)
  connect(gain.y, hea5.u)
  connect(gain.y, hea7.u)
  connect(sin_1.ports[1], res_12.port_a)
  connect(sin_1.ports[2], res_3.port_a)
  connect(sou_1.ports[1], res_11.port_a)
  connect(sou_1.ports[2], res_2.port_a)
  connect(sin_1.ports[3], res_1.port_a)
  connect(sin_1.ports[4], res_6.port_a)
  connect(sou_1.ports[3], res_5.port_a)
  connect(sou_1.ports[4], res_7.port_a)
  connect(mix1.ports[1], res_4.port_a)
  connect(mix2.ports[1], res_8.port_a)
  connect(senTem1a.T,che1. u1)
  connect(senTem2a.T,che1. u2)
  connect(senTem1b.T,che2. u2)
  connect(senTem2b.T,che2. u1)
  connect(senTem4a.T,che4. u2)
  connect(senTem3a.T,che4. u1)
  connect(senTem4b.T,che3. u1)
  connect(senTem3b.T,che3. u2)
  connect(senTem6a.T,che6. u2)
  connect(senTem5a.T,che6. u1)
  connect(senTem6b.T,che5. u1)
  connect(senTem5b.T,che5. u2)
  connect(senTem8a.T,che8. u2)
  connect(senTem7a.T,che8. u1)
  connect(senTem8b.T,che7. u1)
  connect(senTem7b.T,che7. u2)
  connect(senTem3a.T,che10. u1)
  connect(senTem7a.T,che10. u2)
  connect(senTem2b.T,che9. u1)
  connect(senTem5b.T,che9. u2)
  connect(res_12.port_b, senTem2a.port_a)
  connect(senTem2a.port_b, hea2.port_a)
  connect(hea2.port_b, senTem2b.port_a)
  connect(senTem2b.port_b, senTem1b.port_b)
  connect(hea1.port_b, senTem1b.port_a)
  connect(res_11.port_b, senTem1a.port_a)
  connect(senTem1a.port_b, hea1.port_a)
  connect(res_2.port_b, senTem3a.port_a)
  connect(senTem3a.port_b, hea3.port_a)
  connect(hea3.port_b, senTem3b.port_a)
  connect(senTem3b.port_b, mix1.ports[2])
  connect(hea4.port_b, senTem4b.port_a)
  connect(res_3.port_b, senTem4a.port_a)
  connect(senTem4a.port_b, hea4.port_a)
  connect(senTem4b.port_b, res_4.port_b)
  connect(res_5.port_b, senTem6a.port_a)
  connect(senTem6a.port_b, hea6.port_a)
  connect(hea6.port_b, senTem6b.port_a)
  connect(senTem6b.port_b, senTem5b.port_b)
  connect(senTem5b.port_a, hea5.port_b)
  connect(hea5.port_a, senTem5a.port_b)
  connect(senTem5a.port_a, res_1.port_b)
  connect(res_7.port_b, senTem8a.port_a)
  connect(senTem8a.port_b, hea8.port_a)
  connect(hea8.port_b, senTem8b.port_a)
  connect(senTem8b.port_b, res_8.port_b)
  connect(mix2.ports[2], senTem7b.port_b)
  connect(senTem7b.port_a, hea7.port_b)
  connect(hea7.port_a, senTem7a.port_b)
  connect(senTem7a.port_a, res_6.port_b)
end HeaterCooler_u;


Nominal water mass flow rate

within AixLib.Fluid.Interfaces.Examples;
model Humidifier_u
  extends Modelica.Icons.Example;

 package Medium = AixLib.Media.Air;
  parameter Modelica.Units.SI.MassFlowRate mWat_flow_nominal=0.001
    "Nominal water mass flow rate";
  Humidifier hea1(redeclare package Medium =
        Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  Modelica.Blocks.Sources.Constant TDb(k=293.15) "Drybulb temperature"
  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=4,
    p(displayUnit="Pa") = 101435,
    T=293.15)
  AixLib.Fluid.FixedResistances.PressureDrop res_11(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_12(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium,
    use_p_in=true,
    T=288.15,
    nPorts=4)
    Modelica.Blocks.Sources.Constant POut(k=101325)
    Modelica.Blocks.Sources.Ramp u(
    duration=3600,
    startTime=0,
    height=1,
    offset=0) "Control signal"
  Humidifier hea2(
    redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  Modelica.Blocks.Math.Gain gain(k=-1)
  Humidifier hea3(
    redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_2(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_3(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  Humidifier hea4(
    redeclare package Medium = Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_4(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.MixingVolumes.MixingVolume mix1(
    redeclare package Medium = Medium,
    V=0.000001,
    nPorts=2,
    m_flow_nominal=0.5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Math.Add che1(k2=-1)
  Modelica.Blocks.Sources.RealExpression y1(y=hea2.staB.T)
  Modelica.Blocks.Sources.RealExpression y2(y=hea1.staB.T)
  Modelica.Blocks.Math.Add che2(k2=-1)
  Modelica.Blocks.Sources.RealExpression y3(y=hea2.staA.T)
  Modelica.Blocks.Sources.RealExpression y4(y=hea1.staA.T)
  Modelica.Blocks.Math.Add che3(k2=-1)
  Modelica.Blocks.Sources.RealExpression y5(y=hea4.staB.T)
  Modelica.Blocks.Sources.RealExpression y6(y=hea3.staB.T)
  Modelica.Blocks.Math.Add che4(k2=-1)
  Modelica.Blocks.Sources.RealExpression y7(y=hea4.staA.T)
  Modelica.Blocks.Sources.RealExpression y8(y=hea3.staA.T)
  Humidifier hea5(redeclare package Medium =
        Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_1(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_5(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  Humidifier hea6(                               redeclare package Medium =
        Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  Humidifier hea7(redeclare package Medium =
        Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_6(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.FixedResistances.PressureDrop res_7(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  Humidifier hea8(                               redeclare package Medium =
        Medium,
    m_flow_nominal=0.5,
    mWat_flow_nominal=mWat_flow_nominal,
    dp_nominal=50,
    show_T=true,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heater and cooler"
  AixLib.Fluid.FixedResistances.PressureDrop res_8(
    redeclare package Medium = Medium,
    dp_nominal=5,
    m_flow_nominal=0.5)
  AixLib.Fluid.MixingVolumes.MixingVolume mix2(
                                           redeclare package Medium = Medium, V=
       0.000001,
    nPorts=2,
    m_flow_nominal=0.5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  Modelica.Blocks.Math.Add che5(k2=-1)
  Modelica.Blocks.Sources.RealExpression y9(y=hea6.staB.T)
  Modelica.Blocks.Sources.RealExpression y10(
                                            y=hea5.staB.T)
  Modelica.Blocks.Math.Add che6(k2=-1)
  Modelica.Blocks.Sources.RealExpression y11(
                                            y=hea6.staA.T)
  Modelica.Blocks.Sources.RealExpression y12(
                                            y=hea5.staA.T)
  Modelica.Blocks.Math.Add che7(k2=-1)
  Modelica.Blocks.Sources.RealExpression y13(
                                            y=hea8.staB.T)
  Modelica.Blocks.Sources.RealExpression y14(
                                            y=hea7.staB.T)
  Modelica.Blocks.Math.Add che8(k2=-1)
  Modelica.Blocks.Sources.RealExpression y15(
                                            y=hea8.staA.T)
  Modelica.Blocks.Sources.RealExpression y16(
                                            y=hea7.staA.T)
  Modelica.Blocks.Math.Add che9(k2=-1)
  Modelica.Blocks.Sources.RealExpression y17(y=hea2.staB.T)
  Modelica.Blocks.Sources.RealExpression y18(y=hea5.staB.T)
  Modelica.Blocks.Math.Add che10(k2=-1)
  Modelica.Blocks.Sources.RealExpression y19(y=hea4.staA.T)
  Modelica.Blocks.Sources.RealExpression y20(y=hea7.staA.T)
  Modelica.Blocks.Math.Add che11(k2=-1)
  Modelica.Blocks.Sources.RealExpression y21(y=hea2.staB.X[1])
  Modelica.Blocks.Sources.RealExpression y22(y=hea1.staB.X[1])
  Modelica.Blocks.Math.Add che12(k2=-1)
  Modelica.Blocks.Sources.RealExpression y23(
                                            y=hea2.staA.X[1])
  Modelica.Blocks.Sources.RealExpression y24(
                                            y=hea1.staA.X[1])
  Modelica.Blocks.Math.Add che13(k2=-1)
  Modelica.Blocks.Sources.RealExpression y25(
                                            y=hea4.staB.X[1])
  Modelica.Blocks.Sources.RealExpression y26(
                                            y=hea3.staB.X[1])
  Modelica.Blocks.Math.Add che14(k2=-1)
  Modelica.Blocks.Sources.RealExpression y27(
                                            y=hea4.staA.X[1])
  Modelica.Blocks.Sources.RealExpression y28(
                                            y=hea3.staA.X[1])
  Modelica.Blocks.Math.Add che15(k2=-1)
  Modelica.Blocks.Sources.RealExpression y29(
                                            y=hea6.staB.X[1])
  Modelica.Blocks.Sources.RealExpression y30(
                                            y=hea5.staB.X[1])
  Modelica.Blocks.Math.Add che16(k2=-1)
  Modelica.Blocks.Sources.RealExpression y31(
                                            y=hea6.staA.X[1])
  Modelica.Blocks.Sources.RealExpression y32(
                                            y=hea5.staA.X[1])
  Modelica.Blocks.Math.Add che17(k2=-1)
  Modelica.Blocks.Sources.RealExpression y33(
                                            y=hea8.staB.X[1])
  Modelica.Blocks.Sources.RealExpression y34(
                                            y=hea7.staB.X[1])
  Modelica.Blocks.Math.Add che18(k2=-1)
  Modelica.Blocks.Sources.RealExpression y35(
                                            y=hea8.staA.X[1])
  Modelica.Blocks.Sources.RealExpression y36(
                                            y=hea7.staA.X[1])
  Modelica.Blocks.Math.Add che19(k2=-1)
  Modelica.Blocks.Sources.RealExpression y37(y=hea2.staB.X[1])
  Modelica.Blocks.Sources.RealExpression y38(y=hea5.staB.X[1])
  Modelica.Blocks.Math.Add che20(k2=-1)
  Modelica.Blocks.Sources.RealExpression y39(y=hea4.staA.X[1])
  Modelica.Blocks.Sources.RealExpression y40(y=hea7.staA.X[1])

protected
  model Humidifier
    "Model for humidifier that adds a variable for the thermodynamic states at its ports"
    extends AixLib.Fluid.Humidifiers.Humidifier_u;
   Medium.ThermodynamicState staA=
      Medium.setState_phX(port_a.p,
                          actualStream(port_a.h_outflow),
                          actualStream(port_a.Xi_outflow))
      "Thermodynamic state in port a";
   Medium.ThermodynamicState staB=
      Medium.setState_phX(port_b.p,
                          actualStream(port_b.h_outflow),
                          actualStream(port_b.Xi_outflow))
      "Thermodynamic state in port b";
  end Humidifier;
equation
  connect(POut.y,sin_1. p_in)
  connect(TDb.y,sou_1. T_in)
  connect(res_11.port_b, hea1.port_a)
  connect(u.y, hea1.u)
  connect(gain.y, hea2.u)
  connect(u.y, gain.u)
  connect(res_12.port_b, hea2.port_a)
  connect(res_2.port_b, hea3.port_a)
  connect(u.y, hea3.u)
  connect(gain.y, hea4.u)
  connect(res_3.port_b, hea4.port_a)
  connect(hea4.port_b, res_4.port_b)
  connect(hea1.port_b, hea2.port_b)
  connect(y1.y,che1. u1)
  connect(y2.y,che1. u2)
  connect(y3.y,che2. u1)
  connect(y4.y,che2. u2)
  connect(y5.y,che3. u1)
  connect(y6.y,che3. u2)
  connect(y7.y,che4. u1)
  connect(y8.y,che4. u2)
  connect(res_1.port_b, hea5.port_a)
  connect(res_5.port_b, hea6.port_a)
  connect(res_6.port_b,hea7. port_a)
  connect(res_7.port_b,hea8. port_a)
  connect(hea8.port_b,res_8. port_b)
  connect(hea5.port_b,hea6. port_b)
  connect(y9.y,che5. u1)
  connect(y10.y,che5. u2)
  connect(y11.y,che6. u1)
  connect(y12.y,che6. u2)
  connect(y13.y,che7. u1)
  connect(y14.y,che7. u2)
  connect(y15.y,che8. u1)
  connect(y16.y,che8. u2)
  connect(y17.y,che9. u1)
  connect(y18.y,che9. u2)
  connect(y19.y,che10. u1)
  connect(y20.y,che10. u2)
  connect(u.y, hea6.u)
  connect(u.y, hea8.u)
  connect(gain.y, hea5.u)
  connect(gain.y, hea7.u)
  connect(y21.y,che11. u1)
  connect(y22.y,che11. u2)
  connect(y23.y,che12. u1)
  connect(y24.y,che12. u2)
  connect(y25.y,che13. u1)
  connect(y26.y,che13. u2)
  connect(y27.y,che14. u1)
  connect(y28.y,che14. u2)
  connect(y29.y,che15. u1)
  connect(y30.y,che15. u2)
  connect(y31.y,che16. u1)
  connect(y32.y,che16. u2)
  connect(y33.y,che17. u1)
  connect(y34.y,che17. u2)
  connect(y35.y,che18. u1)
  connect(y36.y,che18. u2)
  connect(y37.y,che19. u1)
  connect(y38.y,che19. u2)
  connect(y39.y,che20. u1)
  connect(y40.y,che20. u2)
  connect(sin_1.ports[1], res_12.port_a)
  connect(sin_1.ports[2], res_3.port_a)
  connect(sou_1.ports[1], res_11.port_a)
  connect(sou_1.ports[2], res_2.port_a)
  connect(sin_1.ports[3], res_1.port_a)
  connect(sin_1.ports[4], res_6.port_a)
  connect(sou_1.ports[3], res_5.port_a)
  connect(sou_1.ports[4], res_7.port_a)
  connect(hea3.port_b, mix1.ports[1])
  connect(mix1.ports[2], res_4.port_a)
  connect(hea7.port_b, mix2.ports[1])
  connect(mix2.ports[2], res_8.port_a)
end Humidifier_u;


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


Test model for prescribed outlet state. Model that demonstrates

AixLib.Fluid.Interfaces.PrescribedOutlet
with mass fraction setpoint.

within AixLib.Fluid.Interfaces.Examples;
model PrescribedOutlet "Test model for prescribed outlet state"
  extends Modelica.Icons.Example;
  extends AixLib.Fluid.Interfaces.Examples.BaseClasses.PrescribedOutletState;

equation
  connect(setHeaHigPow.y[1], heaHigPow.TSet)
  connect(setHeaHigPow.y[2], heaHigPow.X_wSet)
  connect(setCooLimPow.y[1], cooLimPow.TSet)
  connect(setCooLimPow.y[2], cooLimPow.X_wSet)
  connect(setHeaCooUnl.y[1], heaCooUnl.TSet)
  connect(setHeaCooUnl.y[2], heaCooUnl.X_wSet)
  connect(setHeaCooUnl.y[1], steSta.TSet)
  connect(setHeaCooUnl.y[2], steSta.X_wSet)
end PrescribedOutlet;


Test model for prescribed outlet state. Model that demonstrates

AixLib.Fluid.Interfaces.PrescribedOutlet
with temperature setpoint.

within AixLib.Fluid.Interfaces.Examples;
model PrescribedOutlet_TSetOnly "Test model for prescribed outlet state"
  extends Modelica.Icons.Example;
  extends AixLib.Fluid.Interfaces.Examples.BaseClasses.PrescribedOutletState(
    steSta(use_X_wSet=false),
    heaHigPow(use_X_wSet=false),
    cooLimPow(use_X_wSet=false),
    heaCooUnl(use_X_wSet=false));

equation
  connect(setHeaHigPow.y[1], heaHigPow.TSet)
  connect(setCooLimPow.y[1], cooLimPow.TSet)
  connect(setHeaCooUnl.y[1], heaCooUnl.TSet)
  connect(setHeaCooUnl.y[1], steSta.TSet)
end PrescribedOutlet_TSetOnly;


Test model for prescribed outlet state

within AixLib.Fluid.Interfaces.Examples;
model PrescribedOutlet_Water
  "Test model for prescribed outlet state"
  extends Modelica.Icons.Example;
  extends AixLib.Fluid.Interfaces.Examples.BaseClasses.PrescribedOutletState(
    redeclare package Medium = AixLib.Media.Water,
    steSta(use_X_wSet=false),
    heaHigPow(use_X_wSet=false),
    cooLimPow(use_X_wSet=false),
    heaCooUnl(use_X_wSet=false));

equation
  connect(setHeaHigPow.y[1], heaHigPow.TSet)
  connect(setCooLimPow.y[1], cooLimPow.TSet)
  connect(setHeaCooUnl.y[1], heaCooUnl.TSet)
  connect(setHeaCooUnl.y[1], steSta.TSet)
end PrescribedOutlet_Water;


within AixLib.Fluid.Interfaces.Examples;
model PrescribedOutlet_X_wSetOnly
  "Test model for prescribed outlet state"
  extends Modelica.Icons.Example;
  extends AixLib.Fluid.Interfaces.Examples.BaseClasses.PrescribedOutletState(
    heaHigPow(use_TSet=false),
    cooLimPow(use_TSet=false),
    heaCooUnl(use_TSet=false),
    steSta(use_TSet=false));

equation
  connect(setHeaHigPow.y[2], heaHigPow.X_wSet)
  connect(setCooLimPow.y[2], cooLimPow.X_wSet)
  connect(setHeaCooUnl.y[2], heaCooUnl.X_wSet)
  connect(setHeaCooUnl.y[2], steSta.X_wSet)
end PrescribedOutlet_X_wSetOnly;


within AixLib.Fluid.Interfaces.Examples;
model ReverseFlowHumidifier
  "Model that tests the reverse flow for a humidifier"
  extends Modelica.Icons.Example;
package Medium = AixLib.Media.Air;
  Modelica.Blocks.Math.Add cheTem(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Blocks.Math.Add cheEnt(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Blocks.Math.Add cheMas(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  AixLib.Fluid.Humidifiers.Humidifier_u humBac(
    redeclare package Medium = Medium,
    dp_nominal=0,
    m_flow(start=1),
    m_flow_nominal=1,
    mWat_flow_nominal=0.1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Humidifier with backward flow"
  AixLib.Fluid.Humidifiers.Humidifier_u humFor(
    redeclare package Medium = Medium,
    dp_nominal=0,
    m_flow(start=1),
    m_flow_nominal=1,
    mWat_flow_nominal=0.1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Humidifier with forward flow"
  Modelica.Blocks.Sources.Constant u2(k=0.01) "Control input"
  Modelica.Fluid.Sources.MassFlowSource_T source1(
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    use_T_in=false,
    use_X_in=false,
    T(displayUnit="K") = 323.15,
    X={0.01,0.99},
    nPorts=1,
    m_flow=0.5) "Fluid source"
  AixLib.Fluid.Sources.Boundary_pT  sink1(
    redeclare package Medium = Medium,
    nPorts=2) "Fluid sink"
  Sensors.SpecificEnthalpy senEnt1(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
    "Specific enthalpy sensor"
  AixLib.Fluid.Sensors.Temperature senTem1(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
    "Temperature sensor"
  Sensors.MassFraction senMas1(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
    "Mass fraction sensor"
  AixLib.Fluid.Sensors.Temperature senTem2(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
    "Temperature sensor"
  Sensors.SpecificEnthalpy senEnt2(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
    "Specific enthalpy sensor"
  Sensors.MassFraction senMas2(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
    "Mass fraction sensor"
  FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    from_dp=true,
    linearized=false,
    dp_nominal=1000) "Fixed resistance"
  FixedResistances.PressureDrop res2(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    from_dp=true,
    linearized=false,
    dp_nominal=1000) "Fixed resistance"
  Modelica.Fluid.Sources.MassFlowSource_T source2(
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    use_T_in=false,
    use_X_in=false,
    T(displayUnit="K") = 323.15,
    X={0.01,0.99},
    nPorts=1,
    m_flow=0.5) "Fluid source"

equation
  connect(u2.y, humFor.u)
  connect(u2.y, humBac.u)
  connect(humFor.port_b, senTem1.port)
  connect(humFor.port_b, senEnt1.port)
  connect(humFor.port_b, senMas1.port)
  connect(humBac.port_a, senTem2.port)
  connect(humBac.port_a, senEnt2.port)
  connect(humBac.port_a, senMas2.port)
  connect(humFor.port_b, res1.port_a)
  connect(res1.port_b, sink1.ports[1])
  connect(humBac.port_a, res2.port_a)
  connect(res2.port_b, sink1.ports[2])
  connect(senTem1.T,cheTem. u1)
  connect(senEnt1.h_out,cheEnt. u1)
  connect(senMas1.X,cheMas. u1)
  connect(senTem2.T,cheTem. u2)
  connect(senEnt2.h_out,cheEnt. u2)
  connect(senMas2.X,cheMas. u2)
  connect(humFor.port_a, source1.ports[1])
  connect(source2.ports[1], humBac.port_b)
end ReverseFlowHumidifier;


within AixLib.Fluid.Interfaces.Examples;
model ReverseFlowMassExchanger
  "Model that tests the reverse flow for a mass exchanger"
  extends Modelica.Icons.Example;
package Medium = AixLib.Media.Air;
  Modelica.Blocks.Math.Add cheTem(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Blocks.Math.Add cheEnt(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Blocks.Math.Add cheMas(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Fluid.Sources.MassFlowSource_T source2(
    m_flow=1,
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    use_T_in=false,
    use_X_in=false,
    nPorts=1,
    T(displayUnit="degC") = 303.15,
    X={0.02,0.98})
  AixLib.Fluid.MassExchangers.ConstantEffectiveness masExcFor(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    m1_flow_nominal=1,
    m2_flow_nominal=1,
    dp1_nominal=0,
    dp2_nominal=0,
    epsL=0) "Mass exchanger with forward flow"
  AixLib.Fluid.MassExchangers.ConstantEffectiveness masExcRev(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    m1_flow_nominal=1,
    m2_flow_nominal=1,
    dp1_nominal=0,
    dp2_nominal=0,
    epsL=0) "Mass exchanger with reverse flow"
  AixLib.Fluid.Sources.Boundary_pT sink2(
     redeclare package Medium = Medium,
     nPorts=2) "Fluid sink"
  FixedResistances.PressureDrop res3(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    from_dp=true,
    linearized=false,
    dp_nominal=1000) "Fixed resistance"
  FixedResistances.PressureDrop res4(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    from_dp=true,
    linearized=false,
    dp_nominal=1000) "Fixed resistance"
  Sensors.SpecificEnthalpy senEnt3(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  AixLib.Fluid.Sensors.Temperature senTem3(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Sensors.MassFraction senMas3(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Sensors.SpecificEnthalpy senEnt4(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  AixLib.Fluid.Sensors.Temperature senTem4(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Sensors.MassFraction senMas4(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Modelica.Blocks.Math.Add cheTem1(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Blocks.Math.Add cheEnt1(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Blocks.Math.Add cheMas1(k2=-1)
    "Check whether the outputs of the forward flow and reverse flow model are identical"
  Modelica.Fluid.Sources.MassFlowSource_T source3(
    m_flow=1,
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    use_T_in=false,
    use_X_in=false,
    X={0.01,0.99},
    nPorts=1,
    T(displayUnit="degC") = 293.15)
  Modelica.Fluid.Sources.MassFlowSource_T source4(
    m_flow=1,
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    use_T_in=false,
    use_X_in=false,
    nPorts=1,
    T(displayUnit="degC") = 303.15,
    X={0.02,0.98})

  Modelica.Fluid.Sources.MassFlowSource_T source1(
    m_flow=1,
    redeclare package Medium = Medium,
    use_m_flow_in=false,
    use_T_in=false,
    use_X_in=false,
    X={0.01,0.99},
    nPorts=1,
    T(displayUnit="degC") = 293.15)
  Sources.Boundary_pT sink1(
    redeclare package Medium = Medium,
    nPorts=2) "Fluid sink"
  Sensors.SpecificEnthalpy senEnt1(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  AixLib.Fluid.Sensors.Temperature senTem1(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Sensors.MassFraction senMas1(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  AixLib.Fluid.Sensors.Temperature senTem2(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Sensors.SpecificEnthalpy senEnt2(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  Sensors.MassFraction senMas2(redeclare package Medium = Medium,
      warnAboutOnePortConnection=false)
  FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    from_dp=true,
    linearized=false,
    dp_nominal=1000) "Fixed resistance"
  FixedResistances.PressureDrop res2(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    from_dp=true,
    linearized=false,
    dp_nominal=1000) "Fixed resistance"

equation
  connect(res1.port_b, sink1.ports[1])
  connect(res2.port_b, sink1.ports[2])
  connect(senTem1.T,cheTem. u1)
  connect(senEnt1.h_out,cheEnt. u1)
  connect(senMas1.X,cheMas. u1)
  connect(senTem2.T,cheTem. u2)
  connect(senEnt2.h_out,cheEnt. u2)
  connect(senMas2.X,cheMas. u2)
  connect(masExcFor.port_b1, res1.port_a)
  connect(masExcFor.port_a1, source1.ports[1])
  connect(masExcRev.port_a1, res2.port_a)
  connect(source2.ports[1], masExcFor.port_a2)
  connect(masExcRev.port_a1, senTem2.port)
  connect(masExcRev.port_a1, senEnt2.port)
  connect(masExcRev.port_a1, senMas2.port)
  connect(masExcFor.port_b1, senTem1.port)
  connect(masExcFor.port_b1, senEnt1.port)
  connect(masExcFor.port_b1, senMas1.port)
  connect(masExcFor.port_b2, res3.port_a)
  connect(masExcRev.port_a2, res4.port_a)
  connect(res3.port_b, sink2.ports[1])
  connect(res4.port_b, sink2.ports[2])
  connect(senTem3.T,cheTem1. u1)
  connect(senTem4.T,cheTem1. u2)
  connect(senEnt3.h_out,cheEnt1. u1)
  connect(senEnt4.h_out,cheEnt1. u2)
  connect(senMas3.X,cheMas1. u1)
  connect(senMas4.X,cheMas1. u2)
  connect(masExcFor.port_b2, senTem3.port)
  connect(masExcFor.port_b2, senEnt3.port)
  connect(masExcFor.port_b2, senMas3.port)
  connect(masExcRev.port_a2, senTem4.port)
  connect(masExcRev.port_a2, senEnt4.port)
  connect(masExcRev.port_a2, senMas4.port)
  connect(source3.ports[1], masExcRev.port_b1)
  connect(source4.ports[1], masExcRev.port_b2)
end ReverseFlowMassExchanger;


within AixLib.Fluid.Interfaces.Examples;
model StaticTwoPortConservationEquation
  "Model that tests the static two port conservation equation"
extends Modelica.Icons.Example;
 package MediumW = AixLib.Media.Water "Medium model";
 package MediumA = AixLib.Media.Air "Medium model";

  Modelica.Blocks.Sources.Constant mWat_flow(k=0)
    "Water mass flow rate added to the control volume"
  Modelica.Blocks.Sources.TimeTable QSen_flow(startTime=0, table=[
                                0,-100;
                                900,-100;
                                900,0;
                                1800,0;
                                1800,100])
    "Sensible heat flow rate added to the control volume"

  SubModel modWatRev(
    redeclare package Medium = MediumW,
    allowFlowReversal=true,
    use_mWat_flow = false) "Submodel for energy and mass balance"
  SubModel modWatNoRev(
    redeclare package Medium = MediumW,
    allowFlowReversal=false,
    use_mWat_flow = false) "Submodel for energy and mass balance"
  SubModel modAirRev(
    redeclare package Medium = MediumA,
    allowFlowReversal=true,
    use_mWat_flow = true) "Submodel for energy and mass balance"
  SubModel modAirNoRev(
    redeclare package Medium = MediumA,
    allowFlowReversal=false,
    use_mWat_flow = true) "Submodel for energy and mass balance"
equation

  connect(QSen_flow.y, modWatRev.Q_flow)
  connect(mWat_flow.y, modWatRev.mWat_flow)
protected
  model SubModel
    replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
      "Medium model";
    Sources.MassFlowSource_T bou(
      nPorts=1,
      redeclare package Medium = Medium,
      m_flow=0.01) "Boundary condition for mass flow rate"
    AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation conEqn(
      redeclare package Medium = Medium,
      m_flow_nominal=0.01,
      show_T=true,
      allowFlowReversal=allowFlowReversal,
      use_mWat_flow=use_mWat_flow,
      prescribedHeatFlowRate=true) "Steady-state conservation equation"
    AixLib.Fluid.Sources.Boundary_pT sin(
      use_p_in=false,
      redeclare package Medium = Medium,
      nPorts=1,
      p=101325,
      T=283.15) "Sink"

    Modelica.Blocks.Interfaces.RealInput Q_flow(unit="W")
    Modelica.Blocks.Interfaces.RealInput mWat_flow(unit="kg/s")
    parameter Boolean use_mWat_flow
      "Set to true to enable exchange of moisture";
    parameter Boolean allowFlowReversal=true
      "= false to simplify equations, assuming, but not enforcing, no flow reversal";
  equation
    connect(conEqn.port_b, sin.ports[1])
    connect(conEqn.port_a, bou.ports[1])
    connect(Q_flow, conEqn.Q_flow)
    connect(mWat_flow, conEqn.mWat_flow)
  end SubModel;
equation
  connect(QSen_flow.y, modWatNoRev.Q_flow)
  connect(mWat_flow.y, modWatNoRev.mWat_flow)
  connect(QSen_flow.y, modAirRev.Q_flow)
  connect(mWat_flow.y, modAirRev.mWat_flow)
  connect(QSen_flow.y, modAirNoRev.Q_flow)
  connect(mWat_flow.y, modAirNoRev.mWat_flow)
end StaticTwoPortConservationEquation;


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


Test model for prescribed outlet state

within AixLib.Fluid.Interfaces.Examples.BaseClasses;
partial model PrescribedOutletState "Test model for prescribed outlet state"

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

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

  AixLib.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    use_T_in=false,
    p(displayUnit="Pa"),
    T=293.15,
    nPorts=4) "Sink"
  AixLib.Fluid.Interfaces.PrescribedOutlet heaHigPow(
    redeclare package Medium = Medium,
    QMax_flow=1.0e10,
    mWatMax_flow = 0.001,
    m_flow_small=1E-4*abs(m_flow_nominal),
    show_T=true,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Steady-state model of the heater with high capacity"
  Modelica.Blocks.Sources.CombiTimeTable setHeaHigPow(table=[
    0,    20.0, 0.012;
    120,  20.0, 0.012;
    500,  60.0, 0.020;
    800,  10.0, 0.005;
    1200, 30.0, 0.015],
    offset={273.15,0},
    smoothness = Modelica.Blocks.Types.Smoothness.ConstantSegments)
    "Setpoint heating and humidification"
  AixLib.Fluid.Interfaces.PrescribedOutlet cooLimPow(
    redeclare package Medium = Medium,
    QMin_flow=-1000,
    mWatMin_flow = -0.001,
    m_flow_small=1E-4*abs(m_flow_nominal),
    show_T=true,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Steady-state model of the cooler with limited capacity"
  Modelica.Blocks.Sources.CombiTimeTable setCooLimPow(table=[
    0,    20.0, 0.008;
    120,  20.0, 0.008;
    500,  15.0, 0.004;
    800,  60.0, 0.015;
    1200, 10.0, 0.002],
    offset={273.15,0},
    smoothness = Modelica.Blocks.Types.Smoothness.ConstantSegments)
    "Setpoint cooling and dehumidification"
  AixLib.Fluid.Interfaces.PrescribedOutlet heaCooUnl(
    redeclare package Medium = Medium,
    m_flow_small=1E-4*abs(m_flow_nominal),
    show_T=true,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Steady-state model of the heater or cooler with unlimited capacity"
  AixLib.Fluid.Interfaces.PrescribedOutlet steSta(
    redeclare package Medium = Medium,
    m_flow_small=1E-4*abs(m_flow_nominal),
    show_T=true,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Steady-state model of the heater or cooler with unlimited capacity"
  Modelica.Blocks.Sources.CombiTimeTable setHeaCooUnl(table=[
    0,    20.0, 0.012;
    120,  20.0, 0.012;
    500,  15.0, 0.008;
    800,  10.0, 0.005;
    1200, 30.0, 0.015],
    offset={273.15,0},
    smoothness = Modelica.Blocks.Types.Smoothness.ConstantSegments)
    "Setpoint cooling, heating, dehumidification and humidification"
  Modelica.Blocks.Sources.Ramp m_flow(
    height=-2*m_flow_nominal,
    duration=100,
    offset=m_flow_nominal,
    startTime=1000) "Mass flow rate"
  AixLib.Fluid.Sources.MassFlowSource_T sou1(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=293.15,
    nPorts=1) "Flow source"
  AixLib.Fluid.Sources.MassFlowSource_T sou2(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=293.15,
    nPorts=1) "Flow source"
  AixLib.Fluid.Sources.MassFlowSource_T sou3(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=293.15,
    nPorts=1) "Flow source"
  AixLib.Fluid.Sources.MassFlowSource_T sou4(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=293.15,
    nPorts=1) "Flow source"
equation

  connect(m_flow.y, sou1.m_flow_in)
  connect(m_flow.y, sou2.m_flow_in)
  connect(m_flow.y, sou3.m_flow_in)
  connect(sou1.ports[1], heaHigPow.port_a)
  connect(sou2.ports[1], cooLimPow.port_a)
  connect(sou3.ports[1], heaCooUnl.port_a)
  connect(heaCooUnl.port_b, sin.ports[1])
  connect(cooLimPow.port_b, sin.ports[2])
  connect(heaHigPow.port_b, sin.ports[3])
  connect(m_flow.y, sou4.m_flow_in)
  connect(sou4.ports[1], steSta.port_a)
  connect(steSta.port_b, sin.ports[4])
end PrescribedOutletState;


within AixLib.Fluid.MassExchangers;
model ConstantEffectiveness
  "Heat and moisture exchanger with constant effectiveness"
  extends AixLib.Fluid.HeatExchangers.BaseClasses.PartialEffectiveness(
  redeclare replaceable package Medium1 =
        Modelica.Media.Interfaces.PartialCondensingGases,
  redeclare replaceable package Medium2 =
        Modelica.Media.Interfaces.PartialCondensingGases,
  sensibleOnly1=false,
  sensibleOnly2=false,
  final prescribedHeatFlowRate1=true,
  final prescribedHeatFlowRate2=true,
  Q1_flow = epsS * QMax_flow + QLat_flow,
  Q2_flow = -Q1_flow,
  mWat1_flow = +mWat_flow,
  mWat2_flow = -mWat_flow);

  parameter Modelica.Units.SI.Efficiency epsS(max=1) = 0.8
    "Sensible heat exchanger effectiveness";
  parameter Modelica.Units.SI.Efficiency epsL(max=1) = 0.8
    "Latent heat exchanger effectiveness";

  Modelica.Units.SI.HeatFlowRate QLat_flow
    "Latent heat exchange from medium 2 to medium 1";

  Medium1.MassFraction X_w_in1 "Inlet water mass fraction of medium 1";
  Medium2.MassFraction X_w_in2 "Inlet water mass fraction of medium 2";

  Modelica.Units.SI.MassFlowRate mWat_flow
    "Water flow rate from medium 2 to medium 1";
  Modelica.Units.SI.MassFlowRate mMax_flow
    "Maximum water flow rate from medium 2 to medium 1";

protected
  parameter Integer i1_w(min=1, fixed=false) "Index for water substance";
  parameter Integer i2_w(min=1, fixed=false) "Index for water substance";
  Real gai1(min=0, max=1) "Auxiliary variable for smoothing at zero flow";
  Real gai2(min=0, max=1) "Auxiliary variable for smoothing at zero flow";
initial algorithm
  i1_w:= -1;
  i2_w:= -1;
  for i in 1:Medium1.nXi loop
      if Modelica.Utilities.Strings.isEqual(string1=Medium1.substanceNames[i],
                                            string2="Water",
                                            caseSensitive=false) then
      i1_w := i;
    end if;
   end for;
  for i in 1:Medium2.nXi loop
      if Modelica.Utilities.Strings.isEqual(string1=Medium2.substanceNames[i],
                                            string2="Water",
                                            caseSensitive=false) then
      i2_w := i;
    end if;
   end for;
    assert(i1_w > 0, "Substance 'water' is not present in Medium1 '"
         + Medium1.mediumName + "'.\n"
         + "Check medium model.");
    assert(i2_w > 0, "Substance 'water' is not present in Medium2 '"
         + Medium2.mediumName + "'.\n"
         + "Check medium model.");
equation
  // Definitions for effectiveness model
  X_w_in1 = Modelica.Fluid.Utilities.regStep(m1_flow,
                  state_a1_inflow.X[i1_w],
                  state_b1_inflow.X[i1_w], m1_flow_small);
  X_w_in2 = Modelica.Fluid.Utilities.regStep(m2_flow,
                  state_a2_inflow.X[i2_w],
                  state_b2_inflow.X[i2_w], m2_flow_small);

  // mass exchange
  // Compute a gain that goes to zero near zero flow rate.
  // This is required to smoothen the heat transfer at very small flow rates.
  // Note that gaiK = 1 for abs(mK_flow) > mK_flow_small
  gai1 = Modelica.Fluid.Utilities.regStep(abs(m1_flow) - 0.75*m1_flow_small,
              1, 0, 0.25*m1_flow_small);
  gai2 = Modelica.Fluid.Utilities.regStep(abs(m2_flow) - 0.75*m2_flow_small,
              1, 0, 0.25*m2_flow_small);

  mMax_flow = smooth(1, min(smooth(1, gai1 * abs(m1_flow)),
                            smooth(1, gai2 * abs(m2_flow)))) * (X_w_in2 - X_w_in1);
  mWat_flow = epsL * mMax_flow;
  // As enthalpyOfCondensingGas is dominated by the latent heat of phase change,
  // we simplify and use Medium1.enthalpyOfVaporization for the
  // latent heat that is exchanged among the fluid streams.
  // This is simply added to QSen_flow, while mass is conserved because
  // of the assignment of mWat1_flow and mWat2_flow.
  QLat_flow = mWat_flow * Medium1.enthalpyOfVaporization(Medium1.T_default);
end ConstantEffectiveness;


Package with mass exchanger models

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


Water temperature

within AixLib.Fluid.MassExchangers.Examples;
model ConstantEffectiveness
  extends Modelica.Icons.Example;

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

  AixLib.Fluid.Sources.Boundary_pT sin_2(
    redeclare package Medium = Medium2, T=273.15 + 10,
    use_p_in=true,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp PIn(
    height=200,
    duration=60,
    offset=101330)
  AixLib.Fluid.Sources.Boundary_pT sou_2(
    redeclare package Medium = Medium2, T=273.15 + 5,
    use_p_in=true,
    use_T_in=true,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp TWat(
    height=10,
    duration=60,
    offset=273.15 + 30,
    startTime=60) "Water temperature"
  Modelica.Blocks.Sources.Constant TDb(k=293.15) "Drybulb temperature"
    Modelica.Blocks.Sources.Constant POut(k=101325)
  AixLib.Fluid.Sources.Boundary_pT sin_1(
    redeclare package Medium = Medium1,
    T=273.15 + 30,
    X={0.012,1 - 0.012},
    use_p_in=true,
    p=300000,
    nPorts=1)
  AixLib.Fluid.Sources.Boundary_pT sou_1(
    redeclare package Medium = Medium1,
    T=273.15 + 50,
    X={0.012,1 - 0.012},
    use_T_in=true,
    p=100000,
    nPorts=1)
    Modelica.Blocks.Sources.Ramp PSin_1(
    duration=60,
    startTime=240,
    height=100,
    offset=1E5 - 110)
  AixLib.Fluid.MassExchangers.ConstantEffectiveness hex(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow(start=5),
    m2_flow(start=5),
    m1_flow_nominal=5,
    m2_flow_nominal=5,
    dp1_nominal=100,
    dp2_nominal=100,
    show_T=true)

equation
  connect(PIn.y,sou_2. p_in)
  connect(TDb.y, sou_2.T_in)
  connect(TWat.y, sou_1.T_in)
  connect(PSin_1.y, sin_1.p_in)
  connect(sou_1.ports[1], hex.port_a1)
  connect(hex.port_a2, sou_2.ports[1])
  connect(POut.y, sin_2.p_in)
  connect(hex.port_b1, sin_1.ports[1])
  connect(hex.port_b2, sin_2.ports[1])
end ConstantEffectiveness;


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


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers;
model EnthalpyExchanger
  "model for a parallel membrane enthalpy exchanger"

  // Medium in air ducts
  replaceable package Medium = AixLib.Media.Air
    "medium in the air ducts"

  // General parameter
  parameter Integer n(min=2)=2
    "number of discrecete volumes in flow direction";
  parameter Integer nParallel(min=1)
    "number of parallel membranes";

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

  //----------------------Air Ducts------------------------------------

  // Geometry
  parameter Modelica.Units.SI.Length lengthDuct
    "length of ducts in flow direction"
  parameter Modelica.Units.SI.Length heightDuct "height of ducts"
  parameter Modelica.Units.SI.Length widthDuct "width of ducts"
  parameter Boolean couFloArr=true
    "true: counter-flow arrangement; false: quasi-counter-flow arrangement"
  parameter Real aspRatCroToTot=0 "cross flow portion in exchanger"

  // Heat and mass transfer parameters
  parameter Boolean uniWalTem
    "true if uniform wall temperature boundary conditions"
  parameter Boolean local
    "true if heat and mass transfer are locally resolved"
  parameter Integer nWidth(min=1) = 1
    "number of segments in width direction"
  parameter Boolean recDuct
    "true if rectangular duct is used for Nusselt/Sherwood number calculation,
    else flat gap is used."

  // pressure losses
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "nominal mass flow rate";
  parameter Modelica.Units.SI.Pressure dp_nominal "nominal pressure drop";

  //-----------------------Membrane-------------------------------------

  // Geometry
  parameter Modelica.Units.SI.Length lengthMem=lengthDuct
    "length of membranes in flow direction"
  parameter Modelica.Units.SI.Length widthMem=widthDuct "width of membranes"
  parameter Modelica.Units.SI.Length thicknessMem "thickness of membranes"
  parameter Modelica.Units.SI.SpecificHeatCapacity cpMem
    "mass weighted heat capacity of membrane"

  // Membrane properties
  parameter Modelica.Units.SI.ThermalConductivity lambdaMem
    "thermal conductivity of membrane"
  parameter Modelica.Units.SI.Density rhoMem "density of membrane"

  // calculated parameter
  parameter Modelica.Units.SI.Area[n] surfaceAreas=fill(lengthMem*widthMem/n, n)
    "Heat transfer areas"

  //Advanced
  parameter Boolean useConPer=true
    "true, if permeabilty of membrane is assumed to be constant"
  parameter Real conPerMem(unit="mol/(m.s.Pa)")=9E5
    "constant permeability of membrane if useConPer=true"

  // Initialization
  parameter Modelica.Units.SI.MassFlowRate m_flow_start=m_flow_nominal
    "Start value for mass flow rate"
  parameter Medium.AbsolutePressure p_a1_start=Medium.p_default
      "Start value of pressure at port a1"
  parameter Medium.AbsolutePressure p_b1_start=p_a1_start
      "Start value of pressure at port b1"
  parameter Medium.AbsolutePressure p_a2_start=Medium.p_default
      "Start value of pressure at port a2"
  parameter Medium.AbsolutePressure p_b2_start=p_a2_start
      "Start value of pressure at port b2"
  final parameter Medium.AbsolutePressure[n] ps_start=if n > 1 then linspace(
        p_a1_start, p_b1_start, n) else {(p_a1_start + p_b1_start)/2}
      "Start value of pressure";

  parameter Medium.Temperature T_start=Medium.T_default
    "Start value of temperature"
  parameter Modelica.Units.SI.Pressure p_start=Medium.p_default
    "reference pressure"
  parameter Medium.MassFraction X_start[Medium.nX](
       quantity=Medium.substanceNames)=Medium.X_default
      "Start value of mass fractions m_i/m"
  parameter Medium.ExtraProperty C_start[Medium.nC](
       quantity=Medium.extraPropertiesNames)=fill(0, Medium.nC)
      "Start value of trace substances"
  parameter Modelica.Units.SI.Temperature T_start_m
    "membrane temperature start value"
  parameter Modelica.Units.SI.TemperatureDifference dT_start
    "start value for temperature between air ducts"
  parameter Modelica.Units.SI.PartialPressure p_start_m
    "start value for mean partial pressure at membrane's surface"
  parameter Modelica.Units.SI.PartialPressure dp_start
    "Start value for partial pressure gradient over membrane"

  BaseClasses.AirDuct airDuct2(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dp_nominal,
    final nNodes=n,
    final nParallel=nParallel,
    final nWidth=nWidth,
    final lengthDuct=lengthDuct,
    final widthDuct=widthDuct,
    final heightDuct=heightDuct,
    final uniWalTem=uniWalTem,
    final local=local,
    final recDuct=recDuct,
    final energyDynamics=energyDynamics,
    final p_start=p_start,
    final T_start=T_start,
    final X_start=X_start,
    final C_start=C_start,
    final couFloArr=couFloArr,
    final p_a_start=p_a2_start,
    final p_b_start=p_b2_start)
  BaseClasses.AirDuct airDuct1(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dp_nominal,
    final nNodes=n,
    final nParallel=nParallel,
    final nWidth=nWidth,
    final lengthDuct=lengthDuct,
    final widthDuct=widthDuct,
    final heightDuct=heightDuct,
    final uniWalTem=uniWalTem,
    final local=local,
    final recDuct=recDuct,
    final energyDynamics=energyDynamics,
    final p_start=p_start,
    final T_start=T_start,
    final X_start=X_start,
    final C_start=C_start,
    final couFloArr=couFloArr,
    final p_a_start=p_a1_start,
    final p_b_start=p_b1_start)
  BaseClasses.Membrane membrane(
    final nNodes=n,
    final nParallel=nParallel,
    final lengthMem=lengthMem,
    final widthMem=widthMem,
    final thicknessMem=thicknessMem,
    final cpMem=cpMem,
    final lambdaMem=lambdaMem,
    final rhoMem=rhoMem,
    final useConPer=useConPer,
    final conPerMem=conPerMem,
    final T_start=T_start_m,
    final dT_start=dT_start,
    final p_start=p_start,
    final dp_start=dp_start,
    final couFloArr=couFloArr,
    final energyDynamics=energyDynamics)

  Modelica.Blocks.Interfaces.RealInput perMem(unit="mol/(m.s.Pa)")
    if not useConPer "membrane permeability in Barrer"
//   Modelica.Blocks.Interfaces.RealInput[n] coeCroCouSens if not couFloArr
//     "coefficient for heat transfer reduction due to cross-flow portion";
//   Modelica.Blocks.Interfaces.RealInput[n] coeCroCouLats if not couFloArr
//     "coefficient for mass transfer reduction due to cross-flow portion";
  Modelica.Fluid.Interfaces.FluidPort_a port_a1(
    redeclare final package Medium=Medium)
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b port_b1(
    redeclare final package Medium=Medium)
    "Fluid connector b (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_a port_a2(
    redeclare final package Medium=Medium)
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b port_b2(
    redeclare final package Medium=Medium)
    "Fluid connector b (positive design flow direction is from port_a to port_b)"
  //Modelica.Thermal.HeatTransfer.Components.HeatCapacitor heatCapacityHousing(
  //  C=cpHou*mHou)

protected
  Modelica.Blocks.Interfaces.RealInput perMemInt(unit="mol/(m.s.Pa)");

  BaseClasses.HeatTransfer.CrossFlowReduction heaRedFac(
    final n=n,
    final nParallel=nParallel,
    final m_flow1=airDuct1.port_a.m_flow,
    final m_flow2=airDuct2.port_a.m_flow,
    final lambdaMem=lambdaMem,
    final surfaceAreas=surfaceAreas,
    final thicknessMem=thicknessMem,
    final hCons1=airDuct1.heatTransfer.hCons,
    final hCons2=airDuct2.heatTransfer.hCons,
    final aspRatCroToTot=aspRatCroToTot,
    final cp1=Medium.specificHeatCapacityCp(airDuct1.states[1]),
    final cp2=Medium.specificHeatCapacityCp(airDuct2.states[1]))
      if not couFloArr;
  BaseClasses.MassTransfer.CrossFlowReduction masRedFac(
    final n=n,
    final nParallel=nParallel,
    final m_flow1=airDuct1.port_a.m_flow,
    final m_flow2=airDuct2.port_a.m_flow,
    final surfaceAreas=surfaceAreas,
    final thicknessMem=thicknessMem,
    final kCons1=airDuct1.massTransfer.kCons,
    final kCons2=airDuct2.massTransfer.kCons,
    final aspRatCroToTot=aspRatCroToTot)
      if not couFloArr;

equation
  if useConPer then
    perMemInt = conPerMem;
  end if;
  connect(perMemInt, perMem);

  connect(heaRedFac.coeCroCous, airDuct1.coeCroCouSens);
  connect(heaRedFac.coeCroCous, airDuct2.coeCroCouSens);
  connect(heaRedFac.coeCroCous, membrane.coeCroCouSens);
  connect(masRedFac.coeCroCous, airDuct1.coeCroCouLats);
  connect(masRedFac.coeCroCous, airDuct2.coeCroCouLats);
  connect(masRedFac.coeCroCous, membrane.coeCroCouLats);

  connect(perMemInt, masRedFac.perMem);

  connect(airDuct1.heatPorts[n:-1:1], membrane.heatPorts_a[1:n])
  connect(airDuct1.massPorts[n:-1:1], membrane.massPorts_a[1:n])
  connect(membrane.heatPorts_b, airDuct2.heatPorts)
  connect(membrane.massPorts_b, airDuct2.massPorts)
  connect(perMem, membrane.perMem)
  connect(airDuct1.port_a, port_a1)
  connect(airDuct1.port_b, port_b1)
  connect(airDuct2.port_a, port_a2)
  connect(airDuct2.port_b, port_b2)
  //connect(heatCapacityHousing.port, airDuct2.heatPorts[n])
  //connect(heatCapacityHousing.port, airDuct1.heatPorts[n])
end EnthalpyExchanger;


within AixLib.Fluid.MassExchangers;
package MembraneBasedEnthalpyExchangers "package containing membrane-based enthalpy exchanger models"
extends Modelica.Icons.VariantsPackage;
end MembraneBasedEnthalpyExchangers;


model of the air duct

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses;
model AirDuct "model of the air duct"
  extends Interfaces.PartialTwoPortInterface(
    redeclare package Medium = AixLib.Media.Air,
    port_a(h_outflow(start=h_outflow_start),p(start=p_a_start)),
    port_b(h_outflow(start=h_outflow_start),p(start=p_b_start)));

  extends AixLib.Fluid.Interfaces.TwoPortFlowResistanceParameters(
    final computeFlowResistance=true);

  // General
  parameter Integer nNodes = 2
    "number of discrete volumes (over length) in the air duct";
  parameter Integer nParallel = 2
    "number of parallel air ducts";
  parameter Integer nWidth(min=1) = 1
    "number of segments in width direction";

  // Geometry
  parameter Modelica.Units.SI.Length lengthDuct
    "length in flow direction of duct"
  parameter Modelica.Units.SI.Length widthDuct "width of duct"
  parameter Modelica.Units.SI.Length heightDuct "height of duct"
  parameter Boolean couFloArr=true
    "true: counter-flow arrangement; false: quasi-counter-flow arrangement"

  // Heat and Mass transfer
  parameter Boolean uniWalTem
    "true if uniform wall temperature, else uniform wall heat flux"
  parameter Boolean local
    "true if local Nusselt/Sherwood number, else average"
  parameter Boolean recDuct
    "true if rectangular duct is used for Nusselt/Sherwood number calculation,
    else flat gap is used."

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

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

  // Initialization
  parameter Medium.AbsolutePressure p_a_start=Medium.p_default
      "Start value of pressure at port a"
  parameter Medium.AbsolutePressure p_b_start=p_a_start
      "Start value of pressure at port b"
  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"

  // Variables
  Modelica.Units.SI.Length[nNodes] lengths={i*(lengthDuct/((nNodes + 1)*nNodes/
      2)) for i in 1:nNodes} "length of segements in flow direction";
  Modelica.Units.SI.Area[nNodes] croSecs=fill(heightDuct*widthDuct, nNodes)
    "cross section of duct segments";
  Modelica.Units.SI.Velocity[nNodes] vs={port_a.m_flow/Medium.density(states[i])
      /croSecs[i] for i in 1:nNodes}/nParallel "velocity in air duct segments";
  Modelica.Units.SI.PartialPressure[nNodes] ps={vol[i].p*vol[i].X_w*(Ms[i]/
      M_steam) for i in 1:nNodes};
  Modelica.Units.SI.MolarMass[nNodes] Ms={1/(vol[i].X_w/M_steam + (1 - vol[i].X_w)
      /M_air) for i in 1:nNodes};

  Medium.ThermodynamicState[nNodes] states={Medium.setState_pTX(
    vol[i].p,
    vol[i].T,
    vol[i].Xi) for i in 1:nNodes};

  Modelica.Units.SI.SpecificEnthalpy dhAds=adsorptionEnthalpy.dhAds
    "adsorption enthalpy";

  // Inputs
  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouSens if not couFloArr
    "coefficient for heat transfer reduction due to cross-flow portion";
  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouLats if not couFloArr
    "coefficient for mass transfer reduction due to cross-flow portion";

  // Heat and mass transfer models
  model HeatTransfer = BaseClasses.HeatTransfer.LocalDuctConvectiveHeatFlow;

  model MassTransfer = BaseClasses.MassTransfer.LocalDuctConvectiveMassFlow;

  HeatTransfer heatTransfer(
    redeclare package Medium=Medium,
    n=nNodes,
    nWidth=nWidth,
    lengths=lengths,
    states=states,
    surfaceAreas={lengths[i] * widthDuct for i in 1:nNodes},
    vs=vs,
    heights=fill(heightDuct,nNodes),
    widths=fill(widthDuct,nNodes),
    nParallel=nParallel,
    uniWalTem=uniWalTem,
    local=local,
    recDuct=recDuct,
    coeCroCous=coeCroCouSenInts);

  MassTransfer massTransfer(
    redeclare package Medium=Medium,
    n=nNodes,
    nWidth=nWidth,
    lengths=lengths,
    states=states,
    surfaceAreas={lengths[i] * widthDuct for i in 1:nNodes},
    vs=vs,
    ps=ps,
    heights=fill(heightDuct,nNodes),
    widths=fill(widthDuct,nNodes),
    nParallel=nParallel,
    uniWalTem=uniWalTem,
    local=local,
    recDuct=recDuct,
    coeCroCous=coeCroCouLatInts);

  AixLib.Fluid.MixingVolumes.MixingVolumeMoistAir vol[nNodes](
    redeclare each final package Medium = Medium,
    each nPorts=2,
    each V=lengthDuct/nNodes*widthDuct*heightDuct,
    each final allowFlowReversal=allowFlowReversal,
    each final mSenFac=1,
    each final m_flow_nominal=m_flow_nominal,
    each final energyDynamics=energyDynamics,
    each final massDynamics=massDynamics,
    each final p_start=p_start,
    each final T_start=T_start,
    each final X_start=X_start,
    each final C_start=C_start,
    each final use_C_flow=false) "Volume for fluid stream"

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

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPorts[nNodes]
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow
    prescribedHeatFlow[nNodes]
  Utilities.MassTransfer.MassPort massPorts[nNodes]
  Modelica.Blocks.Sources.RealExpression Q_flow[nNodes](y=heatTransfer.heatPorts.Q_flow
         - massTransfer.massPorts.m_flow*dhAds)
  Modelica.Blocks.Sources.RealExpression mWat_flow[nNodes](
    y=massTransfer.massPorts.m_flow)
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";
  parameter Medium.ThermodynamicState sta_start=Medium.setState_pTX(
      T=T_start, p=p_start, X=X_start);
  parameter Modelica.Units.SI.SpecificEnthalpy h_outflow_start=
      Medium.specificEnthalpy(sta_start) "Start value for outflowing enthalpy";
  constant Modelica.Units.SI.MolarMass M_steam=0.01802 "Molar mass of steam";
  constant Modelica.Units.SI.MolarMass M_air=0.028949 "Molar mass of dry air";

  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouSenInts
    "coefficient for heat transfer reduction due to cross-flow portion";
  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouLatInts
    "coefficient for heat transfer reduction due to cross-flow portion";

  BaseClasses.HeatTransfer.AdsorptionEnthalpy
    adsorptionEnthalpy(
    F=5E-6,
    n=2,
    v_0=5.5E-5,
    T=senTem.T,
    phi=senRelHum.phi)
  Sensors.TemperatureTwoPort senTem(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
  Sensors.RelativeHumidityTwoPort senRelHum(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal)

equation
  if couFloArr then
    coeCroCouSenInts = fill(1,nNodes);
    coeCroCouLatInts = fill(1,nNodes);
  end if;
  connect(coeCroCouSens,coeCroCouSenInts);
  connect(coeCroCouLats,coeCroCouLatInts);

  connect(heatPorts, heatTransfer.heatPorts);
  connect(massPorts, massTransfer.massPorts);
  connect(port_a, preDro.port_a)
  connect(preDro.port_b, vol[1].ports[1])

  for i in 1:nNodes-1 loop
    connect(vol[i].ports[2],vol[i+1].ports[1]);
  end for;
  connect(prescribedHeatFlow.port, vol.heatPort)
  connect(Q_flow.y, prescribedHeatFlow.Q_flow)
  connect(mWat_flow.y, vol.mWat_flow)
  connect(vol[nNodes].ports[2], senTem.port_a)
  connect(senTem.port_b, senRelHum.port_a)
  connect(senRelHum.port_b, port_b)
end AirDuct;


model of membrane. This model provides a thin membrane layer. Here the coupled heat and
  mass transfer through the membrane is calculated using the heat
  transfer model LocalMembraneHeatTransfer and the mass transfer model
  LocalMembraneMassTransfer.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses;
model Membrane "model of membrane"

  parameter Integer nNodes = 2
    "number of discrete volumes";
  parameter Integer nParallel = 1
    "number of parallel membranes";

  // Parameters
  parameter Modelica.Units.SI.Length lengthMem
    "length of membrane in flow direction"
  parameter Modelica.Units.SI.Length widthMem "width of membrane"
  parameter Modelica.Units.SI.Length thicknessMem "thickness of membrane"
  parameter Boolean couFloArr=true
    "true: counter-flow arrangement; false: quasi-counter-flow arrangement"
  parameter Modelica.Units.SI.SpecificHeatCapacity cpMem
    "mass weighted heat capacity of membrane"
  parameter Modelica.Units.SI.ThermalConductivity lambdaMem
    "thermal conductivity of membrane"
  parameter Modelica.Units.SI.Density rhoMem "density of membrane"

  //Advanced
  parameter Boolean useConPer=true
    "true, if permeabilty of membrane is assumed to be constant"
  parameter Real conPerMem(unit="mol/(m.s.Pa)")=9E5
    "constant permeability of membrane if useConPer=true"

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

  // Initialization
  parameter Modelica.Units.SI.Temperature T_start
    "start value of membrane's temperature"
  parameter Modelica.Units.SI.TemperatureDifference dT_start
    "start value for temperature difference between heatPorts_a and heatPorst_b"
  parameter Modelica.Units.SI.PartialPressure p_start
    "start value for mean partial pressure of water vapour at membrane's surface"
  parameter Modelica.Units.SI.PartialPressure dp_start
    "start value for partial pressure difference between membrane's surfaces"

  // Inputs
  Modelica.Blocks.Interfaces.RealInput perMem(unit="mol/(m.s.Pa)")
    if not useConPer "membrane permeability in Barrer"
  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouSens if not couFloArr
    "coefficient for heat transfer reduction due to cross-flow portion";
  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouLats if not couFloArr
    "coefficient for mass transfer reduction due to cross-flow portion";

  // Heat and Mass Transfer models
  model HeatTransfer=BaseClasses.HeatTransfer.MembraneHeatTransfer
    "heat transfer model in membrane";
  model MassTransfer=BaseClasses.MassTransfer.MembraneMassTransfer
    "mass transfer model in membrane";

  HeatTransfer heatTransfer(
    thicknessMem=thicknessMem,
    lambdaMem=lambdaMem,
    lengthMem=lengthMem,
    widthMem=widthMem,
    rhoMem=rhoMem,
    cpMem=cpMem,
    nParallel=nParallel,
    T_start=T_start,
    dT_start=dT_start,
    n=nNodes,
    coeCroCous=coeCroCouSenInts,
    energyDynamics=energyDynamics);

  MassTransfer massTransfer(
    thicknessMem=thicknessMem,
    lengthMem=lengthMem,
    widthMem=widthMem,
    rhoMem=rhoMem,
    perMem=perMemInt,
    nParallel=nParallel,
    p_start=p_start,
    dp_start=dp_start,
    n=nNodes,
    coeCroCous=coeCroCouLatInts);

  // Ports
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPorts_a[nNodes]
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPorts_b[nNodes]
  Utilities.MassTransfer.MassPort massPorts_a[nNodes]
  Utilities.MassTransfer.MassPort massPorts_b[nNodes]

protected
  Modelica.Blocks.Interfaces.RealInput perMemInt(unit="mol/(m.s.Pa)");

  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouSenInts
    "coefficient for heat transfer reduction due to cross-flow portion";
  Modelica.Blocks.Interfaces.RealInput[nNodes] coeCroCouLatInts
    "coefficient for heat transfer reduction due to cross-flow portion";

equation
  if useConPer then
    perMemInt = conPerMem;
  end if;
  if couFloArr then
    coeCroCouSenInts = fill(1,nNodes);
    coeCroCouLatInts = fill(1,nNodes);
  end if;
  connect(coeCroCouSens,coeCroCouSenInts);
  connect(coeCroCouLats,coeCroCouLatInts);

  connect(perMemInt, perMem);

  connect(heatPorts_a,heatTransfer.heatPorts_a);
  connect(heatPorts_b,heatTransfer.heatPorts_b);

  connect(massPorts_a,massTransfer.massPorts_a);
  connect(massPorts_b,massTransfer.massPorts_b);
end Membrane;


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers;
package BaseClasses "package with base claesses for membrane-based enthalpy exchanger"
  extends Modelica.Icons.BasesPackage;

end BaseClasses;


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses;
package Functions "package with base functions to calculate heat and mass transfer in enthalpy exchanger"
end Functions;