within AixLib;
package Airflow "Package to compute airflow and contaminant transport between rooms"
  extends Modelica.Icons.Package;
end Airflow;


Ideal model for the usage of an air curtain in the context of low order retail zones.

within AixLib.Airflow.AirCurtain;
model AirCurtainSimplified
  "Ideal model for the usage of an air curtain in the context of low order retail zones"
  parameter Modelica.Units.SI.VolumeFlowRate V_flowAirCur=5
    "Design volume flow rate of the air curtain";
  parameter Modelica.Units.SI.TemperatureDifference TAddAirCur=5
    "Temperature increase over the air curtain";
  parameter Real etaAirCur = 0.73
    "Efficiency of the air curtain";
  parameter Modelica.Units.SI.Density rho=1.25 "Air density";
  parameter Modelica.Units.SI.SpecificHeatCapacity c=1000
    "Specific heat capacity of air";
  parameter Modelica.Units.SI.Temperature TBou=287.15
    "Threshold of the ambient temperature when aircurtain becomes active";
  parameter Modelica.Units.SI.Power PAirCur=27500
    "The thermal Power of the air curtain, simplified use";
  Utilities.Psychrometrics.MixedTemperature mixedTemperature
  Modelica.Blocks.Interfaces.RealInput TAmb "Ambient airtemperature in K"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_b
    port_b "heat port for heat transfer"

  Modelica.Blocks.Interfaces.RealOutput Power "Power used by the air curtain"
  Modelica.Blocks.Interfaces.RealInput schedule "Signal for the schedule"
equation

  if TAmb <= TBou and schedule > 0 then
    mixedTemperature.flowRate_flow2 = (1 - etaAirCur) * V_flowAirCur;
    mixedTemperature.flowRate_flow1 = etaAirCur * V_flowAirCur;
    mixedTemperature.temperature_flow1 = port_b.T + TAddAirCur;
    port_b.Q_flow = - etaAirCur * V_flowAirCur * rho * c * (mixedTemperature.mixedTemperatureOut - port_b.T);
    Power = PAirCur;
  else
    mixedTemperature.flowRate_flow2 = (1 - etaAirCur) * V_flowAirCur;
    mixedTemperature.flowRate_flow1 = etaAirCur * V_flowAirCur;
    mixedTemperature.temperature_flow1 = port_b.T;
    port_b.Q_flow = 0;
    Power = 0;
  end if;

  connect(TAmb, mixedTemperature.temperature_flow2)
end AirCurtainSimplified;


Package of different air curtain models

within AixLib.Airflow;
package AirCurtain "Package of different air curtain models"
end AirCurtain;


This model is an example for the use of an air curtain in the low order model.

within AixLib.Airflow.AirCurtain.Examples;
model AirCurtain
  "This model is an example for the use of an air curtain in the low order model"
  extends Modelica.Icons.Example;
  AirCurtainSimplified                    airCurtainSimplyfied(
    V_flowAirCur=5,
    TAddAirCur=5,
    etaAirCur=0.73,
    PAirCur=50000,
    TBou=287.15)
  ThermalZones.HighOrder.Components.DryAir.Airload airload(T0=293.15, V=48)
  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    calTSky=AixLib.BoundaryConditions.Types.SkyTemperatureCalculation.HorizontalRadiation,
    computeWetBulbTemperature=false,
    filNam=Modelica.Utilities.Files.loadResource(
        "modelica://AixLib/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data reader"

  Modelica.Blocks.Sources.Pulse pulse(
    amplitude=1,
    width=50,
    period=86400,
    offset=0,
    startTime=25200)
  BoundaryConditions.WeatherData.Bus        weaBus
    "Weather data bus"
equation
  connect(airCurtainSimplyfied.port_b, airload.port)
  connect(pulse.y, airCurtainSimplyfied.schedule)
  connect(weaDat.weaBus, weaBus)
  connect(weaBus.TDryBul, airCurtainSimplyfied.TAmb)
end AirCurtain;


Air Handling Unit with Heat Recovery System, Cooling, Heating, Humidification (adiabatic), Dehumidification.

within AixLib.Airflow.AirHandlingUnit;
model AHU
  "Air Handling Unit with Heat Recovery System, Cooling, Heating, Humidification (adiabatic), Dehumidification"
  extends AixLib.Airflow.AirHandlingUnit.BaseClasses.PartialAHU;
  /*
 indices and abbreviations:
 HRS = heat recovery system
 sup = supply air
 eta = extract air
 oda = outdoor air
 eha = exhaust air
 BPF = By-pass factor
 DeHu = dehumidification
 Hu = humidification
 H = heat(ing)
 C = cool(ing)
 sat = saturation
 phi_t is the HRS' efficiency not a relative humidity like other phis
 */

  //// Variables
  // Booleans for transitions to State Machines
  inner Boolean stateToDeHuHRS_true;
  inner Boolean stateToDeHuHRS_false;
  inner Boolean stateToHuPreHHRS_true;
  inner Boolean stateToHuPreHHRS_false;
  inner Boolean stateToHuCHRS_true;
  inner Boolean stateToHuCHRS_false;
  inner Boolean stateToOnlyHeatingHRS_true;
  inner Boolean stateToOnlyHeatingHRS_false;
  inner Boolean stateToOnlyCoolingHRS_true;
  inner Boolean stateToOnlyCoolingHRS_false;

  Boolean tooHighX(start=false);
  Boolean tooLowX(start=false);
  Boolean choiceX(start=true);
  Boolean allCond(start=false);

  // Variables that will be set with parameteres of HRS efficiency
  inner Real phi_t_withHRS(start=efficiencyHRS_enabled)
    "efficiency of HRS in the AHU modes when HRS is enabled";
  inner Real phi_t_withoutHRS(start=efficiencyHRS_disabled)
    "efficiency of HRS in the AHU modes when HRS is disabled";
  inner Real phi_t(start=0.5);

  inner Modelica.Units.SI.Temperature T_oda;
                                      //(start=288.15);
  inner Modelica.Units.SI.Temperature T_1(start=290.15);
  inner Modelica.Units.SI.Temperature T_5(start=293.15);
  inner Modelica.Units.SI.Temperature T_sup(start=295.15);
  inner Modelica.Units.SI.Temperature T_eta(start=296.15);
  inner Modelica.Units.SI.Temperature T_6;
                                    //(start=296.15);

  inner Modelica.Units.SI.MassFraction X_oda(start=0.007);
  Modelica.Units.SI.MassFraction X_odaSat(start=0.007);
  Modelica.Units.SI.MassFraction X_odaRaw(start=0.007);
  inner Modelica.Units.SI.MassFraction X_sup(start=0.008);
  Modelica.Units.SI.MassFraction X_supplyMin(start=0.006);
  Modelica.Units.SI.MassFraction X_supplyMax(start=0.010);
  inner Modelica.Units.SI.MassFraction X_supMin(start=0.006);
  inner Modelica.Units.SI.MassFraction X_supMax(start=0.010);
  Modelica.Units.SI.MassFraction X_extractAir(start=0.008);
  Modelica.Units.SI.MassFraction X_eta(start=0.008);
  Real phi_sup(start=0.5);

  inner Modelica.Units.SI.HeatFlowRate Q_dot_C(start=1e-3);
  inner Modelica.Units.SI.HeatFlowRate Q_dot_H(start=1e-3);
  Modelica.Units.SI.Power P_el_sup(start=1e-3);
  Modelica.Units.SI.Power P_el_eta(start=1e-3);
  inner Modelica.Units.SI.VolumeFlowRate V_dot_sup(start=1e-3);
  inner Modelica.Units.SI.VolumeFlowRate V_dot_eta(start=1e-3);

  // Constants from formulas collection of Thermodynamik (institute: LTT)
  constant Modelica.Units.SI.SpecificHeatCapacityAtConstantPressure c_pL_iG=1E3;
  constant Modelica.Units.SI.SpecificHeatCapacityAtConstantPressure c_pW_iG=
      1.86E3;
  constant Modelica.Units.SI.SpecificEnthalpy r_0=2465E3
    "enthalpy of vaporization at temperature between T_dew(X_sup=0.008)=11 degC and T_sup = 22 degC";
  constant Modelica.Units.SI.Density rho=1.2;
  constant Modelica.Units.SI.Pressure p_0=101325;
  constant Modelica.Units.SI.SpecificEnthalpy dhV=2501.3E3;
  constant Modelica.Units.SI.Temperature T_0=273.15;
  constant Real molarMassRatio=Modelica.Media.IdealGases.Common.SingleGasesData.H2O.MM
      /Modelica.Media.Air.SimpleAir.MM_const;

  // auxiliary variable
  Modelica.Units.SI.TemperatureDifference dTFan;
  Modelica.Units.SI.Temperature TsupplyAirOut(start=295.15);

  // Sampler (time-continous to time-discrete variables)

  Modelica.Clocked.RealSignals.Sampler.SampleVectorizedAndClocked sample(n=9)

  Modelica.Clocked.ClockSignals.Clocks.PeriodicRealClock periodicClock(
    solverMethod="ExplicitRungeKutta4",
    useSolver=true,
    period=clockPeriodGeneric)

  //
  ////////////////////////////
  //State Machines////////////
  ////////////////////////////
  //
  //Start State

  block StartState
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;

  equation
    Q_dot_C = previous(Q_dot_C);
    Q_dot_H = previous(Q_dot_H);
  end StartState;

  StartState startState

  //
  //
  // (comments for state machines only in the dehumidification state machine as representive comments)
  //
  // Dehumidification

  block DeHuHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2(start=290);
    Modelica.Units.SI.Temperature T_3(start=282);
    Modelica.Units.SI.Temperature T_4(start=282);
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMax;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;
    outer parameter Real BPF_DeHu;
    Modelica.Units.SI.SpecificEnthalpy h_2(start=0.003) "h_in of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_surface(start=0.002)
      "h_surface of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_CoilOut(start=0.001) "h_out of cooler";
    Modelica.Units.SI.Pressure p_sat_surface(start=2300);
    Modelica.Units.SI.MassFraction X_surface(start=0.005);
    Modelica.Units.SI.Temperature T_surface(start=280);
    Modelica.Units.SI.Temperature T_CoilOut(start=278);

  equation
    phi_t = phi_t_withHRS "heat recovery system is enabled";
    X_sup = previous(X_supMax);
    T_1 = T_2;
    T_3 = T_CoilOut;
    T_4 = T_3;

    BPF_DeHu = (h_CoilOut - h_surface)/max(h_2 - h_surface, 0.01);
    h_2 = c_pL_iG*(previous(T_2) - T_0) + previous(X_oda)*(c_pW_iG*(previous(
      T_2) - T_0) + dhV);
    h_surface = c_pL_iG*(T_surface - T_0) + X_surface*(c_pW_iG*(T_surface - T_0)
       + dhV);
    h_CoilOut = c_pL_iG*(T_CoilOut - T_0) + X_sup*(c_pW_iG*(T_CoilOut - T_0) +
      dhV);
    (previous(T_2) - T_surface)/max(previous(X_oda) - X_surface, 0.00009) = (
      T_CoilOut - T_surface)/max(previous(X_supMax) - X_surface, 0.00001);

    /*
  p_sat_surface = 611.2*exp(17.62*(T_surface - T_0)/(243.12 + T_surface - T_0));
  //Magnus formula over water, improved by Sonntag (1990), Range: -45 degC to +60 degC
  2 Alternatives for calculation of water vapor pressure, which are not so stable during simulation:
  p_sat_surface = 10^(-7.90298*(373.15/T_surface - 1)
          +5.02808*log10(373.15/T_surface)
          -1.3816*10^(-7)*(10^(11.344*(1 - T_surface/373.15))-1)
          +8.1328*10^(-3)*(10^(-3.49149*(373.15/T_surface - 1))-1)
          +log10(1013.246))*100; //The Goff Gratch equation for the vapor pressure over liquid water covers a region of -50 degC to +102 degC.
*/
    p_sat_surface = Modelica.Media.Air.MoistAir.saturationPressure(T_surface);

    X_surface = molarMassRatio*p_sat_surface/(p_0 - p_sat_surface);

    Q_dot_C = previous(V_dot_sup)*rho*((c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - T_CoilOut) + (previous(X_oda) - X_sup)*r_0);
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + X_sup*c_pW_iG)*(previous(T_5) -
      T_CoilOut);
  end DeHuHRS_true;
  DeHuHRS_true deHuHRS_true "Dehumidification and Heat Recovery System enabled"

  //
  //
  //
  //

  block DeHuHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2(start=290);
    Modelica.Units.SI.Temperature T_3(start=282);
    Modelica.Units.SI.Temperature T_4(start=282);
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMax;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;
    outer parameter Real BPF_DeHu;
    Modelica.Units.SI.SpecificEnthalpy h_2(start=0.003) "h_in of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_surface(start=0.002)
      "h_surface of cooler";
    Modelica.Units.SI.SpecificEnthalpy h_CoilOut(start=0.001) "h_out of cooler";
    Modelica.Units.SI.Pressure p_sat_surface(start=2300);
    Modelica.Units.SI.MassFraction X_surface(start=0.005);
    Modelica.Units.SI.Temperature T_surface(start=280);
    Modelica.Units.SI.Temperature T_CoilOut(start=278);

  equation
    phi_t = phi_t_withoutHRS "heat recovery system is disabled";
    X_sup = previous(X_supMax);
    T_1 = T_2;
    T_3 = T_CoilOut;
    T_4 = T_3;

    BPF_DeHu = (h_CoilOut - h_surface)/max(h_2 - h_surface, 0.01);
    h_2 = c_pL_iG*(previous(T_2) - T_0) + previous(X_oda)*(c_pW_iG*(previous(
      T_2) - T_0) + dhV);
    h_surface = c_pL_iG*(T_surface - T_0) + X_surface*(c_pW_iG*(T_surface - T_0)
       + dhV);
    h_CoilOut = c_pL_iG*(T_CoilOut - T_0) + X_sup*(c_pW_iG*(T_CoilOut - T_0) +
      dhV);
    (previous(T_2) - T_surface)/max(previous(X_oda) - X_surface, 0.00009) = (
      T_CoilOut - T_surface)/max(previous(X_supMax) - X_surface, 0.00001);

    /*
  p_sat_surface = 611.2*exp(17.62*(T_surface - T_0)/(243.12 + T_surface - T_0));
  //Magnus formula over water, improved by Sonntag (1990), Range: -45 degC to +60 degC
  2 Alternatives for calculation of water vapor pressure, which are not so stable during simulation:
  p_sat_surface = 10^(-7.90298*(373.15/T_surface - 1)
          +5.02808*log10(373.15/T_surface)
          -1.3816*10^(-7)*(10^(11.344*(1 - T_surface/373.15))-1)
          +8.1328*10^(-3)*(10^(-3.49149*(373.15/T_surface - 1))-1)
          +log10(1013.246))*100; //The Goff Gratch equation for the vapor pressure over liquid water covers a region of -50 degC to +102 degC.
*/
    p_sat_surface = Modelica.Media.Air.MoistAir.saturationPressure(T_surface);

    X_surface = molarMassRatio*p_sat_surface/(p_0 - p_sat_surface);

    Q_dot_C = previous(V_dot_sup)*rho*((c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - T_CoilOut) + (previous(X_oda) - X_sup)*r_0);
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + X_sup*c_pW_iG)*(previous(T_5) -
      T_CoilOut);
  end DeHuHRS_false;
  DeHuHRS_false deHuHRS_false
    "Dehumidification and Heat Recovery System disabled"

  //
  //
  //
  // Humidification

  block HuPreHHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    X_sup = previous(X_supMin);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_1)) + previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
  end HuPreHHRS_true;
  HuPreHHRS_true huPreHHRS_true
    "Humidification with Preheating and Heat Recovery System enabled"

  //
  //
  //
  //

  block HuPreHHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    X_sup = previous(X_supMin);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_1)) + previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
  end HuPreHHRS_false;
  HuPreHHRS_false huPreHHRS_false
    "Humidification with Preheating and Heat Recovery System disabled"

  //
  //
  //
  //

  block HuCHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    X_sup = previous(X_supMin);
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3)) - previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
    Q_dot_H = 0;
  end HuCHRS_true;
  HuCHRS_true huCHRS_true
    "Humidification with additional Cooling and Heat Recovery System enabled"

  //
  //
  //
  //

  block HuCHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer input Modelica.Units.SI.MassFraction X_supMin;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    X_sup = previous(X_supMin);
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3)) - previous(V_dot_sup)*rho*(previous(
      X_supMin) - previous(X_oda))*r_0
      "Thermal Power consumption for Humidification due to Eurovent 6/8 eq. (7.3) or (7.8)";
    Q_dot_H = 0;
  end HuCHRS_false;
  HuCHRS_false huCHRS_false
    "Humidification with additional Cooling and Heat Recovery System disabled"

  //
  //
  //
  // Only Heating

  block OnlyHeatingHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    T_1 = T_2;
    T_2 = T_3;
    T_3 = T_4;
    X_sup = previous(X_oda);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_4));
  end OnlyHeatingHRS_true;
  OnlyHeatingHRS_true onlyHeatingHRS_true
    "Heating and Heat Recovery System enabled"

  //
  //
  //
  //

  block OnlyHeatingHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    T_1 = T_2;
    T_2 = T_3;
    T_3 = T_4;
    X_sup = previous(X_oda);

    Q_dot_C = 0;
    Q_dot_H = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_5) - previous(T_4));
  end OnlyHeatingHRS_false;
  OnlyHeatingHRS_false onlyHeatingHRS_false
    "Heating and Heat Recovery System disabled"

  //
  //
  //
  // Only Cooling

  block OnlyCoolingHRS_true
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withHRS;

  equation
    phi_t = phi_t_withHRS;
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;
    X_sup = previous(X_oda);

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3));
    Q_dot_H = 0;
  end OnlyCoolingHRS_true;
  OnlyCoolingHRS_true onlyCoolingHRS_true
    "Cooling and Heat Recovery System enabled"

  //
  //
  //
  //

  block OnlyCoolingHRS_false
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_C;
    outer output Modelica.Units.SI.HeatFlowRate Q_dot_H;
    outer input Modelica.Units.SI.Temperature T_oda;
    outer input Modelica.Units.SI.Temperature T_1;
    Modelica.Units.SI.Temperature T_2;
    Modelica.Units.SI.Temperature T_3;
    Modelica.Units.SI.Temperature T_4;
    outer input Modelica.Units.SI.Temperature T_5;
    outer input Modelica.Units.SI.Temperature T_6;
    outer input Modelica.Units.SI.MassFraction X_oda;
    outer output Modelica.Units.SI.MassFraction X_sup;
    outer input Modelica.Units.SI.VolumeFlowRate V_dot_sup;
    outer output Real phi_t;
    outer input Real phi_t_withoutHRS;

  equation
    phi_t = phi_t_withoutHRS;
    T_1 = T_2;
    T_3 = T_4;
    T_4 = T_5;
    X_sup = previous(X_oda);

    Q_dot_C = previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(
      previous(T_2) - previous(T_3));
    Q_dot_H = 0;
  end OnlyCoolingHRS_false;
  OnlyCoolingHRS_false onlyCoolingHRS_false
    "Cooling and Heat Recovery System disabled"

  //
  //
  //
  ////////////////////////////
  //EQUATION//////EQUATION////
  ////////////////////////////
  //
  //
  //

  Modelica.Blocks.Sources.RealExpression hold_phi_sup(y=hold(previous(phi_sup)))
  Modelica.Blocks.Sources.RealExpression TsupAirOut(y=hold(TsupplyAirOut))
    "see if else decision in source code"
  StateExtra stateExtra
equation
  // variables that will be set with parameteres of HRS efficiency
  phi_t_withHRS = if HRS then efficiencyHRS_enabled else 0;
  phi_t_withoutHRS = if HRS then efficiencyHRS_disabled else 0;

  //// sampler inputs
  // connecting clock signal with sampler
  connect(periodicClock.y, sample.clock)

  // converting inputs (coming from the outside of AHUFull) into time-discrete variables for state machines.

  X_supplyMin = sample.u[5];
  X_supplyMax = sample.u[6];
  X_extractAir = sample.u[7];

  T_oda = sample.y[1];
  X_odaRaw = sample.y[2];
  T_sup = sample.y[3];
  T_eta = sample.y[4];
  X_supMin = sample.y[5];
  X_supMax = sample.y[6];
  X_eta = sample.y[7];
  V_dot_sup = sample.y[8];
  V_dot_eta = sample.y[9];

  // absolute humidity for state of saturated outdoor air
  X_odaSat = molarMassRatio*(611.2*exp(17.62*(T_oda - T_0)/(243.12 + T_oda -
    T_0)))/(p_0 - (611.2*exp(17.62*(T_oda - T_0)/(243.12 + T_oda - T_0))));
  // if absolute humidity from weather file should be in region of phi_oda>1 then restrict to absolute humdity for phi_oda=1. Prevents calculation errors!
  X_oda = if X_odaRaw > X_odaSat then X_odaSat else X_odaRaw;

  // calculates T_1 according to assumption of HRS' efficiency phi_t
  phi_t = (T_1 - T_oda)/(T_6 - T_oda + 1e-3);

  // conditions for transitions to State Machines
  tooHighX = if previous(X_oda) > previous(X_supMax) then true else false;
  tooLowX = if previous(X_oda) < previous(X_supMin) then true else false;
  choiceX = if
     (tooHighX and not dehumidification)
     or
     (tooLowX and not humidification)
     or
     (previous(X_oda) <= previous(X_supMax) and previous(X_oda) >= previous(X_supMin))
     then true else false;

  // now really the conditions for the transitions
  stateToDeHuHRS_true = if
     tooHighX
     and dehumidification and HRS then true else false;

  stateToDeHuHRS_false = if
    tooHighX
    and dehumidification and not HRS then true else false;

  stateToHuPreHHRS_true = if
    tooLowX
    and
    ((previous(T_5) >= previous(T_1))
    or
    ((previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) >= abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))))
    and humidification and HRS then true else false;

  stateToHuPreHHRS_false = if
    tooLowX
    and
    ((previous(T_5) >= previous(T_1))
    or
    ((previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) >= abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))))
    and humidification and not HRS then true else false;

  stateToHuCHRS_true = if
    tooLowX
    and
    (previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) < abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))
    and humidification and HRS then true else false;

  stateToHuCHRS_false = if
    tooLowX
    and
    (previous(T_5) < previous(T_1))
    and
    (abs(previous(V_dot_sup)*rho*(previous(X_sup) - previous(X_oda))*r_0) < abs(previous(V_dot_sup)*rho*(c_pL_iG + previous(X_oda)*c_pW_iG)*(previous(T_1) - previous(T_5))))
    and humidification and not HRS then true else false;

  stateToOnlyHeatingHRS_true = if
     choiceX
     and
     (previous(T_5) >= pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and heating and HRS then true else false;

  stateToOnlyHeatingHRS_false = if
     choiceX
     and
     (previous(T_5) >= pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and heating and not HRS then true else false;

  stateToOnlyCoolingHRS_true = if
     choiceX
     and
     (previous(T_5) < pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and cooling and HRS then true else false;

  stateToOnlyCoolingHRS_false = if
     choiceX
     and
     (previous(T_5) < pre(T_oda) + phi_t_withoutHRS*(pre(T_6) - pre(T_oda)))
     and cooling and not HRS then true else false;

  X_supplyMin = (molarMassRatio*phi_supplyAir[1]*
    Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir))/(p_0 -
    phi_supplyAir[1]*Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir));
  X_supplyMax = (molarMassRatio*phi_supplyAir[2]*
    Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir))/(p_0 -
    phi_supplyAir[2]*Modelica.Media.Air.MoistAir.saturationPressure(T_supplyAir));
  X_extractAir = (molarMassRatio*phi_extractAir*
    Modelica.Media.Air.MoistAir.saturationPressure(T_extractAir))/(p_0 -
    phi_extractAir*Modelica.Media.Air.MoistAir.saturationPressure(T_extractAir));

  // calculation of T_5 and T_6 regarding the electrical power consumption
  P_el_sup = V_dot_sup*dp_sup/eta_sup
    "Calculation of electrical power consumption";
  P_el_sup = V_dot_sup*rho*(c_pL_iG + X_sup*c_pW_iG)*(T_sup - T_5)
    "Calculation of T_5 by using V_dot_sup, efficiency eta_sup and input variable T_sup";
  P_el_eta = V_dot_eta*dp_eta/eta_eta
    "Calculation of electrical power consumption";
  P_el_eta = V_dot_eta*rho*(c_pL_iG + X_eta*c_pW_iG)*(T_6 - T_eta)
    "Calculation of T_6 by using V_dot_eta, efficiency eta_eta and input variable T_eta";

  // Calculation of relativ humidity of supply Air. Necessary for some superior model assamblies.
  X_sup = (molarMassRatio*phi_sup*
    Modelica.Media.Air.MoistAir.saturationPressure(T_sup))/(p_0 - phi_sup*
    Modelica.Media.Air.MoistAir.saturationPressure(T_sup));

  // converts time-discrete outputs of state machines into time-continous variables and limitation of thermal energies so that they cannot be negative
  allCond = if stateToDeHuHRS_true or stateToDeHuHRS_false or
    stateToHuPreHHRS_true or stateToHuPreHHRS_false or stateToHuCHRS_true or
    stateToHuCHRS_false or stateToOnlyHeatingHRS_true or
    stateToOnlyHeatingHRS_false or stateToOnlyCoolingHRS_true or
    stateToOnlyCoolingHRS_false then true else false;

  Vflow_out = hold(V_dot_sup);
  if Vflow_out > 0 and hold(V_dot_eta) <= 0 then
    Pel = hold(P_el_sup);
  elseif Vflow_out <= 0 and hold(V_dot_eta) > 0 then
    Pel = hold(P_el_eta);
  elseif Vflow_out > 0 and hold(V_dot_eta) > 0 then
    Pel = hold(P_el_eta) + hold(P_el_sup);
  else
    Pel = 0;
  end if;

  QflowH = if hold(Q_dot_H) > 0 then hold(Q_dot_H) else 0;
  QflowC = if hold(Q_dot_C) > 0 then hold(Q_dot_C) else 0;

  // The following part decides whether T_supplyAir input connector is passed through or outdoor air temp (+ slight changes) is used. Only necessery if either only heating or cooling is activated.
  if
    heating and not cooling and not dehumidification and not humidification then
    TsupplyAirOut = if stateToOnlyHeatingHRS_true or stateToOnlyHeatingHRS_false then T_sup else T_oda + phi_t_withoutHRS*(T_6 - T_oda) + dTFan;
  elseif
    cooling and not heating and not dehumidification and not humidification then
    TsupplyAirOut = if stateToOnlyCoolingHRS_true or stateToOnlyCoolingHRS_false then T_sup else T_oda + phi_t_withoutHRS*(T_6 - T_oda) + dTFan;
  elseif
    not heating and not cooling and not dehumidification and not humidification then
    TsupplyAirOut = T_oda + phi_t_withoutHRS*(T_6 - T_oda) + dTFan;
  else
    TsupplyAirOut = T_sup;
  end if;
  // with:
  P_el_sup = dTFan * V_dot_sup * rho * (c_pL_iG + X_oda * c_pW_iG);

  // transitions and conditions between state machines.
  initialState(startState)
  transition(
    startState,
    deHuHRS_true,
    stateToDeHuHRS_true,
    priority=1,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    deHuHRS_true,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToDeHuHRS_true==false,
  transition(
    startState,
    deHuHRS_false,
    stateToDeHuHRS_false,
    priority=2,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    deHuHRS_false,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToDeHuHRS_false==false,
  transition(
    startState,
    onlyHeatingHRS_true,
    stateToOnlyHeatingHRS_true,
    priority=7,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    startState,
    onlyHeatingHRS_false,
    stateToOnlyHeatingHRS_false,
    priority=8,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    startState,
    onlyCoolingHRS_true,
    stateToOnlyCoolingHRS_true,
    priority=9,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    startState,
    onlyCoolingHRS_false,stateToOnlyCoolingHRS_false,
    priority=10,
    immediate=false,
    reset=false,
    synchronize=false)
  transition(
    onlyHeatingHRS_true,
    startState,true,
    immediate=false,
    reset=false,
    synchronize=false,
    priority=11)
  //stateToOnlyHeatingHRS_true==false,
  transition(
    onlyHeatingHRS_false,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToOnlyHeatingHRS_false==false,
  transition(
    onlyCoolingHRS_true,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToOnlyCoolingHRS_true==false,
  transition(
    onlyCoolingHRS_false,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToOnlyCoolingHRS_false==false,
  transition(
    startState,
    huPreHHRS_true,
    stateToHuPreHHRS_true,
    priority=5,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huPreHHRS_true,
    startState,
    true,
    immediate=false,
    reset=false,
    synchronize=true,
    priority=11)
  //stateToHuPreHHRS_true==false,
  transition(
    startState,
    huPreHHRS_false,
    stateToHuPreHHRS_false,
    priority=6,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huPreHHRS_false,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToHuPreHHRS_false==false,
  transition(
    startState,
    huCHRS_true,
    stateToHuCHRS_true,
    priority=3,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huCHRS_true,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToHuCHRS_true==false,
  transition(
    startState,
    huCHRS_false,
    stateToHuCHRS_false,
    priority=4,
    immediate=true,
    reset=false,
    synchronize=false)
  transition(
    huCHRS_false,
    startState,
    true,
    priority=11,
    immediate=false,
    reset=false,
    synchronize=true)
  //stateToHuCHRS_false==false,

  connect(T_outdoorAir, sample.u[1])
  connect(X_outdoorAir, sample.u[2])
  connect(T_supplyAir, sample.u[3])
  connect(T_extractAir, sample.u[4])
  connect(Vflow_in, sample.u[8])
  connect(Vflow_in_extractAir_internal, sample.u[9]);
  connect(hold_phi_sup.y, phi_supply)
  connect(TsupAirOut.y, T_supplyAirOut)
public
  block StateExtra
  end StateExtra;
equation
  transition(
    startState,
    stateExtra,Q_dot_C > 0 and Q_dot_H > 0,
    immediate=false,
    reset=false,
    priority=11,synchronize=false)
  transition(
    stateExtra,
    startState,true,
    immediate=false,
    reset=false,synchronize=false,priority=1)
end AHU;


No AHU. This model can be seen as
  a dummy. Connectors exist due to partialAHU but outputs are zero and
  inputs do not have any effect. As a conclusion it is easier to choose
  whether an AHU exist in a building or not. For an example see
  AixLib.Building.LowOrder.Examples.MultizoneExample.

within AixLib.Airflow.AirHandlingUnit;
model NoAHU "No AHU"
  extends AixLib.Airflow.AirHandlingUnit.BaseClasses.PartialAHU;
  Modelica.Blocks.Sources.Constant dummyPhi_supply(k=0.5)
  Modelica.Blocks.Sources.Constant zeroVFlowOut(k(unit="m3/s") = 0)
  Modelica.Blocks.Sources.Constant dummyT_supplyAirOut(k=293)
  Modelica.Blocks.Sources.CombiTimeTable zeroPowerElAndHeat1(
    tableOnFile=false,
    table=[0,0.0],
    columns={2},
    extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint)
equation
  connect(dummyPhi_supply.y, phi_supply)
  connect(zeroVFlowOut.y, Vflow_out)
  connect(dummyT_supplyAirOut.y, T_supplyAirOut)
  connect(zeroPowerElAndHeat1.y[1], QflowC)
  connect(zeroPowerElAndHeat1.y[1], QflowH)
  connect(zeroPowerElAndHeat1.y[1], Pel)
end NoAHU;


Defines necessary parameters and connectors. Base class to provide
  connectors. Thus, it is possible to declare parameters in a general
  way in superior building model and give the opportunity whether an
  AHU exist or
  does not.

within AixLib.Airflow.AirHandlingUnit.BaseClasses;
partial model PartialAHU "Defines necessary parameters and connectors"

  parameter Real clockPeriodGeneric(min=0) = 1800
    "time period in s for sampling (= converting time-continous into time-discrete) input variables. Recommendation: half of the duration of one simulation interval"
    // Booleans for possible AHU modes
  inner parameter Boolean heating=true "Heating Function of AHU"
  inner parameter Boolean cooling=true "Cooling Function of AHU"
  inner parameter Boolean dehumidificationSet=if heating and cooling then true
       else false
    "Dehumidification Function of AHU (Cooling and Heating must be enabled)"
  inner parameter Boolean humidificationSet=if heating and cooling then true else false
    "Humidification Function of AHU (Cooling and Heating must be enabled)"
  inner Boolean dehumidification;
  inner Boolean humidification;
  inner parameter Real BPF_DeHu(
    min=0,
    max=1) = 0.2
    "By-pass factor of cooling coil during dehumidification. Necessary to
    calculate the real outgoing enthalpy flow of heat exchanger in
    dehumidification mode taking the surface enthalpy of the cooling coil into account"
  inner parameter Boolean HRS=true
    "Is a HeatRecoverySystem physically integrated in the AHU?"
  parameter Boolean use_Vflow_in_extractAir=false
    "If incoming volume flow of outdoor/supply air should not equal the
    volume flow of extract air, set this parameter to true"
  // Efficiency of HRS
  parameter Real efficiencyHRS_enabled(
    min=0,
    max=1) = 0.8 "efficiency of HRS in the AHU modes when HRS is enabled"
  parameter Real efficiencyHRS_disabled(
    min=0,
    max=1) = 0.2
    "taking a little heat transfer into account although HRS is disabled
    (in case that a HRS is physically installed in the AHU)"
  // assumed increase in ventilator pressure
  parameter Modelica.Units.SI.Pressure dp_sup=800
    "pressure difference over supply fan"
  parameter Modelica.Units.SI.Pressure dp_eta=800
    "pressure difference over extract fan"
  // assumed efficiencies of the ventilators
  parameter Modelica.Units.SI.Efficiency eta_sup=0.7 "efficiency of supply fan"
  parameter Modelica.Units.SI.Efficiency eta_eta=0.7
    "efficiency of extract fan"

  Modelica.Blocks.Interfaces.RealInput Vflow_in(unit="m3/s") "m3/s"
  Modelica.Blocks.Interfaces.RealInput T_outdoorAir(unit="K", start=288.15) "K"
  Modelica.Blocks.Interfaces.RealInput X_outdoorAir(start=0.007)
    "kg of water/kg of dry air"
  Modelica.Blocks.Interfaces.RealInput T_extractAir(unit="K", start=296.15) "K"
  Modelica.Blocks.Interfaces.RealInput phi_extractAir(start=0.8)
    "relativ Humidity [Range: 0...1]"
  Modelica.Blocks.Interfaces.RealOutput phi_supply(start=0.8)
    "relativ Humidity [Range: 0...1]"
  Modelica.Blocks.Interfaces.RealInput T_supplyAir(unit="K", start=295.15)
    "K (use as PortIn)"
  Modelica.Blocks.Interfaces.RealInput phi_supplyAir[2](start={0.4,0.6})
    "relativ Humidity [Range: 0...1] (Vector: [1] min, [2] max)"
  Modelica.Blocks.Interfaces.RealOutput QflowC(unit="W", min=0, start=0.01)
    "The absorbed cooling power supplied from a cooling circuit [W]"
  Modelica.Blocks.Interfaces.RealOutput QflowH(unit="W", min=0, start=0.01)
    "The absorbed heating power supplied from a heating circuit [W]"
  Modelica.Blocks.Interfaces.RealOutput Pel(unit="W", min=0, start=1e-3)
    "The consumed electrical power supplied from the mains [W]"
  Modelica.Blocks.Interfaces.RealOutput Vflow_out(unit="m3/s",start=1e-3)
    "supply volume flow in m3/s"
  Modelica.Blocks.Interfaces.RealOutput T_supplyAirOut(unit="K", start=295.15)
    "K (use as PortOut)"
  Modelica.Blocks.Interfaces.RealInput Vflow_in_extractAir(unit="m3/s")
if use_Vflow_in_extractAir "Volume flow of extract air"
protected
  Modelica.Blocks.Interfaces.RealInput Vflow_in_extractAir_internal(unit="m3/s") "Needed to connect to conditional connector";
equation
  dehumidification = if dehumidificationSet and heating and cooling then dehumidificationSet else false;
  humidification = if humidificationSet and heating and cooling then humidificationSet else false;

  connect(Vflow_in_extractAir, Vflow_in_extractAir_internal);

  if not use_Vflow_in_extractAir then
    Vflow_in_extractAir_internal = Vflow_in;
  end if;
end PartialAHU;


Example to test all states of the AHU model - Play with the possible modes (boolean parameters for: heating, cooling, de-/humidification.

within AixLib.Airflow.AirHandlingUnit.Examples;
model AHU
  "Example to test all states of the AHU model - Play with the possible modes (boolean parameters for: heating, cooling, de-/humidification"
    extends Modelica.Icons.Example;

  Modelica.Blocks.Sources.Sine tempOutside(
    amplitude=10,
    f=1/86400,
    phase=-3.1415/2,
    offset=292)
  Modelica.Blocks.Sources.Constant Vflow_in(k=100)
  Modelica.Blocks.Sources.Constant desiredT_sup(k=293)
  .AixLib.Airflow.AirHandlingUnit.AHU ahu(
    clockPeriodGeneric=30,
    heating=true,
    cooling=true,
    HRS=true)
  Modelica.Blocks.Sources.Constant phi_roomMin(k=0.47)
  Modelica.Blocks.Sources.Constant phi_roomMax(k=0.55)

  Modelica.Blocks.Sources.Sine waterLoadOutside(
    f=1/86400,
    offset=0.008,
    amplitude=0.002,
    phase=-0.054829518451402)
  Modelica.Blocks.Sources.Constant phi_RoomExtractAir(k=0.6)
  Modelica.Blocks.Sources.Sine tempAddInRoom(
    f=1/86400,
    amplitude=2,
    phase=-3.1415/4,
    offset=1.7)
  Modelica.Blocks.Math.Add addToExtractTemp
  Modelica.Blocks.Interfaces.RealOutput QFlowCool(
   final quantity="Power",
   final unit="W")
  Modelica.Blocks.Interfaces.RealOutput QFlowHeat(
   final quantity="Power",
   final unit="W")
  Modelica.Blocks.Interfaces.RealOutput PEl(
   final quantity="Power",
   final unit="W")
equation

  connect(desiredT_sup.y, ahu.T_supplyAir)
  connect(tempOutside.y, ahu.T_outdoorAir)
  connect(Vflow_in.y, ahu.Vflow_in)
  connect(phi_roomMin.y, ahu.phi_supplyAir[1])
  connect(waterLoadOutside.y, ahu.X_outdoorAir)
  connect(phi_RoomExtractAir.y, ahu.phi_extractAir)
  connect(phi_roomMax.y, ahu.phi_supplyAir[2])
  connect(ahu.T_extractAir, addToExtractTemp.y)
  connect(tempAddInRoom.y, addToExtractTemp.u1)
  connect(desiredT_sup.y, addToExtractTemp.u2)
  connect(ahu.QflowC, QFlowCool)
  connect(ahu.QflowH, QFlowHeat)
  connect(ahu.Pel, PEl)
end AHU;


within AixLib.Airflow.AirHandlingUnit;
package Examples "Contains examples for Air Handling Units"
extends Modelica.Icons.ExamplesPackage;
end Examples;


within AixLib.Airflow.FacadeVentilationUnit;
model FacadeVentilationUnit
  "Facade Ventilation Unit (FVU) equipped with a recuperator"
  replaceable package Water = AixLib.Media.Water
    "Water Model in the system";
  replaceable package Air = AixLib.Media.Air
    "Air Model in the system";

  parameter AixLib.Airflow.FacadeVentilationUnit.DataBase.FVUBaseRecord
    fVUParam=AixLib.Airflow.FacadeVentilationUnit.DataBase.FVUBaseRecord()
    "Record containing the characteristic parameters of the unit";

  parameter Modelica.Units.SI.ThermodynamicTemperature T_start=273.15 + 20
    "Initial temperature in unit";

  AixLib.Airflow.FacadeVentilationUnit.BaseClasses.SetPower fanExhaustAir(
    redeclare package Medium = Air,
    noUnits=fVUParam.noUnits,
    m_flow_nominal=fVUParam.m2_flow_nominal_heater,
    T_start=T_start,
    p_start=fVUParam.dp2_nominal_heater)
    "The fan on the exhaust air side"
  AixLib.Airflow.FacadeVentilationUnit.BaseClasses.SetPower fanSupplyAir(
    redeclare package Medium = Air,
    noUnits=fVUParam.noUnits,
    m_flow_nominal=fVUParam.m2_flow_nominal_heater,
    p_start=5*fVUParam.dp2_nominal_heater,
    dp_nominal=5*fVUParam.dp2_nominal_heater)
    "The fan on the supply air side"
  Modelica.Fluid.Sensors.Temperature extractAirTemperature(redeclare package Medium =
               Air) "Temperature of the extract air"
  AixLib.Fluid.HeatExchangers.ConstantEffectiveness heater(
    redeclare package Medium2 = Air,
    redeclare package Medium1 = Water,
    m1_flow_nominal=fVUParam.m1_flow_nominal_heater,
    m2_flow_nominal=fVUParam.m2_flow_nominal_heater,
    dp1_nominal(displayUnit="Pa") = fVUParam.dp1_nominal_heater,
    dp2_nominal(displayUnit="Pa") = fVUParam.dp2_nominal_heater)
    "The heat exchanger used for heating"
  Modelica.Fluid.Interfaces.FluidPort_b exhaustAirConnector(redeclare package Medium =
               Air) "Connector to the exhaust air sink"
  Modelica.Fluid.Interfaces.FluidPort_a freshAirConnector(redeclare package Medium =
               Air) "Connector to the fresh air source"
  Modelica.Fluid.Interfaces.FluidPort_a extractAirConnector(redeclare package Medium =
               Air) "Connector to the extract air source"
  Modelica.Fluid.Interfaces.FluidPort_b supplyAirConnector(redeclare package Medium =
               Air) "Connector to the supply air sink"
  AixLib.Fluid.HeatExchangers.ConstantEffectiveness cooler(
    redeclare package Medium2 = Air,
    redeclare package Medium1 = Water,
    dp1_nominal(displayUnit="Pa") = fVUParam.dp1_nominal_cooler,
    dp2_nominal(displayUnit="Pa") = fVUParam.dp2_nominal_cooler,
    m1_flow_nominal=fVUParam.m1_flow_nominal_cooler,
    m2_flow_nominal=fVUParam.m2_flow_nominal_cooler)
    "The heat exchanger used for cooling"
  Modelica.Fluid.Interfaces.FluidPort_b heaterReturnConnector(redeclare package
                                                                                Medium =
               Water) "Connector to the heating water sink"
  Modelica.Fluid.Interfaces.FluidPort_a heaterFlowConnector(redeclare package Medium =
               Water) "Connector to the heating water source"
  Modelica.Fluid.Interfaces.FluidPort_b coolerReturnConnector(redeclare package
                                                                                Medium =
               Water) "Connector to the cooling water source"
  Modelica.Fluid.Interfaces.FluidPort_a coolerFlowConnector(redeclare package Medium =
               Water) "Connector to the cooling water source"
  Modelica.Fluid.Sensors.Temperature freshAirTemperature(redeclare package Medium =
               Air) "Temperature of the fresh air"
  Modelica.Fluid.Sensors.Temperature exhaustAirTemperature(redeclare package Medium =
               Air) "Temperature of the exhaust air"
  Modelica.Fluid.Sensors.Temperature coolerTemperature(redeclare package Medium =
           Air) "Temperature of the supply air stream behind the cooler"
  Modelica.Fluid.Sensors.Temperature heatRecoveryTemperature(redeclare package Medium =
               Air) "Temperature behind the recuperator"

  Modelica.Blocks.Math.Add oppositeOpening(k1=-1)
    "Provides the relative opening of the complementary damper of the
    recuperator"
  Modelica.Blocks.Sources.Constant one(k=1) "Output the Real value 1 "
  Modelica.Fluid.Sensors.Temperature mixAirTemperature(redeclare package Medium =
           Air) "Temperature of the mixed circulation and fresh air streams"
  inner Modelica.Fluid.System system
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperCirculationAir(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeLong,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
                 "Damper that controls the air stream that is recirculated"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperBypass(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeLong,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
    "The second of two dampers that control the air flow through the
    recuperator"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperHeatRecovery(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeLong,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
    "The first of two dampers that control the air flow through the recuperator"
  Modelica.Fluid.Sensors.Temperature heaterTemperature(redeclare package Medium =
                Air) "Temperature of the supply air stream behind the heater"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening damperFreshAir(
    redeclare package Medium = Air,
    riseTime=fVUParam.damperRiseTimeShort,
    m_flow_nominal=fVUParam.m_flow_nominal_damper,
    dpValve_nominal=fVUParam.dp_nominal_damper)
                 "Can be used to disconnect the unit from fresh air source"
  AixLib.Fluid.HeatExchangers.ConstantEffectiveness recuperator(
    redeclare package Medium1 = Air,
    redeclare package Medium2 = Air,
    eps=0.6,
    m1_flow_nominal=fVUParam.m2_flow_nominal_heater,
    m2_flow_nominal=fVUParam.m2_flow_nominal_heater,
    dp1_nominal=fVUParam.dp2_nominal_heater,
    dp2_nominal=fVUParam.dp2_nominal_heater)
    "The heat exchanger used for recovering heat or cold from extract air
    stream"
  Modelica.Fluid.Vessels.ClosedVolume volume(
    nPorts=4,
    use_portsData=false,
    V=0.01,
    redeclare package Medium = Air,
    T_start=T_start)
    "Volume where the circulation air and the fresh air stream mix"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening heatingValve(
    redeclare package Medium = Water,
    riseTime=fVUParam.damperRiseTimeLong,
    dpValve_nominal=fVUParam.dp1_nominal_heater,
    m_flow_nominal=fVUParam.m1_flow_nominal_heater)
    "Valve controlling the heating water flow into the unit"
  AixLib.Fluid.Actuators.Valves.TwoWayQuickOpening coolingValve(
    redeclare package Medium = Water,
    riseTime=fVUParam.damperRiseTimeLong,
    dpValve_nominal=fVUParam.dp1_nominal_heater,
    m_flow_nominal=fVUParam.m1_flow_nominal_heater)
    "Valve controlling the cooling water flow into the unit"
  AixLib.Controls.Interfaces.FVUControlBus fVUControlBus
    "Bus with controller signals"
equation

  connect(cooler.port_b2, supplyAirConnector)
  connect(extractAirTemperature.port, extractAirConnector)
  connect(freshAirTemperature.port, freshAirConnector)
  connect(exhaustAirTemperature.port, fanExhaustAir.port_b)
  connect(cooler.port_b2, coolerTemperature.port)

  connect(oppositeOpening.u2, one.y)

  connect(mixAirTemperature.port, fanSupplyAir.port_a)
  connect(freshAirConnector, freshAirConnector)
  connect(oppositeOpening.y, damperBypass.y)
  connect(extractAirConnector, extractAirConnector)
  connect(heaterTemperature.port, heater.port_b2)
  connect(damperFreshAir.port_b, damperHeatRecovery.port_a)
  connect(freshAirConnector, damperFreshAir.port_a)
  connect(damperFreshAir.port_b, damperBypass.port_a)
  connect(fanSupplyAir.port_b, heater.port_a2)
  connect(extractAirConnector, recuperator.port_a2)
  connect(recuperator.port_b2, fanExhaustAir.port_a)
  connect(recuperator.port_b1, volume.ports[1])
  connect(damperBypass.port_b, volume.ports[2])
  connect(damperCirculationAir.port_b, volume.ports[3])
  connect(fanSupplyAir.port_a, volume.ports[4])
  connect(heatRecoveryTemperature.port, recuperator.port_b1)
  connect(heater.port_b2, cooler.port_a2)
  connect(heater.port_a1, heatingValve.port_a)
  connect(heatingValve.port_b, heaterFlowConnector)
  connect(coolerReturnConnector, cooler.port_b1)
  connect(cooler.port_a1, coolingValve.port_a)
  connect(coolingValve.port_b, coolerFlowConnector)
  connect(heaterReturnConnector, heater.port_b1)
  connect(extractAirConnector, damperCirculationAir.port_a)
  connect(damperCirculationAir.y, fVUControlBus.circulationDamperOpening)
  connect(fanSupplyAir.powerShare, fVUControlBus.fanSupplyAirPower)
  connect(fanExhaustAir.powerShare, fVUControlBus.fanExhaustAirPower)
  connect(damperFreshAir.y, fVUControlBus.freshAirDamperOpening)
  connect(damperHeatRecovery.y, fVUControlBus.hRCDamperOpening)
  connect(oppositeOpening.u1, fVUControlBus.hRCDamperOpening)
  connect(heatingValve.y, fVUControlBus.heatingValveOpening)
  connect(coolingValve.y, fVUControlBus.coolingValveOpening)
  connect(damperHeatRecovery.port_b, recuperator.port_a1)
  connect(fanExhaustAir.port_b, exhaustAirConnector)
  connect(coolerTemperature.T, fVUControlBus.supplyTemperature)
  connect(mixAirTemperature.T, fVUControlBus.mixTemperature)
end FacadeVentilationUnit;


within AixLib.Airflow;
package FacadeVentilationUnit "Package for decentralized air handling unit"
end FacadeVentilationUnit;


within AixLib.Airflow.FacadeVentilationUnit.BaseClasses;
model SetPower
  "This model defines a specific mass flow rate based on the input power
    share"

  extends Modelica.Fluid.Interfaces.PartialTwoPort;

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=0.05
    "Nominal mass flow rate of fan";
  parameter Medium.AbsolutePressure p_start=Medium.p_default
    "Start value of pressure";
  parameter Integer noUnits=1 "Number of identical FVU units";
  parameter Modelica.Units.SI.PressureDifference dp_nominal=500
    "Initial pressure difference";
  parameter Medium.Temperature T_start=Medium.T_default
    "Start value of temperature";

  Modelica.Blocks.Tables.CombiTable1Dv volumeFlow(table=[0,1; 0.1,25; 0.2,40;
        0.3,60; 0.4,90; 0.5,100; 0.6,140; 0.7,175; 0.8,200; 0.9,225; 1,260])
    "Correlates the relative input signal and a volume flow rate"
  Modelica.Blocks.Interfaces.RealInput powerShare(
    min=0,
    max=1,
    nominal=0.6) "Power share 0..1 for fan"

  AixLib.Fluid.Movers.FlowControlled_m_flow fan(
    redeclare package Medium = Medium,
    addPowerToMedium=false,
    m_flow_nominal=m_flow_nominal,
    T_start=T_start,
    m_flow(start=m_flow_nominal),
    dp(start=dp_nominal),
    dp_nominal=dp_nominal,
    p_start=p_start,
    riseTime=120,
    nominalValuesDefineDefaultPressureCurve=true)
    "Mass-flow-controlled mover setting mass flow rate from table"
  Modelica.Blocks.Math.Gain transforMassFlow(k=1.2/3600*noUnits, y(unit="kg/s"))
    "Used to transform the volume flow rate in m3/h into a mass flow rate in kg/s"
equation

  connect(port_a, fan.port_a)
  connect(fan.port_b, port_b)
  connect(powerShare, volumeFlow.u[1])
  connect(transforMassFlow.u, volumeFlow.y[1])
  connect(transforMassFlow.y, fan.m_flow_in)
end SetPower;


within AixLib.Airflow.FacadeVentilationUnit;
package DataBase "Contains parameter records of the facade ventilation unit"
extends Modelica.Icons.Package;
end DataBase;


within AixLib.Airflow.FacadeVentilationUnit.Examples;
model FacadeVentilationUnit
  "Example showing the use of facade ventilation unit and controller"
  extends Modelica.Icons.Example;

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

  AixLib.Controls.AirHandling.FVUController FVUController(
      maxSupFanPower=0.6,
      maxExFanPower=0.6)
    "Comprehensive rule-based controller for the facade ventilation unit"
  AixLib.Airflow.FacadeVentilationUnit.FacadeVentilationUnit FVU(redeclare
      package                                                                      Air =
                    Medium1, redeclare package Water = Medium2)
    "The facade ventilation unit to be tested in this example"
  AixLib.Fluid.Sources.Boundary_pT freshAirSource(
    nPorts=1,
    redeclare package Medium = Medium1,
    use_T_in=true,
    p(displayUnit="Pa") = 101300) "Sink of the exhaust air"
  AixLib.Fluid.Sources.Boundary_pT exhaustAirSink(
    nPorts=1,
    redeclare package Medium = Medium1,
    p(displayUnit="Pa") = 101300) "Source of freah air"
  AixLib.Fluid.Sources.Boundary_pT heatingSnk(
    redeclare package Medium = Medium2,
    nPorts=1,
    p=100000) "Sink of the heating water"
  AixLib.Fluid.Sources.Boundary_pT coolingSink(
    redeclare package Medium = Medium2,
    nPorts=1,
    p=100000) "Sink of the cooling water"
  AixLib.Fluid.Sources.Boundary_pT coolingSource(
    redeclare package Medium = Medium2,
    use_T_in=true,
    nPorts=1,
    p=101000) "Source of the cooling water"
  AixLib.Fluid.Sources.Boundary_pT heatingSource(
    redeclare package Medium = Medium2,
    use_T_in=true,
    nPorts=1,
    p=101000) "Source of the heating water"
  AixLib.Fluid.Sources.Boundary_pT supplyAirSink(
    redeclare package Medium = Medium1,
    use_T_in=false,
    nPorts=1,
    p(displayUnit="Pa") = 101300) "Sink of the supply air"
  AixLib.Fluid.Sources.Boundary_pT extractAirSource(
    nPorts=1,
    redeclare package Medium = Medium1,
    use_T_in=true,
    p(displayUnit="Pa") = 101300) "Source of the extract air"
  Modelica.Blocks.Sources.Constant heatingWaterTemperature(k=273.15 + 30)
    "Provides a test value of the heating water temperatrure"
  Modelica.Blocks.Sources.Constant coolingWaterTemperature(k=273.15 + 17)
    "Provides a test value of the cooling water temperatiure"
  AixLib.Fluid.Sensors.TemperatureTwoPort supplyAirTemperature(redeclare
      package                                                                    Medium =
                       Medium1, m_flow_nominal=0.1)
    "Measures the supply air temperature"
  Modelica.Blocks.Sources.Sine roomTemperature(
    amplitude=5,
    f=1/86400,
    phase=3.1415926535898,
    offset=273.15 + 20) "Provides a test value of the room temperature"
  Modelica.Blocks.Sources.Sine roomSetTemperature(
    amplitude=5,
    f=1/86400,
    phase=1.5707963267949,
    offset=273.15 + 20) "Provides a test value of the room set temperature"
  Modelica.Blocks.Sources.Constant co2Concentration(k=1000)
    "Provides a test value of the CO2 concnetration"
  Modelica.Blocks.Sources.Sine outdoorTemperature(
    amplitude=5,
    f=1/86400,
    offset=273.15 + 10) "Provides a test value of the outdoor temperature"
  AixLib.Controls.Interfaces.FVUControlBus fVUControlBus
  "Bus with controller sginals"
equation
  connect(FVU.extractAirConnector, extractAirSource.ports[1])
  connect(heatingSnk.ports[1], FVU.heaterReturnConnector)
  connect(coolingSource.ports[1], FVU.coolerFlowConnector)
  connect(heatingWaterTemperature.y, heatingSource.T_in)
  connect(coolingWaterTemperature.y, coolingSource.T_in)
  connect(FVU.coolerReturnConnector, coolingSink.ports[1])
  connect(heatingSource.ports[1], FVU.heaterFlowConnector)
  connect(exhaustAirSink.ports[1], FVU.exhaustAirConnector)
  connect(freshAirSource.ports[1], FVU.freshAirConnector)
  connect(FVU.supplyAirConnector, supplyAirTemperature.port_a)
  connect(supplyAirTemperature.port_b, supplyAirSink.ports[1])
  connect(FVU.fVUControlBus, FVUController.fVUControlBus)
  connect(FVUController.fVUControlBus, fVUControlBus)
  connect(roomTemperature.y, extractAirSource.T_in)
  connect(outdoorTemperature.y,freshAirSource. T_in)
  connect(roomTemperature.y, fVUControlBus.roomTemperature)
  connect(outdoorTemperature.y, fVUControlBus.outdoorTemperature)
  connect(roomSetTemperature.y, fVUControlBus.roomSetTemperature)
  connect(co2Concentration.y, fVUControlBus.co2Concentration)
end FacadeVentilationUnit;


Powerlaw with coefficient for mass flow rate. This model describes the one-directional pressure driven air flow through an opening, using the equation

within AixLib.Airflow.Multizone;
model Coefficient_m_flow "Powerlaw with coefficient for mass flow rate"
  extends AixLib.Airflow.Multizone.BaseClasses.PartialOneWayFlowElement(
    m_flow=rho*AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
        C=C,
        dp=dp,
        m=m,
        a=a,
        b=b,
        c=c,
        d=d,
        dp_turbulent=dp_turbulent),
    final m_flow_nominal=k*dp_turbulent,
    final m_flow_small=1E-4*abs(m_flow_nominal));
  extends AixLib.Airflow.Multizone.BaseClasses.PowerLawResistanceParameters(
    m = 0.5);
  parameter Real k "Flow coefficient, k = m_flow/ dp^m";
protected
  parameter Real C=k/rho_default "Flow coefficient, C = V_flow/dp^m";
end Coefficient_m_flow;


Power law with coefficient for volume flow rate. This model describes the one-directional pressure driven air flow through an opening, using the equation

within AixLib.Airflow.Multizone;
model Coefficient_V_flow "Power law with coefficient for volume flow rate"
  extends AixLib.Airflow.Multizone.BaseClasses.PartialOneWayFlowElement(
    m_flow = V_flow*rho,
    V_flow = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
      C=C,
      dp=dp,
      m=m,
      a=a,
      b=b,
      c=c,
      d=d,
      dp_turbulent=dp_turbulent),
    final m_flow_nominal=rho_default*C*dp_turbulent,
    final m_flow_small=1E-4*abs(m_flow_nominal));
   extends AixLib.Airflow.Multizone.BaseClasses.PowerLawResistanceParameters(
     m = 0.5);

  parameter Real C "Flow coefficient, C = V_flow/ dp^m";
end Coefficient_V_flow;


Door model using discretization along height coordinate. This model describes the bi-directional air flow through an open door.

within AixLib.Airflow.Multizone;
model DoorDiscretizedOpen
  "Door model using discretization along height coordinate"
  extends AixLib.Airflow.Multizone.BaseClasses.DoorDiscretized;

  parameter Real CD=0.65 "Discharge coefficient"

protected
  constant Real mFixed = 0.5 "Fixed value for flow coefficient";
  constant Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  constant Real a = gamma
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real b = 1/8*mFixed^2 - 3*gamma - 3/2*mFixed + 35.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real c = -1/4*mFixed^2 + 3*gamma + 5/2*mFixed - 21.0/4
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real d = 1/8*mFixed^2 - gamma - mFixed + 15.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
equation
  m=mFixed;
  A = wOpe*hOpe;
  CVal = CD*dA*sqrt(2/rho_default);
  // orifice equation
  for i in 1:nCom loop
    dV_flow[i] = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
      C=CVal,
      dp=dpAB[i],
      m=mFixed,
      a=a,
      b=b,
      c=c,
      d=d,
      dp_turbulent=dp_turbulent);
  end for;
end DoorDiscretizedOpen;


within AixLib.Airflow.Multizone;
model DoorDiscretizedOperable
  "Door model using discretization along height coordinate"
  extends AixLib.Airflow.Multizone.BaseClasses.DoorDiscretized;

  parameter Modelica.Units.SI.PressureDifference dpCloRat(
    min=0,
    displayUnit="Pa") = 4 "Pressure drop at rating condition of closed door"

  parameter Real CDCloRat(min=0, max=1)=1
    "Discharge coefficient at rating conditions of closed door"

  parameter Modelica.Units.SI.Area LClo(min=0)
    "Effective leakage area of closed door"

  parameter Real CDOpe=0.65 "Discharge coefficient of open door"
  parameter Real CDClo=0.65 "Discharge coefficient of closed door"

  parameter Real mOpe = 0.5 "Flow exponent for door of open door"
  parameter Real mClo= 0.65 "Flow exponent for crack of closed door"

  Modelica.Blocks.Interfaces.RealInput y(min=0, max=1, unit="1")
    "Opening signal, 0=closed, 1=open"
protected
  parameter Modelica.Units.SI.Area AOpe=wOpe*hOpe "Open aperture area";
  parameter Modelica.Units.SI.Area AClo(fixed=false) "Closed aperture area";

  Real COpe "Open aperture flow coefficient, C = V_flow/ dp^m";
  Real CClo "Closed aperture flow coefficient, C = V_flow/ dp^m";

 Real fraOpe "Fraction of aperture that is open";
initial equation
  AClo=CDClo/CDCloRat * LClo * dpCloRat^(0.5-mClo);
equation
  fraOpe =y;
  CClo = CDClo * AClo/nCom * sqrt(2/rho_default);
  COpe = CDOpe * AOpe/nCom * sqrt(2/rho_default);

  // flow exponent
  m    = fraOpe*mOpe + (1-fraOpe)*mClo;
  // opening area
  A = fraOpe*AOpe + (1-fraOpe)*AClo;
  // friction coefficient for power law
  CVal = fraOpe*COpe + (1-fraOpe)*CClo;

  // orifice equation
  for i in 1:nCom loop
    dV_flow[i] = AixLib.Airflow.Multizone.BaseClasses.powerLaw(C=CVal,
      dp=dpAB[i],
      m=m,
      dp_turbulent=dp_turbulent);
  end for;
end DoorDiscretizedOperable;


Door model for bi-directional air flow between rooms. Model for bi-directional air flow through a large opening such as a door.

within AixLib.Airflow.Multizone;
model DoorOpen
  "Door model for bi-directional air flow between rooms"
  extends AixLib.Airflow.Multizone.BaseClasses.Door(
    final vAB = VAB_flow/AOpe,
    final vBA = VBA_flow/AOpe);

  parameter Real CD=0.65 "Discharge coefficient"

  parameter Real m = 0.5 "Flow coefficient"

protected
  constant Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  constant Real a = gamma
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real b = 1/8*m^2 - 3*gamma - 3/2*m + 35.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real c = -1/4*m^2 + 3*gamma + 5/2*m - 21.0/4
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real d = 1/8*m^2 - gamma - m + 15.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";

  parameter Real CVal=CD*AOpe*sqrt(2/rho_default)
    "Flow coefficient, C = V_flow/ dp^m";
  parameter Real kT = rho_default * CD * AOpe/3 *
    sqrt(Modelica.Constants.g_n /(Medium.T_default*conTP) * hOpe)
    "Constant coefficient for buoyancy driven air flow rate";

  parameter Modelica.Units.SI.MassFlowRate m_flow_turbulent=CVal*rho_default*
      sqrt(dp_turbulent)
    "Mass flow rate where regularization to laminar flow occurs for temperature-driven flow";

equation
  // Air flow rate due to static pressure difference
  VABp_flow = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(C=CVal,
      dp=port_a1.p-port_a2.p,
      m=m,
      a=a,
      b=b,
      c=c,
      d=d,
      dp_turbulent=dp_turbulent);
  // Air flow rate due to buoyancy
  // Because powerLawFixedM requires as an input a pressure difference pa-pb,
  // we convert Ta-Tb by multiplying it with rho*R, and we divide
  // above the constant expression by (rho*R)^m on the right hand-side of kT.
  // Note that here, k is for mass flow rate, whereas in powerLawFixedM, it is for volume flow rate.
  // We can use m=0.5 as this is from Bernoulli.
  mABt_flow = AixLib.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp(
      k=kT,
      dp=conTP*(Medium.temperature(state_a1_inflow)-Medium.temperature(state_a2_inflow)),
      m_flow_turbulent=m_flow_turbulent);
end DoorOpen;


Door model for bi-directional air flow between rooms that can be open or closed. Model for bi-directional air flow through a large opening such as a door which can be opened or closed
based on the control input signal <i>y</i>.

within AixLib.Airflow.Multizone;
model DoorOperable
  "Door model for bi-directional air flow between rooms that can be open or closed"
  extends AixLib.Airflow.Multizone.BaseClasses.Door(
    final vAB = VAB_flow/A,
    final vBA = VBA_flow/A);

  parameter Real CDOpe=0.65 "Discharge coefficient of open door"

  parameter Real mOpe = 0.5 "Flow exponent for door of open door"

  parameter Modelica.Units.SI.Area LClo(min=0)
    "Effective leakage area of closed door"

  parameter Real mClo= 0.65 "Flow exponent for crack of closed door"

  parameter Modelica.Units.SI.PressureDifference dpCloRat(
    min=0,
    displayUnit="Pa") = 4 "Pressure drop at rating condition of closed door"

  parameter Real CDCloRat(min=0, max=1)=1
    "Discharge coefficient at rating conditions of closed door"

  Modelica.Blocks.Interfaces.RealInput y(min=0, max=1, unit="1")
    "Opening signal, 0=closed, 1=open"

protected
  parameter Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  parameter Real[2] a = {gamma, gamma}
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real b[2] = {1/8*m^2 - 3*gamma - 3/2*m + 35.0/8 for m in {mOpe, mClo}}
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real c[2] = {-1/4*m^2 + 3*gamma + 5/2*m - 21.0/4 for m in {mOpe, mClo}}
    "Polynomial coefficient for regularized implementation of flow resistance";
  parameter Real d[2] = {1/8*m^2 - gamma - m + 15.0/8 for m in {mOpe, mClo}}
    "Polynomial coefficient for regularized implementation of flow resistance";

  parameter Modelica.Units.SI.Area AClo=LClo*dpCloRat^(0.5 - mClo)
    "Closed area";
  parameter Real CVal[2]=
    {CDOpe*AOpe*sqrt(2/rho_default),
    CDCloRat*AClo*sqrt(2/rho_default)}
    "Flow coefficient, C = V_flow/ dp^m";

  parameter Real kT = rho_default * CDOpe * AOpe/3 *
    sqrt(Modelica.Constants.g_n /(Medium.T_default*conTP) * hOpe)
    "Constant coefficient for buoyancy driven air flow rate";

  parameter Modelica.Units.SI.MassFlowRate m_flow_turbulent=CVal[1]*rho_default
      *sqrt(dp_turbulent)
    "Mass flow rate where regularization to laminar flow occurs for temperature-driven flow";

  Modelica.Units.SI.VolumeFlowRate VABpOpeClo_flow[2](each nominal=0.001)
    "Volume flow rate from A to B if positive due to static pressure difference";

  Modelica.Units.SI.Area A "Current opening area";
equation
  // Air flow rate due to static pressure difference
  VABpOpeClo_flow = AixLib.Airflow.Multizone.BaseClasses.powerLawFixedM(
    C=CVal,
    dp=port_a1.p-port_a2.p,
    m={mOpe, mClo},
    a=a,
    b=b,
    c=c,
    d=d,
    dp_turbulent=dp_turbulent);
  VABp_flow = y*VABpOpeClo_flow[1] + (1-y)*VABpOpeClo_flow[2];
  A = y*AOpe + (1-y)*AClo;
  // Air flow rate due to buoyancy
  // Because powerLawFixedM requires as an input a pressure difference pa-pb,
  // we convert Ta-Tb by multiplying it with rho*R, and we divide
  // above the constant expression by (rho*R)^m on the right hand-side of kT.
  mABt_flow = y*AixLib.Fluid.BaseClasses.FlowModels.basicFlowFunction_dp(
      k=kT,
      dp=conTP*(Medium.temperature(state_a1_inflow)-Medium.temperature(state_a2_inflow)),
      m_flow_turbulent=m_flow_turbulent);
end DoorOperable;


Effective air leakage area. This model describes the one-directional pressure driven
air flow through a crack-like opening, using the equation

within AixLib.Airflow.Multizone;
model EffectiveAirLeakageArea "Effective air leakage area"
  extends AixLib.Airflow.Multizone.Coefficient_V_flow(
    m=0.65,
    final C=L * CDRat * sqrt(2.0/rho_default) * dpRat^(0.5-m));

  parameter Modelica.Units.SI.PressureDifference dpRat(
    min=0,
    displayUnit="Pa") = 4 "Pressure drop"
  parameter Real CDRat(
    min=0,
    max=1) = 1 "Discharge coefficient"

  parameter Modelica.Units.SI.Area L(min=0) "Effective leakage area";

  Modelica.Units.SI.Velocity v(nominal=1) = V_flow/L "Average velocity";
end EffectiveAirLeakageArea;


within AixLib.Airflow.Multizone;
model MediumColumn
  "Vertical shaft with no friction and no storage of heat and mass"

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

  parameter Modelica.Units.SI.Length h(min=0) = 3 "Height of shaft";
  parameter AixLib.Airflow.Multizone.Types.densitySelection densitySelection
    "Select how to pick density"

  Modelica.Fluid.Interfaces.FluidPort_a port_a(
    redeclare package Medium = Medium,
    p(start=Medium.p_default))
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b port_b(
    redeclare package Medium = Medium,
    p(start=Medium.p_default))
    "Fluid connector b (positive design flow direction is from port_a to port_b)"

  Modelica.Units.SI.VolumeFlowRate V_flow
    "Volume flow rate at inflowing port (positive when flow from port_a to port_b)";
  Modelica.Units.SI.MassFlowRate m_flow
    "Mass flow rate from port_a to port_b (m_flow > 0 is design flow direction)";
  Modelica.Units.SI.PressureDifference dp(displayUnit="Pa")
    "Pressure difference between port_a and port_b";
  Modelica.Units.SI.Density rho "Density in medium column";
protected
  Medium.ThermodynamicState sta_a=Medium.setState_phX(
      port_a.p,
      actualStream(port_a.h_outflow),
      actualStream(port_a.Xi_outflow)) "Medium properties in port_a";
  Medium.MassFraction Xi[Medium.nXi] "Mass fraction used to compute density";
initial equation
  // The next assert tests for all allowed values of the enumeration.
  // Testing against densitySelection > 0 gives an error in OpenModelica as enumerations start with 1.
  assert(densitySelection == AixLib.Airflow.Multizone.Types.densitySelection.fromTop
     or densitySelection == AixLib.Airflow.Multizone.Types.densitySelection.fromBottom
     or densitySelection == AixLib.Airflow.Multizone.Types.densitySelection.actual,
    "You need to set the parameter \"densitySelection\" for the model MediumColumn.");
equation
  // Design direction of mass flow rate
  m_flow = port_a.m_flow;

  // Pressure difference between ports
  // Xi is computed first as it is used in two expression, and in one
  // of them only one component is used.
  // We test for Medium.nXi == 0 as Modelica.Media.Air.SimpleAir has no
  // moisture and hence Xi[1] is an illegal statement.
  // We first compute temperature and then invoke a density function that
  // takes temperature as an argument. Simply calling a density function
  // of a medium that takes enthalpy as an argument would be dangerous
  // as different media can have different datum for the enthalpy.
  if (densitySelection == AixLib.Airflow.Multizone.Types.densitySelection.fromTop) then
      Xi = inStream(port_a.Xi_outflow);
      rho = AixLib.Utilities.Psychrometrics.Functions.density_pTX(
        p=Medium.p_default,
        T=Medium.temperature(Medium.setState_phX(port_a.p, inStream(port_a.h_outflow), Xi)),
        X_w=if Medium.nXi == 0 then 0 else Xi[1]);
  elseif (densitySelection == AixLib.Airflow.Multizone.Types.densitySelection.fromBottom) then
      Xi = inStream(port_b.Xi_outflow);
      rho = AixLib.Utilities.Psychrometrics.Functions.density_pTX(
        p=Medium.p_default,
        T=Medium.temperature(Medium.setState_phX(port_b.p, inStream(port_b.h_outflow), Xi)),
        X_w=if Medium.nXi == 0 then 0 else Xi[1]);
   else
      Xi = actualStream(port_a.Xi_outflow);
      rho = AixLib.Utilities.Psychrometrics.Functions.density_pTX(
        p=Medium.p_default,
        T=Medium.temperature(Medium.setState_phX(port_a.p, actualStream(port_a.h_outflow), Xi)),
        X_w=if Medium.nXi == 0 then 0 else Xi[1]);
  end if;

  V_flow = m_flow/Medium.density(sta_a);

  dp = port_a.p - port_b.p;
  dp = -h*rho*Modelica.Constants.g_n;

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

  // Mass balance (no storage)
  port_a.m_flow + port_b.m_flow = 0;

  // Transport of substances
  port_a.Xi_outflow = inStream(port_b.Xi_outflow);
  port_b.Xi_outflow = inStream(port_a.Xi_outflow);

  port_a.C_outflow = inStream(port_b.C_outflow);
  port_b.C_outflow = inStream(port_a.C_outflow);
end MediumColumn;


within AixLib.Airflow.Multizone;
model MediumColumnDynamic
  "Vertical shaft with no friction and storage of heat and mass"
  extends AixLib.Fluid.Interfaces.LumpedVolumeDeclarations(
    final massDynamics=energyDynamics);

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

  parameter Modelica.Units.SI.Length h(min=0) = 3 "Height of shaft";

  Modelica.Fluid.Interfaces.FluidPort_a port_a(
    redeclare final package Medium = Medium,
    p(start=Medium.p_default))
    "Fluid connector a (positive design flow direction is from port_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b port_b(
    redeclare final package Medium = Medium,
    p(start=Medium.p_default))
    "Fluid connector b (positive design flow direction is from port_a to port_b)"

  parameter Modelica.Units.SI.Volume V "Volume in medium shaft";

  // Heat transfer through boundary
  parameter Boolean use_HeatTransfer = false
    "= true to use the HeatTransfer model"

  // m_flow_nominal is not used by vol, since this component
  // can only be configured as a dynamic model.
  // Therefore we set it to about 10 air changes per hour
  AixLib.Fluid.MixingVolumes.MixingVolume vol(
    final nPorts=2,
    redeclare final package Medium = Medium,
    final m_flow_nominal=V/360,
    final V=V,
    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) "Air volume in the shaft"

  MediumColumn colTop(
    redeclare final package Medium = Medium,
    final densitySelection=AixLib.Airflow.Multizone.Types.densitySelection.fromBottom,
    h=h/2)
    "Medium column that connects to top port"

  MediumColumn colBot(
    redeclare final package Medium = Medium,
    final densitySelection=AixLib.Airflow.Multizone.Types.densitySelection.fromTop,
    h=h/2)
    "Medium colum that connects to bottom port"

  replaceable model HeatTransfer =
      Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.IdealHeatTransfer
    constrainedby
    Modelica.Fluid.Vessels.BaseClasses.HeatTransfer.PartialVesselHeatTransfer
    "Wall heat transfer"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heatPort if use_HeatTransfer
    "Heat port to exchange energy with the fluid volume"

equation
  connect(colBot.port_a, vol.ports[1])
  connect(vol.ports[2], colTop.port_b)
  connect(colTop.port_a, port_a)

  connect(colBot.port_b, port_b)
  connect(heatPort, vol.heatPort)
end MediumColumnDynamic;


Orifice. This model describes the mass flow rate and pressure difference relation
of an orifice in the form

within AixLib.Airflow.Multizone;
model Orifice "Orifice"
  extends AixLib.Airflow.Multizone.Coefficient_V_flow(
    m=0.5,
    final C=CD*A*sqrt(2.0/rho_default));

  parameter Modelica.Units.SI.Area A "Area of orifice"
  parameter Real CD=0.65 "Discharge coefficient"

  Modelica.Units.SI.Velocity v(nominal=1) = V_flow/A "Average velocity";
end Orifice;


within AixLib.Airflow;
package Multizone "Package with models for multizone airflow and contaminant transport"
  extends Modelica.Icons.VariantsPackage;
end Multizone;


Powerlaw with flow coefficient and flow exponent fitted based on 2 datapoints. Model that fits the flow coefficient of the massflow version of the
orifice equation based on 2 datapoints of mass flow rate and pressure difference.

within AixLib.Airflow.Multizone;
model Points_m_flow
  "Powerlaw with flow coefficient and flow exponent fitted based on 2 datapoints"
  extends AixLib.Airflow.Multizone.Coefficient_m_flow(final k=
    mMea_flow_nominal[1]/(dpMea_nominal[1]^m2),
    final m=m2);

  parameter Modelica.Units.SI.PressureDifference dpMea_nominal[2](each displayUnit="Pa")
    "Pressure difference of two test points"
  parameter Modelica.Units.SI.MassFlowRate mMea_flow_nominal[2]
    "Mass flow rate of two test points"
protected
  parameter Real m2 = (log(mMea_flow_nominal[1]) - log(mMea_flow_nominal[2]))/
             (log(dpMea_nominal[1]) -log(dpMea_nominal[2])) "Flow exponent";
end Points_m_flow;


Powerlaw with flow coeffient fitted based on flow exponent and 1 datapoint. Model that fits the flow coefficient of the massflow version of the
orifice equation based on 1 datapoint of mass flow rate and pressure difference, and given flow exponent.

within AixLib.Airflow.Multizone;
model Point_m_flow
  "Powerlaw with flow coeffient fitted based on flow exponent and 1 datapoint"
  extends AixLib.Airflow.Multizone.Coefficient_m_flow(final k=mMea_flow_nominal/
        (dpMea_nominal^m));
  parameter Modelica.Units.SI.PressureDifference dpMea_nominal(displayUnit="Pa")
    "Pressure difference of test point"
  parameter Modelica.Units.SI.MassFlowRate mMea_flow_nominal
    "Mass flow rate of test point"
end Point_m_flow;


Mass flow(y-axis) vs Pressure(x-axis) cubic spline fit model based from table data, with last two points linearly interpolated. This model describes the one-directional pressure driven air flow through an
opening based on user-provided tabular data describing the relation between mass flow rate
and pressure difference over the component.

within AixLib.Airflow.Multizone;
model Table_m_flow
  "Mass flow(y-axis) vs Pressure(x-axis) cubic spline fit model based from table data, with last two points linearly interpolated"
  extends AixLib.Airflow.Multizone.BaseClasses.PartialOneWayFlowElement(
    m_flow = AixLib.Utilities.Math.Functions.interpolate(
      u=dp,
      xd=dpMea_nominal,
      yd=mMea_flow_nominal,
      d=d),
    final m_flow_nominal=max(abs(dpMea_nominal[1]), abs(dpMea_nominal[end])));

  parameter Modelica.Units.SI.PressureDifference dpMea_nominal[:](each displayUnit="Pa")
    "Pressure difference of test points"
  parameter Modelica.Units.SI.MassFlowRate mMea_flow_nominal[:]
    "Mass flow rate of test points"
protected
  parameter Real[size(dpMea_nominal, 1)] d = AixLib.Utilities.Math.Functions.splineDerivatives(
    x=dpMea_nominal,
    y=mMea_flow_nominal,
    ensureMonotonicity=true)
    "Derivatives at the support points";
initial equation
  assert(size(dpMea_nominal, 1) == size(mMea_flow_nominal, 1),
    "Size of parameters are size(dpMea_nominal, 1) = " + String(size(dpMea_nominal, 1)) +
    " and size(mMea_flow_nominal, 1) = " + String(size(mMea_flow_nominal, 1)) + ". They must be equal.");
end Table_m_flow;


Volume flow(y-axis) vs Pressure(x-axis) cubic spline fit model based on table data, with last two points linearly interpolated. This model describes the one-directional pressure driven air flow through an
opening based on user-provided tabular data describing the relation between volume flow rate
and pressure difference over the component.

within AixLib.Airflow.Multizone;
model Table_V_flow
  "Volume flow(y-axis) vs Pressure(x-axis) cubic spline fit model based on table data, with last two points linearly interpolated"
  extends AixLib.Airflow.Multizone.Table_m_flow(
    final mMea_flow_nominal = VMea_flow_nominal*rho_default);

  parameter Modelica.Units.SI.VolumeFlowRate VMea_flow_nominal[:]
    "Volume flow rate of test points"
initial equation
  assert(size(dpMea_nominal, 1) == size(VMea_flow_nominal, 1),
    "Size of parameters are size(dpMea_nominal, 1) = " + String(size(dpMea_nominal, 1)) +
    " and size(VMea_flow_nominal, 1) = " + String(size(VMea_flow_nominal, 1)) + ". They must be equal.");
end Table_V_flow;


User's Guide

within AixLib.Airflow.Multizone;
package UsersGuide "User's Guide"
  extends Modelica.Icons.Information;

end UsersGuide;


Zonal flow with input air change per second. This model computes the air exchange between volumes.

within AixLib.Airflow.Multizone;
model ZonalFlow_ACS "Zonal flow with input air change per second"
  extends AixLib.Airflow.Multizone.BaseClasses.ZonalFlow;

  parameter Boolean useDefaultProperties = false
    "Set to true to use constant density";
  parameter Modelica.Units.SI.Volume V "Volume of room";

  Modelica.Blocks.Interfaces.RealInput ACS
    "Air change per seconds, relative to the smaller of the two volumes"
protected
  Modelica.Units.SI.VolumeFlowRate V_flow
    "Volume flow rate at standard pressure";
  Modelica.Units.SI.MassFlowRate m_flow "Mass flow rate";
  parameter Medium.ThermodynamicState sta_default = Medium.setState_pTX(T=Medium.T_default,
         p=Medium.p_default, X=Medium.X_default);
  parameter Modelica.Units.SI.Density rho_default=Medium.density(sta_default)
    "Density, used to compute fluid volume";

  Medium.ThermodynamicState sta_a1_inflow=
      Medium1.setState_phX(port_a1.p, port_b1.h_outflow, port_b1.Xi_outflow)
    "Medium properties in port_a1";
  Medium.ThermodynamicState sta_a2_inflow=
      Medium1.setState_phX(port_a2.p, port_b2.h_outflow, port_b2.Xi_outflow)
    "Medium properties in port_a2";

equation
  when useDefaultProperties and initial() then
   assert( abs(1-rho_default/((Medium.density(sta_a1_inflow) + Medium.density(sta_a2_inflow))/2))  < 0.2,
    "Wrong density. Densities need to match.");
// The next three lines have been removed as they cause
// a compilation error in OpenModelica.
//    + "\n Medium.density(sta_a1) = " + String(Medium.density(sta_a1_inflow))
//    + "\n Medium.density(sta_a2) = " + String(Medium.density(sta_a2_inflow))
//    + "\n rho_nominal            = " + String(rho_default));
  end when;
  V_flow = V * ACS;
  m_flow / V_flow = if useDefaultProperties then rho_default else (Medium.density(sta_a1_inflow) + Medium.density(sta_a2_inflow))/2;
  // assign variable in base class
  port_a1.m_flow = m_flow;
  port_a2.m_flow = m_flow;
end ZonalFlow_ACS;


within AixLib.Airflow.Multizone;
model ZonalFlow_m_flow "Zonal flow with input air change per second"
  extends AixLib.Airflow.Multizone.BaseClasses.ZonalFlow;
   Modelica.Blocks.Interfaces.RealInput mAB_flow "Mass flow rate from A to B, positive if flow from port_a1 to port_b1"
  Modelica.Blocks.Interfaces.RealInput mBA_flow "Mass flow rate from B to A, positive if flow from port_a2 to port_b2"

equation
  port_a1.m_flow = mAB_flow;
  port_a2.m_flow = mBA_flow;
end ZonalFlow_m_flow;


within AixLib.Airflow.Multizone.BaseClasses;
partial model Door
  "Partial door model for bi-directional flow"
  extends AixLib.Fluid.Interfaces.PartialFourPortInterface(
    redeclare final package Medium1 = Medium,
    redeclare final package Medium2 = Medium,
    final allowFlowReversal1=true,
    final allowFlowReversal2=true,
    final m1_flow_nominal=10/3600*1.2,
    final m2_flow_nominal=m1_flow_nominal,
    final m1_flow_small=1E-4*abs(m1_flow_nominal),
    final m2_flow_small=1E-4*abs(m2_flow_nominal));

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

  parameter Modelica.Units.SI.Length wOpe=0.9 "Width of opening"
  parameter Modelica.Units.SI.Length hOpe=2.1 "Height of opening"

  parameter Modelica.Units.SI.PressureDifference dp_turbulent(
    min=0,
    displayUnit="Pa") = 0.01
    "Pressure difference where laminar and turbulent flow relation coincide"

  Modelica.Units.SI.VolumeFlowRate VAB_flow(nominal=0.001)
    "Volume flow rate from A to B if positive";
  Modelica.Units.SI.VolumeFlowRate VBA_flow(nominal=0.001)
    "Volume flow rate from B to A if positive";

  input Modelica.Units.SI.Velocity vAB(nominal=0.01)
    "Average velocity from A to B";
  input Modelica.Units.SI.Velocity vBA(nominal=0.01)
    "Average velocity from B to A";

protected
  final parameter Modelica.Units.SI.Area AOpe=wOpe*hOpe "Open aperture area";

  constant Real conTP = AixLib.Media.Air.dStp*Modelica.Media.IdealGases.Common.SingleGasesData.Air.R_s
    "Conversion factor for converting temperature difference to pressure difference";

  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default);

  parameter Modelica.Units.SI.Density rho_default=Medium.density(sta_default)
    "Density";

  Modelica.Units.SI.VolumeFlowRate VABp_flow(nominal=0.001)
    "Volume flow rate from A to B if positive due to static pressure difference";
  Modelica.Units.SI.MassFlowRate mABt_flow(nominal=0.001)
    "Mass flow rate from A to B if positive due to buoyancy";

equation
  // Net flow rate
  port_a1.m_flow = (rho_default * VABp_flow/2 + mABt_flow);
  port_b2.m_flow = (rho_default * VABp_flow/2 - mABt_flow);

  // Average velocity (using the whole orifice area)
  VAB_flow = (max(port_a1.m_flow, 0) + max(port_b2.m_flow, 0))/rho_default;
  VBA_flow = (max(port_a2.m_flow, 0) + max(port_b1.m_flow, 0))/rho_default;

  // Energy balance (no storage, no heat loss/gain)
  port_a1.h_outflow = inStream(port_b1.h_outflow);
  port_b1.h_outflow = inStream(port_a1.h_outflow);
  port_a2.h_outflow = inStream(port_b2.h_outflow);
  port_b2.h_outflow = inStream(port_a2.h_outflow);

  // Mass balance (no storage)
  port_a1.m_flow = -port_b1.m_flow;
  port_a2.m_flow = -port_b2.m_flow;

  port_a1.Xi_outflow = inStream(port_b1.Xi_outflow);
  port_b1.Xi_outflow = inStream(port_a1.Xi_outflow);
  port_a2.Xi_outflow = inStream(port_b2.Xi_outflow);
  port_b2.Xi_outflow = inStream(port_a2.Xi_outflow);

  // Transport of trace substances
  port_a1.C_outflow = inStream(port_b1.C_outflow);
  port_b1.C_outflow = inStream(port_a1.C_outflow);
  port_a2.C_outflow = inStream(port_b2.C_outflow);
  port_b2.C_outflow = inStream(port_a2.C_outflow);
end Door;


Door model using discretization along height coordinate. This is a partial model for the bi-directional air flow through a door.

within AixLib.Airflow.Multizone.BaseClasses;
partial model DoorDiscretized
  "Door model using discretization along height coordinate"
  extends AixLib.Airflow.Multizone.BaseClasses.TwoWayFlowElementBuoyancy;

  parameter Integer nCom=10 "Number of compartments for the discretization";

  parameter Modelica.Units.SI.PressureDifference dp_turbulent(
    min=0,
    displayUnit="Pa") = 0.01
    "Pressure difference where laminar and turbulent flow relation coincide. Recommended: 0.01";

  Modelica.Units.SI.PressureDifference dpAB[nCom](each nominal=1)
    "Pressure difference between compartments";
  Modelica.Units.SI.Velocity v[nCom](each nominal=0.01)
    "Velocity in compartment from A to B";
  Modelica.Units.SI.Velocity vTop "Velocity at top of opening from A to B";
  Modelica.Units.SI.Velocity vBot "Velocity at bottom of opening from A to B";

protected
  parameter Modelica.Units.SI.Length dh=hOpe/nCom "Height of each compartment";

  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default);

  parameter Modelica.Units.SI.Density rho_default=Medium.density(sta_default)
    "Density, used to compute fluid volume";

  parameter Real hAg[nCom](each unit="m2/s2")=
    {Modelica.Constants.g_n*(hA - (i - 0.5)*dh) for i in 1:nCom}
    "Product g*h_i for each compartment";

  parameter Real hBg[nCom](each unit="m2/s2")=
    {Modelica.Constants.g_n*(hB - (i - 0.5)*dh) for i in 1:nCom}
    "Product g*h_i for each compartment";
  Modelica.Units.SI.AbsolutePressure pA[nCom](each nominal=101325)
    "Pressure in compartments of room A";
  Modelica.Units.SI.AbsolutePressure pB[nCom](each nominal=101325)
    "Pressure in compartments of room B";

  Modelica.Units.SI.VolumeFlowRate dV_flow[nCom]
    "Volume flow rate through compartment from A to B";
  Modelica.Units.SI.VolumeFlowRate dVAB_flow[nCom]
    "Volume flow rate through compartment from A to B if positive";
  Modelica.Units.SI.VolumeFlowRate dVBA_flow[nCom]
    "Volume flow rate through compartment from B to A if positive";
  Modelica.Units.SI.VolumeFlowRate VZerCom_flow=VZer_flow/nCom
    "Small flow rate for regularization";

  Real m(min=0.5, max=1) "Flow exponent, m=0.5 for turbulent, m=1 for laminar";
  Real CVal "Flow coefficient for each compartment, C = V_flow/ dp^m";
  Modelica.Units.SI.Area dA "Compartment area";
  Real gaiFlo[nCom] "Gain to sum up the positive flows and set the negative to zero in a differentiable way";
equation
  dA = A/nCom;

  for i in 1:nCom loop
    // pressure drop in each compartment
    pA[i] = port_a1.p + rho_a1_inflow*hAg[i];
    pB[i] = port_a2.p + rho_a2_inflow*hBg[i];
    dpAB[i] = pA[i] - pB[i];
    v[i] = dV_flow[i]/dA;
    // assignment of net volume flows
    gaiFlo[i] = AixLib.Utilities.Math.Functions.smoothHeaviside(x=dV_flow[i], delta=VZerCom_flow);
    dVAB_flow[i] =  dV_flow[i] * gaiFlo[i];
    dVBA_flow[i] = -dV_flow[i] * (1-gaiFlo[i]);
  end for;
  // add positive and negative flows
  VAB_flow = sum(dVAB_flow);
  VBA_flow = sum(dVBA_flow);
  vTop = v[nCom];
  vBot = v[1];
end DoorDiscretized;


Interface that defines parameters for error control. This is an interface that defines parameters used for error control.

within AixLib.Airflow.Multizone.BaseClasses;
model ErrorControl "Interface that defines parameters for error control"
  parameter Boolean forceErrorControlOnFlow = true
    "Flag to force error control on m_flow. Set to true if interested in flow rate"
end ErrorControl;


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


Partial model for flow resistance with one-way flow. This partial model is used to model one way flow-elements.
It holds the conservation equations and should be extended by
definition of one of the following variables:

within AixLib.Airflow.Multizone.BaseClasses;
partial model PartialOneWayFlowElement
  "Partial model for flow resistance with one-way flow"
  extends AixLib.Fluid.Interfaces.PartialTwoPortInterface(
    final allowFlowReversal=true);
  extends AixLib.Airflow.Multizone.BaseClasses.ErrorControl;

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

  parameter Boolean useDefaultProperties=true
    "Set to false to use density and viscosity based on actual medium state, rather than using default values"
  parameter Modelica.Units.SI.PressureDifference dp_turbulent(min=0, displayUnit="Pa") = 0.1
    "Pressure difference where laminar and turbulent flow relation coincide. Recommended = 0.1"

  Modelica.Units.SI.VolumeFlowRate V_flow = m_flow/rho
    "Volume flow rate through the component";
  Modelica.Units.SI.Density rho "Fluid density at port_a";

protected
  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default)
    "State of the medium at the medium default properties";
  parameter Modelica.Units.SI.Density rho_default=Medium.density(sta_default)
    "Density at the medium default properties";
  parameter Modelica.Units.SI.DynamicViscosity dynVis_default=
    Medium.dynamicViscosity(sta_default)
    "Dynamic viscosity at the medium default properties";

  Medium.ThermodynamicState sta "State of the medium in the component";
  Modelica.Units.SI.DynamicViscosity dynVis "Dynamic viscosity";
  Real mExc(quantity="Mass", final unit="kg")
    "Air mass exchanged (for purpose of error control only)";

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

equation
  if forceErrorControlOnFlow then
    der(mExc) = port_a.m_flow;
  else
    der(mExc) = 0;
  end if;

  if useDefaultProperties then
    sta = sta_default;
    rho = rho_default;
    dynVis = dynVis_default;

  else
    sta = if homotopyInitialization then
        Medium.setState_phX(
          port_a.p,
          homotopy(
            actual=actualStream(port_a.h_outflow),
            simplified=inStream(port_a.h_outflow)),
          homotopy(
            actual=actualStream(port_a.Xi_outflow),
            simplified=inStream(port_a.Xi_outflow)))
      else
        Medium.setState_phX(
          port_a.p,
          actualStream(port_a.h_outflow),
          actualStream(port_a.Xi_outflow));

    rho = Medium.density(sta);
    dynVis = Medium.dynamicViscosity(sta);
  end if;

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

  // Mass balance (no storage)
  port_a.m_flow + port_b.m_flow = 0;

  // Transport of substances
  port_a.Xi_outflow = inStream(port_b.Xi_outflow);
  port_b.Xi_outflow = inStream(port_a.Xi_outflow);

  port_a.C_outflow = inStream(port_b.C_outflow);
  port_b.C_outflow = inStream(port_a.C_outflow);

  m_flow=port_a.m_flow;
end PartialOneWayFlowElement;


Power law used in orifice equations. This model describes the mass flow rate and pressure difference relation
of an orifice in the form

within AixLib.Airflow.Multizone.BaseClasses;
function powerLaw "Power law used in orifice equations"
  extends Modelica.Icons.Function;

  input Real C "Flow coefficient, C = V_flow/ dp^m";
  input Modelica.Units.SI.PressureDifference dp(displayUnit="Pa")
    "Pressure difference";
  input Real m(min=0.5, max=1)
    "Flow exponent, m=0.5 for turbulent, m=1 for laminar";
  input Modelica.Units.SI.PressureDifference dp_turbulent(
    min=0,
    displayUnit="Pa") = 0.001 "Pressure difference where regularization starts";
  output Modelica.Units.SI.VolumeFlowRate V_flow "Volume flow rate";
protected
  constant Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  Real a
    "Polynomial coefficient for regularized implementation of flow resistance";
  Real b
    "Polynomial coefficient for regularized implementation of flow resistance";
  Real c
    "Polynomial coefficient for regularized implementation of flow resistance";
  Real d
    "Polynomial coefficient for regularized implementation of flow resistance";
  Real pi "Normalized pressure";
  Real pi2 "Square of normalized pressure";
algorithm
 if (dp >= dp_turbulent) then
   V_flow :=C *dp^m;
 elseif (dp <= -dp_turbulent) then
   V_flow :=-C*(-dp)^m;
 else
   a := gamma;
   b := 1/8*m^2 - 3*gamma - 3/2*m + 35.0/8;
   c := -1/4*m^2 + 3*gamma + 5/2*m - 21.0/4;
   d := 1/8*m^2 - gamma - m + 15.0/8;
   pi  := dp/dp_turbulent;
   pi2 := pi*pi;
   V_flow :=C *dp_turbulent^m * pi * ( a + pi2 * ( b + pi2 * ( c + pi2 * d)));
 end if;
end powerLaw;


Power law used in orifice equations when m is constant. This model describes the mass flow rate and pressure difference relation
of an orifice in the form

within AixLib.Airflow.Multizone.BaseClasses;
function powerLawFixedM
  "Power law used in orifice equations when m is constant"
  extends Modelica.Icons.Function;

  input Real C "Flow coefficient, C = V_flow/ dp^m";
  input Modelica.Units.SI.PressureDifference dp(displayUnit="Pa")
    "Pressure difference";
  input Real m(min=0.5, max=1)
    "Flow exponent, m=0.5 for turbulent, m=1 for laminar";
  input Real a "Polynomial coefficient";
  input Real b "Polynomial coefficient";
  input Real c "Polynomial coefficient";
  input Real d "Polynomial coefficient";
  input Modelica.Units.SI.PressureDifference dp_turbulent(min=0) = 0.001
    "Pressure difference where regularization starts";
  output Modelica.Units.SI.VolumeFlowRate V_flow "Volume flow rate";
protected
  constant Real gamma(min=1) = 1.5
    "Normalized flow rate where dphi(0)/dpi intersects phi(1)";
  Real pi "Normalized pressure";
  Real pi2 "Square of normalized pressure";
algorithm
 if (dp >= dp_turbulent) then
   V_flow :=C *dp^m;
 elseif (dp <= -dp_turbulent) then
   V_flow :=-C*(-dp)^m;
 else
   pi  := dp/dp_turbulent;
   pi2 := pi*pi;
   V_flow :=C *dp_turbulent^m * pi * ( a + pi2 * ( b + pi2 * ( c + pi2 * d)));
 end if;
end powerLawFixedM;