within Buildings.Airflow.Multizone.BaseClasses;
package Examples "Collection of models that illustrate model use and test models"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


Test model for power law function. This examples demonstrates the

Buildings.Airflow.Multizone.BaseClasses.powerLaw
function.

within Buildings.Airflow.Multizone.BaseClasses.Examples;
model PowerLaw "Test model for power law function"
  extends Modelica.Icons.Example;
  parameter Real C = 2/10^m "Flow coefficient, k = V_flow/ dp^m";

  parameter Real m(min=0.5, max=1) = 0.5
    "Flow exponent, m=0.5 for turbulent, m=1 for laminar";
  parameter Modelica.Units.SI.PressureDifference dp_turbulent(min=0) = 5
    "Pressure difference where regularization starts";

  Modelica.Units.SI.PressureDifference dp "Pressure difference";
  Modelica.Units.SI.VolumeFlowRate V_flow "Volume flow rate";
equation
  dp = 10*(-1+2*time);
  V_flow = Buildings.Airflow.Multizone.BaseClasses.powerLaw(
    dp=dp,
    C=C,
    m=m,
    dp_turbulent=dp_turbulent);
end PowerLaw;


Test model for power law function. This examples demonstrates the

Buildings.Airflow.Multizone.BaseClasses.powerLaw
and

Buildings.Airflow.Multizone.BaseClasses.powerLawFixedM
functions.
They need to return the same function value.
This is verified by an assert statement.

within Buildings.Airflow.Multizone.BaseClasses.Examples;
model PowerLawFixedM "Test model for power law function"
  extends Modelica.Icons.Example;
  parameter Real C = 2/10^m "Flow coefficient, C = V_flow/ dp^m";

  constant Real m(min=0.5, max=1) = 0.5
    "Flow exponent, m=0.5 for turbulent, m=1 for laminar";
  parameter Modelica.Units.SI.PressureDifference dp_turbulent(min=0) = 5
    "Pressure difference where regularization starts";

  Modelica.Units.SI.PressureDifference dp "Pressure difference";
  Modelica.Units.SI.VolumeFlowRate V_flow
    "Volume flow rate computed with model powerLaw";
  Modelica.Units.SI.VolumeFlowRate VFixed_flow
    "Volume flow rate computed with model powerLawFixed";

  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*m^2 - 3*gamma - 3/2*m + 35.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real c = -1/4*m^2 + 3*gamma + 5/2*m - 21.0/4
    "Polynomial coefficient for regularized implementation of flow resistance";
  constant Real d = 1/8*m^2 - gamma - m + 15.0/8
    "Polynomial coefficient for regularized implementation of flow resistance";

equation
  dp = 10*(-1+2*time);
  V_flow = Buildings.Airflow.Multizone.BaseClasses.powerLaw(
    dp=dp,
    C=C,
    m=m,
    dp_turbulent=dp_turbulent);
  VFixed_flow = Buildings.Airflow.Multizone.BaseClasses.powerLawFixedM(
    C=C,
    dp=dp,
    m=m,
    a=a,
    b=b,
    c=c,
    d=d,
    dp_turbulent=dp_turbulent);
  assert(abs(V_flow-VFixed_flow) < 1E-10, "Error: The two implementations of the power law model need to give identical results");
end PowerLawFixedM;


Test model for wind pressure function. This examples demonstrates the

Buildings.Airflow.Multizone.BaseClasses.windPressureLowRise
function.

within Buildings.Airflow.Multizone.BaseClasses.Examples;
model WindPressureLowRise "Test model for wind pressure function"
  extends Modelica.Icons.Example;
  parameter Real Cp0 = 0.6
    "Wind pressure coefficient for normal wind incidence angle";
  Modelica.Units.SI.Angle incAng "Wind incidence angle (0: normal to wall)";
  parameter Real G = Modelica.Math.log(0.5) "Natural logarithm of side ratio";
  Real Cp "Wind pressure coefficient";
equation
  incAng=time*2*Modelica.Constants.pi;
  Cp =Buildings.Airflow.Multizone.BaseClasses.windPressureLowRise(
    Cp0=Cp0,
    G=G,
    alpha=incAng);
end WindPressureLowRise;


Test model for wind pressure profile function. This examples demonstrates the

Buildings.Airflow.Multizone.BaseClasses.windPressureProfile
function.

within Buildings.Airflow.Multizone.BaseClasses.Examples;
model WindPressureProfile
  "Test model for wind pressure profile function"
  extends Modelica.Icons.Example;

  parameter Modelica.Units.SI.Angle incAngSurNor[:](
    each displayUnit="deg")=
      {0, 45, 90, 135, 180, 225, 270, 315}*Modelica.Constants.pi/180
    "Wind incidence angles, relative to the surface normal (normal=0), first point must be 0, last smaller than 2 pi(=360 deg)";
  parameter Real Cp[:](
    each final unit="1")=
      {0.4, 0.1, -0.3, -0.35, -0.2, -0.35, -0.3, 0.1}
    "Cp values at the corresponding incAngSurNor";

  Modelica.Units.SI.Angle  alpha "Wind incidence angle (0: normal to wall)";
  Real CpAct "Wind pressure coefficient";

protected
  final parameter Integer n=size(incAngSurNor, 1)
    "Number of data points provided by user";
  final parameter Modelica.Units.SI.Angle incAngExt[n + 3](each displayUnit=
        "deg") = cat(
    1,
    {incAngSurNor[n - 1] - (2*Modelica.Constants.pi)},
    incAngSurNor,
    2*Modelica.Constants.pi .+ {incAngSurNor[1],incAngSurNor[2]})
    "Extended number of incidence angles";
  final parameter Real CpExt[n+3]=cat(1, {Cp[n-1]}, Cp, {Cp[1], Cp[2]})
    "Extended number of Cp values";

  final parameter Real[n+3] deri=
      Buildings.Utilities.Math.Functions.splineDerivatives(
      x=incAngExt,
      y=CpExt,
      ensureMonotonicity=false) "Derivatives for table interpolation";

  Modelica.Blocks.Sources.Ramp ramp(
    duration=500,
    height=3*360,
    offset=-360)
    "Ramp model generating a singal from -360 to 720";

initial equation
  assert(size(incAngSurNor, 1) == size(Cp, 1), "In " + getInstanceName() +
    ": Size of parameters are size(CpincAng, 1) = " + String(size(incAngSurNor,
    1)) + " and size(Cp, 1) = " + String(size(Cp, 1)) + ". They must be equal.");

  assert(abs(incAngSurNor[1]) < 1E-4, "In " + getInstanceName() +
    ": First point in the table CpAngAtt must be 0.");

  assert(2*Modelica.Constants.pi - incAngSurNor[end] > 1E-4, "In " +
    getInstanceName() +
    ": Last point in the table CpAngAtt must be smaller than 2 pi (360 deg).");

equation
   alpha=Modelica.Constants.D2R*ramp.y;
   CpAct =Buildings.Airflow.Multizone.BaseClasses.windPressureProfile(
    alpha=alpha,
    incAngTab=incAngExt,
    CpTab=CpExt,
    d=deri) "Actual wind pressure coefficient";
end WindPressureProfile;


within Buildings.Airflow.Multizone.Examples;
model ChimneyShaftNoVolume
  "Model with chimney effect and a steady-state model of a shaft"
  extends Modelica.Icons.Example;
  package Medium = Modelica.Media.Air.SimpleAir;

  Buildings.Fluid.MixingVolumes.MixingVolume roo(
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 20,
    redeclare package Medium = Medium,
    m_flow_nominal=0.05,
    p_start=101325,
    nPorts=3) "Air volume of a room"
  Buildings.Airflow.Multizone.Orifice oriChiTop(
    m=0.5,
    redeclare package Medium = Medium,
    A=0.01) "Orifice at top"
  Buildings.Fluid.Sources.MassFlowSource_T boundary(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=293.15,
    nPorts=1) "Mass flow rate boundary condition"
  Buildings.Fluid.Sources.Boundary_pT bou0(
    redeclare package Medium = Medium,
    T=273.15,
    nPorts=2) "Pressure boundary condition"
  Buildings.Airflow.Multizone.Orifice oriBot(
    m=0.5,
    redeclare package Medium = Medium,
    A=0.01) "Orifice"
  Modelica.Blocks.Sources.CombiTimeTable mRoo_flow(tableOnFile=false, table=[0,
        0.05; 600,0.05; 601,0; 1800,0; 1801,-0.05; 2400,-0.05; 2401,0; 3600,0])
    "Mass flow into and out of room to fill the medium column with air of different temperature"
  MediumColumn staOut(
    redeclare package Medium = Medium,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop,
    h=1.5) "Model for stack effect outside the room"
  Buildings.Airflow.Multizone.Orifice oriChiBot(
    m=0.5,
    redeclare package Medium = Medium,
    A=0.01) "Orifice at bottom"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea
    "Prescribed heat flow rate"
  Modelica.Blocks.Continuous.LimPID con(
    Td=10,
    yMax=1,
    yMin=-1,
    Ti=60,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    k=5) "Controller to maintain volume temperature"
  Modelica.Blocks.Sources.Constant TSet(k=293.15) "Temperature set point"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temSen
    "Temperature sensor"
  Modelica.Blocks.Math.Gain gain(k=3000) "Gain for heat flow rate"
  Buildings.Airflow.Multizone.MediumColumn sha(redeclare package Medium = Medium,
      densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.actual) "Shaft of chimney"
  MediumColumn staIn(
    redeclare package Medium = Medium,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom,
    h=1.5) "Model for stack effect inside the room"

equation
  connect(TSet.y, con.u_s)
  connect(temSen.T, con.u_m)
  connect(gain.u, con.y)
  connect(gain.y, preHea.Q_flow)
  connect(sha.port_a, oriChiTop.port_a)
  connect(sha.port_b, oriChiBot.port_b)
  connect(staOut.port_b, oriBot.port_a)
  connect(preHea.port, roo.heatPort)
  connect(roo.heatPort, temSen.port)
  connect(bou0.ports[1], oriChiTop.port_b)
  connect(bou0.ports[2], staOut.port_a)
  connect(oriBot.port_b, staIn.port_a)
  connect(mRoo_flow.y[1], boundary.m_flow_in)
  connect(boundary.ports[1], roo.ports[1])
  connect(roo.ports[2], staIn.port_b)
  connect(roo.ports[3], oriChiBot.port_a)
end ChimneyShaftNoVolume;


within Buildings.Airflow.Multizone.Examples;
model ChimneyShaftWithVolume
  "Model with chimney effect and a dynamic model of a shaft"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;

  Buildings.Fluid.MixingVolumes.MixingVolume roo(
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 20,
    redeclare package Medium = Medium,
    m_flow_nominal=0.05,
    p_start=101325,
    nPorts=3) "Air volume of a room"
  Buildings.Airflow.Multizone.Orifice oriChiTop(
    m=0.5,
    redeclare package Medium = Medium,
    A=0.01) "Orifice at top"
  Buildings.Fluid.Sources.MassFlowSource_T boundary(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    T=293.15,
    nPorts=1) "Mass flow rate boundary condition"
  Buildings.Fluid.Sources.Boundary_pT bou0(
    redeclare package Medium = Medium,
    T=273.15,
    nPorts=2) "Pressure boundary condition"
  Buildings.Airflow.Multizone.Orifice oriBot(
    m=0.5,
    redeclare package Medium = Medium,
    A=0.01) "Orifice"
  Modelica.Blocks.Sources.CombiTimeTable mRoo_flow(tableOnFile=false, table=[0,
        0.05; 600,0.05; 601,0; 1800,0; 1801,-0.05; 2400,-0.05; 2401,0; 3600,0])
    "Mass flow into and out of room to fill the medium column with air of different temperature"
  MediumColumn staOut(
    redeclare package Medium = Medium,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop,
    h=1.5) "Model for stack effect outside the room"
  Buildings.Airflow.Multizone.Orifice oriChiBot(
    m=0.5,
    redeclare package Medium = Medium,
    A=0.01) "Orifice at bottom"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea
    "Prescribed heat flow"
  Modelica.Blocks.Continuous.LimPID con(
    Td=10,
    yMax=1,
    yMin=-1,
    Ti=60,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    k=5) "Controller to maintain volume temperature"
  Modelica.Blocks.Sources.Constant TSet(k=293.15) "Temperature set point"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temSen
    "Temperature sensor"
  Modelica.Blocks.Math.Gain gain(k=3000) "Gain for heat flow rate"
  Buildings.Airflow.Multizone.MediumColumnDynamic sha(
    redeclare package Medium = Medium,
    V=3,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Shaft of chimney"
  MediumColumn staIn(
    redeclare package Medium = Medium,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom,
    h=1.5) "Model for stack effect inside the room"

equation
  connect(TSet.y, con.u_s)
  connect(temSen.T, con.u_m)
  connect(gain.u, con.y)
  connect(gain.y, preHea.Q_flow)
  connect(sha.port_a, oriChiTop.port_a)
  connect(sha.port_b, oriChiBot.port_b)
  connect(staOut.port_b, oriBot.port_a)
  connect(preHea.port, roo.heatPort)
  connect(roo.heatPort, temSen.port)
  connect(bou0.ports[1], oriChiTop.port_b)
  connect(bou0.ports[2], staOut.port_a)
  connect(oriBot.port_b, staIn.port_a)
  connect(mRoo_flow.y[1], boundary.m_flow_in)
  connect(boundary.ports[1], roo.ports[1])
  connect(roo.ports[2], staIn.port_b)
  connect(roo.ports[3], oriChiBot.port_a)
end ChimneyShaftWithVolume;


Model with three closed doors

within Buildings.Airflow.Multizone.Examples;
model ClosedDoors "Model with three closed doors"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Specialized.Air.PerfectGas;

  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooAB(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    forceErrorControlOnFlow=true) "Discretized door"

  Buildings.Fluid.MixingVolumes.MixingVolume volA(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=4,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Control volume"
  Buildings.Fluid.MixingVolumes.MixingVolume volB(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=4,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Control volume"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFlo
    "Prescribed heat flow rate boundary condition"
  Modelica.Blocks.Sources.Sine sinBou(f=1/3600)
    "Signal for heat flow rate boundary condition"
  Modelica.Blocks.Math.Gain gai(k=100) "Gain for heat flow boundary condition"
  Buildings.Fluid.MixingVolumes.MixingVolume volC(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=4,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Control volume"
  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooAC(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    forceErrorControlOnFlow=true) "Discretized door"
  Modelica.Blocks.Sources.Constant yDoor(k=0) "Input signal for door opening"
  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooBC(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    forceErrorControlOnFlow=true) "Discretized door"
equation
  connect(gai.y, preHeaFlo.Q_flow)
  connect(sinBou.y, gai.u)
  connect(yDoor.y, dooAB.y)
  connect(yDoor.y, dooAC.y)
  connect(yDoor.y, dooBC.y)
  connect(preHeaFlo.port, volB.heatPort)
  connect(volC.ports[1], dooAC.port_b1)
  connect(volC.ports[2], dooAC.port_a2)
  connect(volC.ports[3], dooBC.port_b1)
  connect(volC.ports[4], dooBC.port_a2)
  connect(volB.ports[1], dooAB.port_b1)
  connect(volB.ports[2], dooAB.port_a2)
  connect(volB.ports[3], dooBC.port_a1)
  connect(volB.ports[4], dooBC.port_b2)
  connect(volA.ports[1], dooAC.port_b2)
  connect(volA.ports[2], dooAC.port_a1)
  connect(volA.ports[3], dooAB.port_b2)
  connect(volA.ports[4], dooAB.port_a1)
end ClosedDoors;


within Buildings.Airflow.Multizone.Examples;
model CO2TransportStep "Model with transport of CO2 through buoyancy driven flow"
  extends Buildings.Airflow.Multizone.Validation.ThreeRoomsContam(
    volWes(nPorts=5),
    volTop(nPorts=3),
    volEas(nPorts=6));

  Buildings.Fluid.Sensors.TraceSubstances CO2SenTop(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "CO2 sensor"
  Buildings.Fluid.Sensors.TraceSubstances CO2SenWes(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "CO2 sensor"
  Buildings.Fluid.Sensors.TraceSubstances CO2SenEas(
    redeclare package Medium = Medium,
    warnAboutOnePortConnection = false)
    "CO2 sensor"
  Modelica.Blocks.Sources.Pulse pulse(
    amplitude=8.18E-6,
    width=1/24/10,
    period=86400,
    startTime=3600) "Pulse signal for CO2 flow source"
  Buildings.Fluid.Sources.TraceSubstancesFlowSource sou(
    redeclare package Medium = Medium,
    use_m_flow_in=true,
    nPorts=1) "CO2 source"
equation
  connect(sou.m_flow_in, pulse.y)
  connect(sou.ports[1], volWes.ports[4])
  connect(CO2SenWes.port, volWes.ports[5])
  connect(CO2SenTop.port, volTop.ports[3])
  connect(CO2SenEas.port, volEas.ports[6])
end CO2TransportStep;


within Buildings.Airflow.Multizone.Examples;
model NaturalVentilation
  "Model with flow reversal due to density difference"
  extends Modelica.Icons.Example;

  package Medium = Buildings.Media.Air;

  Buildings.Fluid.MixingVolumes.MixingVolume volA(
    redeclare package Medium = Medium,
    V=2.5*10*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 18,
    nPorts=2,
    m_flow_nominal=0.001) "Control volume"

  Buildings.Airflow.Multizone.Orifice oriOutBot(
    redeclare package Medium = Medium,
    A=0.1,
    m=0.5,
    dp_turbulent=0.1) "Orifice"
  Buildings.Airflow.Multizone.MediumColumn colOut(
    redeclare package Medium = Medium,
    h=3,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriOutTop(
    redeclare package Medium = Medium,
    A=0.1,
    m=0.5,
    dp_turbulent=0.1) "Orifice"
  Buildings.Airflow.Multizone.MediumColumn colRooTop(
    redeclare package Medium = Medium,
    h=3,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Fluid.MixingVolumes.MixingVolume volOut(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=1E10,
    T_start=273.15 + 20,
    nPorts=2,
    m_flow_nominal=0.001) "Control volume"

  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFlo
    "Prescribed heat flow rate boundary condition"
  Modelica.Blocks.Sources.Step q_flow(
    height=-100,
    offset=100,
    startTime=3600) "Step function for heat flow boundary condition"
equation
  connect(q_flow.y, preHeaFlo.Q_flow)
  connect(oriOutBot.port_b, volOut.ports[1])
  connect(preHeaFlo.port, volA.heatPort)
  connect(volA.ports[1], oriOutBot.port_a)
  connect(volA.ports[2], colRooTop.port_b)
  connect(colRooTop.port_a, oriOutTop.port_a)
  connect(volOut.ports[2], colOut.port_b)
  connect(colOut.port_a, oriOutTop.port_b)
end NaturalVentilation;


within Buildings.Airflow.Multizone.Examples;
model OneEffectiveAirLeakageArea "Model with an effective air leakage area"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;

  Buildings.Fluid.MixingVolumes.MixingVolume volA(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Control volume"
  Buildings.Fluid.MixingVolumes.MixingVolume volB(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=1,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Control volume"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFlo
    "Prescribed heat flow rate boundary condition"
  Modelica.Blocks.Sources.Sine heaFloBou(f=1/3600)
    "Signal for heat flow rate boundary condition"
  Modelica.Blocks.Math.Gain gai(k=100)
    "Gain for heat flow rate boundary condition"
  Buildings.Airflow.Multizone.EffectiveAirLeakageArea cra(redeclare package
      Medium = Medium, L=20E-4)
    "Crack model, parameterized with effective leakage area"
  Buildings.Fluid.Sources.MassFlowSource_T sou(
    redeclare package Medium = Medium,
    nPorts=1,
    use_m_flow_in=true) "Prescribed mass flow rate boundary condition"
  Modelica.Blocks.Sources.Ramp ramSou(
    duration=3600,
    height=0.01,
    offset=0,
    startTime=1800)
    "Ramp signal for prescribed mass flow rate boundary condition"
equation
  connect(sou.ports[1], volA.ports[1])
  connect(ramSou.y, sou.m_flow_in)
  connect(volB.ports[1], cra.port_b)
  connect(volA.ports[2], cra.port_a)
  connect(preHeaFlo.port, volB.heatPort)
  connect(gai.y, preHeaFlo.Q_flow)
  connect(gai.u, heaFloBou.y)
end OneEffectiveAirLeakageArea;


Model with one open and one closed door

within Buildings.Airflow.Multizone.Examples;
model OneOpenDoor "Model with one open and one closed door"
  extends Modelica.Icons.Example;

  package Medium = Modelica.Media.Air.SimpleAir;

  Buildings.Airflow.Multizone.DoorDiscretizedOpen dooOpe(
    redeclare package Medium = Medium) "Discretized door"

  Buildings.Fluid.MixingVolumes.MixingVolume volA(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPorts=4,
    m_flow_nominal=0.01) "Control volume"
  Buildings.Fluid.MixingVolumes.MixingVolume volB(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPorts=4,
    m_flow_nominal=0.01) "Control volume"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHeaFlo
    "Prescribed heat flow rate boundary condition"
  Modelica.Blocks.Sources.Sine heaSou(f=1/3600)
    "Signal for heat flow rate boundary condition"
  Modelica.Blocks.Math.Gain gai(k=100)
    "Gain for heat flow rate boundary condition"
  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooOpeClo(redeclare package
      Medium = Medium, LClo=20*1E-4) "Discretized door"
  Modelica.Blocks.Sources.Ramp ramp(
    duration=120,
    height=1,
    offset=0,
    startTime=1000) "Ramp signal for door opening"
equation
  connect(gai.y, preHeaFlo.Q_flow)
  connect(heaSou.y, gai.u)
  connect(ramp.y, dooOpeClo.y)
  connect(preHeaFlo.port, volB.heatPort)
  connect(volA.ports[1], dooOpeClo.port_b2)
  connect(volA.ports[2], dooOpeClo.port_a1)
  connect(volA.ports[3], dooOpe.port_b2)
  connect(volA.ports[4], dooOpe.port_a1)
  connect(volB.ports[1], dooOpe.port_b1)
  connect(volB.ports[2], dooOpe.port_a2)
  connect(volB.ports[3], dooOpeClo.port_b1)
  connect(volB.ports[4], dooOpeClo.port_a2)
end OneOpenDoor;


within Buildings.Airflow.Multizone.Examples;
model OneRoom
  "Model with one room for the validation of the multizone air exchange models"

  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;

  Buildings.Fluid.MixingVolumes.MixingVolume volEas(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 20,
    V=2.5*5*5,
    nPorts=2,
    m_flow_nominal=0.001,
    massDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial)
    "Control volume for room"

  Buildings.Airflow.Multizone.Orifice oriOutBot(
    redeclare package Medium = Medium,
    A=0.01,
    m=0.5) "Orifice at bottom"
  Buildings.Airflow.Multizone.MediumColumn colOutTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriOutTop(
    redeclare package Medium = Medium,
    A=0.01,
    m=0.5) "Orifice at top"
  Buildings.Airflow.Multizone.MediumColumn colEasInTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Fluid.MixingVolumes.MixingVolume volOut(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 10,
    V=1E12,
    p_start=Medium.p_default,
    nPorts=2,
    m_flow_nominal=0.001)
    "Control volume for outside"

  Buildings.Airflow.Multizone.MediumColumn colEasInBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.MediumColumn colOutBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
equation
  connect(colEasInTop.port_a, oriOutTop.port_a)
  connect(colEasInTop.port_b, volEas.ports[1])
  connect(colEasInBot.port_a, volEas.ports[2])
  connect(colEasInBot.port_b, oriOutBot.port_a)
  connect(oriOutBot.port_b, colOutBot.port_b)
  connect(colOutBot.port_a, volOut.ports[1])
  connect(colOutTop.port_b, volOut.ports[2])
  connect(colOutTop.port_a, oriOutTop.port_b)
end OneRoom;


Model with an orifice

within Buildings.Airflow.Multizone.Examples;
model Orifice "Model with an orifice"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  Buildings.Airflow.Multizone.Orifice ori(redeclare package Medium = Medium, A=
        0.2) "Orifice"
  Buildings.Fluid.Sources.Boundary_pT roo1(
    redeclare package Medium = Medium,
    use_p_in=true,
    nPorts=1,
    T=278.15) "Pressure boundary condition"
  Buildings.Fluid.Sources.Boundary_pT roo2(
    redeclare package Medium = Medium,
    use_p_in=true,
    nPorts=1,
    T=293.15) "Pressure boundary condition"
  Modelica.Blocks.Sources.Ramp ram(
    duration=0.5,
    height=2,
    offset=-1,
    startTime=0.25) "Ramp signal for pressure boundary condition"
  Modelica.Blocks.Sources.Constant preBou(k=100000)
    "Constant pressure boundary condition"
  Modelica.Blocks.Math.Add add "Adder for pressure boundary condition"
  Buildings.Fluid.Sensors.DensityTwoPort den1(
    redeclare package Medium = Medium,
    m_flow_nominal=0.1,
    initType=Modelica.Blocks.Types.Init.InitialState) "Density sensor"
  Buildings.Fluid.Sensors.DensityTwoPort den2(
    redeclare package Medium = Medium,
    m_flow_nominal=0.1,
    initType=Modelica.Blocks.Types.Init.InitialState) "Density sensor"
equation
  connect(preBou.y, add.u1)
  connect(ram.y, add.u2)
  connect(preBou.y, roo1.p_in)
  connect(add.y, roo2.p_in)
  connect(roo1.ports[1], den1.port_a)
  connect(den1.port_b, ori.port_a)
  connect(ori.port_b, den2.port_a)
  connect(den2.port_b, roo2.ports[1])
end Orifice;


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


Model with powerlaw models

within Buildings.Airflow.Multizone.Examples;
model PowerLaw "Model with powerlaw models"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  Coefficient_m_flow pow_m_flow(
    redeclare package Medium = Medium,
    m=0.59,
    k=3.33e-5) "Mass flow rate based on powerlaw, direct input for m and C"
  Buildings.Fluid.Sources.Boundary_pT roo1(
    redeclare package Medium = Medium,
    use_p_in=true,
    nPorts=1,
    T=278.15) "Room 1"
  Buildings.Fluid.Sources.Boundary_pT roo2(
    redeclare package Medium = Medium,
    use_p_in=true,
    nPorts=1,
    T=293.15) "Room 2"
  Modelica.Blocks.Sources.Ramp ramp1(
    duration=0.5,
    height=6,
    offset=-3,
    startTime=0.25) "Ramp"
  Modelica.Blocks.Sources.Constant pressure(k=100000) "Pressure"
  Modelica.Blocks.Math.Add add "Add"
  Buildings.Fluid.Sensors.DensityTwoPort den1(
    redeclare package Medium = Medium,
    m_flow_nominal=0.1,
    tau=0,
    initType=Modelica.Blocks.Types.Init.InitialState) "Density sensor"
  Buildings.Fluid.Sensors.DensityTwoPort den2(
    redeclare package Medium = Medium,
    m_flow_nominal=0.1,
    tau=0,
    initType=Modelica.Blocks.Types.Init.InitialState) "Density sensor"
  Coefficient_V_flow pow_V_flow(
    redeclare package Medium = Medium,
    m=0.59,
    C=3.33e-5/1.2)
    "Volume flow rate based on powerlaw, direct input for m and C"
  Point_m_flow pow_1dat(
    redeclare package Medium = Medium,
    dpMea_nominal = 50,
    m=0.59,
    mMea_flow_nominal=1.2/3600)
    "Mass flow rate based on powerlaw, input of m and 1 test data point."
  Points_m_flow pow_2dat(
    redeclare package Medium = Medium,
    dpMea_nominal = {1, 50},
    mMea_flow_nominal={0.12, 1.2}/3600)
    "Mass flow rate based on powerlaw, input of 2 test data points."
equation
  connect(pressure.y, add.u1)
  connect(ramp1.y, add.u2)
  connect(pressure.y, roo1.p_in)
  connect(add.y, roo2.p_in)
  connect(roo1.ports[1], den1.port_a)
  connect(den1.port_b, pow_m_flow.port_a)
  connect(pow_m_flow.port_b, den2.port_a)
  connect(den2.port_b, roo2.ports[1])
  connect(den1.port_b, pow_V_flow.port_a)
  connect(pow_V_flow.port_b, den2.port_a)
  connect(den1.port_b, pow_1dat.port_a)
  connect(den1.port_b, pow_2dat.port_a)
  connect(pow_1dat.port_b, den2.port_a)
  connect(pow_2dat.port_b, den2.port_a)
end PowerLaw;


within Buildings.Airflow.Multizone.Examples;
model PressurizationData
  "Model showing how the 'Powerlaw_1DataPoint' model can be used when data is available from a pressurization test."
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;

  parameter Real n50=3 "ACH50, air changes at 50 Pa";

  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
  Fluid.Sources.Outside_CpLowRise west(
    redeclare package Medium = Medium,
    s=5,
    azi=Buildings.Types.Azimuth.W,
    Cp0=0.6,
    nPorts=1) "Model with outside conditions"
  Fluid.Sources.Outside_CpLowRise east(
    redeclare package Medium = Medium,
    s=5,
    azi=Buildings.Types.Azimuth.E,
    Cp0=0.6,
    nPorts=1) "Model with outside conditions"
  Fluid.MixingVolumes.MixingVolume room(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Room model"
  Buildings.Airflow.Multizone.Point_m_flow pow_1dat(
    dpMea_nominal(displayUnit="Pa") = 50,
    redeclare package Medium = Medium,
    m=0.66,
    mMea_flow_nominal=0.5*(room.V*n50*1.2))
    "Crack in envelope representing 50% of the leakage area"
  Buildings.Airflow.Multizone.Point_m_flow pow_1dat1(
    dpMea_nominal(displayUnit="Pa") = 50,
    redeclare package Medium = Medium,
    m=0.66,
    mMea_flow_nominal=0.5*(room.V*n50*1.2))
    "Crack in envelope representing 50% of the leakage area"
equation
  connect(weaDat.weaBus, west.weaBus)
  connect(east.weaBus, weaDat.weaBus)
  connect(east.ports[1], pow_1dat.port_a)
  connect(pow_1dat.port_b,room. ports[1])
  connect(pow_1dat1.port_a,room. ports[2])
  connect(pow_1dat1.port_b, west.ports[1])
end PressurizationData;


within Buildings.Airflow.Multizone.Examples;
model ReverseBuoyancy
  "Model with four rooms and buoyancy-driven air circulation that reverses direction"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  Buildings.Fluid.MixingVolumes.MixingVolume volBotEas(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=2.5*5*5,
    T_start=273.15 + 25,
    nPorts=5,
    m_flow_nominal=0.001) "Volume of bottom floor, east room"
  Buildings.Airflow.Multizone.Orifice oriOutBot(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice at bottom"
  Buildings.Airflow.Multizone.MediumColumn colOutTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriOutTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice at top"
  Buildings.Airflow.Multizone.MediumColumn colEasInTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.MediumColumn colEasInBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.MediumColumn colOutBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  MediumColumn colWesBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriWesTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice between west rooms"
  Buildings.Airflow.Multizone.MediumColumn colWesTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooOpeClo(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    wOpe=1,
    hOpe=2.2,
    hA=3/2,
    hB=3/2,
    CDOpe=0.78,
    CDClo=0.78,
    nCom=10,
    vZer=0.01,
    dp_turbulent=0.1) "Discretized door"
  Fluid.Delays.DelayFirstOrder volBotWes(
    redeclare package Medium = Medium,
    m_flow_nominal=1.2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau=2.5*5*5,
    T_start=273.15 + 22,
    nPorts=3,
    p_start=101325) "Volume of bottom floor, west room"
  Modelica.Blocks.Sources.Constant ope(k=1) "Constant signal for door opening"
  Buildings.Airflow.Multizone.MediumColumn col1EasBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriEasTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice between east rooms"
  Buildings.Airflow.Multizone.MediumColumn colEasTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Fluid.MixingVolumes.MixingVolume volTopEas(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=2.5*5*10,
    T_start=273.15 + 21,
    nPorts=3,
    m_flow_nominal=0.001) "Volume of top floor, east room"
  Buildings.Fluid.MixingVolumes.MixingVolume volTopWes(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 20,
    V=2.5*5*10,
    nPorts=3,
    m_flow_nominal=0.001) "Volume of top floor, west room"
  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooOpeCloTop(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    wOpe=1,
    hOpe=2.2,
    hA=3/2,
    hB=3/2,
    CDOpe=0.78,
    CDClo=0.78,
    nCom=10,
    vZer=0.01,
    dp_turbulent=0.1) "Discretized door"
  Buildings.Fluid.Sources.Boundary_pT volOut(
    redeclare package Medium = Medium,
    p=100000,
    T=283.15,
    nPorts=2) "Ambient conditions"
equation
  connect(ope.y, dooOpeClo.y)
  connect(ope.y, dooOpeCloTop.y)
  connect(oriEasTop.port_b, colEasTop.port_b)
  connect(oriWesTop.port_b, colWesBot.port_a)
  connect(oriWesTop.port_a, colWesTop.port_b)
  connect(oriOutBot.port_b, colOutBot.port_b)
  connect(colEasInBot.port_b, oriOutBot.port_a)
  connect(colEasInTop.port_a, oriOutTop.port_a)
  connect(oriOutTop.port_b, colOutTop.port_a)
  connect(volBotWes.ports[1], dooOpeClo.port_b2)
  connect(volBotWes.ports[2], dooOpeClo.port_a1)
  connect(colWesBot.port_b, volBotWes.ports[3])
  connect(volTopWes.ports[1], colWesTop.port_a)
  connect(volTopWes.ports[2], dooOpeCloTop.port_b2)
  connect(volTopWes.ports[3], dooOpeCloTop.port_a1)
  connect(volTopEas.ports[1], dooOpeCloTop.port_b1)
  connect(dooOpeCloTop.port_a2, volTopEas.ports[2])
  connect(colEasTop.port_a, volTopEas.ports[3])
  connect(oriEasTop.port_a, col1EasBot.port_a)
  connect(dooOpeClo.port_b1, volBotEas.ports[1])
  connect(dooOpeClo.port_a2, volBotEas.ports[2])
  connect(colEasInBot.port_a, volBotEas.ports[3])
  connect(colEasInTop.port_b, volBotEas.ports[4])
  connect(col1EasBot.port_b, volBotEas.ports[5])
  connect(colOutBot.port_a, volOut.ports[1])
  connect(colOutTop.port_b, volOut.ports[2])
end ReverseBuoyancy;


within Buildings.Airflow.Multizone.Examples;
model ReverseBuoyancy3Zones
  "Model with three rooms and buoyancy-driven air circulation that reverses direction"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  Buildings.Fluid.MixingVolumes.MixingVolume volEas(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=2.5*5*5,
    T_start=273.15 + 25,
    nPorts=5,
    m_flow_nominal=0.001) "Control volume for east room"
  Buildings.Airflow.Multizone.Orifice oriOutBot(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice at bottom of east room"
  Buildings.Airflow.Multizone.MediumColumn colOutTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriOutTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice at top of east room"
  Buildings.Airflow.Multizone.MediumColumn colEasInTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Fluid.MixingVolumes.MixingVolume volOut(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=1E12,
    T_start=273.15 + 15,
    nPorts=2,
    m_flow_nominal=0.001) "Control volume for outside"
  Buildings.Airflow.Multizone.MediumColumn colEasInBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.MediumColumn colOutBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.MediumColumn colWesBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriWesTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice between west room and top"
  Buildings.Airflow.Multizone.MediumColumn colWesTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.DoorDiscretizedOperable dooOpeClo(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    wOpe=1,
    hOpe=2.2,
    hA=3/2,
    hB=3/2,
    CDOpe=0.78,
    CDClo=0.78,
    nCom=10,
    vZer=0.01,
    dp_turbulent=0.1) "Discretized door"
  Modelica.Blocks.Sources.Constant ope(k=1) "Constant signal for door opening"
  Buildings.Airflow.Multizone.MediumColumn col1EasBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column to compute static pressure of air"
  Buildings.Airflow.Multizone.Orifice oriEasTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01,
    dp_turbulent=0.1) "Orifice between east room and top"
  Buildings.Airflow.Multizone.MediumColumn colEasTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column to compute static pressure of air"
  Buildings.Fluid.MixingVolumes.MixingVolume volTop(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15 + 20,
    m_flow_nominal=0.001,
    V=2.5*10*10,
    nPorts=2) "Control volume for top floor room"
  Buildings.Fluid.MixingVolumes.MixingVolume volWes(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    V=2.5*5*5,
    T_start=273.15 + 22,
    nPorts=3,
    m_flow_nominal=0.001) "Control volume for west room"
equation
  connect(dooOpeClo.port_b2, volWes.ports[1])
  connect(dooOpeClo.port_a1, volWes.ports[2])
  connect(dooOpeClo.port_b1, volEas.ports[1])
  connect(dooOpeClo.port_a2, volEas.ports[2])
  connect(colWesTop.port_b, oriWesTop.port_a)
  connect(oriWesTop.port_b, colWesBot.port_a)
  connect(colWesBot.port_b, volWes.ports[3])
  connect(colEasTop.port_b, oriEasTop.port_b)
  connect(oriEasTop.port_a, col1EasBot.port_a)
  connect(colEasInBot.port_a, volEas.ports[3])
  connect(colEasInTop.port_b, volEas.ports[4])
  connect(col1EasBot.port_b, volEas.ports[5])
  connect(colOutTop.port_b, volOut.ports[1])
  connect(volOut.ports[2], colOutBot.port_a)
  connect(colOutBot.port_b, oriOutBot.port_b)
  connect(oriOutBot.port_a, colEasInBot.port_b)
  connect(colEasInTop.port_a, oriOutTop.port_a)
  connect(oriOutTop.port_b, colOutTop.port_a)
  connect(ope.y, dooOpeClo.y)
  connect(colWesTop.port_a, volTop.ports[1])
  connect(colEasTop.port_a, volTop.ports[2])
end ReverseBuoyancy3Zones;


within Buildings.Airflow.Multizone.Examples;
model TrickleVent
  "Model with a trickle vent modelled using the models with flow based on tabulated data"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;

  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
      filNam=Modelica.Utilities.Files.loadResource(
        "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Weather data reader"
  Fluid.Sources.Outside_CpLowRise west(
    redeclare package Medium = Medium,
    s=5,
    azi=Buildings.Types.Azimuth.W,
    Cp0=0.6,
    nPorts=1) "Model with outside conditions"
  Fluid.Sources.Outside_CpLowRise east(
    redeclare package Medium = Medium,
    s=5,
    azi=Buildings.Types.Azimuth.E,
    Cp0=0.6,
    nPorts=1) "Model with outside conditions"
  Fluid.MixingVolumes.MixingVolume room(
    redeclare package Medium = Medium,
    V=2.5*5*5,
    nPorts=2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01) "Room model"
  Modelica.Thermal.HeatTransfer.Sources.PrescribedHeatFlow preHea
    "Prescribed heat flow"
  Modelica.Blocks.Continuous.LimPID con(
    Td=10,
    yMax=1,
    yMin=-1,
    Ti=60,
    controllerType=Modelica.Blocks.Types.SimpleController.P,
    k=5) "Controller to maintain volume temperature"
  Modelica.Blocks.Sources.Constant TSet(k=293.15) "Temperature set point"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor temSen
    "Temperature sensor"
  Modelica.Blocks.Math.Gain gain(k=3000) "Gain block"
  Buildings.Airflow.Multizone.Table_m_flow tabDat_m_flow(
    redeclare package Medium = Medium,
    dpMea_nominal = {-50,  -25,  -10,  -5,  -3,  -2,  -1,  0,  1,  2,  3,  4.5,  50},
    mMea_flow_nominal = {-0.08709, -0.06158, -0.03895, -0.02754, -0.02133, -0.01742, -0.01232, 0, 0.01232, 0.01742, 0.02133, 0.02613, 0.02614})
    "Self regulating trickle vent"
  Buildings.Airflow.Multizone.Table_V_flow tabDat_V_flow(
    redeclare package Medium = Medium,
    dpMea_nominal = {-50,  -25,  -10,  -5,  -3,  -2,  -1,  0,  1,  2,  3,  4.5,  50},
    VMea_flow_nominal = {-0.104508, -0.073896, -0.04674, -0.033048, -0.025596, -0.020904, -0.014784, 0, 0.014784, 0.020904, 0.025596, 0.031356,  0.031368})
   "Self regulating trickle vent"
equation
  connect(weaDat.weaBus, west.weaBus)
  connect(east.weaBus, weaDat.weaBus)
  connect(TSet.y,con. u_s)
  connect(temSen.T,con. u_m)
  connect(gain.u,con. y)
  connect(gain.y,preHea. Q_flow)
  connect(room.heatPort, temSen.port)
  connect(preHea.port,room. heatPort)
  connect(east.ports[1], tabDat_m_flow.port_a)
  connect(tabDat_m_flow.port_b,room. ports[1])
  connect(tabDat_V_flow.port_a,room. ports[2])
  connect(tabDat_V_flow.port_b, west.ports[1])
end TrickleVent;


within Buildings.Airflow.Multizone.Examples;
model ZonalFlow "Model with prescribed air exchange between two volumes"
  extends Modelica.Icons.Example;
  package Medium = Buildings.Media.Air;
  parameter Modelica.Units.SI.Volume volA=100 "Volume of room A";
  parameter Modelica.Units.SI.Volume volB=1 "Volume of room B";
  Buildings.Fluid.MixingVolumes.MixingVolume rooA(
    V=volA,
    redeclare package Medium = Medium,
    X_start={0.015,0.985},
    T_start=303.15,
    nPorts=4,
    m_flow_nominal=0.001,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Room A"
  Buildings.Fluid.MixingVolumes.MixingVolume rooB(
    V=volB,
    redeclare package Medium = Medium,
    X_start={0.01,0.99},
    T_start=293.15,
    nPorts=4,
    m_flow_nominal=0.001,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Room B"
  Modelica.Blocks.Sources.Constant ACS(k=5/3600) "Air change rate per second"
  ZonalFlow_ACS zonFlo(
    redeclare package Medium = Medium,
    V=min(volA, volB))
    "Model for prescribed flow exchange between two volume with air change per second as input"
  Modelica.Blocks.Sources.Constant m_flow(k=0.02) "Exchange mass flow rate"
  ZonalFlow_m_flow floExc(redeclare package Medium = Medium)
    "Model for prescribed flow exchange between two volumes with mass flow rate as inputs"
equation
  connect(rooA.ports[1], zonFlo.port_a1)
  connect(zonFlo.port_b1, rooB.ports[1])
  connect(zonFlo.port_b2, rooA.ports[2])
  connect(zonFlo.port_a2, rooB.ports[2])
  connect(zonFlo.ACS, ACS.y)
  connect(floExc.mAB_flow, m_flow.y)
  connect(m_flow.y, floExc.mBA_flow)
  connect(floExc.port_a1, rooA.ports[3])
  connect(floExc.port_b1, rooB.ports[3])
  connect(floExc.port_a2, rooB.ports[4])
  connect(floExc.port_b2, rooA.ports[4])
end ZonalFlow;


Package with type definitions

within Buildings.Airflow.Multizone;
package Types "Package with type definitions"
  extends Modelica.Icons.TypesPackage;
end Types;


within Buildings.Airflow.Multizone.Validation;
model DoorOpenClosed
  "Model with operable door and door that is always open"
  extends Modelica.Icons.Example;

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

  Fluid.Sources.Boundary_pT bouA(
    redeclare package Medium = Medium,
    p(displayUnit="Pa") = 101330,
    T=294.15,
    nPorts=5) "Boundary condition at side a"

  Fluid.Sources.Boundary_pT bouB(
    redeclare package Medium = Medium,
    p(displayUnit="Pa") = 101325,
    T=293.15,
    nPorts=5) "Boundary condition at side b"

  Buildings.Airflow.Multizone.DoorOpen doo(
    redeclare package Medium = Medium)
    "Open door that is always open"

  EffectiveAirLeakageArea lea(
    redeclare package Medium = Medium,
    m=0.65,
    dp_turbulent=0.01,
    L=20*1E-4) "Leakage flow element"
  DoorOperable dooOpeClo(
    redeclare package Medium = Medium,
    LClo=20*1E-4)
               "Operable door"
  Modelica.Blocks.Sources.Step yDoo(startTime=0.5) "Door opening signal"
  Fluid.Sensors.MassFlowRate senMasFlo1(redeclare package Medium = Medium)
    "Mass flow rate sensor"
  Fluid.Sensors.MassFlowRate senMasFlo2(
    redeclare package Medium = Medium)
    "Mass flow rate sensor"
  Modelica.Blocks.Math.Add mNet_flow(y(final unit="kg/s"))
    "Net air flow rate from A to B through the operable door"
  Modelica.Blocks.Sources.Step yDooCom(
    height=-1,
    offset=1,
    startTime=0.5) "Outputs 1 if door is closed"
  Modelica.Blocks.Math.Product mNetClo_flow(y(final unit="kg/s"))
    "Mass flow rate if door is closed"
equation
  connect(bouA.ports[1], doo.port_a1)
  connect(bouA.ports[2], doo.port_b2)
  connect(bouA.ports[3], lea.port_a)
  connect(bouA.ports[4], dooOpeClo.port_a1)
  connect(bouA.ports[5], dooOpeClo.port_b2)
  connect(doo.port_b1, bouB.ports[1])
  connect(doo.port_a2, bouB.ports[2])
  connect(lea.port_b, bouB.ports[3])
  connect(yDoo.y, dooOpeClo.y)
  connect(dooOpeClo.port_b1, senMasFlo1.port_a)
  connect(senMasFlo1.port_b, bouB.ports[4])
  connect(dooOpeClo.port_a2,senMasFlo2. port_a)
  connect(senMasFlo2.port_b, bouB.ports[5])
  connect(senMasFlo1.m_flow, mNet_flow.u1)
  connect(senMasFlo2.m_flow, mNet_flow.u2)
  connect(yDooCom.y, mNetClo_flow.u2)
  connect(mNet_flow.y, mNetClo_flow.u1)
end DoorOpenClosed;


Validation model to verify one way flow implementation


within Buildings.Airflow.Multizone.Validation;
model OpenDoorBuoyancyDynamic
  "Model with open door and buoyancy driven flow only"
  extends Modelica.Icons.Example;

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

  Buildings.Airflow.Multizone.DoorOpen doo(
    redeclare package Medium = Medium)
    "Door"

  Buildings.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium,
    nPorts=1) "Pressure boundary"

  Fluid.MixingVolumes.MixingVolume bouA(
    redeclare package Medium = Medium,
    T_start=292.15,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=3) "Boundary condition at side a"

  Buildings.Fluid.MixingVolumes.MixingVolume bouB(
    redeclare package Medium = Medium,
    T_start=294.15,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=2) "Boundary condition at side b"
  DoorDiscretizedOpen dooDis(
    forceErrorControlOnFlow=false,
    redeclare package Medium = Medium,
    vZer=0.000001) "Door"
  Fluid.Sources.Boundary_pT bou1(
    redeclare package Medium = Medium,
    nPorts=1) "Pressure boundary"
  Fluid.MixingVolumes.MixingVolume bouADis(
    redeclare package Medium = Medium,
    T_start=292.15,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=3) "Boundary condition at side a"
  Fluid.MixingVolumes.MixingVolume bouBDis(
    redeclare package Medium = Medium,
    T_start=294.15,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=2) "Boundary condition at side b"
equation
  connect(doo.port_b1, bouB.ports[1])
  connect(doo.port_a2, bouB.ports[2])
  connect(doo.port_a1, bouA.ports[1])
  connect(doo.port_b2, bouA.ports[2])
  connect(bou.ports[1], bouA.ports[3])
  connect(bou1.ports[1], bouADis.ports[1])
  connect(dooDis.port_a1, bouADis.ports[2])
  connect(dooDis.port_b2, bouADis.ports[3])
  connect(dooDis.port_b1, bouBDis.ports[1])
  connect(dooDis.port_a2, bouBDis.ports[2])
end OpenDoorBuoyancyDynamic;


within Buildings.Airflow.Multizone.Validation;
model OpenDoorBuoyancyPressureDynamic
  "Model with open door and buoyancy and pressure driven flow"
  extends Modelica.Icons.Example;

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

  Buildings.Airflow.Multizone.DoorOpen doo(redeclare package Medium = Medium)
    "Door"

  Buildings.Fluid.Sources.Boundary_pT bou(
    redeclare package Medium = Medium,
    nPorts=1) "Pressure boundary"

  Fluid.MixingVolumes.MixingVolume bouA(
    redeclare package Medium = Medium,
    T_start=292.15,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=3) "Boundary condition at side a"

  Buildings.Fluid.MixingVolumes.MixingVolume bouB(
    redeclare package Medium = Medium,
    T_start=294.15,
    p_start=101320,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=2) "Boundary condition at side b"
  DoorDiscretizedOpen dooDis(redeclare package Medium = Medium) "Door"
  Fluid.Sources.Boundary_pT bouDis(redeclare package Medium = Medium, nPorts=1)
    "Pressure boundary"
  Fluid.MixingVolumes.MixingVolume bouADis(
    redeclare package Medium = Medium,
    T_start=292.15,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=3) "Boundary condition at side a"
  Fluid.MixingVolumes.MixingVolume bouBDis(
    redeclare package Medium = Medium,
    T_start=294.15,
    p_start=101320,
    V=2.5*5*5,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=0.01,
    nPorts=2) "Boundary condition at side b"
equation
  connect(doo.port_b1, bouB.ports[1])
  connect(doo.port_a2, bouB.ports[2])
  connect(doo.port_a1, bouA.ports[1])
  connect(doo.port_b2, bouA.ports[2])
  connect(bou.ports[1], bouA.ports[3])

  connect(dooDis.port_b1, bouBDis.ports[1])
  connect(dooDis.port_a2, bouBDis.ports[2])
  connect(dooDis.port_a1, bouADis.ports[1])
  connect(dooDis.port_b2, bouADis.ports[2])
  connect(bouDis.ports[1], bouADis.ports[3])
end OpenDoorBuoyancyPressureDynamic;


within Buildings.Airflow.Multizone.Validation;
model OpenDoorPressure
  "Model with one open door and only pressure-driven flow"
  extends Modelica.Icons.Example;

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

  Buildings.Airflow.Multizone.DoorOpen doo(
    redeclare package Medium = Medium)
    "Door"

  Fluid.Sources.Boundary_pT bouA(
    redeclare package Medium = Medium,
    p(displayUnit="Pa") = 101325,
    nPorts=4) "Boundary condition at side a"

  Fluid.Sources.Boundary_pT bouB(
    redeclare package Medium = Medium,
    use_p_in=true,
    p(displayUnit="Pa"),
    nPorts=4) "Boundary condition at side b"

  DoorDiscretizedOpen dooDis(
    redeclare package Medium = Medium,
    hA=2.1/2,
    hB=2.1/2) "Door"
  Modelica.Blocks.Sources.TimeTable bouPre(
    table=[
      0.0,0;
      1,0;
      1,5;
      2,5;
      2,10;
      3,10;
      3,15;
      4,15;
      4,20;
      5,20;
      5,25;
      6,25;
      6,30;
      7,30;
      7,35;
      8,35;
      8,40;
      24,40],
    timeScale=3600,
    offset=101325-20) "Pressure boundary condition"
equation
  connect(doo.port_b1, bouB.ports[1])
  connect(doo.port_a2, bouB.ports[2])
  connect(doo.port_a1, bouA.ports[1])
  connect(doo.port_b2, bouA.ports[2])
  connect(bouA.ports[3], dooDis.port_a1)
  connect(bouA.ports[4], dooDis.port_b2)
  connect(dooDis.port_b1, bouB.ports[3])
  connect(dooDis.port_a2, bouB.ports[4])
  connect(bouPre.y, bouB.p_in)
end OpenDoorPressure;


within Buildings.Airflow.Multizone.Validation;
model OpenDoorTemperature
  "Model with one open door and only temperature-driven flow"
  extends Modelica.Icons.Example;

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

  Buildings.Airflow.Multizone.DoorOpen doo(
    redeclare package Medium = Medium)
    "Door"

  Fluid.Sources.Boundary_pT bouA(
    redeclare package Medium = Medium,
    nPorts=4) "Boundary condition at side a"

  Fluid.Sources.Boundary_pT bouB(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=4) "Boundary condition at side b"

  DoorDiscretizedOpen dooDis(
    redeclare package Medium = Medium,
    hA=2.1/2,
    hB=2.1/2) "Door"
  Modelica.Blocks.Sources.TimeTable bouTem(
    table=[
      0.0,0;
      1,0;
      1,5;
      2,5;
      2,10;
      3,10;
      3,15;
      4,15;
      4,20;
      5,20;
      5,25;
      6,25;
      6,30;
      7,30;
      7,35;
      8,35;
      8,40;
      24,40],
    timeScale=3600,
    offset=273.15) "Temperature boundary condition"
equation
  connect(doo.port_b1, bouB.ports[1])
  connect(doo.port_a2, bouB.ports[2])
  connect(doo.port_a1, bouA.ports[1])
  connect(doo.port_b2, bouA.ports[2])
  connect(bouA.ports[3], dooDis.port_a1)
  connect(bouA.ports[4], dooDis.port_b2)
  connect(dooDis.port_b1, bouB.ports[3])
  connect(dooDis.port_a2, bouB.ports[4])
  connect(bouTem.y, bouB.T_in)
end OpenDoorTemperature;


Collection of validation models

within Buildings.Airflow.Multizone;
package Validation "Collection of validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.Airflow.Multizone.Validation;
model ThreeRoomsContam
  "Model with three rooms for the validation of the multizone air exchange models"
  extends Modelica.Icons.Example;

  package Medium = Buildings.Media.Air(extraPropertiesNames={"CO2"});

  Buildings.Fluid.MixingVolumes.MixingVolume volEas(
    redeclare package Medium = Medium,
    T_start=273.15 + 20,
    V=2.5*5*5*1,
    nPorts=5,
    m_flow_nominal=0.001,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Air volume east room"

  Buildings.Airflow.Multizone.Orifice oriOutBot(
    redeclare package Medium = Medium,
    A=0.01,
    m=0.5) "Orifice at bottom of facade"
  Buildings.Airflow.Multizone.MediumColumn colOutTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column for bottom floor outside air"
  Buildings.Airflow.Multizone.Orifice oriOutTop(
    redeclare package Medium = Medium,
    A=0.01,
    m=0.5) "Orifice at top of facade"
  Buildings.Airflow.Multizone.MediumColumn colEasInTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column for bottom floor"
  Buildings.Fluid.Sources.Boundary_pT volOut(
    redeclare package Medium = Medium,
    nPorts=2,
    p(displayUnit="Pa") = 101325,
    T=283.15) "Outside air boundary condition"

  Buildings.Airflow.Multizone.MediumColumn colEasInBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column for bottom floor"
  Buildings.Airflow.Multizone.MediumColumn colOutBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column for bottom floor outside air"
  Buildings.Airflow.Multizone.MediumColumn colWesBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column for bottom floor"
  Buildings.Airflow.Multizone.Orifice oriWesTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01) "Orifice between top and bottom west floor"

  Buildings.Airflow.Multizone.MediumColumn colWesTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column for top floor"

  replaceable DoorOpen dooOpeClo(
    redeclare package Medium = Medium,
    wOpe=1,
    hOpe=2.2,
    dp_turbulent(displayUnit="Pa") = 0.01,
    CD=0.78,
    m=0.5)  constrainedby Fluid.Interfaces.PartialFourPortInterface
    "Door"
  Buildings.Fluid.MixingVolumes.MixingVolume volWes(
    redeclare package Medium = Medium,
    T_start=273.15 + 25,
    nPorts=3,
    V=2.5*5*5,
    m_flow_nominal=0.001,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Air volume west floor"
  Buildings.Airflow.Multizone.MediumColumn col1EasBot(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromBottom)
    "Medium column for bottom floor"
  Buildings.Airflow.Multizone.Orifice oriEasTop(
    redeclare package Medium = Medium,
    m=0.5,
    A=0.01) "Orifice between top and bottom east floor"
  Buildings.Airflow.Multizone.MediumColumn colEasTop(
    redeclare package Medium = Medium,
    h=1.5,
    densitySelection=Buildings.Airflow.Multizone.Types.densitySelection.fromTop)
    "Medium column for top floor"
  Buildings.Fluid.MixingVolumes.MixingVolume volTop(
    redeclare package Medium = Medium,
    T_start=273.15 + 20,
    V=2.5*5*10*1,
    nPorts=2,
    m_flow_nominal=0.001,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Air volume top floor"

  Buildings.HeatTransfer.Sources.FixedTemperature TTop(T=293.15)
    "Fixed temperature"
  Buildings.HeatTransfer.Sources.FixedTemperature TWes(T=298.15)
    "Fixed temperature"
  Buildings.HeatTransfer.Sources.FixedTemperature TEas(T=293.15)
    "Fixed temperature"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conTop(G=1E9)
    "Thermal conductor"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conWes(G=1E9)
    "Thermal conductor"
  Modelica.Thermal.HeatTransfer.Components.ThermalConductor conEas(G=1E9)
    "Thermal conductor"
equation
  connect(volWes.ports[1], dooOpeClo.port_b2)
  connect(volWes.ports[2], dooOpeClo.port_a1)
  connect(volWes.ports[3], colWesBot.port_b)
  connect(colWesBot.port_a, oriWesTop.port_b)
  connect(oriWesTop.port_a, colWesTop.port_b)
  connect(colWesTop.port_a, volTop.ports[1])
  connect(volTop.ports[2], colEasTop.port_a)
  connect(colEasTop.port_b, oriEasTop.port_b)
  connect(oriEasTop.port_a, col1EasBot.port_a)
  connect(dooOpeClo.port_b1, volEas.ports[1])
  connect(volEas.ports[2], dooOpeClo.port_a2)
  connect(colEasInBot.port_a, volEas.ports[3])
  connect(volEas.ports[4], colEasInTop.port_b)
  connect(volEas.ports[5], col1EasBot.port_b)
  connect(colEasInTop.port_a, oriOutTop.port_a)
  connect(oriOutTop.port_b, colOutTop.port_a)
  connect(colOutTop.port_b, volOut.ports[1])
  connect(colOutBot.port_a, volOut.ports[2])
  connect(colOutBot.port_b, oriOutBot.port_b)
  connect(oriOutBot.port_a, colEasInBot.port_b)

  connect(TTop.port, conTop.port_a)
  connect(conTop.port_b, volTop.heatPort)
  connect(TWes.port, conWes.port_a)
  connect(conWes.port_b, volWes.heatPort)
  connect(TEas.port, conEas.port_a)
  connect(conEas.port_b, volEas.heatPort)
end ThreeRoomsContam;


within Buildings.Airflow.Multizone.Validation;
model ThreeRoomsContamDiscretizedDoor
  "Model with three rooms for the validation of the multizone air exchange models"
  extends Buildings.Airflow.Multizone.Validation.ThreeRoomsContam(
    redeclare Buildings.Airflow.Multizone.DoorDiscretizedOperable dooOpeClo(
    redeclare package Medium = Medium,
    LClo=20*1E-4,
    wOpe=1,
    hOpe=2.2,
    CDOpe=0.78,
    CDClo=0.78,
    nCom=10,
    hA=3/2,
    hB=3/2,
    dp_turbulent(displayUnit="Pa") = 0.01));
  Modelica.Blocks.Sources.Constant open1(k=1)
    "Constant signal for door opening"
equation
  connect(open1.y, dooOpeClo.y)
end ThreeRoomsContamDiscretizedDoor;


within Buildings;
package Applications "Package with models for different application domains"
  extends Modelica.Icons.VariantsPackage;
end Applications;


Package with base classes

within Buildings.Applications;
package BaseClasses "Package with base classes"
extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.Applications.BaseClasses;
package Controls "Package with control components for Buildings.Applications examples"
  extends Modelica.Icons.Package;
end Controls;


Staging control for variable speed pumps. This model implements a simple staging control logic for variable speed pumps.

within Buildings.Applications.BaseClasses.Controls;
model VariableSpeedPumpStage "Staging control for variable speed pumps"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.Time tWai "Waiting time";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Nominal mass flow rate of the identical variable-speed pumps";
  parameter Real minSpe(unit="1",min=0,max=1) = 0.05
    "Minimum speed ratio required by variable speed pumps";
  parameter Modelica.Units.SI.MassFlowRate criPoiFlo=0.7*m_flow_nominal
    "Critcal point of flowrate for switch pump on or off";
  parameter Modelica.Units.SI.MassFlowRate deaBanFlo=0.1*m_flow_nominal
    "Deadband for critical point of flowrate";
  parameter Real criPoiSpe = 0.5
    "Critical point of speed signal for switching on or off";
  parameter Real deaBanSpe = 0.3
    "Deadband for critical point of speed signal";

  Modelica.Blocks.Interfaces.RealInput masFloPum
    "Total mass flowrate in the variable speed pumps"
  Modelica.Blocks.Interfaces.RealInput speSig
    "Speed signal"
  Modelica.Blocks.Interfaces.RealOutput y[2]
    "On/off signal - 0: off; 1: on"

  Modelica.StateGraph.Transition con1(
    enableTimer=true,
    waitTime=tWai,
    condition=speSig > minSpe and on == true)
    "Fire condition 1: free cooling to partially mechanical cooling"
  Modelica.StateGraph.StepWithSignal oneOn(nIn=2, nOut=2)
    "One chiller is commanded on"
  Modelica.StateGraph.InitialStep off(nIn=1, nOut=1)
    "Free cooling mode"
  Modelica.StateGraph.StepWithSignal twoOn(nIn=1, nOut=1)
    "Two chillers are commanded on"
  Modelica.StateGraph.Transition con2(
    enableTimer=true,
    waitTime=tWai,
    condition=speSig > criPoiSpe + deaBanSpe and
      masFloPum > criPoiFlo + deaBanFlo)
    "Fire condition 2: partially mechanical cooling to fully mechanical cooling"
  Modelica.StateGraph.Transition con3(
    enableTimer=true,
    waitTime=tWai,
    condition=speSig < criPoiSpe - deaBanSpe or masFloPum < criPoiFlo -
        deaBanFlo or on == false)
    "Fire condition 3: fully mechanical cooling to partially mechanical cooling"
  Modelica.StateGraph.Transition con4(
    enableTimer=true,
    waitTime=tWai,
    condition=speSig <= minSpe or on == false)
    "Fire condition 4: partially mechanical cooling to free cooling"
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
  Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(
    table=[0,0,0;
           1,1,0;
           2,1,1])
    "Determine which pump should be on - rotation control is not considered here"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt(
    final integerTrue=1,
    final integerFalse=0)
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1(
    final integerFalse=0, final integerTrue=2)
  Buildings.Controls.OBC.CDL.Integers.Add addInt
    "Outputs how many pumps are to be commanded on"
  Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea
    "Comparison from integer to real signal for number of pumps"

  Modelica.Blocks.Interfaces.BooleanInput on
    "On signal of the plant"
equation
  connect(off.outPort[1], con1.inPort)
  connect(con1.outPort, oneOn.inPort[1])
  connect(con2.inPort, oneOn.outPort[1])
  connect(con2.outPort, twoOn.inPort[1])
  connect(twoOn.outPort[1], con3.inPort)
  connect(con4.outPort, off.inPort[1])
  connect(con3.outPort, oneOn.inPort[2])
  connect(con4.inPort, oneOn.outPort[2])
  connect(combiTable1Ds.y, y)
  connect(booToInt.u, oneOn.active)
  connect(twoOn.active, booToInt1.u)
  connect(booToInt.y, addInt.u1)
  connect(booToInt1.y, addInt.u2)
  connect(addInt.y, intToRea.u)
  connect(intToRea.y, combiTable1Ds.u)
end VariableSpeedPumpStage;


Collection of validation models

within Buildings.Applications.BaseClasses.Controls;
package Validation "Collection of validation models"
extends Modelica.Icons.ExamplesPackage;
end Validation;


Test the model ChillerWSE.Examples.BaseClasses.VariableSpeedPumpStageControl. This model test the staging controller for variable-speed pumps. The staging controller is located in

Buildings.Applications.BaseClasses.Controls.VariableSpeedPumpStage.

within Buildings.Applications.BaseClasses.Controls.Validation;
model VariableSpeedPumpStage
  "Test the model ChillerWSE.Examples.BaseClasses.VariableSpeedPumpStageControl"
  extends Modelica.Icons.Example;
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=100
    "Nominal mass flowrate";

  Buildings.Applications.BaseClasses.Controls.VariableSpeedPumpStage
    varSpePumSta(tWai=30, m_flow_nominal=m_flow_nominal,
    criPoiSpe=0.6)
    "Staging controller for variable speed pumps"
  Modelica.Blocks.Sources.Pulse speSig(
    amplitude=0.8,
    period=180,
    offset=0.2) "Speed signal"
  Modelica.Blocks.Sources.Sine masFlo(
    offset=0.5*m_flow_nominal,
    f=1/360,
    amplitude=0.5*m_flow_nominal) "Mass flowrate"
  Modelica.Blocks.Sources.BooleanConstant on "Plant on signal"
equation
  connect(speSig.y, varSpePumSta.speSig)
  connect(masFlo.y, varSpePumSta.masFloPum)
  connect(on.y, varSpePumSta.on)
end VariableSpeedPumpStage;


Multiple identical electric chillers. This model implements a chiller parallel with num identical chillers. For the chiller model please see
Buildings.Fluid.Chillers.ElectricEIR.

within Buildings.Applications.BaseClasses.Equipment;
model ElectricChillerParallel "Multiple identical electric chillers"
  extends Buildings.Applications.DataCenters.ChillerCooled.Equipment.BaseClasses.PartialParallelElectricEIR(
    redeclare final Buildings.Fluid.Chillers.ElectricEIR chi[num](
      final per=per));

  replaceable parameter Buildings.Fluid.Chillers.Data.ElectricEIR.Generic per[
    numAct] "Performance data"
end ElectricChillerParallel;


Identical m_flow controlled pumps. This model implements a parallel of identical pumps with m_flow being controlled.
The number can be specified by setting a value of num.
The shutoff valves are used to avoid circulating flow among pumps.

within Buildings.Applications.BaseClasses.Equipment;
model FlowMachine_m "Identical m_flow controlled pumps"
  extends Buildings.Applications.DataCenters.ChillerCooled.Equipment.BaseClasses.PartialPumpParallel(
    redeclare final Buildings.Fluid.Movers.FlowControlled_m_flow pum(
      each final m_flow_nominal = m_flow_nominal,
      final m_flow_start=yPump_start*m_flow_nominal,
      each final dpMax=dpMax),
    rhoStd=Medium.density_pTX(101325, 273.15+4, Medium.X_default));

  // Note: Below we set a huge value for dpMax. This is needed for Dymola 2023
  // to run
  // simulateModel("Buildings.Applications.DataCenters.ChillerCooled.Examples.IntegratedPrimarySecondaryEconomizer", stopTime=86400, method="Cvode", tolerance=1e-07, resultFile="IntegratedPrimarySecondaryEconomizer");
  // on commit 3362be949be55b3c1e320faec8c8bac999f98ba4.
  // It seems to be an issue of Dymola evaluating the assertion before convergence,
  // because the result file does not show such large a pressure, and the model
  // works fine with Optimica.
  parameter Modelica.Units.SI.Pressure dpMax(
    displayUnit="Pa")=2*max(pum.per.pressure.dp)+6E11
    "Maximum pressure allowed to operate the model, if exceeded, the simulation stops with an error"

  Modelica.Blocks.Math.Gain gaiM_flow[num](each final k=m_flow_nominal)
    "Gain for mass flow rate"

equation
  connect(swi.y, gaiM_flow.u)
  connect(gaiM_flow.y, pum.m_flow_in)
end FlowMachine_m;


Identical speed controlled flow machines. This model implements a parallel of identical pumps with speed being controlled.
The number can be specified by setting a value of num.
The shutoff valves are used to avoid circulating flow among pumps.

within Buildings.Applications.BaseClasses.Equipment;
model FlowMachine_y "Identical speed controlled flow machines"
  extends Buildings.Applications.DataCenters.ChillerCooled.Equipment.BaseClasses.PartialPumpParallel(
    redeclare final Buildings.Fluid.Movers.SpeedControlled_y pum(final y_start=yPump_start),
    rhoStd=Medium.density_pTX(101325, 273.15+4, Medium.X_default));

equation
  connect(swi.y, pum.y)
end FlowMachine_y;


within Buildings.Applications.BaseClasses;
package Equipment "Equipment models for systems in applications package"
  extends Modelica.Icons.VariantsPackage;
end Equipment;


within Buildings.Applications.BaseClasses.Equipment.Validation;
model ElectricChillerParallel "Model that test electric chiller parallel"
  extends Modelica.Icons.Example;

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

  parameter Modelica.Units.SI.Power P_nominal=-per1.QEva_flow_nominal/per1.COP_nominal
    "Nominal compressor power (at y=1)";
  parameter Modelica.Units.SI.TemperatureDifference dTEva_nominal=10
    "Temperature difference evaporator inlet-outlet";
  parameter Modelica.Units.SI.TemperatureDifference dTCon_nominal=10
    "Temperature difference condenser outlet-inlet";
  parameter Real COPc_nominal = 3 "Chiller COP";
  parameter Modelica.Units.SI.MassFlowRate mEva_flow_nominal=per1.mEva_flow_nominal
    "Nominal mass flow rate at evaporator";
  parameter Modelica.Units.SI.MassFlowRate mCon_flow_nominal=per1.mCon_flow_nominal
    "Nominal mass flow rate at condenser";

  parameter Buildings.Fluid.Chillers.Data.ElectricEIR.ElectricEIRChiller_McQuay_WSC_471kW_5_89COP_Vanes
    per1 "Chiller performance data"
  parameter Buildings.Fluid.Chillers.Data.ElectricEIR.ElectricEIRChiller_York_YT_563kW_10_61COP_Vanes
    per2 "Chiller performance data"
  Buildings.Applications.BaseClasses.Equipment.ElectricChillerParallel chiPar(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    m1_flow_nominal=mEva_flow_nominal,
    m2_flow_nominal=mCon_flow_nominal,
    dp1_nominal=6000,
    dp2_nominal=6000,
    dpValve_nominal={6000,6000},
    per={per1,per2})
    "Chillers with identical nominal parameters but different performance curves"
  Fluid.Sources.Boundary_pT sou1(
    redeclare package Medium = Medium1,
    p=Medium1.p_default + 18E3,
    use_T_in=true,
    T=298.15,
    nPorts=1) "Pressure boundary condition"
  Fluid.Sources.Boundary_pT sou2(
    redeclare package Medium = Medium2,
    p=Medium2.p_default + 18E3,
    use_T_in=true,
    T=291.15,
    nPorts=1) "Pressure boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sin1(
    redeclare package Medium = Medium1, nPorts=1) "Pressure boundary condition"
  Buildings.Fluid.Sources.Boundary_pT sin2(
    redeclare package Medium = Medium2, nPorts=1) "Pressure boundary condition"
  Modelica.Blocks.Sources.Ramp TSet(
    duration=3600,
    startTime=3*3600,
    offset=273.15 + 10,
    height=8) "Set point for leaving chilled water temperature"
  Modelica.Blocks.Sources.Ramp TCon_in(
    height=10,
    offset=273.15 + 20,
    duration=3600,
    startTime=2*3600) "Condenser inlet temperature"
  Modelica.Blocks.Sources.Ramp TEva_in(
    offset=273.15 + 15,
    height=5,
    startTime=3600,
    duration=3600) "Evaporator inlet temperature"
  Modelica.Blocks.Sources.Pulse pulse(period=3600/2)
   "Pulse input signal"
  Modelica.Blocks.Logical.GreaterThreshold greaterThreshold(threshold=0.5)
    "Switch to switch chiller on or off"
  Buildings.Fluid.FixedResistances.PressureDrop res1(
    redeclare package Medium = Medium1,
    m_flow_nominal=mCon_flow_nominal,
    dp_nominal=6000) "Flow resistance"
  Buildings.Fluid.FixedResistances.PressureDrop res2(
    dp_nominal=6000,
    redeclare package Medium = Medium2,
    m_flow_nominal=mEva_flow_nominal) "Flow resistance"

equation
  connect(chiPar.port_b1, res1.port_a)
  connect(res2.port_a, chiPar.port_b2)
  connect(greaterThreshold.y, chiPar.on[1])
  connect(greaterThreshold.y, chiPar.on[2])
  connect(TSet.y, chiPar.TSet)

  connect(TCon_in.y, sou1.T_in)
  connect(TEva_in.y, sou2.T_in)

  connect(greaterThreshold.u, pulse.y)

  connect(res1.port_b, sin1.ports[1])
  connect(sou1.ports[1], chiPar.port_a1)
  connect(res2.port_b, sin2.ports[1])
  connect(chiPar.port_a2, sou2.ports[1])
end ElectricChillerParallel;


Collection of validation models

within Buildings.Applications.BaseClasses.Equipment;
package Validation "Collection of validation models"
extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.Applications.BaseClasses.Equipment.Validation;
model PumpParallel "Example that tests the model pump parallels"
  extends Modelica.Icons.Example;

  package MediumW = Buildings.Media.Water "Medium model";
  parameter Integer numPum=2 "The number of pumps";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=6000/3600*1.2
    "Nominal mass flow rate";
  parameter Real thr1=1E-4 "Threshold for shutoff valves in parallel 1";
  parameter Real thr2=thr1*m_flow_nominal "Threshold for shutoff valves in parallel 2";

  Buildings.Applications.BaseClasses.Equipment.FlowMachine_y pumPar1(
    redeclare package Medium = MediumW,
    num=numPum,
    dpValve_nominal=6000,
    redeclare Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos32slash1to12 per,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    threshold=thr1,
    tau=1,
    use_riseTime=false) "Pumps with speed controlled"

  Buildings.Fluid.FixedResistances.PressureDrop dp2(
    redeclare package Medium = MediumW,
    dp_nominal=3000,
    m_flow_nominal=6000/3600*1.2)
    "Pressure drop"

  Buildings.Fluid.FixedResistances.PressureDrop dp1(
    redeclare package Medium = MediumW,
    m_flow_nominal=6000/3600*1.2,
    dp_nominal=300)
    "Pressure drop"

  Buildings.Fluid.Sources.Boundary_pT sou(
    redeclare package Medium = MediumW,
    use_p_in=false,
    nPorts=2,
    p=101325,
    T=293.15)
    "Source"

  Buildings.Fluid.Sources.Boundary_pT sin(
    redeclare package Medium = MediumW,
    use_p_in=false,
    nPorts=2,
    p=101325,
    T=293.15)
    "Sink"

  Modelica.Blocks.Sources.Pulse y[numPum](
    each amplitude=1,
    each width=50,
    each period=120,
    each offset=0,
    each startTime=0)
    "Input signal"

  Buildings.Applications.BaseClasses.Equipment.FlowMachine_m pumPar2(
    redeclare package Medium = MediumW,
    num=numPum,
    dpValve_nominal=6000,
    redeclare Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos32slash1to12 per,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    threshold=thr2,
    tau=1)
    "Pumps with m_flow controlled"

  Buildings.Fluid.FixedResistances.PressureDrop dp3(
    redeclare package Medium = MediumW,
    m_flow_nominal=6000/3600*1.2,
    dp_nominal=300)
    "Pressure drop"

  Buildings.Fluid.FixedResistances.PressureDrop dp4(
    redeclare package Medium = MediumW,
    dp_nominal=3000,
    m_flow_nominal=6000/3600*1.2)
    "Pressure drop"

equation
  connect(dp2.port_a, pumPar1.port_b)
  connect(dp1.port_b, pumPar1.port_a)
  connect(sou.ports[1], dp1.port_a)
  connect(y.y, pumPar1.u)
  connect(dp3.port_a, sou.ports[2])
  connect(dp3.port_b, pumPar2.port_a)
  connect(pumPar2.port_b, dp4.port_a)
  connect(dp4.port_b, sin.ports[1])
  connect(y.y, pumPar2.u)
  connect(dp2.port_b, sin.ports[2])
end PumpParallel;


Package with models for data centers

within Buildings.Applications;
package DataCenters "Package with models for data centers"
  extends Modelica.Icons.VariantsPackage;
end DataCenters;


Package with type definitions

within Buildings.Applications.DataCenters;
package Types "Package with type definitions"
  extends Modelica.Icons.TypesPackage;

  type CoolingModes = enumeration(
      FreeCooling "Free cooling mode",
      PartialMechanical "Partial mechanical cooling",
      FullMechanical "Holiday") "Full mechanical cooling"
end Types;


within Buildings.Applications.DataCenters;
package ChillerCooled "Package for data centers that use chilled water plants and air-based equipment cooling"
  extends Modelica.Icons.VariantsPackage;
end ChillerCooled;


Chiller staging control logic. This is a chiller staging control that works as follows:

within Buildings.Applications.DataCenters.ChillerCooled.Controls;
model ChillerStage "Chiller staging control logic"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.Time tWai "Waiting time";
  parameter Modelica.Units.SI.Power QEva_nominal
    "Nominal cooling capaciaty(Negative means cooling)";
  parameter Modelica.Units.SI.Power criPoiLoa=0.55*QEva_nominal
    "Critical point of cooling load for switching one chiller on or off";
  parameter Modelica.Units.SI.Power dQ=0.25*QEva_nominal
    "Deadband for critical point of cooling load";
  parameter Modelica.Units.SI.Temperature criPoiTem=279.15
    "Critical point of temperature for switching one chiller on or off";
  parameter Modelica.Units.SI.TemperatureDifference dT=1
    "Deadband width for critical point of switching temperature";

  Modelica.Blocks.Interfaces.IntegerInput cooMod
    "Cooling mode signal, integer value of
    Buildings.Applications.DataCenters.Types.CoolingMode"
  Modelica.Blocks.Interfaces.RealInput QTot
    "Total cooling load in the chillers, negative"
  Modelica.Blocks.Interfaces.RealOutput y[2]
    "On/off signal for the chillers - 0: off; 1: on"
  Modelica.Blocks.Interfaces.RealInput TCHWSup(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Temperature of leaving chilled water "

  Modelica.StateGraph.Transition con1(
    enableTimer=true,
    waitTime=tWai,
    condition=cooMod > Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling))
    "Fire condition 1: free cooling to partially mechanical cooling"
  Modelica.StateGraph.StepWithSignal oneOn(nIn=2, nOut=2)
    "One chiller is commanded on"
  Modelica.StateGraph.InitialStep off(nIn=1, nOut=1)
                                             "Free cooling mode"
  Modelica.StateGraph.StepWithSignal twoOn(nIn=1, nOut=1)
                                           "Two chillers are commanded on"
  Modelica.StateGraph.Transition con2(
    enableTimer=true,
    waitTime=tWai,
    condition=cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FullMechanical) and
    (-QTot > -(criPoiLoa + dQ) or TCHWSup > criPoiTem + dT))
    "Fire condition 2: partially mechanical cooling to fully mechanical cooling"
  Modelica.StateGraph.Transition con3(
    enableTimer=true,
    waitTime=tWai,
    condition=(-QTot < -(criPoiLoa - dQ) or TCHWSup < criPoiTem - dT))
    "Fire condition 3: fully mechanical cooling to partially mechanical cooling"
  Modelica.StateGraph.Transition con4(
    enableTimer=true,
    waitTime=tWai,
    condition=cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling))
    "Fire condition 4: partially mechanical cooling to free cooling"
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot

  Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(
    table=[0,0,0;
           1,1,0;
           2,1,1])

  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt(
    final integerTrue=1,
    final integerFalse=0)
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1(
    final integerFalse=0, final integerTrue=2)
  Buildings.Controls.OBC.CDL.Integers.Add addInt
  Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea
equation
  connect(off.outPort[1], con1.inPort)
  connect(con1.outPort, oneOn.inPort[1])
  connect(con2.inPort, oneOn.outPort[1])
  connect(con2.outPort, twoOn.inPort[1])
  connect(twoOn.outPort[1], con3.inPort)
  connect(con4.outPort, off.inPort[1])
  connect(con3.outPort, oneOn.inPort[2])
  connect(con4.inPort, oneOn.outPort[2])
  connect(combiTable1Ds.y, y)
  connect(twoOn.active, booToInt1.u)
  connect(oneOn.active, booToInt.u)
  connect(booToInt.y, addInt.u1)
  connect(booToInt1.y, addInt.u2)
  connect(addInt.y, intToRea.u)
  connect(intToRea.y, combiTable1Ds.u)
end ChillerStage;


Staging control for constant speed pumps. This model describes a simple staging control for two constant-speed pumps in
a chilled water plant with two chillers and a waterside economizer (WSE). The staging sequence
is shown as below.

within Buildings.Applications.DataCenters.ChillerCooled.Controls;
model ConstantSpeedPumpStage "Staging control for constant speed pumps"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.Time tWai "Waiting time";

  Modelica.Blocks.Interfaces.IntegerInput cooMod
    "Cooling mode - 0:off,  1: free cooling mode; 2: partially mechanical cooling; 3: fully mechanical cooling"
  Modelica.Blocks.Interfaces.IntegerInput numOnChi
    "The number of running chillers"
  Modelica.Blocks.Interfaces.RealOutput y[2] "On/off signal - 0: off; 1: on"

  Modelica.StateGraph.Transition con1(
    enableTimer=true,
    waitTime=tWai,
    condition=
     cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling)
       or
     cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.PartialMechanical)
       or
     cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FullMechanical))
    "Fire condition 1: free cooling to partially mechanical cooling"
  Modelica.StateGraph.StepWithSignal oneOn(nIn=2, nOut=2)
    "One chiller is commanded on"
  Modelica.StateGraph.InitialStep off(nIn=1, nOut=1)
                                             "Free cooling mode"
  Modelica.StateGraph.StepWithSignal twoOn(nIn=1, nOut=1)
                                           "Two chillers are commanded on"
  Modelica.StateGraph.Transition con2(
    enableTimer=true,
    waitTime=tWai,
    condition=
      cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling)
        or
      cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.PartialMechanical)
        or
      (cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FullMechanical) and numOnChi > 1))
    "Fire condition 2: partially mechanical cooling to fully mechanical cooling"
  Modelica.StateGraph.Transition con3(
    enableTimer=true,
    waitTime=tWai,
    condition=cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FullMechanical)
    and numOnChi < 2)
    "Fire condition 3: fully mechanical cooling to partially mechanical cooling"
  Modelica.StateGraph.Transition con4(
    enableTimer=true,
    waitTime=tWai,
    condition=cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling))
    "Fire condition 4: partially mechanical cooling to free cooling"
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
  Modelica.Blocks.Tables.CombiTable1Ds combiTable1Ds(table=[0,0,0; 1,1,0; 2,1,1])

  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt(
    final integerTrue=1,
    final integerFalse=0)
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1(
    final integerFalse=0, final integerTrue=2)
  Buildings.Controls.OBC.CDL.Integers.Add addInt
  Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea

equation
  connect(off.outPort[1], con1.inPort)
  connect(con1.outPort, oneOn.inPort[1])
  connect(con2.inPort, oneOn.outPort[1])
  connect(con2.outPort, twoOn.inPort[1])
  connect(twoOn.outPort[1], con3.inPort)
  connect(con4.outPort, off.inPort[1])
  connect(con3.outPort, oneOn.inPort[2])
  connect(con4.inPort, oneOn.outPort[2])
  connect(combiTable1Ds.y, y)
  connect(oneOn.active, booToInt.u)
  connect(twoOn.active, booToInt1.u)
  connect(booToInt.y, addInt.u1)
  connect(booToInt1.y, addInt.u2)
  connect(intToRea.y, combiTable1Ds.u)
  connect(addInt.y, intToRea.u)
end ConstantSpeedPumpStage;


Mode controller for integrated waterside economizer and chiller. Controller that outputs if the chilled water system is in Free Cooling (FC) mode,
Partially Mechanical Cooling (PMC) mode or Fully Mechanical Cooling (FMC) mode.

within Buildings.Applications.DataCenters.ChillerCooled.Controls;
model CoolingMode
  "Mode controller for integrated waterside economizer and chiller"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.Time tWai "Waiting time";
  parameter Modelica.Units.SI.TemperatureDifference deaBan1
    "Dead band width 1 for switching chiller on ";
  parameter Modelica.Units.SI.TemperatureDifference deaBan2
    "Dead band width 2 for switching waterside economizer off";
  parameter Modelica.Units.SI.TemperatureDifference deaBan3
    "Dead band width 3 for switching waterside economizer on ";
  parameter Modelica.Units.SI.TemperatureDifference deaBan4
    "Dead band width 4 for switching chiller off";

  Modelica.Blocks.Interfaces.RealInput TCHWRetWSE(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC")
    "Temperature of entering chilled water that flows to waterside economizer "
  Modelica.Blocks.Interfaces.RealInput TCHWSupWSE(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC")
    "Temperature of leaving chilled water that flows out from waterside economizer"
  Modelica.Blocks.Interfaces.RealInput TCHWSupSet(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Supply chilled water temperature setpoint "
  Modelica.Blocks.Interfaces.RealInput TApp(
    final quantity="TemperatureDifference",
    final unit="K",
    displayUnit="degC") "Approach temperature in the cooling tower"
  Modelica.Blocks.Interfaces.IntegerOutput y
    "Cooling mode signal, integer value of Buildings.Applications.DataCenters.Types.CoolingMode"

  Modelica.StateGraph.Transition con1(
    enableTimer=true,
    waitTime=tWai,
    condition=TCHWSupWSE > TCHWSupSet + deaBan1)
    "Fire condition 1: free cooling to partially mechanical cooling"
  Modelica.StateGraph.StepWithSignal parMecCoo(nIn=2, nOut=2)
    "Partial mechanical cooling mode"
  Modelica.StateGraph.InitialStepWithSignal freCoo(nIn=1, nOut=1)
                                                          "Free cooling mode"
  Modelica.StateGraph.StepWithSignal fulMecCoo(nIn=1, nOut=1)
                                               "Fully mechanical cooling mode"
  Modelica.StateGraph.Transition con2(
    enableTimer=true,
    waitTime=tWai,
    condition=TCHWRetWSE < TCHWSupWSE + deaBan2)
    "Fire condition 2: partially mechanical cooling to fully mechanical cooling"
  Modelica.StateGraph.Transition con3(
    enableTimer=true,
    waitTime=tWai,
    condition=TCHWRetWSE > TWetBul + TApp + deaBan3)
    "Fire condition 3: fully mechanical cooling to partially mechanical cooling"
  Modelica.StateGraph.Transition con4(
    enableTimer=true,
    waitTime=tWai,
    condition=TCHWSupWSE <= TCHWSupSet + deaBan4)
    "Fire condition 4: partially mechanical cooling to free cooling"
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
  Modelica.Blocks.Interfaces.RealInput TWetBul(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC")
    "Wet bulb temperature of outdoor air"

  Modelica.Blocks.MathInteger.MultiSwitch swi(
    y_default=0,
    nu=3,
    expr={Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling),
          Integer(Buildings.Applications.DataCenters.Types.CoolingModes.PartialMechanical),
          Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FullMechanical)})
    "Switch boolean signals to real signal"

equation
  connect(freCoo.outPort[1], con1.inPort)
  connect(con1.outPort, parMecCoo.inPort[1])
  connect(con2.inPort, parMecCoo.outPort[1])
  connect(con2.outPort, fulMecCoo.inPort[1])
  connect(fulMecCoo.outPort[1], con3.inPort)
  connect(con4.outPort, freCoo.inPort[1])
  connect(con3.outPort, parMecCoo.inPort[2])
  connect(con4.inPort, parMecCoo.outPort[2])
  connect(swi.y, y)
  connect(freCoo.active, swi.u[1])
  connect(parMecCoo.active, swi.u[2])
  connect(fulMecCoo.active, swi.u[3])
end CoolingMode;


Cooling mode controller in the chilled water system with a non-integrated  waterside economizer. Chilled water plant with a non-integrated waterside economizer (WSE) have two cooling modes:
free cooling (FC) mode and fully mechanical cooling (FMC) mode. This model determines when to
activate FC or FMC for a chilled water system with 2 chillers and 1 waterside economizer.

within Buildings.Applications.DataCenters.ChillerCooled.Controls;
model CoolingModeNonIntegrated
  "Cooling mode controller in the chilled water system with a non-integrated  waterside economizer"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.TemperatureDifference deaBan
    "Dead band width for switching waterside economizer off ";
  parameter Modelica.Units.SI.Temperature TSwi
    "Temperature transition to free cooling mode";
  parameter Modelica.Units.SI.Time tWai "Waiting time";

  Modelica.Blocks.Interfaces.IntegerInput numOnChi
    "Number of running chillers"
  Modelica.Blocks.Interfaces.RealInput TWetBul(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC")
    "Wet bulb temperature of outdoor air"
  Modelica.Blocks.Interfaces.RealInput TCHWSup(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Temperature of leaving chilled water "
  Modelica.Blocks.Interfaces.RealInput TCHWSupSet(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Temperature setpoint of leaving chilled water "
  Modelica.Blocks.Interfaces.IntegerOutput y
    "Cooling mode signal (1: free cooling mode, 3: fully mechanical cooling)"

  Modelica.StateGraph.InitialStepWithSignal freCoo(nIn=1, nOut=1)
    "Free cooling mode"
  Modelica.StateGraph.StepWithSignal fulMecCoo(nIn=1, nOut=1)
    "Fully mechanical cooling mode"
  Modelica.StateGraph.Transition con1(
    enableTimer=true,
    waitTime=tWai,
    condition=TWetBul > TSwi + deaBan or TCHWSup > TCHWSupSet + deaBan)
    "Fire condition 1: free cooling to fully mechanical cooling"
  Modelica.Blocks.MathInteger.MultiSwitch swi(
    nu=2,
    y_default=0,
    expr={Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FreeCooling),
        Integer(Buildings.Applications.DataCenters.Types.CoolingModes.FullMechanical)})
    "Switch boolean signals to real signal"
  Modelica.StateGraph.Transition con2(
    enableTimer=true,
    waitTime=tWai,
    condition=TWetBul <= TSwi - deaBan and numOnChi == 1)
    "Fire condition 2: fully mechanical cooling to free cooling"
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
equation
  connect(freCoo.outPort[1],con1. inPort)
  connect(con1.outPort,fulMecCoo. inPort[1])
  connect(fulMecCoo.outPort[1], con2.inPort)
  connect(con2.outPort, freCoo.inPort[1])
  connect(freCoo.active, swi.u[1])
  connect(fulMecCoo.active, swi.u[2])
  connect(swi.y, y)
end CoolingModeNonIntegrated;


Controller for the fan speed in cooling towers. This model describes a simple cooling tower speed controller for
a chilled water system with integrated waterside economizers.

within Buildings.Applications.DataCenters.ChillerCooled.Controls;
model CoolingTowerSpeed "Controller for the fan speed in cooling towers"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Blocks.Types.SimpleController controllerType=
    Modelica.Blocks.Types.SimpleController.PI
    "Type of controller"
  parameter Real k(min=0, unit="1") = 1
    "Gain of controller"
  parameter Modelica.Units.SI.Time Ti(min=Modelica.Constants.small) = 0.5
    "Time constant of integrator block"
  parameter Modelica.Units.SI.Time Td(min=0) = 0.1
    "Time constant of derivative block"
  parameter Real yMax(start=1)=1
   "Upper limit of output"
  parameter Real yMin=0
   "Lower limit of output"
  parameter Boolean reverseActing=false
    "Set to true for throttling the water flow rate through a cooling coil controller"
  Modelica.Blocks.Interfaces.RealInput TCHWSupSet(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Chilled water supply temperature setpoint"
  Modelica.Blocks.Interfaces.RealInput TCWSupSet(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Condenser water supply temperature setpoint"
  Modelica.Blocks.Interfaces.RealInput TCHWSup(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Chilled water supply temperature "
  Modelica.Blocks.Interfaces.RealInput TCWSup(
    final quantity="ThermodynamicTemperature",
    final unit="K",
    displayUnit="degC") "Condenser water supply temperature "
  Modelica.Blocks.Interfaces.RealOutput y
    "Speed signal for cooling tower fans"

  Modelica.Blocks.Sources.Constant uni(k=1) "Unit"
  Modelica.Blocks.Sources.BooleanExpression pmcMod(
    y= cooMod == Integer(Buildings.Applications.DataCenters.Types.CoolingModes.PartialMechanical))
    "Partially mechanical cooling mode"

  Modelica.Blocks.Interfaces.IntegerInput cooMod
    "Cooling mode signal, integer value of
    Buildings.Applications.DataCenters.Types.CoolingMode"
  Buildings.Controls.Continuous.LimPID conPID(
    controllerType=controllerType,
    k=k,
    Ti=Ti,
    Td=Td,
    yMax=yMax,
    yMin=yMin,
    reverseActing=reverseActing)
    "PID controller"
  Modelica.Blocks.Math.IntegerToBoolean fmcMod(threshold=3)
    "Fully mechanical cooling mode"

protected
  Modelica.Blocks.Logical.Switch swi1
    "Switch 1"
  Modelica.Blocks.Logical.Switch swi2
    "Switch 2"
  Modelica.Blocks.Logical.Switch swi3
    "Switch 3"

equation
  connect(TCWSupSet, swi1.u1)
  connect(TCHWSupSet, swi1.u3)
  connect(swi1.y, conPID.u_s)
  connect(fmcMod.y, swi2.u2)
  connect(TCWSup, swi2.u1)
  connect(TCHWSup, swi2.u3)
  connect(swi2.y, conPID.u_m)
  connect(pmcMod.y, swi3.u2)
  connect(uni.y, swi3.u1)
  connect(conPID.y, swi3.u3)
  connect(swi3.y, y)
  connect(fmcMod.y, swi1.u2)
  connect(cooMod, fmcMod.u)
end CoolingTowerSpeed;


within Buildings.Applications.DataCenters.ChillerCooled;
package Controls "Package with control components for Buildings.Applications.DataCenters.ChillerCooled.Examples"
  extends Modelica.Icons.Package;
end Controls;


Model that implements an on and off controller for a reheater. This model can be used to generate on/off signal for the reheater inside the AHU.

within Buildings.Applications.DataCenters.ChillerCooled.Controls;
model Reheat "Model that implements an on and off controller for a reheater"

  parameter Real yValSwi(min=0, max=1, unit="1")
    "Switch point for valve signal";
  parameter Real yValDeaBan(min=0, max=1, unit="1")
    "Deadband for valve signal";
  parameter Modelica.Units.SI.TemperatureDifference dTSwi
    "Switch point for temperature difference";
  parameter Modelica.Units.SI.TemperatureDifference dTDeaBan
    "Deadband for temperature difference";
  parameter Modelica.Units.SI.Time tWai "Waiting time";

  Modelica.Blocks.Interfaces.RealInput yVal(
    min=0,
    max=1,
    unit="1") "Valve position"
  Modelica.Blocks.Interfaces.RealInput dT(
    final quantity="ThermodynamicTemperature",
    final unit="K")
    "Temperature difference"
  Modelica.Blocks.Interfaces.BooleanOutput y
    "On and off signal for the reheater"

  Modelica.StateGraph.InitialStepWithSignal off(nIn=1, nOut=1)
                                                "Off"
  Modelica.StateGraph.StepWithSignal on(nIn=1, nOut=1)
                                        "On"
  Modelica.StateGraph.Transition offToOn(
    enableTimer=true,
    waitTime=tWai,
    condition=yVal <= yValSwi - yValDeaBan and dT < dTSwi - dTDeaBan)
    "Conditions that switch off to on"
  Modelica.StateGraph.Transition onToOff(
    condition=yVal > yValSwi+yValDeaBan or dT > dTSwi+dTDeaBan,
    enableTimer=true,
    waitTime=tWai)
    "Conditions that switch on to off"

  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot
equation
  connect(off.outPort[1], offToOn.inPort)
  connect(offToOn.outPort, on.inPort[1])
  connect(on.outPort[1], onToOff.inPort)
  connect(onToOff.outPort, off.inPort[1])
  connect(on.active, y)
end Reheat;