model that calculates the adsorption enthalpy based on the Dubinin-Astakhov equation. This model calculates the adsorption enthalpy of water vapour for an
  microporous absorbent. It is based on the Dubinin-Astakhov equation
  for sorption. All equations are taken from [1].

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
model AdsorptionEnthalpy
  "model that calculates the adsorption enthalpy based on the Dubinin-Astakhov equation"

  //============ parameters ====================

  //calculation of water uptake in adsorbent
  parameter Real F
    "material specific asdoprtion characteristic constant";
  parameter Real n
    "material specific asdoprtion characteristic constant";
  parameter Modelica.Units.SI.SpecificVolume v_0(min=0)
    "micropore volume per unit mass of absorbent";

  //calculation of adsorption heat
protected
  constant Real R_g(unit="J/(kg.K)") = 461.4 "specific gas constant of water vapour";
  constant Real A(unit="m.m.m/(kg.K)") = 1.8105E-6
    "constant for density calculation of water vapour";
    //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane
  constant Real B(unit="m.m.m.K/kg") = 138.08E-3
    "constant for density calculation of water vapour";
    //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane

  //============ variables =====================
public
  Modelica.Units.SI.MassFraction w(min=0)
    "actual water uptake of adsorbent in kg/kg";
  Modelica.Units.SI.MassFraction w_0(min=0)
    "maximum water uptake of adsorbent in kg/kg (material specific)";
  Modelica.Units.SI.Density rho "density of water vapour";
  Real dw0_dT(unit="1/K")
    "derivative of maximum water uptake by temperature";
  Modelica.Units.SI.SpecificEnthalpy dh_v "vaporization enthalpy of water";
  Modelica.Units.SI.SpecificEnthalpy q_st "adsorption enthalpy of water";

  input Modelica.Units.SI.Temperature T "Temperature in K";
  input Real phi(min=0.01,max=0.99)
    "relative Humidity, range:0.01...0.99";
  Modelica.Blocks.Interfaces.RealOutput dhAds
    "adsorption enthalpy in J/kgK"
equation

  rho = 1/(A*T+B/T);
  //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane

  w_0 = rho * v_0;
  //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane

  w = w_0 * exp(-F*(-T*log(phi))^n);
  //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane

  dw0_dT = (B/T^2-A)*v_0/(A*T+B/T)^2;
  //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane

  q_st = dh_v + R_g * T * (-1/F * log(w/w_0))^(1/n) * (1/T + 1/(n*w_0*log(w/w_0)) * dw0_dT);
  //Min et al: Coupled heat and mass transfer during moisture exchange across a membrane

  dh_v = 2500E3; //for first test, needs to be changed depending on temperature

  dhAds = max(min(q_st,4E6),dh_v);
end AdsorptionEnthalpy;


model that calculates reduction factor for heat transfer in quasi-counter flow arrangement. This model calculates a reduction factor for a cross-counter-flow
  arrangement. The calculation is based on the Efficiency-NTU-Method.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
model CrossFlowReduction
  "model that calculates reduction factor for heat transfer in quasi-counter flow arrangement"

  // Parameters
  parameter Integer n=1 "number of discrete elements in flow direction";
  parameter Integer nParallel=1 "number of parallel membranes";

  parameter Modelica.Units.SI.Length thicknessMem "thickness of membranes";
  parameter Modelica.Units.SI.ThermalConductivity lambdaMem
    "thermal conductivity of membrane";
  parameter Modelica.Units.SI.Area[n] surfaceAreas "Heat transfer areas";
  parameter Real aspRatCroToTot "cross flow portion of transfer area";

  // Variables
  Real[n] h_tots "total heat transfer coefficient";
  Real[n] NTUs "number of heat transfer units";

  // Inputs
  input Modelica.Units.SI.HeatCapacity cp1 "heat capacity of air flow 1";
  input Modelica.Units.SI.HeatCapacity cp2 "heat capacity of air flow 2";
  input Modelica.Units.SI.CoefficientOfHeatTransfer[n] hCons1
    "convective heat transfer coefficients of air flow 1";
  input Modelica.Units.SI.CoefficientOfHeatTransfer[n] hCons2
    "convective heat transfer coefficients of air flow 2";
  input Modelica.Units.SI.MassFlowRate m_flow1 "mass flow rate of air flow 1";
  input Modelica.Units.SI.MassFlowRate m_flow2 "mass flow rate of air flow 2";

  // Outputs
  Modelica.Blocks.Interfaces.RealOutput[n] coeCroCous
    "coefficient for heat transfer reduction due to cross-flow portion";

equation

  for i in 1:n loop
    1/h_tots[i] = 1/hCons1[i] + thicknessMem/lambdaMem + 1/hCons2[i];
    NTUs[i] = h_tots[i]*(surfaceAreas[i]*nParallel)/min(m_flow1*cp1,m_flow2*cp2);
    coeCroCous[i] = BaseClasses.Functions.CoefficientCrossToCounterFlow(NTUs[i])*
      aspRatCroToTot + (1 - aspRatCroToTot);
  end for;
end CrossFlowReduction;


heat transfer model for locally resolved rectangular ducts in quasi-counter
  flow arrangement. This heat transfer model calculates the convective heat flow for
  local distribution using the function
  convectiveHeatTransferCoefficient. The heat flow is calculated as
  follows.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
model LocalDuctConvectiveHeatFlow
  "heat transfer model for locally resolved rectangular ducts in quasi-counter
  flow arrangement"
  extends PartialDuctHeatTransfer;

  parameter Real nParallel "number of parallel ducts";

  input Real[n] coeCroCous
    "coefficient for heat transfer reduction due to cross-flow portion";

equation
  Q_flows={hCons[i]*coeCroCous[i]*surfaceAreas[i]*(heatPorts[i].T - Ts[i])
    *nParallel for i in 1:n};
end LocalDuctConvectiveHeatFlow;


model for heat transfer through a membrane. This heat transfer model calculates the locally resolved heat flow
  through a thin membrane using the thermal conductivity
  λMembrane and the membrane thickness
  δMembrane .

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
model MembraneHeatTransfer
  "model for heat transfer through a membrane"

  // General Parameters
  parameter Integer n = 2
    "Segmentation of membrane";
  parameter Integer nParallel
    "number of parallel air ducts";

  // 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 Modelica.Units.SI.ThermalConductivity lambdaMem
    "thermal conductivity of membrane";
  parameter Modelica.Units.SI.Density rhoMem "density of membrane";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpMem
    "mass weighted heat capacity of membrane";

  parameter Modelica.Units.SI.Mass mMem=rhoMem*(lengthMem*widthMem*thicknessMem)
      *nParallel "mass of membrane"
  parameter Modelica.Units.SI.Area areaMem=lengthMem*widthMem*nParallel
    "surface area of membrane"

  // 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
    "membrane temperature start value";
  parameter Modelica.Units.SI.TemperatureDifference dT_start
    "start value for temperature difference between heatPorts_a and heatPorst_b";

  // Inputs
  input Real[n] coeCroCous
    "coefficient for heat transfer reduction due to cross-flow portion";

  // Mass
  Modelica.Units.SI.Mass[n] m=fill(mMem/n, n) "Distribution of wall mass";

  // Temperatures
  Modelica.Units.SI.Temperature[n] Tb(each start=T_start + 0.5*dT_start)
    "Temperature at side b";
  Modelica.Units.SI.Temperature[n] Ta(each start=T_start - 0.5*dT_start)
    "Temperature at side a";
  Modelica.Units.SI.Temperature[n] Ts "Membrane temperature";

  // Ports
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a[n] heatPorts_a
    "Heat port to component boundary"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a[n] heatPorts_b
    "Heat port to component boundary"

initial equation
  if energyDynamics == Modelica.Fluid.Types.Dynamics.SteadyStateInitial then
    der(Ts) = zeros(n);
  elseif energyDynamics == Modelica.Fluid.Types.Dynamics.FixedInitial then
    Ts = ones(n)*T_start;
  end if;

equation
  for i in 1:n loop
    assert(m[i] > 0, "Membrane has negative dimensions");
    if energyDynamics == Modelica.Fluid.Types.Dynamics.SteadyState then
      0 = heatPorts_a[i].Q_flow + heatPorts_b[i].Q_flow;
    else
      cpMem*m[i]*der(Ts[i]) =
        heatPorts_a[i].Q_flow + heatPorts_b[i].Q_flow;
    end if;
    heatPorts_a[i].Q_flow = lambdaMem / thicknessMem * coeCroCous[i] *
      (Ta[i]-Ts[i]) * areaMem/n;
    heatPorts_b[i].Q_flow = lambdaMem / thicknessMem * coeCroCous[i] *
      (Tb[i]-Ts[i]) * areaMem/n;
  end for;

  Ta = heatPorts_a.T;
  Tb = heatPorts_b.T;
end MembraneHeatTransfer;


package with heat transfer models

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses;
package HeatTransfer "package with heat transfer models"
end HeatTransfer;


partial model for rectangular duct heat transfer models. This model calculates the convective heat transfer coefficient
  <i>α</i> using the nusselt number correlation for rectangular air
  ducts by Muzychka and Yovanovich [1] (see function
  NusseltNumberMuzychka).

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
partial model PartialDuctHeatTransfer
  "partial model for rectangular duct heat transfer models"
  extends PartialFlowHeatTransfer;

  parameter Integer nWidth(min=1) "number of parallel segments in width direction";

  parameter Modelica.Units.SI.Length[n] heights "height of duct";
  parameter Modelica.Units.SI.Length[n] widths "width of duct";

  Real[n] aspRats "aspect ratio between duct height and width";
  parameter Boolean uniWalTem
    "true if uniform wall temperature boundary conditions";
  parameter Boolean local
    "true if local nusslet number or false if average shall be calculated";
  parameter Boolean recDuct
    "true if rectangular duct is used for Sherwood number calculation, else flat gap is used.";

  Modelica.Units.SI.CoefficientOfHeatTransfer[n] hCons;

  // Variables
  Modelica.Units.SI.ThermalConductivity[n] lambdas
    "thermal conductivity of medium";
  Modelica.Units.SI.Density[n] rhos "density of medium";
  Modelica.Units.SI.DynamicViscosity[n] mus "dynamic viscosity of medium";
  Real[n] Prs "Prandtl number";
  Real[n] Res "Reynolds number";
  Real[n] Nus "Nusselt number";
  Modelica.Units.SI.Area[n] croSecs "cross section of duct";
  Real[n] zSterns "dimensionless length";

equation

  rhos = Medium.density(states);
  mus = Medium.dynamicViscosity(states);
  lambdas = Medium.thermalConductivity(states);
  Prs = Medium.prandtlNumber(states);

  for i in 1:n loop
    croSecs[i] = heights[i]*(widths[i]/nWidth);
    aspRats[i] = heights[i]/widths[i];
    zSterns[i] = (sum(lengths)/sqrt(croSecs[i]))/max(0.001,Res[i]*Prs[i]);
    if recDuct then
      Res[i] =
        Modelica.Fluid.Pipes.BaseClasses.CharacteristicNumbers.ReynoldsNumber(
          rho=rhos[i],
          mu=mus[i],
          v=vs[i],
          D=2*croSecs[i]);
      Nus[i] =Functions.NusseltNumberMuzychka(
        Re=Res[i],
        Pr=Prs[i],
        aspRat=aspRats[i],
        zStern=zSterns[i],
        uniWalTem=uniWalTem,
        local=local,
        gamma=0.1);
      hCons[i] = (Nus[i]*lambdas[i])/sqrt(croSecs[i]);
    else
      Res[i] =
        Modelica.Fluid.Pipes.BaseClasses.CharacteristicNumbers.ReynoldsNumber(
          rho=rhos[i],
          mu=mus[i],
          v=vs[i],
          D=2*heights[i]);
      Nus[i] =Functions.NusseltNumberStephan(
        Re=Res[i],
        Pr=Prs[i],
        length=lengths[i],
        dimension=2*heights[i]);
      hCons[i] = (Nus[i]*lambdas[i])/(2*heights[i]);
    end if;
  end for;
end PartialDuctHeatTransfer;


base class for any flow heat transfer correlation.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
partial model PartialFlowHeatTransfer
  "base class for any flow heat transfer correlation"
  extends PartialHeatTransfer;

  // Additional inputs provided to flow heat transfer model
  input Modelica.Units.SI.Velocity[n] vs
    "Mean velocities of fluid flow in segments";

  input Modelica.Units.SI.Length[n] lengths "Lengths along flow path";
end PartialFlowHeatTransfer;


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.HeatTransfer;
partial model PartialHeatTransfer
  "Common interface for heat transfer models"

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

  parameter Integer n=1 "Number of heat transfer segments in x-Direction"

  // Inputs provided to heat transfer model
  input Medium.ThermodynamicState[n] states
    "Thermodynamic states of flow segments";

  input Modelica.Units.SI.Area[n] surfaceAreas "Heat transfer areas";

  // Outputs defined by heat transfer model
  output Modelica.Units.SI.HeatFlowRate[n] Q_flows "Heat flow rates";

  // Heat ports
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a[n] heatPorts
    "Heat port to component boundary"

  // Variables
  Modelica.Units.SI.Temperature[n] Ts=Medium.temperature(states)
    "Temperature at states";
equation
  Q_flows =heatPorts.Q_flow;
end PartialHeatTransfer;


model that calculates reduction factor for mass transfer in quasi-counter flow arrangement. This model calculates a reduction factor for a cross-counter-flow
  arrangement. The calculation is based on the Efficiency-NTU-Method.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.MassTransfer;
model CrossFlowReduction
  "model that calculates reduction factor for mass transfer in quasi-counter flow arrangement"

  // Parameters
  parameter Integer n=1 "number of discrete elements in flow direction";
  parameter Integer nParallel=1 "number of parallel membranes";

  parameter Modelica.Units.SI.Length thicknessMem "thickness of membranes";
  parameter Modelica.Units.SI.Area[n] surfaceAreas "Heat transfer areas";
  parameter Real aspRatCroToTot "ratio of cross flow of air duct";

  // Constants
  constant Real C_conv = 3.35*10^(-16)
    "conversion factor for permeance to calculate SI-units from Barrer";
  constant Modelica.Units.SI.MolarMass M_steam=0.01802;

  // Variables
  Real[n] k_tots "total mass transfer coefficient";
  Real[n] NTUs "number of heat transfer units";

  // Inputs
  Modelica.Blocks.Interfaces.RealInput perMem(unit="mol/(m.s.Pa)")
    "membrane permeability in Barrer";
  input Real[n] kCons1
    "convective mass transfer coefficients of air flow 1";
  input Real[n] kCons2
    "convective mass transfer coefficients of air flow 2";
  input Modelica.Units.SI.MassFlowRate m_flow1 "mass flow rate of air flow 1";
  input Modelica.Units.SI.MassFlowRate m_flow2 "mass flow rate of air flow 2";

  // Outputs
  Modelica.Blocks.Interfaces.RealOutput[n] coeCroCous
    "coefficient for heat transfer reduction due to cross-flow portion";

equation

  for i in 1:n loop
    1/k_tots[i] = 1/kCons1[i]+thicknessMem/(perMem*C_conv*M_steam)+1/kCons2[i];
    NTUs[i] = k_tots[i]*(surfaceAreas[i]*nParallel)/min(m_flow1,m_flow2);
    coeCroCous[i] = BaseClasses.Functions.CoefficientCrossToCounterFlow(NTUs[i])*
      aspRatCroToTot + (1 - aspRatCroToTot);
  end for;
end CrossFlowReduction;


mass transfer model for locally resolved rectangular ducts in quasi-counter
  flow arrangement. This mass transfer model calculates the convective mass flow for
  local distribution using the function
  convectiveMassTransferCoefficient. The mass flow is calculated as
  follows.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.MassTransfer;
model LocalDuctConvectiveMassFlow
  "mass transfer model for locally resolved rectangular ducts in quasi-counter
  flow arrangement"
  extends PartialDuctMassTransfer;

  parameter Real nParallel "number of parallel ducts";

  input Real[n] coeCroCous
    "coefficient for mass transfer reduction due to cross-flow portion";

equation
  m_flows={kCons[i]*coeCroCous[i]*surfaceAreas[i]*(massPorts[i].p - ps[i])
    *nParallel for i in 1:n};
end LocalDuctConvectiveMassFlow;


model for mass transfer through membrane in
  quasi-counter flow arrangement. This model calculates the locally distributed mass transfer through a
  thin membrane. The model is based on the Solution-Diffusion model. It
  uses the permeability to describe the process of sorption, diffusion
  and desorption of the water vapour. For detailed information see [1].

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.MassTransfer;
model MembraneMassTransfer "model for mass transfer through membrane in
  quasi-counter flow arrangement"

  // General Parameter
  parameter Integer n = 2
    "Segmentation of membrane";
  parameter Real nParallel
    "number of parallel air ducts";

  // Parameter
  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 Modelica.Units.SI.Density rhoMem "density of membrane";
  parameter Modelica.Units.SI.Area areaMem=lengthMem*widthMem*nParallel
    "surface area of membrane"

  // Initialization
  parameter Modelica.Units.SI.PartialPressure p_start
    "start value for mean partial pressure at membrane's surfaces";
  parameter Modelica.Units.SI.PartialPressure dp_start
    "start value for partial pressure difference between membrane's surfaces";

  // Inputs
  input Real perMem(unit="mol/(m.s.Pa)") "membrane's permeability in Barrer";

  input Real[n] coeCroCous
    "coefficient for mass transfer reduction due to cross-flow portion";

  // Ports
  Utilities.MassTransfer.MassPort[n] massPorts_a
    "mass port to component boundary"
  Utilities.MassTransfer.MassPort[n] massPorts_b
    "mass port to component boundary"

protected
  constant Real cCon = 3.33*10^(-16)
    "conversion factor for permeability to calculate SI-units from Barrer";
  // 1 Barrer = 3.33*10^(-16) (mol*m)/(m²*s*Pa)
  // calculated from: Stern, S.A.: The "Barrer" Permeability Unit.
  //                  J. of Polym. Sci. Vol. 6. 1968
  constant Modelica.Units.SI.MolarMass M_steam=0.01802;
//   constant Modelica.SIunits.MolarMass M_air = 0.028949;
  // source: Detlev Möller: Luft: Chemie, Physik, Biologie, Reinhaltung, Recht.
  //         Walter de Gruyter, 2003, ISBN 3-11-016431-0, S. 173

equation
  for i in 1:n loop
    0 = massPorts_a[i].m_flow + massPorts_b[i].m_flow;
    massPorts_a[i].m_flow = (perMem * cCon * M_steam) * coeCroCous[i] *
      (massPorts_a[i].p - massPorts_b[i].p) / thicknessMem * areaMem/n;
  end for;
end MembraneMassTransfer;


package with mass transfer models

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses;
package MassTransfer "package with mass transfer models"
end MassTransfer;


partial model for rectangular duct mass transfer models. This model calculates the convective mass transfer coefficient
  <i>β</i> using the nusselt number correlation for rectangular air
  ducts by Muzychka and Yovanovich [1] and the analogy between heat and
  mass transfer (see function SherwoodNumberMuzychka).

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.MassTransfer;
partial model PartialDuctMassTransfer
  "partial model for rectangular duct mass transfer models"
  extends PartialFlowMassTransfer;

  parameter Integer nWidth(min=1) "number of parallel segments in width direction";

  parameter Modelica.Units.SI.Length[n] heights "height of duct";
  parameter Modelica.Units.SI.Length[n] widths "width of duct";

  Real[n] aspRats "aspect ratio between duct height and width";
  parameter Boolean uniWalTem
    "true if uniform wall temperature boundary conditions";
  parameter Boolean local
    "true if local Sherwood number or false if average shall be calculated";
  parameter Boolean recDuct
    "true if rectangular duct is used for Sherwood number calculation, else flat gap is used.";

  Real[n] kCons;

  // Variables
  Modelica.Units.SI.ThermalConductivity[n] lambdas
    "thermal conductivity of medium";
  Modelica.Units.SI.Density[n] rhos "density of medium";
  Modelica.Units.SI.DynamicViscosity[n] mus "dynamic viscosity of medium";
  Real[n] Scs "Schmidt number";
  Real[n] Res "Reynolds number";
  Real[n] Shs "Shwerwood number";
  Modelica.Units.SI.Area[n] croSecs "cross section of duct";
  Real[n] zSterns "dimensionless length";

protected
  constant Modelica.Units.SI.MolarMass M_air=28.96;
  constant Modelica.Units.SI.MolarMass M_steam=18.02;
  constant Real sigmaAir = 3.711 "distance of air molecules in Atom";
  constant Real sigmaSteam = 2.655 "distance of steam molecules in Atom";

  Real[n] omegas "collision integral";
  Modelica.Units.SI.DiffusionCoefficient[n] Ds
    "diffusion coefficient for water vapour into air";

equation

  rhos = Medium.density(states);
  mus = Medium.dynamicViscosity(states);
  lambdas = Medium.thermalConductivity(states);

  for i in 1:n loop
    croSecs[i] = heights[i]*(widths[i]/nWidth);
    aspRats[i] = heights[i]/widths[i];
    omegas[i] =Functions.CollisionIntegral(T=Medium.temperature(states[i]));
    Ds[i] =Functions.DiffusionCoefficient(
      M_1=M_air,
      M_2=M_steam,
      T=Medium.temperature(states[i]),
      p=1,
      sigma1=sigmaAir,
      sigma2=sigmaSteam,
      omega=omegas[i]);
    Scs[i] = mus[i]/(rhos[i]*Ds[i]);
    zSterns[i] = (sum(lengths)/sqrt(croSecs[i]))/max(0.001,Res[i]*Scs[i]);
    if recDuct then
      Res[i] =
      Modelica.Fluid.Pipes.BaseClasses.CharacteristicNumbers.ReynoldsNumber(
      rho=rhos[i],
      mu=mus[i],
      v=vs[i],
      D=sqrt(croSecs[i]));
      Shs[i]=Functions.SherwoodNumberMuzychka(
        Re=Res[i],
        Sc=Scs[i],
        aspRat=aspRats[i],
        zStern=zSterns[i],
        uniWalTem=uniWalTem,
        local=local,
        gamma=0.1);
      kCons[i] = (Shs[i]*rhos[i]*Ds[i])/sqrt(croSecs[i]);
    else
      Res[i] =
      Modelica.Fluid.Pipes.BaseClasses.CharacteristicNumbers.ReynoldsNumber(
        rho=rhos[i],
        mu=mus[i],
        v=vs[i],
        D=2*heights[i]);
      Shs[i]=Functions.SherwoodNumberStephan(
        Re=Res[i],
        Sc=Scs[i],
        length=lengths[i],
        dimension=2*heights[i]);
      kCons[i] = (Shs[i]*rhos[i]*Ds[i])/(2*heights[i]);
    end if;
  end for;
end PartialDuctMassTransfer;


base class for any flow mass transfer correlation. Base class for mass transfer models of flow devices.

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.MassTransfer;
partial model PartialFlowMassTransfer
  "base class for any flow mass transfer correlation"
  extends PartialMassTransfer;

  // Additional inputs provided to flow heat transfer model
  input Modelica.Units.SI.Velocity[n] vs
    "Mean velocities of fluid flow in segments";

  input Modelica.Units.SI.Length[n] lengths "Lengths along flow path";
end PartialFlowMassTransfer;


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.BaseClasses.MassTransfer;
partial model PartialMassTransfer
  "Common interface for mass transfer models"

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

  parameter Integer n=1 "Number of heat transfer segments in x-Direction"

  // Inputs provided to heat transfer model
  input Medium.ThermodynamicState[n] states
    "Thermodynamic states of flow segments";

  input Modelica.Units.SI.Area[n] surfaceAreas "Heat transfer areas";

  // Outputs defined by heat transfer model
  output Modelica.Units.SI.MassFlowRate[n] m_flows "Mass flow rates";

  // Heat ports
  AixLib.Utilities.MassTransfer.MassPort[n] massPorts
    "Heat port to component boundary"

  // Variables
  input Modelica.Units.SI.PartialPressure[n] ps "partial pressure at states";

equation
  m_flows =massPorts.m_flow;
end PartialMassTransfer;


Example for enthalpy Exchanger

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers;
package Examples "Example for enthalpy Exchanger"
extends Modelica.Icons.ExamplesPackage;
end Examples;


example test for enthalpy exchanger

within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.Examples;
model Test_EnthalpyExchanger "example test for enthalpy exchanger"
  extends Modelica.Icons.Example;
  EnthalpyExchanger enthalpyExchanger(
    redeclare package Medium = Media.Air,
    n=15,
    nParallel=184,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    lengthDuct=0.34,
    heightDuct=0.0025,
    widthDuct=0.3,
    couFloArr=false,
    aspRatCroToTot=0.1,
    uniWalTem=true,
    local=true,
    nWidth=30,
    recDuct=true,
    m_flow_nominal=400/3600*1.18,
    dp_nominal(displayUnit="Pa") = 120,
    thicknessMem=110E-6,
    cpMem=1900,
    lambdaMem=0.34,
    rhoMem(displayUnit="kg/m3") = 920,
    p_a1_start=souAirHot.p,
    p_b1_start=sinAirHot.p,
    p_a2_start=souAirCol.p,
    p_b2_start=sinAirCol.p,
    T_start_m=293.15,
    dT_start=10,
    p_start_m(displayUnit="Pa") = 2000,
    dp_start(displayUnit="Pa") = 100)
  Sources.Boundary_pT souAirHot(
    redeclare package Medium = Media.Air,
    use_p_in=true,
    T=295.15,
    X={0.008,1 - 0.008},
    nPorts=1)
  Sources.Boundary_pT sinAirHot(
    redeclare package Medium = Media.Air,
    p(displayUnit="Pa"),
    nPorts=1)
  Sources.Boundary_pT souAirCol(
    redeclare package Medium = Media.Air,
    use_p_in=true,
    use_T_in=true,
    use_Xi_in=true,
    X={0.008,1 - 0.008},
    nPorts=1)
  Sources.Boundary_pT sinAirCol(
    redeclare package Medium = Media.Air,
    p(displayUnit="Pa"),
    nPorts=1)
  Modelica.Blocks.Sources.Ramp p_in(
    height=-60,
    duration=600,
    offset=101440,
    startTime=3600)
  Modelica.Blocks.Sources.Sine sine(
    amplitude=5,
    f=1/3600,
    offset=278.15)
  Modelica.Blocks.Sources.Sine sine1(
    amplitude=0.002,
    f=1/3600,
    offset=0.003)
  Sensors.TemperatureTwoPort senTemHotIn(redeclare package Medium = Media.Air,
      m_flow_nominal=400/3600*1.18)
  Sensors.TemperatureTwoPort senTemHotOut(redeclare package Medium = Media.Air,
      m_flow_nominal=400/3600*1.18)
  Sensors.TemperatureTwoPort senTemColIn(redeclare package Medium = Media.Air,
      m_flow_nominal=400/3600*1.18)
  Sensors.TemperatureTwoPort senTemColOut(redeclare package Medium = Media.Air,
      m_flow_nominal=400/3600*1.18)
  Sensors.MassFractionTwoPort senMasFraHotIn(
    redeclare package Medium = Media.Air,
    m_flow_nominal=400/3600*1.18,
    X_start=0.005)
  Sensors.MassFractionTwoPort senMasFraHotOut(
    redeclare package Medium = Media.Air,
    m_flow_nominal=400/3600*1.18,
    X_start=0.005)
  Sensors.MassFractionTwoPort senMasFraColIn(
    redeclare package Medium = Media.Air,
    m_flow_nominal=400/3600*1.18,
    X_start=0.003)
  Sensors.MassFractionTwoPort senMasFraColOut(
    redeclare package Medium = Media.Air,
    m_flow_nominal=400/3600*1.18,
    X_start=0.003)
  Modelica.Blocks.Interaction.Show.RealValue realValue
  Modelica.Blocks.Interaction.Show.RealValue realValue1
  Modelica.Blocks.Sources.RealExpression senEff(
    y=(senTemColOut.T - senTemColIn.T)/max(1E-6, senTemHotIn.T - senTemColIn.T))
  Modelica.Blocks.Sources.RealExpression latEff(
    y=(senMasFraColOut.X - senMasFraColIn.X)/
    max(1E-6, senMasFraHotIn.X - senMasFraColIn.X))
equation
  connect(p_in.y, souAirHot.p_in)
  connect(p_in.y, souAirCol.p_in)
  connect(sine.y, souAirCol.T_in)
  connect(sine1.y, souAirCol.Xi_in[1])
  connect(souAirHot.ports[1], senTemHotIn.port_a)
  connect(enthalpyExchanger.port_b1, senTemHotOut.port_a)
  connect(souAirCol.ports[1], senTemColIn.port_a)
  connect(enthalpyExchanger.port_b2, senTemColOut.port_a)
  connect(senTemHotIn.port_b, senMasFraHotIn.port_a)
  connect(senMasFraHotIn.port_b, enthalpyExchanger.port_a1)
  connect(senTemHotOut.port_b, senMasFraHotOut.port_a)
  connect(senMasFraHotOut.port_b, sinAirHot.ports[1])
  connect(senTemColIn.port_b, senMasFraColIn.port_a)
  connect(senMasFraColIn.port_b, enthalpyExchanger.port_a2)
  connect(senTemColOut.port_b, senMasFraColOut.port_a)
  connect(senMasFraColOut.port_b, sinAirCol.ports[1])
  connect(senEff.y, realValue.numberPort)
  connect(latEff.y, realValue1.numberPort)
end Test_EnthalpyExchanger;


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.Validation;
model DynamicValidation
  "example containing validation for dynamic behaviour of membrane-based enthalpy exchanger"
  extends Modelica.Icons.Example;

  // parameters (for better change on the fly)
  parameter Integer nParallel=184
    "Number of identical parallel flow devices";
  parameter Integer n = 15
    "number of discrete segments";
  parameter Modelica.Units.SI.Length heightDuct=0.00225 "height of duct";
  parameter Modelica.Units.SI.Length widthDuct=0.305 "width of duct";
  parameter Modelica.Units.SI.Length lengthDuct=0.34
    "length of duct in flow direction";
  parameter Real aspRatCroToTot = 0.25 "aspect ratio of cross flow";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=400/3600*1.18
    "nominal mass flow rate";
  parameter Modelica.Units.SI.Pressure dp_nominal=119.5 "nominal pressure drop";
  parameter Modelica.Units.SI.Length thicknessMem=110E-6
    "thickness of membrane";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpMem=1900
    "mass weighted heat capacity of membrane";
  parameter Modelica.Units.SI.ThermalConductivity lambdaMem=0.24
    "thermal conductivity of membrane";
  parameter Modelica.Units.SI.Density rhoMem=920 "density of membrane";
  parameter Modelica.Units.SI.Temperature T_start=283.15
    "membrane temperature start value";
  parameter Modelica.Units.SI.Temperature dT=10
    "Start value for port_b.T - port_a.T";
  parameter Modelica.Units.SI.Pressure p_start=1200.0
    "membrane concentration start value";
  parameter Modelica.Units.SI.Pressure dp=100.0
    "Start value for concentration gradient in membrane";
  parameter Modelica.Units.SI.MassFlowRate m_flow_start=m_flow_nominal
    "Start value for mass flow rate";
  parameter Real A=5.38E7
    "constant A of linear dependency equation for permeability";
  parameter Real B=4.64E5
    "constant B of linear dependency equation for permeability";

  EnthalpyExchanger enthalpyExchanger(
    redeclare package Medium = Media.Air,
    n=n,
    nParallel=nParallel,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    lengthDuct=lengthDuct,
    heightDuct=heightDuct,
    widthDuct=widthDuct,
    couFloArr=false,
    aspRatCroToTot=aspRatCroToTot,
    uniWalTem=true,
    local=true,
    nWidth=30,
    recDuct=true,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=dp_nominal,
    thicknessMem=thicknessMem,
    cpMem=cpMem,
    lambdaMem=lambdaMem,
    rhoMem=rhoMem,
      useConPer=false,
    T_start_m=T_start,
    dT_start=dT,
    p_start_m=p_start,
    dp_start=dp)
  AixLib.Fluid.Sources.Boundary_pT souEta(
    redeclare package Medium = Media.Air,
    use_Xi_in=true,
    nPorts=1,
    use_T_in=true,
    T=294.0495)
  Sensors.MassFractionTwoPort senMasFraEta(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    X_start=0.008)
  Sensors.TemperatureTwoPort senTemEta(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    T_start=293.15)
  Sensors.VolumeFlowRate senVolFloEta(
    redeclare package Medium = Media.Air,
    m_flow_nominal=0.2)
  Sensors.TemperatureTwoPort senTemEha(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15)
  Sensors.MassFractionTwoPort senMasFraEha(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15)
  Sources.Boundary_pT sinEha(
    redeclare package Medium = Media.Air,
    nPorts=1)
  Sources.Boundary_pT souOda(
    redeclare package Medium = Media.Air,
    use_Xi_in=true,
    nPorts=1,
    use_p_in=false,
    use_T_in=true,
    T=294.0495)
  Sensors.MassFractionTwoPort senMasFraOda(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    X_start=0.002)
  Sensors.TemperatureTwoPort senTemOda(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    T_start=283.15)
  Sensors.VolumeFlowRate senVolFloOda(
    redeclare package Medium = Media.Air,
    m_flow_nominal=0.2)
  Sources.Boundary_pT sinSup(
    redeclare package Medium = Media.Air,
    nPorts=1)
  Sensors.MassFractionTwoPort senMasFraSup(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=6)
  Sensors.TemperatureTwoPort senTemSup(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=20)
  Modelica.Blocks.Sources.CombiTimeTable bondaryEta(
    tableOnFile=true,
    tableName="Boundary",
    columns={2,3,4},
    fileName=ModelicaServices.ExternalReferences.loadResource("modelica://AixLib/Resources/Fluid/MembraneBasedEnthalpyExchanger/DynamicValidationEta.txt"),
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint)
  Modelica.Thermal.HeatTransfer.Celsius.ToKelvin toKelvinEta
  Utilities.Psychrometrics.ToTotalAir toTotAirEta
  Modelica.Blocks.Sources.CombiTimeTable bondaryOda(
    tableOnFile=true,
    tableName="Boundary",
    fileName=ModelicaServices.ExternalReferences.loadResource("modelica://AixLib/Resources/Fluid/MembraneBasedEnthalpyExchanger/DynamicValidationOda.txt"),
    columns={2,3,4},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint)
  Modelica.Thermal.HeatTransfer.Celsius.ToKelvin toKelvinOda
  Utilities.Psychrometrics.ToTotalAir toTotAirOda
  Modelica.Blocks.Sources.CombiTimeTable Results(
    tableOnFile=true,
    columns={2,3,4},
    tableName="Result",
    fileName=ModelicaServices.ExternalReferences.loadResource("modelica://AixLib/Resources/Fluid/MembraneBasedEnthalpyExchanger/DynamicValidationResult.txt"),
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint)
  Modelica.Blocks.Interaction.Show.RealValue T_Sup_exp
  Modelica.Blocks.Interaction.Show.RealValue X_Sup_exp
  Modelica.Blocks.Interaction.Show.RealValue V_flow_exp
  Modelica.Blocks.Math.Gain m3hEta(k=3600)
  Modelica.Blocks.Math.Gain m3hOda(k=3600)
  Utilities.Psychrometrics.ToDryAir toDryAirSup
  Modelica.Blocks.Sources.RealExpression sensibleEfficiency(
    y=min(1,max(0,(senTemSup.T-senTemOda.T)/(senTemEta.T-senTemOda.T))))
  Modelica.Blocks.Sources.RealExpression latentEfficiency(
    y=min(1,max(0,(senMasFraSup.X-senMasFraOda.X)/(
      senMasFraEta.X-senMasFraOda.X))))
  Modelica.Blocks.Sources.RealExpression Permeability(
    y=A*abs(senMasFraEta.X-senMasFraOda.X)+B)
  Movers.FlowControlled_dp fan(
    redeclare package Medium = Media.Air,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    dp_start=120,
    dp_nominal=dp_nominal)
  Controls.Continuous.LimPID conPID(
    controllerType=Modelica.Blocks.Types.SimpleController.PI,
    k=10,
    Ti=120,
    yMax=160)
  Movers.FlowControlled_dp fan1(
    redeclare package Medium = Media.Air,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    dp_start=120,
    dp_nominal=dp_nominal)
  Controls.Continuous.LimPID conPID1(
    controllerType=Modelica.Blocks.Types.SimpleController.PI,
    k=10,
    Ti=120,
    yMax=160)
equation
  connect(senMasFraEta.port_b,senTemEta. port_a)
  connect(souEta.ports[1], senMasFraEta.port_a)
  connect(senTemEta.port_b, senVolFloEta.port_a)
  connect(senTemEha.port_b,senMasFraEha. port_a)
  connect(enthalpyExchanger.port_b1, senTemEha.port_a)
  connect(senMasFraEha.port_b, sinEha.ports[1])
  connect(senMasFraOda.port_b,senTemOda. port_a)
  connect(souOda.ports[1], senMasFraOda.port_a)
  connect(senTemOda.port_b, senVolFloOda.port_a)
  connect(senTemSup.port_b,senMasFraSup. port_a)
  connect(senMasFraSup.port_b, sinSup.ports[1])
  connect(enthalpyExchanger.port_b2, senTemSup.port_a)
  connect(toKelvinEta.Kelvin, souEta.T_in)
  connect(toTotAirEta.XiTotalAir, souEta.Xi_in[1])
  connect(bondaryEta.y[1], toKelvinEta.Celsius)
  connect(bondaryEta.y[2], toTotAirEta.XiDry)
  connect(bondaryOda.y[1], toKelvinOda.Celsius)
  connect(toKelvinOda.Kelvin, souOda.T_in)
  connect(bondaryOda.y[2], toTotAirOda.XiDry)
  connect(toTotAirOda.XiTotalAir, souOda.Xi_in[1])
  connect(Results.y[3],V_flow_exp. numberPort)
  connect(Results.y[1], T_Sup_exp.numberPort)
  connect(Results.y[2], X_Sup_exp.numberPort)
  connect(senVolFloEta.V_flow, m3hEta.u)
  connect(senVolFloOda.V_flow, m3hOda.u)
  connect(senMasFraSup.X, toDryAirSup.XiTotalAir)
  connect(Permeability.y, enthalpyExchanger.perMem)
  connect(fan.port_b, enthalpyExchanger.port_a2)
  connect(senVolFloOda.port_b, fan.port_a)
  connect(m3hOda.y, conPID.u_m)
  connect(conPID.y, fan.dp_in)
  connect(Results.y[3], conPID.u_s)
  connect(fan1.port_b, enthalpyExchanger.port_a1)
  connect(senVolFloEta.port_b, fan1.port_a)
  connect(m3hEta.y, conPID1.u_m)
  connect(Results.y[3], conPID1.u_s)
  connect(conPID1.y, fan1.dp_in)
end DynamicValidation;


within AixLib.Fluid.MassExchangers.MembraneBasedEnthalpyExchangers.Validation;
model StaticValidation
  "example containing validation for static behaviour of membrane-based enthalpy exchanger"
  extends Modelica.Icons.Example;

  // parameters (for better change on the fly)
  parameter Integer nParallel=184
    "Number of identical parallel flow devices";
  parameter Integer n = 15
    "number of discrete segments";
  parameter Modelica.Units.SI.Length heightDuct=0.00225 "height of duct";
  parameter Modelica.Units.SI.Length widthDuct=0.305 "width of duct";
  parameter Modelica.Units.SI.Length lengthDuct=0.34
    "length of duct in flow direction";
  parameter Real aspRatCroToTot = 0.25 "aspect ratio of cross flow";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=400/3600*1.18
    "nominal mass flow rate";
  parameter Modelica.Units.SI.Pressure dp_nominal=119.5 "nominal pressure drop";
  parameter Modelica.Units.SI.Length thicknessMem=110E-6
    "thickness of membrane";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpMem=1900
    "mass weighted heat capacity of membrane";
  parameter Modelica.Units.SI.ThermalConductivity lambdaMem=0.24
    "thermal conductivity of membrane";
  parameter Modelica.Units.SI.Density rhoMem=920 "density of membrane";
  parameter Modelica.Units.SI.Temperature T_start=283.15
    "membrane temperature start value";
  parameter Modelica.Units.SI.Temperature dT=10
    "Start value for port_b.T - port_a.T";
  parameter Modelica.Units.SI.Pressure p_start=1200.0
    "membrane concentration start value";
  parameter Modelica.Units.SI.Pressure dp=100.0
    "Start value for concentration gradient in membrane";
  parameter Modelica.Units.SI.MassFlowRate m_flow_start=m_flow_nominal
    "Start value for mass flow rate";
  parameter Real A=5.38E7 "constant A of linear dependency equation for permeability";
  parameter Real B=4.64E5 "constant B of linear dependency equation for permeability";

  EnthalpyExchanger enthalpyExchanger(
    redeclare package Medium = Media.Air,
    n=n,
    nParallel=nParallel,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    lengthDuct=lengthDuct,
    heightDuct=heightDuct,
    widthDuct=widthDuct,
    couFloArr=false,
    aspRatCroToTot=aspRatCroToTot,
    uniWalTem=true,
    local=true,
    nWidth=30,
    recDuct=true,
    m_flow_nominal=m_flow_nominal,
    dp_nominal=dp_nominal,
    thicknessMem=thicknessMem,
    cpMem=cpMem,
    lambdaMem=lambdaMem,
    rhoMem=rhoMem,
      useConPer=false,
    T_start_m=T_start,
    dT_start=dT,
    p_start_m=p_start,
    dp_start=dp)
  AixLib.Fluid.Sources.Boundary_pT souEta(
    redeclare package Medium = Media.Air,
    use_Xi_in=true,
    nPorts=1,
    use_T_in=true,
    T=294.0495)
  Sensors.MassFractionTwoPort senMasFraEta(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    X_start=0.008)
  Sensors.TemperatureTwoPort senTemEta(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    T_start=293.15)
  Sensors.VolumeFlowRate senVolFloEta(
    redeclare package Medium = Media.Air,
    m_flow_nominal=0.2)
  Sensors.TemperatureTwoPort senTemEha(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15)
  Sensors.MassFractionTwoPort senMasFraEha(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15)
  Sources.Boundary_pT sinEha(
    redeclare package Medium = Media.Air,
    nPorts=1)
  Sources.Boundary_pT souOda(
    redeclare package Medium = Media.Air,
    use_Xi_in=true,
    nPorts=1,
    use_p_in=false,
    use_T_in=true,
    T=294.0495)
  Sensors.MassFractionTwoPort senMasFraOda(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    X_start=0.002)
  Sensors.TemperatureTwoPort senTemOda(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=15,
    T_start=283.15)
  Sensors.VolumeFlowRate senVolFloOda(
    redeclare package Medium = Media.Air,
    m_flow_nominal=0.2)
  Sources.Boundary_pT sinSup(
    redeclare package Medium = Media.Air,
    nPorts=1)
  Sensors.MassFractionTwoPort senMasFraSup(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=6)
  Sensors.TemperatureTwoPort senTemSup(
    redeclare package Medium = Media.Air,
    m_flow_nominal=m_flow_nominal,
    tau=20)
  Modelica.Blocks.Sources.CombiTimeTable bondaryEta(
    tableOnFile=true,
    tableName="Boundary",
    columns={2,3,4},
    fileName=ModelicaServices.ExternalReferences.loadResource("modelica://AixLib/Resources/Fluid/MembraneBasedEnthalpyExchanger/StaticValidationEta.txt"),
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    timeScale=2)
  Utilities.Psychrometrics.ToTotalAir toTotAirEta
  Modelica.Blocks.Sources.CombiTimeTable bondaryOda(
    tableOnFile=true,
    tableName="Boundary",
    fileName=ModelicaServices.ExternalReferences.loadResource("modelica://AixLib/Resources/Fluid/MembraneBasedEnthalpyExchanger/StaticValidationOda.txt"),
    columns={2,3,4},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    timeScale=2)
  Utilities.Psychrometrics.ToTotalAir toTotAirOda
  Modelica.Blocks.Sources.CombiTimeTable Results(
    tableOnFile=true,
    columns={2,3,4,5},
    tableName="Result",
    fileName=ModelicaServices.ExternalReferences.loadResource("modelica://AixLib/Resources/Fluid/MembraneBasedEnthalpyExchanger/StaticValidationResult.txt"),
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint,
    timeScale=2)
  Modelica.Blocks.Interaction.Show.RealValue T_Sup_exp
  Modelica.Blocks.Interaction.Show.RealValue X_Sup_exp
  Modelica.Blocks.Interaction.Show.RealValue V_flow_exp
  Modelica.Blocks.Math.Gain m3hEta(k=3600)
  Modelica.Blocks.Math.Gain m3hOda(k=3600)
  Utilities.Psychrometrics.ToDryAir toDryAirSup
  Modelica.Blocks.Sources.RealExpression sensibleEfficiency(
    y=min(1,max(0,(senTemSup.T-senTemOda.T)/(senTemEta.T-senTemOda.T))))
  Modelica.Blocks.Sources.RealExpression latentEfficiency(
    y=min(1,max(0,(senMasFraSup.X-senMasFraOda.X)/
      (senMasFraEta.X-senMasFraOda.X))))
  Modelica.Blocks.Sources.RealExpression Permeability(
    y=A*abs(senMasFraEta.X-senMasFraOda.X)+B)
  Movers.FlowControlled_dp fan(
    redeclare package Medium = Media.Air,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    dp_start=120,
    dp_nominal=dp_nominal)
  Controls.Continuous.LimPID conPID(
    controllerType=Modelica.Blocks.Types.SimpleController.PI,
    k=10,
    Ti=120,
    yMax=160)
  Movers.FlowControlled_dp fan1(
    redeclare package Medium = Media.Air,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    dp_start=120,
    dp_nominal=dp_nominal)
  Controls.Continuous.LimPID conPID1(
    controllerType=Modelica.Blocks.Types.SimpleController.PI,
    k=10,
    Ti=120,
    yMax=160)
equation
  connect(senMasFraEta.port_b,senTemEta. port_a)
  connect(souEta.ports[1], senMasFraEta.port_a)
  connect(senTemEta.port_b, senVolFloEta.port_a)
  connect(senTemEha.port_b,senMasFraEha. port_a)
  connect(enthalpyExchanger.port_b1, senTemEha.port_a)
  connect(senMasFraEha.port_b, sinEha.ports[1])
  connect(senMasFraOda.port_b,senTemOda. port_a)
  connect(souOda.ports[1], senMasFraOda.port_a)
  connect(senTemOda.port_b, senVolFloOda.port_a)
  connect(senTemSup.port_b,senMasFraSup. port_a)
  connect(senMasFraSup.port_b, sinSup.ports[1])
  connect(enthalpyExchanger.port_b2, senTemSup.port_a)
  connect(toTotAirEta.XiTotalAir, souEta.Xi_in[1])
  connect(bondaryEta.y[2], toTotAirEta.XiDry)
  connect(bondaryOda.y[2], toTotAirOda.XiDry)
  connect(toTotAirOda.XiTotalAir, souOda.Xi_in[1])
  connect(Results.y[3],V_flow_exp. numberPort)
  connect(Results.y[1], T_Sup_exp.numberPort)
  connect(Results.y[2], X_Sup_exp.numberPort)
  connect(senVolFloEta.V_flow, m3hEta.u)
  connect(senVolFloOda.V_flow, m3hOda.u)
  connect(senMasFraSup.X, toDryAirSup.XiTotalAir)
  connect(Permeability.y, enthalpyExchanger.perMem)
  connect(fan.port_b, enthalpyExchanger.port_a2)
  connect(senVolFloOda.port_b, fan.port_a)
  connect(m3hOda.y, conPID.u_m)
  connect(conPID.y, fan.dp_in)
  connect(Results.y[3], conPID.u_s)
  connect(fan1.port_b, enthalpyExchanger.port_a1)
  connect(senVolFloEta.port_b, fan1.port_a)
  connect(m3hEta.y, conPID1.u_m)
  connect(Results.y[3], conPID1.u_s)
  connect(conPID1.y, fan1.dp_in)
  connect(bondaryOda.y[1], souOda.T_in)
  connect(bondaryEta.y[1], souEta.T_in)
end StaticValidation;


Zero flow test for constants effectiveness mass exchanger. This model tests whether
ConstantEffectiveness
works correctly at zero flow if one stream is zero.

within AixLib.Fluid.MassExchangers.Validation;
model ConstantEffectivenessZeroFlow
  "Zero flow test for constants effectiveness mass exchanger"
  extends AixLib.Fluid.MassExchangers.Examples.ConstantEffectiveness(
    PSin_1(
      height=0,
      offset=1E5), PIn(height=0, offset=101325));
end ConstantEffectivenessZeroFlow;


Zero flow test for constants effectiveness mass exchanger. This model tests whether
AixLib.Fluid.MassExchangers.ConstantEffectiveness
works correctly at zero flow if both streams are zero.

within AixLib.Fluid.MassExchangers.Validation;
model ConstantEffectivenessZeroFlowBothStreams
  "Zero flow test for constants effectiveness mass exchanger"
  extends AixLib.Fluid.MassExchangers.Examples.ConstantEffectiveness(
    PSin_1(
      height=0,
      offset=1E5),
    PIn(
      height=0,
      offset=101325));
end ConstantEffectivenessZeroFlowBothStreams;


Validation examples

within AixLib.Fluid.MassExchangers;
package Validation "Validation examples"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


Medium in the component

within AixLib.Fluid.MixingVolumes;
model HydraulicSeparator
  import Modelica.Blocks.Math;
  replaceable package Medium =
      Modelica.Media.Interfaces.PartialMedium "Medium in the component"
  parameter Boolean allowFlowReversal=true;

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

    ///////////////////////////////////////////////////////////////////////////
    //Geometric parameters                                                   //
    ///////////////////////////////////////////////////////////////////////////
  parameter Modelica.Units.SI.VolumeFlowRate pumpMaxVolumeFlow
    "Maximum VolumeFlowRate of either primary or secondary Pump";
  parameter Modelica.Units.SI.Velocity vmaxExchange=0.2
    "Maximum velocity of the exchange-flow between top and bottom of the Hydraulic Separator";
  parameter Modelica.Units.SI.Diameter DFlange "Diameter of the flanges";
  parameter Modelica.Units.SI.Diameter D=sqrt(pumpMaxVolumeFlow*4/(Modelica.Constants.pi
      *vmaxExchange))
    "Diameter of the main-body (Calculated by the model to not exceed vmaxExchang)";

    ///////////////////////////////////////////////////////////////////////////
    //Initialization of temperatures                                         //
    ///////////////////////////////////////////////////////////////////////////
  parameter Modelica.Units.SI.Temperature T_top=293.15
    "Initial temperature in the top"
  parameter Modelica.Units.SI.Temperature T_bottom=293.15
    "Initial temperature in the bottom"

    ///////////////////////////////////////////////////////////////////////////
    //Measurement of water exchanged between primary and secondary circuit   //
    ///////////////////////////////////////////////////////////////////////////
  Modelica.Blocks.Interfaces.RealOutput waterExchange
    "Measurement of water exchanged between primary and secondary circuit"
  Modelica.Fluid.Sensors.MassFlowRate massFlowRate(redeclare package Medium =
        Medium)

    ///////////////////////////////////////////////////////////////////////////
    //Ports/ Flanges                                                         //
    ///////////////////////////////////////////////////////////////////////////
  Modelica.Fluid.Interfaces.FluidPort_a port_a_primary(redeclare package Medium =
        Medium) "Top-flange primary circuit"
  Modelica.Fluid.Interfaces.FluidPort_a port_a_secondary(redeclare package Medium =
               Medium) "Bottom-flange secondary circuit"
  Modelica.Fluid.Interfaces.FluidPort_b port_b_secondary(redeclare package Medium =
               Medium) "Top-flange secondary circuit"
  Modelica.Fluid.Interfaces.FluidPort_b port_b_primary(redeclare package Medium =
        Medium) "Bottom-flange primary circuit"

    ///////////////////////////////////////////////////////////////////////////
    //Pipes including main body and flanges                                  //
    ///////////////////////////////////////////////////////////////////////////
  Modelica.Fluid.Pipes.StaticPipe primaryFlow(
    diameter=DFlange,
    length=0.05,
    redeclare package Medium = Medium,
    allowFlowReversal=allowFlowReversal)
  Modelica.Fluid.Pipes.StaticPipe primaryReturn(
    diameter=DFlange,
    length=0.05,
    redeclare package Medium = Medium,
    allowFlowReversal=allowFlowReversal)

  Modelica.Fluid.Pipes.StaticPipe pipe4(diameter=D, length=1.5*D,
    redeclare package Medium = Medium,
    height_ab=1.5*D)
  Modelica.Fluid.Pipes.StaticPipe pipe5(length=1.5*D,
    redeclare package Medium = Medium,
    height_ab=1.5*D,
    diameter=D)
  Modelica.Fluid.Pipes.DynamicPipe      secondaryFlow(
    diameter=DFlange,
    length=0.05,
    redeclare package Medium = Medium,
    use_T_start=true,
    T_start=T_bottom,
    allowFlowReversal=allowFlowReversal,
    use_HeatTransfer=true)
  Modelica.Fluid.Pipes.DynamicPipe      secondaryReturn(
    diameter=DFlange,
    length=0.05,
    redeclare package Medium = Medium,
    use_T_start=true,
    T_start=T_top,
    allowFlowReversal=allowFlowReversal,
    use_HeatTransfer=true)
    ///////////////////////////////////////////////////////////////////////////
    //Thermal Conductor to simulate heat exchange between layers when there  //
    //is no exchange of mass between primary and secondary circuit           //
    ///////////////////////////////////////////////////////////////////////////
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor thermalConductor(G=0.59*(D
        ^2/4*Modelica.Constants.pi)/(3*D))

    ///////////////////////////////////////////////////////////////////////////
    //Volumes determining time scale of dynamic behaviour                    //
    ///////////////////////////////////////////////////////////////////////////
  MixingVolume                        volume2(
    redeclare package Medium = Medium,
    nPorts=2,
    T_start=T_bottom,
    V=(Modelica.Constants.pi/4)*D*D*DFlange*0.5,
    m_flow_nominal=m_flow_nominal)
  MixingVolume                        volume1(
    redeclare package Medium = Medium,
    nPorts=2,
    T_start=T_bottom,
    V=(Modelica.Constants.pi/4)*D*D*DFlange*0.5,
    m_flow_nominal=m_flow_nominal)

equation
  connect(port_a_primary, primaryFlow.port_a)
  connect(port_b_primary, primaryReturn.port_b)
  connect(massFlowRate.m_flow, waterExchange)
  connect(massFlowRate.port_b, pipe5.port_a)
  connect(pipe4.port_b, massFlowRate.port_a)
  connect(secondaryReturn.port_b, port_b_secondary)
  connect(secondaryFlow.port_a, port_a_secondary)
  connect(secondaryFlow.port_b, pipe4.port_a)
  connect(volume1.ports[1], pipe4.port_a)
  connect(primaryReturn.port_a, volume1.ports[2])
  connect(primaryFlow.port_b, volume2.ports[1])
  connect(volume2.ports[2], secondaryReturn.port_a)
  connect(pipe5.port_b, secondaryReturn.port_a)
  connect(secondaryReturn.heatPorts[1], thermalConductor.port_b)
  connect(secondaryFlow.heatPorts[1], thermalConductor.port_a)
end HydraulicSeparator;


Mixing volume with inlet and outlet ports (flow reversal is allowed). This model represents an instantaneously mixed volume.
Potential and kinetic energy at the port are neglected,
and there is no pressure drop at the ports.
The volume can exchange heat through its heatPort.

within AixLib.Fluid.MixingVolumes;
model MixingVolume
  "Mixing volume with inlet and outlet ports (flow reversal is allowed)"
  extends AixLib.Fluid.MixingVolumes.BaseClasses.PartialMixingVolume(
    final initialize_p = not Medium.singleState,
    steBal(final use_C_flow = use_C_flow),
    dynBal(final use_C_flow = use_C_flow));

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

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort(
    T(start=T_start)) "Heat port for heat exchange with the control volume"

  Modelica.Blocks.Interfaces.RealInput[Medium.nC] C_flow if use_C_flow
    "Trace substance mass flow rate added to the medium"

equation
  connect(heaFloSen.port_a, heatPort)
  connect(C_flow, steBal.C_flow)
  connect(C_flow, dynBal.C_flow)
end MixingVolume;


Mixing volume with heat port for latent heat exchange, to be used if moisture is added or removed. Model for an ideally mixed fluid volume and the ability
to store mass and energy. The volume is fixed,
and latent and sensible heat can be exchanged.

within AixLib.Fluid.MixingVolumes;
model MixingVolumeMoistAir
  "Mixing volume with heat port for latent heat exchange, to be used if moisture is added or removed"
  extends AixLib.Fluid.MixingVolumes.BaseClasses.PartialMixingVolume(
    dynBal(
      final use_mWat_flow = true,
      final use_C_flow = use_C_flow),
    steBal(final use_mWat_flow = true,
      final use_C_flow = use_C_flow),
    final initialize_p = not Medium.singleState);

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

  Modelica.Blocks.Interfaces.RealInput mWat_flow(final quantity="MassFlowRate",
                                                 final unit = "kg/s")
    "Water flow rate added into the medium"
  Modelica.Blocks.Interfaces.RealOutput X_w(final unit="kg/kg")
    "Species composition of medium"

  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort(
    T(start=T_start))
    "Heat port for sensible plus latent heat exchange with the control volume"

  Modelica.Blocks.Interfaces.RealInput[Medium.nC] C_flow if use_C_flow
    "Trace substance mass flow rate added to the medium"

protected
  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";

  Modelica.Blocks.Sources.RealExpression XLiq(y=s*Xi)
    "Species composition of the medium"
equation
  connect(mWat_flow, steBal.mWat_flow)
  connect(mWat_flow, dynBal.mWat_flow)
  connect(XLiq.y, X_w)
  connect(heaFloSen.port_a, heatPort)
  connect(C_flow, steBal.C_flow)
  connect(C_flow, dynBal.C_flow)
end MixingVolumeMoistAir;


Package with mixing volumes

within AixLib.Fluid;
package MixingVolumes "Package with mixing volumes"
  extends Modelica.Icons.VariantsPackage;
end MixingVolumes;


Mixing volume with heat and moisture port and initialize_p not set to final. Mixing volume with a heat port.

within AixLib.Fluid.MixingVolumes.BaseClasses;
model MixingVolumeHeatMoisturePort
  "Mixing volume with heat and moisture port and initialize_p not set to final"
  extends AixLib.Fluid.MixingVolumes.BaseClasses.PartialMixingVolume(
  dynBal(
      final use_mWat_flow = true),
    steBal(
      final use_mWat_flow = true));

   Modelica.Blocks.Interfaces.RealInput mWat_flow(final quantity="MassFlowRate",
                                                 final unit = "kg/s")
    "Water flow rate added into the medium"
  Modelica.Blocks.Interfaces.RealOutput X_w(final unit="kg/kg")
    "Species composition of medium"

    Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort(
      T(start=T_start)) "Heat port for heat exchange with the control volume"
protected
  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";

  Modelica.Blocks.Sources.RealExpression XLiq(y=s*Xi)
    "Species composition of the medium"

equation
  connect(mWat_flow, steBal.mWat_flow)
  connect(mWat_flow, dynBal.mWat_flow)
  connect(XLiq.y, X_w)
  connect(heaFloSen.port_a, heatPort)
end MixingVolumeHeatMoisturePort;


Mixing volume with heat port and initialize_p not set to final. Mixing volume with a heat port.

within AixLib.Fluid.MixingVolumes.BaseClasses;
model MixingVolumeHeatPort
  "Mixing volume with heat port and initialize_p not set to final"
  extends AixLib.Fluid.MixingVolumes.BaseClasses.PartialMixingVolume;
    Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort(
      T(start=T_start)) "Heat port for heat exchange with the control volume"
equation
    connect(heaFloSen.port_a, heatPort)
end MixingVolumeHeatPort;


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


within AixLib.Fluid.MixingVolumes.BaseClasses;
model PartialMixingVolume
  "Partial mixing volume with inlet and outlet ports (flow reversal is allowed)"

  extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations;
  parameter Boolean initialize_p = not Medium.singleState
    "= true to set up initial equations for pressure"

  // We set prescribedHeatFlowRate=false so that the
  // volume works without the user having to set this advanced parameter,
  // but to get high robustness, a user can set it to the appropriate value
  // as described in the info section.
  constant Boolean prescribedHeatFlowRate = false
    "Set to true if the model has a prescribed heat flow at its heatPort. If the heat flow rate at the heatPort is only based on temperature difference, then set to false";

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

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal(min=0)
    "Nominal mass flow rate"
  // Port definitions
  parameter Integer nPorts=0 "Number of ports"
  parameter Modelica.Units.SI.MassFlowRate m_flow_small(min=0) = 1E-4*abs(
    m_flow_nominal) "Small mass flow rate for regularization of zero flow"
  parameter Boolean allowFlowReversal = true
    "= false to simplify equations, assuming, but not enforcing, no flow reversal. Used only if model has two ports."
  parameter Modelica.Units.SI.Volume V "Volume";
  Modelica.Fluid.Vessels.BaseClasses.VesselFluidPorts_b ports[nPorts](
      redeclare each package Medium = Medium,
      each h_outflow(nominal=Medium.h_default),
      each Xi_outflow(each nominal=0.01)
      ) "Fluid inlets and outlets"

  Medium.Temperature T = Medium.temperature_phX(
    p=p,
    h=hOut_internal,
    X=if Medium.reducedX then cat(1, Xi, {1-sum(Xi)}) else Xi)
    "Temperature of the fluid";
  Modelica.Blocks.Interfaces.RealOutput U(unit="J")
    "Internal energy of the component";
  Modelica.Units.SI.Pressure p=if nPorts > 0 then ports[1].p else p_start
    "Pressure of the fluid";
  Modelica.Blocks.Interfaces.RealOutput m(unit="kg") "Mass of the component";
  Modelica.Units.SI.MassFraction Xi[Medium.nXi]=XiOut_internal
    "Species concentration of the fluid";
  Modelica.Blocks.Interfaces.RealOutput mXi[Medium.nXi](each unit="kg")
    "Species mass of the component";
  Medium.ExtraProperty C[Medium.nC](nominal=C_nominal) = COut_internal
    "Trace substance mixture content";
  Modelica.Blocks.Interfaces.RealOutput mC[Medium.nC](each unit="kg")
    "Trace substance mass of the component";

protected
  AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation steBal(
    final simplify_mWat_flow = simplify_mWat_flow,
    redeclare final package Medium=Medium,
    final m_flow_nominal = m_flow_nominal,
    final allowFlowReversal = allowFlowReversal,
    final m_flow_small = m_flow_small,
    final prescribedHeatFlowRate=prescribedHeatFlowRate,
    hOut(start=Medium.specificEnthalpy_pTX(
                 p=p_start,
                 T=T_start,
                 X=X_start)))
      if useSteadyStateTwoPort "Model for steady-state balance if nPorts=2"
  AixLib.Fluid.Interfaces.ConservationEquation dynBal(
    final simplify_mWat_flow = simplify_mWat_flow,
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final massDynamics=massDynamics,
    final p_start=p_start,
    final T_start=T_start,
    final X_start=X_start,
    final C_start=C_start,
    final C_nominal=C_nominal,
    final fluidVolume = V,
    final initialize_p = initialize_p,
    m(start=V*rho_start),
    nPorts=nPorts,
    final mSenFac=mSenFac)
      if not useSteadyStateTwoPort "Model for dynamic energy balance"

  // Density at start values, used to compute initial values and start guesses
  parameter Modelica.Units.SI.Density rho_start=Medium.density(
    state=state_start) "Density, used to compute start and guess values";
  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.Density rho_default=Medium.density(
    state=state_default) "Density, used to compute fluid mass";
  final parameter Medium.ThermodynamicState state_start = Medium.setState_pTX(
      T=T_start,
      p=p_start,
      X=X_start[1:Medium.nXi]) "Medium state at start values";
  // See info section for why prescribedHeatFlowRate is used here.
  // The condition below may only be changed if StaticTwoPortConservationEquation
  // contains a correct solution for all foreseeable parameters/inputs.
  // See Buildings, issue 282 for a discussion.
  final parameter Boolean useSteadyStateTwoPort=(nPorts == 2) and
      (prescribedHeatFlowRate or (not allowFlowReversal)) and (
      energyDynamics == Modelica.Fluid.Types.Dynamics.SteadyState) and (
      massDynamics == Modelica.Fluid.Types.Dynamics.SteadyState) and (
      substanceDynamics == Modelica.Fluid.Types.Dynamics.SteadyState) and (
      traceDynamics == Modelica.Fluid.Types.Dynamics.SteadyState)
    "Flag, true if the model has two ports only and uses a steady state balance"
  // Outputs that are needed to assign the medium properties
  Modelica.Blocks.Interfaces.RealOutput hOut_internal(unit="J/kg")
    "Internal connector for leaving temperature of the component";
  Modelica.Blocks.Interfaces.RealOutput XiOut_internal[Medium.nXi](each unit="1")
    "Internal connector for leaving species concentration of the component";
  Modelica.Blocks.Interfaces.RealOutput COut_internal[Medium.nC](each unit="1")
    "Internal connector for leaving trace substances of the component";

  Modelica.Thermal.HeatTransfer.Sources.PrescribedTemperature preTem(
    port(T(start=T_start)))
    "Port temperature"
  Modelica.Blocks.Sources.RealExpression portT(y=T) "Port temperature"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heaFloSen(
    port_a(T(start=T_start)),
    port_b(T(start=T_start)))
    "Heat flow sensor"
equation
  ///////////////////////////////////////////////////////////////////////////
  // asserts
  if not allowFlowReversal then
    assert(ports[1].m_flow > -m_flow_small,
  "In " + getInstanceName() + ": Model has flow reversal,
  but the parameter allowFlowReversal is set to false.
  m_flow_small    = " + String(m_flow_small) + "
  ports[1].m_flow = " + String(ports[1].m_flow) + "
");
  end if;
  // Actual definition of port variables.
  //
  // If the model computes the energy and mass balances as steady-state,
  // and if it has only two ports,
  // then we use the same base class as for all other steady state models.
  if useSteadyStateTwoPort then
  connect(steBal.port_a, ports[1])

  connect(steBal.port_b, ports[2])
    U=0;
    mXi=zeros(Medium.nXi);
    m=0;
    mC=zeros(Medium.nC);
    connect(hOut_internal,  steBal.hOut);
    connect(XiOut_internal, steBal.XiOut);
    connect(COut_internal,  steBal.COut);
  else
      connect(dynBal.ports, ports)
    connect(U,dynBal.UOut);
    connect(mXi,dynBal.mXiOut);
    connect(m,dynBal.mOut);
    connect(mC,dynBal.mCOut);
    connect(hOut_internal,  dynBal.hOut);
    connect(XiOut_internal, dynBal.XiOut);
    connect(COut_internal,  dynBal.COut);
  end if;

  connect(portT.y, preTem.T)
  connect(heaFloSen.port_b, preTem.port)
  connect(heaFloSen.Q_flow, steBal.Q_flow)
  connect(heaFloSen.Q_flow, dynBal.Q_flow)
else
  hOut = port_b.h_outflow;
end if;

Hence, for allowFlowReversal=true, if hOut
were to be used to compute the temperature that
drives heat transfer such as by conduction,
then the heat transfer would depend on upstream and the downstream
temperatures for small mass flow rates.
This can give wrong results. Consider for example a mass flow rate that is positive
but very close to zero. Suppose the upstream temperature is 20°C,
the downstream temperature is 10°C, and the heat port is
connected through a heat conductor to a boundary condition of 20°C.
Then, hOut = (port_b.h_outflow + port_a.h_outflow)/2 and hence
the temperature heatPort.T
is 15°C. Therefore, heat is added to the component.
As the mass flow rate is by assumption very small, the fluid that leaves the component
will have a very high temperature, violating the 2nd law.
To avoid this situation, if
prescribedHeatFlowRate=false, then the model

AixLib.Fluid.Interfaces.ConservationEquation
is used instead of

AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation.

For simple models that uses this model, see

AixLib.Fluid.MixingVolumes.

", revisions="

June 18, 2024, by Michael Wetter:

Added start and nominal attributes
to avoid warnings in OpenModelica due to conflicting values.

This is for IBPSA, #1890.

October 24, 2022, by Michael Wetter:

Improved conversion from Xi to X so that it also works
with media that have reducedX=true.

See #1650.

September 18, 2020, by Michael Wetter:

Set start value for steBal.hOut so that T_start
can be used which is not known in that instance.

See #1397.

February 21, 2020, by Michael Wetter:

Changed icon to display its operating state.

This is for
#1294.

October 30, 2019 by Filip Jorissen:

Added getInstanceName() to flow
reversal check.
This if or
issue 1228.

October 19, 2017, by Michael Wetter:

Changed initialization of pressure from a constant to a parameter.

Removed partial keyword as this model is not partial.

Moved C_flow and use_C_flow to child classes.

This is for
Buildings, issue 1013.

April 11, 2017, by Michael Wetter:

Moved heat port to the extending classes to provide better comment.
Otherwise, the mixing volume without water input would have a comment
that says latent heat can be added at this port.

Removed blocks QSen_flow and
QLat_flow.

This is for issue
Buildings #704.

February 19, 2016 by Filip Jorissen:

Added outputs U, m, mXi, mC for being able to
check conservation of quantities.
This if or
issue 247.

January 22, 2016 by Michael Wetter:

Updated model to use the new parameter use_mWat_flow
rather than sensibleOnly.

January 17, 2016, by Michael Wetter:

Removed protected block masExc as
this revision introduces a conditional connector for the
moisture flow rate in the energy and mass balance models.
This change was done to use the same modeling concept for the
moisture input as is used for the trace substance input.

December 2, 2015, by Filip Jorissen:

Added conditional input C_flow for
handling trace substance insertions.

July 17, 2015, by Michael Wetter:

Added constant simplify_mWat_flow to remove dependencies of the pressure drop
calculation on the moisture balance.

July 1, 2015, by Filip Jorissen:

Set prescribedHeatFlowRate=prescribedHeatflowRate for

AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation.
This results in equations that are solved more easily.
See

issue 282 for a discussion.

June 9, 2015 by Michael Wetter:

Set start value for heatPort.T and changed
type of T to Medium.Temperature rather than
Modelica.Units.SI.Temperature
to avoid an
error because of conflicting start values if
AixLib.Fluid.Chillers.Carnot_y
is translated using pedantic mode in Dymola 2016.
This is for
#426.

June 5, 2015, by Michael Wetter:

Moved assignment of dynBal.U.start
from instance dynBal to the actual model implementation.
This is required for a pedantic model check in Dymola 2016.
It addresses

issue 266.

May 6, 2015, by Michael Wetter:

Improved documentation and changed the test

 final parameter Boolean useSteadyStateTwoPort=(nPorts == 2) and
 prescribedHeatFlowRate and ...

to

 final parameter Boolean useSteadyStateTwoPort=(nPorts == 2) and
 (prescribedHeatFlowRate or (not allowFlowReversal)) and ...

The reason is that if there is no flow reversal, then

AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation
computes hOut =  port_b.h_outflow;, and hence
it is correct to use hOut to compute
temperature-driven heat flow, such as by conduction or convection.
See also the model documentation.

This is for issue

#412.

February 5, 2015, by Michael Wetter:

Changed initalize_p from a parameter to a
constant. This is only required in finite volume models
of heat exchangers (to avoid consistent but redundant initial conditions)
and hence it should be set as a constant.

October 29, 2014, by Michael Wetter:

Made assignment of mFactor final, and changed computation of
density to use default medium states as are also used to compute the
specific heat capacity.

October 21, 2014, by Filip Jorissen:

Added parameter mFactor to increase the thermal capacity.

July 3, 2014, by Michael Wetter:

Added parameter initialize_p. This is required
to enable the coil models to initialize the pressure in the first
volume, but not in the downstream volumes. Otherwise,
the initial equations will be overdetermined, but consistent.
This change was done to avoid a long information message that appears
when translating models.

May 29, 2014, by Michael Wetter:

Removed undesirable annotation Evaluate=true.

February 11, 2014 by Michael Wetter:

Removed Q_flow and added QSen_flow.
This was done to clarify what is sensible and total heat flow rate
as part of the correction of issue
#197.

October 8, 2013 by Michael Wetter:

Removed propagation of show_V_flow
to instance steBal as it has no longer this parameter.

September 13, 2013 by Michael Wetter:

Renamed rho_nominal to rho_start
because this quantity is computed using start values and not
nominal values.

April 18, 2013 by Michael Wetter:

Removed the check of multiple connections to the same element
of a fluid port, as this check required the use of the deprecated
cardinality function.

February 7, 2012 by Michael Wetter:

Revised base classes for conservation equations in AixLib.Fluid.Interfaces.

September 17, 2011 by Michael Wetter:

Removed instance medium as this is already used in dynBal.
Removing the base properties led to 30% faster computing time for a solar thermal system
that contains many fluid volumes.

September 13, 2011 by Michael Wetter:

Changed in declaration of medium the parameter assignment
preferredMediumStates=true to
preferredMediumStates= not (energyDynamics == Modelica.Fluid.Types.Dynamics.SteadyState).
Otherwise, for a steady-state model, Dymola 2012 may differentiate the model to obtain T
as a state. See ticket Dynasim #13596.

July 26, 2011 by Michael Wetter:

Revised model to use new declarations from

AixLib.Fluid.Interfaces.LumpedVolumeDeclarations.

July 14, 2011 by Michael Wetter:

Added start values for mass and internal energy of dynamic balance
model.

May 25, 2011 by Michael Wetter:

Changed implementation of balance equation. The new implementation uses a different model if
exactly two fluid ports are connected, and in addition, the model is used as a steady-state
component. For this model configuration, the same balance equations are used as were used
for steady-state component models, i.e., instead of actualStream(...), the
inStream(...) formulation is used.
This changed required the introduction of a new parameter m_flow_nominal which
is used for smoothing in the steady-state balance equations of the model with two fluid ports.
This implementation also simplifies the implementation of

AixLib.Fluid.MixingVolumes.BaseClasses.PartialMixingVolumeWaterPort,
which now uses the same equations as this model.

Another revision was the removal of the parameter use_HeatTransfer as there is
no noticeable overhead in always having the heatPort connector present.

July 30, 2010 by Michael Wetter:

Added nominal value for mC to avoid wrong trajectory
when concentration is around 1E-7.
See also
https://trac.modelica.org/Modelica/ticket/393.

February 7, 2010 by Michael Wetter:

Simplified model and its base classes by removing the port data
and the vessel area.
Eliminated the base class PartialLumpedVessel.

October 12, 2009 by Michael Wetter:

Changed base class to

AixLib.Fluid.MixingVolumes.BaseClasses.ClosedVolume.

"),
    Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100,
            100}}), graphics={
       Text(
          extent={{-60,-26},{56,-58}},
          textColor={255,255,255},
          textString="V=%V"),
        Text(
          extent={{-152,100},{148,140}},
          textString="%name",
          textColor={0,0,255}),
       Ellipse(
          extent={{-100,98},{100,-102}},
          lineColor={0,0,0},
          fillPattern=FillPattern.Sphere,
          fillColor=DynamicSelect({170,213,255}, min(1, max(0, (1-(T-273.15)/50)))*{28,108,200}+min(1, max(0, (T-273.15)/50))*{255,0,0})),
        Text(
          extent={{62,28},{-58,-22}},
          textColor={255,255,255},
          textString=DynamicSelect("", String(T-273.15, format=".1f")))}),
   __Dymola_LockedEditing="Model from IBPSA");
end PartialMixingVolume;


within AixLib.Fluid.MixingVolumes.BaseClasses.Validation;
model MixingVolumeHeatMoisturePort
  "Validation model for setting the initialization of the pressure for model with moisture port"
  extends AixLib.Fluid.MixingVolumes.BaseClasses.Validation.MixingVolumeHeatPortWater(
    redeclare package Medium = AixLib.Media.Air,
    redeclare AixLib.Fluid.MixingVolumes.BaseClasses.MixingVolumeHeatMoisturePort vol);

  Modelica.Blocks.Sources.Constant const[nEle](each k=0) "Zero input signal"
equation
  connect(const.y, vol.mWat_flow)
end MixingVolumeHeatMoisturePort;


within AixLib.Fluid.MixingVolumes.BaseClasses.Validation;
model MixingVolumeHeatPortAir
  "Validation model for setting the initialization of the pressure for air"
  extends AixLib.Fluid.MixingVolumes.BaseClasses.Validation.MixingVolumeHeatPortWater(
    redeclare package Medium = AixLib.Media.Air);
end MixingVolumeHeatPortAir;


within AixLib.Fluid.MixingVolumes.BaseClasses.Validation;
model MixingVolumeHeatPortWater
  "Validation model for setting the initialization of the pressure for water"
  extends Modelica.Icons.Example;

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

  parameter Integer nEle(min=2)= 3 "Number of volumes"

  replaceable AixLib.Fluid.MixingVolumes.BaseClasses.MixingVolumeHeatPort vol[nEle]
    constrainedby AixLib.Fluid.MixingVolumes.BaseClasses.MixingVolumeHeatPort(
    redeclare each package Medium = Medium,
    each energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final initialize_p={(i == 1 and not Medium.singleState) for i in 1:nEle},
    each m_flow_nominal=1,
    each V=1,
    each nPorts=2) "Mixing volume"

  AixLib.Fluid.FixedResistances.PressureDrop res(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1000) "Pressure drop"

  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium,
    nPorts=1)
    "Boundary condition"

  AixLib.Fluid.FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1000) "Pressure drop"

  AixLib.Fluid.Sources.Boundary_pT bou1(
    redeclare package Medium = Medium,
    nPorts=1)
    "Boundary condition"
equation
  connect(bou.ports[1], res.port_a)
  connect(res.port_b, vol[1].ports[1])
  for i in 1:nEle-1 loop
    connect(vol[i].ports[2], vol[i+1].ports[1]);
  end for;
  connect(res1.port_b, vol[nEle].ports[2])
  connect(bou1.ports[1], res1.port_a)
end MixingVolumeHeatPortWater;


Collection of validation models

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


Medium model for water

within AixLib.Fluid.MixingVolumes.Examples;
model HydraulicSeparator
  extends Modelica.Icons.Example;

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

  AixLib.Fluid.MixingVolumes.HydraulicSeparator hydraulicSeparator(DFlange=
        0.01,
    redeclare package Medium = Medium,
    pumpMaxVolumeFlow=0.03,
    m_flow_nominal=0.1)
  AixLib.Obsolete.Year2021.Fluid.Movers.Pump pump(
    V_flow(start=0.002),
    ControlStrategy=2,
    V_flow_max=12,
    Head_max=10,
    redeclare package Medium = Medium,
    m_flow_small=1e-4)
  Sources.Boundary_pT              boundary_p(
    nPorts=1,
    redeclare package Medium = Medium,
    p=150000)
  MixingVolume heatSource(
    redeclare package Medium = Medium,
    m_flow_small=1e-4,
    nPorts=2,
    m_flow_nominal=0.1,
    V=0.01) "Mixing volume for heat input"
  MixingVolume heatSink(
    redeclare package Medium = Medium,
    m_flow_small=1e-4,
    m_flow_nominal=0.1,
    nPorts=2,
    V=0.01)   "Mixing volume for heat sink"
  FixedResistances.PressureDrop       res1(
    redeclare package Medium = Medium,
    m_flow_nominal=0.1,
    dp_nominal=200) "Hydraulic resistance in primary circuit"
  AixLib.Fluid.Sensors.MassFlowRate  massFlowSensorPrim(redeclare package Medium =
               Medium)
  Modelica.Thermal.HeatTransfer.Sources.FixedHeatFlow fixedHeatFlow(
    Q_flow=1.6e3,
    T_ref=343.15,
    alpha=-0.5)
  AixLib.Obsolete.Year2021.Fluid.Movers.Pump pump1(
    ControlStrategy=2,
    V_flow_max=12,
    Head_max=10,
    redeclare package Medium = Medium,
    m_flow_small=1e-4)
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                        temperatureMixedTop(redeclare package Medium =
               Medium, m_flow_nominal=1)
  FixedResistances.PressureDrop       res2(
    redeclare package Medium = Medium,
    m_flow_nominal=0.1,
    dp_nominal=200) "Hydraulic resistance in secondary circuit"
  AixLib.Obsolete.Year2021.Fluid.Actuators.Valves.SimpleValve simpleValve(redeclare
      package                                                                               Medium = Medium, m_flow_small=1e-4)
  AixLib.Fluid.Sensors.MassFlowRate  massFlowSensor1Sec(redeclare package Medium =
               Medium)
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                        temperatureBottom(redeclare package Medium =
               Medium, m_flow_nominal=1)
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature fixedTemperature(
      T=273.15+20)
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor
    thermalConductor(G=1.6e3/8)
  Modelica.Blocks.Sources.BooleanExpression booleanExpression
  Modelica.Blocks.Sources.BooleanExpression booleanExpression1
  Modelica.Blocks.Sources.Step step(
    startTime=12000,
    height=0.5,
    offset=0.2)
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                        temperatureMixedBottom(redeclare
      package                                                                    Medium =
                       Medium, m_flow_nominal=1)
  AixLib.Fluid.Sensors.TemperatureTwoPort
                                        temperatureTop(redeclare package Medium =
        Medium, m_flow_nominal=1)
equation
  connect(pump.port_b, massFlowSensorPrim.port_a)
  connect(temperatureMixedTop.port_b, pump1.port_a)
  connect(pump1.port_b, res2.port_a)
  connect(res2.port_b, simpleValve.port_a)
  connect(massFlowSensor1Sec.port_b, temperatureBottom.port_a)
  connect(thermalConductor.port_a, fixedTemperature.port)
  connect(pump1.IsNight, booleanExpression1.y)
  connect(pump.IsNight, booleanExpression.y)
  connect(step.y, simpleValve.opening)
  connect(res1.port_a, temperatureMixedBottom.port_b)
  connect(res1.port_b, pump.port_a)
  connect(boundary_p.ports[1], pump.port_a)
  connect(temperatureTop.port_b, hydraulicSeparator.port_a_primary)
  connect(temperatureMixedTop.port_a, hydraulicSeparator.port_b_secondary)
  connect(hydraulicSeparator.port_b_primary, temperatureMixedBottom.port_a)
  connect(hydraulicSeparator.port_a_secondary, temperatureBottom.port_b)
  connect(massFlowSensorPrim.port_b, heatSource.ports[1])
  connect(heatSource.ports[2], temperatureTop.port_a)
  connect(fixedHeatFlow.port, heatSource.heatPort)
  connect(thermalConductor.port_b, heatSink.heatPort)
  connect(massFlowSensor1Sec.port_a, heatSink.ports[1])
  connect(simpleValve.port_b, heatSink.ports[2])
end HydraulicSeparator;


Test model for heat transfer to volume

within AixLib.Fluid.MixingVolumes.Examples;
model MixingVolumeHeatConduction "Test model for heat transfer to volume"
  extends Modelica.Icons.Example;
    package Medium = AixLib.Media.Air;
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor theCon(G=10)
    "Thermal conductor"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heaFlo
    "Heat flow sensor"
  Modelica.Thermal.HeatTransfer.Sources.FixedTemperature TAmb(T=293.15)
    "Ambient temperature"
  Modelica.Fluid.Sources.MassFlowSource_T sou(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=313.15,
    nPorts=1) "Flow source and sink"
  Modelica.Fluid.Sources.FixedBoundary bou(
    redeclare package Medium = Medium,
    T=303.15,
    nPorts=1) "Boundary condition"
  AixLib.Fluid.MixingVolumes.MixingVolume vol(
    V=1,
    redeclare package Medium = Medium,
    m_flow_nominal=0.01,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    allowFlowReversal=true,
    nPorts=2)
  Modelica.Blocks.Sources.Ramp ramp(
    duration=1,
    offset=1,
    height=-2)

  Modelica.Blocks.Math.Gain gain(k=0.01)
equation
  connect(TAmb.port, theCon.port_a)
  connect(heaFlo.port_b, vol.heatPort)
  connect(ramp.y, gain.u)
  connect(gain.y, sou.m_flow_in)
  connect(theCon.port_b, heaFlo.port_a)
  connect(sou.ports[1], vol.ports[1])
  connect(vol.ports[2], bou.ports[1])
end MixingVolumeHeatConduction;


within AixLib.Fluid.MixingVolumes.Examples;
model MixingVolumeMoistAir "Test model for mixing volume with moist air input"
  extends Modelica.Icons.Example;

  package Medium = AixLib.Media.Air;

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

  AixLib.Fluid.MixingVolumes.MixingVolumeMoistAir vol1(
    redeclare package Medium = Medium,
    V=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=m_flow_nominal,
    nPorts=2)                      "Volume"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TSen
    "Temperature sensor"
  Modelica.Blocks.Sources.Constant XSet(k=0.005)
    "Set point for water mass fraction"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFlo
  Modelica.Blocks.Sources.Constant TSet(k=273.15 + 20)
    "Set point for temperature"
  AixLib.Utilities.Psychrometrics.pW_X humRat(use_p_in=false)
    "Conversion from humidity ratio to partial water vapor pressure"
  AixLib.Utilities.Psychrometrics.TDewPoi_pW dewPoi "Dew point temperature"
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heatFlowSensor
  Modelica.Blocks.Continuous.Integrator QSen "Sensible heat transfer"
  Modelica.Blocks.Continuous.Integrator QLat "Enthalpy of extracted water"
  AixLib.Fluid.Sources.MassFlowSource_T sou(
    redeclare package Medium = Medium,
    nPorts=1,
    T=293.15)
  AixLib.Fluid.Sources.Boundary_pT sin(        redeclare package Medium =
        Medium,
    T=293.15,
    nPorts=1)
  AixLib.Controls.Continuous.LimPID PI(
    Ni=0.1,
    yMax=1000,
    k=1,
    Ti=1,
    Td=1,
    wd=0,
    yMin=-1000)
  AixLib.Controls.Continuous.LimPID PI1(
    Ni=0.1,
    Ti=1,
    k=10,
    yMax=1,
    yMin=-1,
    Td=1)
  AixLib.Fluid.Sensors.MassFlowRate mIn_flow(redeclare package Medium =
        Medium)
  AixLib.Fluid.Sensors.MassFlowRate mOut_flow(redeclare package Medium =
        Medium)
  Modelica.Blocks.Math.Add dM_flow(k2=-1)
  Modelica.Blocks.Math.Gain gai(k=200)
  Modelica.Blocks.Math.Gain gai1(k=0.1)

  AixLib.Fluid.FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    from_dp=true,
    dp_nominal=2.5,
    m_flow_nominal=m_flow_nominal)
  Sensors.LatentEnthalpyFlowRate senLatEnt(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    tau=0,
    initType=Modelica.Blocks.Types.Init.SteadyState) "Latent enthalpy inflow"
  Sensors.LatentEnthalpyFlowRate senLatEnt1(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    tau=0,
    initType=Modelica.Blocks.Types.Init.SteadyState) "Latent enthalpy outflow"
  Modelica.Blocks.Math.Add add
equation
  connect(preHeaFlo.port, heatFlowSensor.port_a)
  connect(heatFlowSensor.Q_flow, QSen.u)
  connect(TSet.y, PI.u_s)
  connect(TSen.T, PI.u_m)
  connect(XSet.y, PI1.u_s)
  connect(mOut_flow.m_flow, dM_flow.u1)
  connect(mIn_flow.m_flow, dM_flow.u2)
  connect(gai.y, preHeaFlo.Q_flow)
  connect(PI1.y, gai1.u)
  connect(gai1.y, vol1.mWat_flow)
  connect(vol1.X_w, PI1.u_m)
  connect(vol1.X_w, humRat.X_w)
  connect(sou.ports[1], mIn_flow.port_a)
  connect(heatFlowSensor.port_b, vol1.heatPort)
  connect(TSen.port, vol1.heatPort)
  connect(PI.y, gai.u)
  connect(humRat.p_w, dewPoi.p_w)
  connect(mOut_flow.port_b, res1.port_a)
  connect(res1.port_b, sin.ports[1])
  connect(mIn_flow.port_b, senLatEnt.port_a)
  connect(senLatEnt.port_b, vol1.ports[1])
  connect(vol1.ports[2], senLatEnt1.port_a)
  connect(senLatEnt1.port_b, mOut_flow.port_a)
  connect(add.y, QLat.u)
  connect(add.u1, senLatEnt.H_flow)
  connect(senLatEnt1.H_flow, add.u2)
end MixingVolumeMoistAir;


Test model for heat transfer to volume

within AixLib.Fluid.MixingVolumes.Examples;
model MixingVolumePrescribedHeatFlowRate
  "Test model for heat transfer to volume"
  extends Modelica.Icons.Example;
    package Medium = AixLib.Media.Air;
  Modelica.Thermal.HeatTransfer.Sensors.HeatFlowSensor heaFlo
    "Heat flow sensor"
  Modelica.Fluid.Sources.MassFlowSource_T sou(
    nPorts=1,
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=313.15) "Flow source and sink"
  Modelica.Fluid.Sources.FixedBoundary bou(
    redeclare package Medium = Medium,
    nPorts=1,
    T=303.15) "Boundary condition"
  AixLib.Fluid.MixingVolumes.MixingVolume vol(
    V=1,
    nPorts=2,
    redeclare package Medium = Medium,
    m_flow_nominal=0.01,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    allowFlowReversal=true,
    prescribedHeatFlowRate=true)
  Modelica.Blocks.Sources.Ramp ramp(
    duration=1,
    offset=1,
    height=-2)

  Modelica.Blocks.Math.Gain gain(k=0.01)
  Modelica.Blocks.Sources.Constant const(k=0)
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFlo
    "Prescribed heat flow rate"
equation
  connect(sou.ports[1], vol.ports[1])
  connect(ramp.y, gain.u)
  connect(gain.y, sou.m_flow_in)
  connect(vol.ports[2], bou.ports[1])
  connect(preHeaFlo.port, heaFlo.port_a)
  connect(preHeaFlo.Q_flow, const.y)
  connect(heaFlo.port_b, vol.heatPort)
end MixingVolumePrescribedHeatFlowRate;


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


within AixLib.Fluid.MixingVolumes.Validation;
model CoupledVolumesAir
  "Validation model for two coupled volumes with air"
  extends AixLib.Fluid.MixingVolumes.Validation.CoupledVolumesWater(
    redeclare package Medium = AixLib.Media.Air);
end CoupledVolumesAir;


within AixLib.Fluid.MixingVolumes.Validation;
model CoupledVolumesGlycol47
  "Validation model for two coupled volumes with glycol"
  extends AixLib.Fluid.MixingVolumes.Validation.CoupledVolumesWater(
    redeclare package Medium = Modelica.Media.Incompressible.Examples.Glycol47);
end CoupledVolumesGlycol47;


within AixLib.Fluid.MixingVolumes.Validation;
model CoupledVolumesSpecializedAirPerfectGas
  "Validation model for two coupled volumes with air as a perfect gas"
  extends AixLib.Fluid.MixingVolumes.Validation.CoupledVolumesWater(
    redeclare package Medium =
        AixLib.Media.Specialized.Air.PerfectGas);
end CoupledVolumesSpecializedAirPerfectGas;


within AixLib.Fluid.MixingVolumes.Validation;
model CoupledVolumesSpecializedWaterConstantProperties_pT
  "Validation model for two coupled volumes with water with constant properties"
  extends AixLib.Fluid.MixingVolumes.Validation.CoupledVolumesWater(
    redeclare package Medium =
        AixLib.Media.Specialized.Water.ConstantProperties_pT);
end CoupledVolumesSpecializedWaterConstantProperties_pT;


within AixLib.Fluid.MixingVolumes.Validation;
model CoupledVolumesSpecializedWaterTemperatureDependentDensity
  "Validation model for two coupled volumes with water with temperature dependent density"
  extends AixLib.Fluid.MixingVolumes.Validation.CoupledVolumesWater(
    redeclare package Medium =
        AixLib.Media.Specialized.Water.TemperatureDependentDensity);
end CoupledVolumesSpecializedWaterTemperatureDependentDensity;


within AixLib.Fluid.MixingVolumes.Validation;
model CoupledVolumesWater
  "Validation model for two coupled volumes with water"
  extends Modelica.Icons.Example;

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

  AixLib.Fluid.MixingVolumes.MixingVolume vol(
    redeclare package Medium = Medium,
    nPorts=2,
    m_flow_nominal=1,
    V=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  AixLib.Fluid.MixingVolumes.MixingVolume vol1(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    V=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPorts=1)
  AixLib.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium,
    nPorts=1)
    "Pressure boundary condition"
  AixLib.Fluid.FixedResistances.PressureDrop res(
    redeclare package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=100) "Resistance to decouple initialization of pressure state"
equation
  connect(bou.ports[1], res.port_a)
  connect(res.port_b, vol.ports[1])
  connect(vol.ports[2], vol1.ports[1])
end CoupledVolumesWater;


Test model for mixing volumes

within AixLib.Fluid.MixingVolumes.Validation;
model MixingVolume "Test model for mixing volumes"
  extends Modelica.Icons.Example;

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

    Modelica.Blocks.Sources.Ramp P(
    duration=0.5,
    startTime=0.5,
    height=-10,
    offset=101330)
  AixLib.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = Medium,
    T=293.15,
    use_p_in=true,
    nPorts=3)
  AixLib.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = Medium,
    nPorts=3,
    use_p_in=false,
    p=101325,
    T=283.15)
  AixLib.Fluid.FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium,
    from_dp=true,
    m_flow_nominal=2,
    dp_nominal=2.5)
  MixingVolumes.MixingVolume vol1(
    redeclare package Medium = Medium,
    V=0.1,
    nPorts=2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=2)
  AixLib.Fluid.FixedResistances.PressureDrop res2(
    redeclare package Medium = Medium,
    from_dp=true,
    m_flow_nominal=2,
    dp_nominal=2.5)
  AixLib.Fluid.FixedResistances.PressureDrop res11(
    redeclare package Medium = Medium,
    from_dp=true,
    m_flow_nominal=2,
    dp_nominal=2.5)
  AixLib.Fluid.FixedResistances.PressureDrop res12(
    redeclare package Medium = Medium,
    from_dp=true,
    m_flow_nominal=2,
    dp_nominal=2.5)
  Modelica.Fluid.Vessels.ClosedVolume vol(
    redeclare package Medium = Medium,
    massDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=0.1,
    nPorts=2,
    h_start=45300.945,
    use_portsData=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
  AixLib.Utilities.Diagnostics.CheckEquality cheEqu1
    "Check for equality of results"
  AixLib.Fluid.Sensors.EnthalpyFlowRate entFloRat(
    redeclare package Medium = Medium,
    m_flow_nominal=2) "Enthalpy flow rate"
  AixLib.Fluid.Sensors.EnthalpyFlowRate entFloRat1(
    redeclare package Medium = Medium,
    m_flow_nominal=2) "Enthalpy flow rate"
  AixLib.Fluid.MixingVolumes.MixingVolumeMoistAir vol2(
    redeclare package Medium = Medium,
    V=0.1,
    nPorts=2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=2)
  AixLib.Fluid.FixedResistances.PressureDrop res21(
    redeclare package Medium = Medium,
    from_dp=true,
    m_flow_nominal=2,
    dp_nominal=2.5)
  AixLib.Fluid.FixedResistances.PressureDrop res22(
    redeclare package Medium = Medium,
    from_dp=true,
    m_flow_nominal=2,
    dp_nominal=2.5)
  AixLib.Utilities.Diagnostics.CheckEquality cheEqu2
    "Check for equality of results"
  AixLib.Fluid.Sensors.EnthalpyFlowRate entFloRat2(
    redeclare package Medium = Medium,
    m_flow_nominal=2) "Enthalpy flow rate"
    Modelica.Blocks.Sources.Constant zero(k=0)

  inner Modelica.Fluid.System system
equation
  connect(P.y, sou.p_in)
  connect(res2.port_a, entFloRat.port_b)
  connect(entFloRat2.H_flow, cheEqu2.u2)
  connect(zero.y, vol2.mWat_flow)
  connect(sou.ports[1], res1.port_a)
  connect(sou.ports[2], res11.port_a)
  connect(sou.ports[3], res21.port_a)
  connect(sin.ports[1], res2.port_b)
  connect(sin.ports[2], res12.port_b)
  connect(res22.port_b, sin.ports[3])
  connect(res1.port_b, vol.ports[1])
  connect(vol.ports[2], entFloRat.port_a)
  connect(res11.port_b, vol1.ports[1])
  connect(vol1.ports[2], entFloRat1.port_a)
  connect(res21.port_b, vol2.ports[1])
  connect(vol2.ports[2], entFloRat2.port_a)
  connect(entFloRat2.port_b, res22.port_a)
  connect(entFloRat1.port_b, res12.port_a)
  connect(entFloRat.H_flow, cheEqu1.u1)
  connect(entFloRat.H_flow, cheEqu2.u1)
  connect(entFloRat1.H_flow, cheEqu1.u2)
end MixingVolume;


within AixLib.Fluid.MixingVolumes.Validation;
model MixingVolumeAdiabaticCooling
  "Validation model for mixing volume with adiabatic cooling"
  extends Modelica.Icons.Example;

  package Medium = AixLib.Media.Air "Medium model";
  MixingVolumeMoistAir volSim(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=1,
    V=1,
    final simplify_mWat_flow=true,
    nPorts=1)
    "Mixing volume with water vapor input and simplified water balance"
  MixingVolumeMoistAir volExa(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=1,
    V=1,
    final simplify_mWat_flow=false,
    nPorts=1) "Mixing volume with water vapor input and exact water balance"
  Modelica.Blocks.Sources.Constant mWatFlo(k=0.001) "Water mass flow rate "
  Modelica.Blocks.Sources.RealExpression relErr(
    y=(volSim.heatPort.T - 20)
      /(if abs(volExa.heatPort.T - 20) < 1E-5 then 1 else (volExa.heatPort.T - 20)))
    "Relative error in the temperature difference"
  AixLib.Fluid.Sources.Boundary_pT bou(redeclare package Medium = Medium, nPorts=2)
    "Fixed pressure boundary condition"

equation
  connect(volSim.mWat_flow, mWatFlo.y)
  connect(volExa.mWat_flow, mWatFlo.y)
  connect(bou.ports[1], volSim.ports[1])
  connect(bou.ports[2], volExa.ports[1])
end MixingVolumeAdiabaticCooling;


Validation model for mixing volume with heat input and flow reversal. This model validates the use of the mixing volume with air flowing into and out of the volume
and sensible heat added to the volume.

within AixLib.Fluid.MixingVolumes.Validation;
model MixingVolumeHeatReverseFlow
  "Validation model for mixing volume with heat input and flow reversal"
  extends
    AixLib.Fluid.MixingVolumes.Validation.BaseClasses.MixingVolumeReverseFlow(
      gain(k=10));

  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaDyn
    "Prescribed heat flow rate"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaSte
    "Prescribed heat flow rate"
equation
  connect(gain.y, preHeaDyn.Q_flow)
  connect(gain.y, preHeaSte.Q_flow)
  connect(preHeaDyn.port, volDyn.heatPort)
  connect(preHeaSte.port, volSte.heatPort)
end MixingVolumeHeatReverseFlow;


Validation model for mixing volume with heat input and flow reversal and prescribed heat flow rate. This model is identical to

AixLib.Fluid.MixingVolumes.Validation.MixingVolumeHeatReverseFlow,
except that the steady state volume volSte
is configured to have a prescribed heat flow rate,
which is in this case zero as the heat port is not connected.
This configures volSte to use the two port
steady state heat and mass balance model

AixLib.Fluid.Interfaces.StaticTwoPortConservationEquation.

within AixLib.Fluid.MixingVolumes.Validation;
model MixingVolumeHeatReverseFlowPrescribedHeatFlowRate
  "Validation model for mixing volume with heat input and flow reversal and prescribed heat flow rate"
  extends MixingVolumeHeatReverseFlow(
    prescribedHeatFlowRate=true);
end MixingVolumeHeatReverseFlowPrescribedHeatFlowRate;