Multiple pumps in parallel

within Buildings.Templates.Components.Pumps;
model Multiple "Multiple pumps in parallel"
  extends Buildings.Templates.Components.Interfaces.PartialPumpMultiple(
    final typ=Buildings.Templates.Components.Types.Pump.Multiple);

  replaceable Buildings.Fluid.Movers.SpeedControlled_y pum[nPum](
    redeclare each final package Medium=Medium,
    final per=dat.per,
    each final inputType=Buildings.Fluid.Types.InputType.Continuous,
    each final addPowerToMedium=addPowerToMedium,
    each final energyDynamics=energyDynamics,
    each final tau=tau,
    each final allowFlowReversal=allowFlowReversal)
    "Pumps"
  Fluid.FixedResistances.CheckValve valChe[nPum](
    redeclare each final package Medium = Medium,
    final m_flow_nominal=m_flow_nominal,
    final dpValve_nominal=dpValChe_nominal)
    if have_valChe "Check valve"
  Routing.PassThroughFluid pas[nPum](
    redeclare each final package Medium = Medium) if not have_valChe
    "Fluid pass through if no check valve"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal sigSta[nPum]
    "Start/stop signal"
  Buildings.Controls.OBC.CDL.Reals.Multiply sigCon[nPum]
    "Resulting control signal"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator reaSpe(
    final nout=nPum) if have_var and have_varCom
    "Replicate signal in case of common unique commanded speed"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant speCst[nPum](
    final k=fill(1, nPum)) if not have_var
    "Constant signal in case of constant speed pump"
  Buildings.Controls.OBC.CDL.Routing.RealExtractSignal pasSpe(
    final nin=nPum,
    final nout=nPum) if have_var and not have_varCom
    "Direct pass through for dedicated speed signals"
  Controls.StatusEmulator sta[nPum] "Emulate pump status"
equation
  connect(pum.port_b,valChe. port_a)
  connect(sigSta.y, sigCon.u2)
  connect(sigCon.y, pum.y)
  connect(valChe.port_b, ports_b)
  connect(ports_a, pum.port_a)
  connect(bus.y1, sigSta.u)
  connect(reaSpe.y, sigCon.u1)
  connect(bus.y, reaSpe.u)
  connect(speCst.y, sigCon.u1)
  connect(bus.y, pasSpe.u)
  connect(pasSpe.y, sigCon.u1)
  connect(pum.port_b, pas.port_a)
  connect(pas.port_b, ports_b)
  connect(sta.y1_actual, bus.y1_actual)
  connect(bus.y1, sta.y1)
end Multiple;


Pump models

within Buildings.Templates.Components;
package Pumps "Pump models"
  extends Modelica.Icons.VariantsPackage;
end Pumps;


Single pump

within Buildings.Templates.Components.Pumps;
model Single "Single pump"
  extends Buildings.Templates.Components.Interfaces.PartialPumpSingle(
    final typ=Buildings.Templates.Components.Types.Pump.Single);

  replaceable Buildings.Fluid.Movers.SpeedControlled_y pum(
    redeclare final package Medium=Medium,
    final per=dat.per,
    final inputType=Buildings.Fluid.Types.InputType.Continuous,
    final addPowerToMedium=addPowerToMedium,
    final energyDynamics=energyDynamics,
    final tau=tau,
    final allowFlowReversal=allowFlowReversal)
    "Pump"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal sigSta
    "Start/stop signal"
  Buildings.Controls.OBC.CDL.Reals.Multiply sigCon
    "Resulting control signal"
  Fluid.FixedResistances.CheckValve valChe(
    redeclare final package Medium = Medium,
    final m_flow_nominal=dat.m_flow_nominal,
    final dpValve_nominal=dpValChe_nominal)
    if have_valChe
    "Check valve"
  Routing.PassThroughFluid pas(
    redeclare final package Medium=Medium) if not have_valChe
    "Fluid pass through if no check valve"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant speCst(
    final k=1) if not have_var
    "Constant signal in case of constant speed pump"
  Modelica.Blocks.Routing.RealPassThrough pasSpe if have_var
    "Direct pass through for variable speed signal"
  Controls.StatusEmulator sta "Emulate pump status"
equation
  connect(sigSta.y, sigCon.u2)
  connect(sigCon.y, pum.y)
  connect(port_a, pum.port_a)
  connect(bus.y, pasSpe.u)
  connect(pasSpe.y, sigCon.u1)
  connect(speCst.y, sigCon.u1)
  connect(bus.y1, sigSta.u)
  connect(pum.port_b, valChe.port_a)
  connect(valChe.port_b, port_b)
  connect(pum.port_b, pas.port_a)
  connect(pas.port_b, port_b)
  connect(bus.y1, sta.y1)
  connect(sta.y1_actual, bus.y1_actual)
end Single;


Flow splitter with fixed resistance at each port. This is a model of a flow junction with an optional fixed resistance
in each flow leg and an optional mixing volume at the junction.
This model is identical to

Buildings.Fluid.FixedResistances.Junction
except for the icon which has been changed for better integration
into the templates.

within Buildings.Templates.Components.Routing;
model Junction "Flow splitter with fixed resistance at each port"
  extends Buildings.Fluid.FixedResistances.Junction

  parameter Buildings.Templates.Components.Types.IntegrationPoint icon_pipe1=
      Buildings.Templates.Components.Types.IntegrationPoint.Supply
    "Pipe symbol - Branch 1"
  parameter Buildings.Templates.Components.Types.IntegrationPoint icon_pipe2=
      icon_pipe1 "Pipe symbol - Branch 2"
  parameter Buildings.Templates.Components.Types.IntegrationPoint icon_pipe3=
      icon_pipe1 "Pipe symbol - Branch 3"
end Junction;


within Buildings.Templates.Components.Routing;
model MultipleToMultiple
  "Multiple inlet ports, multiple outlet ports"

  replaceable package Medium =
    Modelica.Media.Interfaces.PartialMedium "Medium in the component"
  parameter Integer nPorts_a
    "Number of inlet ports"
  parameter Integer nPorts_b = nPorts_a
    "Number of outlet ports"
  parameter Boolean have_comLeg = false
    "Set to true for common leg between inlet and outlet ports (headered connection)"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal(min=0)
    "Nominal mass flow rate"
  parameter Modelica.Units.SI.Time tau=10
    "Time constant at nominal flow"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=
    Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  parameter Boolean allowFlowReversal=true
    "= true to allow flow reversal, false restricts to design direction (ports_a -> ports_b)"
  // Diagnostics
  parameter Boolean show_T = false
    "Set to true if actual temperature at port is computed"

  constant Integer icon_xinl = -100
    "Minimum x-coordinate of inlet connection lines";
  constant Integer icon_xout = 100
    "Maximum x-coordinate of outlet connection lines";
  constant Integer icon_offset = 0
    "Offset in y-direction between inlet and outlet in icon layer";
  constant Integer icon_dy = 100
    "Distance in y-direction between each branch in icon layer";
  constant Buildings.Templates.Components.Types.IntegrationPoint icon_pipe=
      Buildings.Templates.Components.Types.IntegrationPoint.Supply
    "Pipe symbol";

  Modelica.Fluid.Interfaces.FluidPorts_a ports_a[nPorts_a](
    redeclare each final package Medium = Medium,
    each m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0),
    each h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    "Fluid connector a (positive design flow direction is from ports_a to ports_b)"
  Modelica.Fluid.Interfaces.FluidPorts_b ports_b[nPorts_b](
    redeclare each final package Medium = Medium,
    each m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0),
    each h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    "Fluid connectors b (positive design flow direction is from ports_a to ports_b)"
  Modelica.Fluid.Interfaces.FluidPort_a port_aComLeg(
    redeclare final package Medium=Medium,
    m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0),
    h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    if have_comLeg "Common leg port - Case with common leg"

  PassThroughFluid pasDed[nPorts_a](
    redeclare each final package Medium=Medium) if not have_comLeg
    "Dedicated fluid pass-through if dedicated arrangement"

  Medium.ThermodynamicState sta_a[nPorts_a]=
      Medium.setState_phX(ports_a.p,
                          noEvent(actualStream(ports_a.h_outflow)),
                          noEvent(actualStream(ports_a.Xi_outflow)))
      if show_T "Medium properties in ports_a";

  Medium.ThermodynamicState sta_b[nPorts_b]=
      Medium.setState_phX(ports_b.p,
                          noEvent(actualStream(ports_b.h_outflow)),
                          noEvent(actualStream(ports_b.Xi_outflow)))
      if show_T "Medium properties in ports_b";

  Fluid.Delays.DelayFirstOrder del(
    redeclare final package Medium=Medium,
    final tau=tau,
    final m_flow_nominal=m_flow_nominal,
    final energyDynamics=energyDynamics,
    final allowFlowReversal=allowFlowReversal,
    final prescribedHeatFlowRate=false,
    final nPorts=nPorts_a+nPorts_b+1)
    if have_controlVolume and have_comLeg
    "Fluid volume to break algebraic loop - Case with common leg"

  PassThroughFluid pasSteInl(redeclare final package Medium = Medium)
    if have_comLeg and not have_controlVolume
    "Fluid pass-through in lieu of control volume - Case with common leg"
  PassThroughFluid pasSteOut(redeclare final package Medium = Medium)
    if have_comLeg and not have_controlVolume
    "Fluid pass-through in lieu of control volume - Case with common leg"

protected
  parameter Boolean have_controlVolume=
    energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Boolean flag used to remove conditional components"

initial equation
  if not have_comLeg then
    assert(nPorts_a==nPorts_b,
    "In "+ getInstanceName() + ": "+
    "In the absence of a common leg (dedicated connection), the number of inlet ports (" +
    String(nPorts_a) + ") must be equal to the number of outlet ports (" +
    String(nPorts_b) +")");
  end if;
equation
  for i in 1:nPorts_a loop
  connect(ports_a[i], pasSteInl.port_a)
  end for;
  for i in 1:nPorts_b loop
    connect(pasSteOut.port_b, ports_b[i])
  end for;
  connect(ports_a, pasDed.port_a)
  connect(pasDed.port_b, ports_b)
  connect(del.ports[nPorts_a+nPorts_b+1], port_aComLeg)
  connect(ports_a, del.ports[1:nPorts_a])
  connect(del.ports[(nPorts_a+1):(nPorts_a+nPorts_b)], ports_b)
  connect(pasSteInl.port_b, port_aComLeg)
  connect(port_aComLeg, pasSteOut.port_a)
end MultipleToMultiple;


within Buildings.Templates.Components.Routing;
model MultipleToSingle "Multiple inlet port, single outlet ports"
  replaceable package Medium =
    Modelica.Media.Interfaces.PartialMedium "Medium in the component"
  parameter Integer nPorts
    "Number of ports"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal(min=0)
    "Nominal mass flow rate"
  parameter Modelica.Units.SI.Time tau=10
    "Time constant at nominal flow"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=
    Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  parameter Boolean allowFlowReversal=true
    "Set to true to allow flow reversal, false restricts to design direction (ports_a -> port_b)"
  // Diagnostics
   parameter Boolean show_T = false
    "Set to true if actual temperature at port is computed"

  constant Integer icon_offset = 0
    "Offset in y-direction between inlet and outlet in icon layer";
  constant Integer icon_dy = 100
    "Distance in y-direction between each branch in icon layer";
  constant Buildings.Templates.Components.Types.IntegrationPoint icon_pipe=
      Buildings.Templates.Components.Types.IntegrationPoint.None "Pipe symbol";

  Modelica.Fluid.Interfaces.FluidPorts_a ports_a[nPorts](
    redeclare each final package Medium = Medium,
    each m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0),
    each h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    "Fluid connector a (positive design flow direction is from ports_a to port_b)"
  Modelica.Fluid.Interfaces.FluidPort_b port_b(
    redeclare final package Medium = Medium,
    m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0),
    h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    "Fluid connectors b (positive design flow direction is from ports_a to port_b)"

  Fluid.Delays.DelayFirstOrder del(
    redeclare final package Medium = Medium,
    final tau=tau,
    final m_flow_nominal=m_flow_nominal,
    final energyDynamics=energyDynamics,
    final allowFlowReversal=allowFlowReversal,
    final prescribedHeatFlowRate=false,
    final nPorts=nPorts+1)
    if have_controlVolume
    "Fluid volume to break algebraic loop"
  PassThroughFluid pasSte(
    redeclare final package Medium=Medium)
    if not have_controlVolume
    "Fluid pass-through in lieu of control volume"

  Medium.ThermodynamicState sta_a[nPorts]=
      Medium.setState_phX(ports_a.p,
                          noEvent(actualStream(ports_a.h_outflow)),
                          noEvent(actualStream(ports_a.Xi_outflow)))
      if show_T "Medium properties in ports_a";
  Medium.ThermodynamicState sta_b=
      Medium.setState_phX(port_b.p,
                          noEvent(actualStream(port_b.h_outflow)),
                          noEvent(actualStream(port_b.Xi_outflow)))
      if show_T "Medium properties in port_b";

protected
  parameter Boolean have_controlVolume=
    energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Boolean flag used to remove conditional components"

equation
  for i in 1:nPorts loop
  connect(ports_a[i], pasSte.port_a)
  end for;
  connect(ports_a, del.ports[1:nPorts])
  connect(del.ports[nPorts+1], port_b)
  connect(pasSte.port_b, port_b)
end MultipleToSingle;


Connection models for fluid routing

within Buildings.Templates.Components;
package Routing "Connection models for fluid routing"
  extends Modelica.Icons.VariantsPackage;
end Routing;


Direct fluid pass-through. This is a model of a direct fluid pass-through used for
templating purposes.

within Buildings.Templates.Components.Routing;
model PassThroughFluid "Direct fluid pass-through"
  extends Buildings.Fluid.Interfaces.PartialTwoPort

  parameter Buildings.Templates.Components.Types.IntegrationPoint icon_pipe=
      Buildings.Templates.Components.Types.IntegrationPoint.Supply
    "Pipe symbol"

equation
  connect(port_a, port_b)
end PassThroughFluid;


within Buildings.Templates.Components.Routing;
model SingleToMultiple "Single inlet port, multiple outlet ports"
  replaceable package Medium =
    Modelica.Media.Interfaces.PartialMedium "Medium in the component"
  parameter Integer nPorts
    "Number of ports"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal(min=0)
    "Nominal mass flow rate"
  parameter Modelica.Units.SI.Time tau=10
    "Time constant at nominal flow"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=
    Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  parameter Boolean allowFlowReversal=true
    "Set to true to allow flow reversal, false restricts to design direction (port_a -> ports_b)"
  // Diagnostics
   parameter Boolean show_T = false
    "Set to true if actual temperature at port is computed"

  constant Integer icon_offset = 0
    "Offset in y-direction between inlet and outlet in icon layer";
  constant Integer icon_dy = 100
    "Distance in y-direction between each branch in icon layer";
  constant Buildings.Templates.Components.Types.IntegrationPoint icon_pipe=
      Buildings.Templates.Components.Types.IntegrationPoint.None "Pipe symbol";

  Modelica.Fluid.Interfaces.FluidPort_a port_a(
    redeclare final package Medium = Medium,
    m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0),
    h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    "Fluid connector a (positive design flow direction is from port_a to ports_b)"
  Modelica.Fluid.Interfaces.FluidPorts_b ports_b[nPorts](
    redeclare each final package Medium = Medium,
    each m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0),
    each h_outflow(start=Medium.h_default, nominal=Medium.h_default))
    "Fluid connectors b (positive design flow direction is from port_a to ports_b)"

  Fluid.Delays.DelayFirstOrder del(
    redeclare final package Medium = Medium,
    final tau=tau,
    final m_flow_nominal=m_flow_nominal,
    final energyDynamics=energyDynamics,
    final allowFlowReversal=allowFlowReversal,
    final prescribedHeatFlowRate=false,
    final nPorts=nPorts+1)
    if have_controlVolume
    "Fluid volume to break algebraic loop"
  PassThroughFluid pasSte(
    redeclare final package Medium=Medium)
    if not have_controlVolume
    "Fluid pass-through in lieu of control volume"

  Medium.ThermodynamicState sta_a=
      Medium.setState_phX(port_a.p,
                          noEvent(actualStream(port_a.h_outflow)),
                          noEvent(actualStream(port_a.Xi_outflow)))
      if show_T "Medium properties in port_a";
  Medium.ThermodynamicState sta_b[nPorts]=
      Medium.setState_phX(ports_b.p,
                          noEvent(actualStream(ports_b.h_outflow)),
                          noEvent(actualStream(ports_b.Xi_outflow)))
      if show_T "Medium properties in ports_b";

protected
  parameter Boolean have_controlVolume=
    energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Boolean flag used to remove conditional components"

equation
  for i in 1:nPorts loop
      connect(pasSte.port_b, ports_b[i])
  end for;
    connect(port_a, pasSte.port_a)
  connect(del.ports[2:nPorts+1], ports_b)
  connect(del.ports[1], port_a)
end SingleToMultiple;


Differential pressure sensor

within Buildings.Templates.Components.Sensors;
model DifferentialPressure "Differential pressure sensor"
  extends Buildings.Templates.Components.Interfaces.PartialSensor(
    y(final unit="Pa", displayUnit="Pa"),
    final m_flow_nominal=0,
    final isDifPreSen=true);

  Buildings.Fluid.Sensors.RelativePressure senRelPre(
    redeclare final package Medium=Medium) if have_sen
    "Relative pressure sensor"
equation
  connect(port_a, senRelPre.port_a)
  connect(senRelPre.p_rel, y)
  connect(senRelPre.port_b, port_b)<br/>
port_(a|b).C_outflow  = zeros(Medium.nC);
</code>
</html>"));
end DifferentialPressure;


Humidity ratio sensor

within Buildings.Templates.Components.Sensors;
model HumidityRatio "Humidity ratio sensor"
  extends Buildings.Templates.Components.Interfaces.PartialSensor(
    y(final unit="kg/kg"),
    final isDifPreSen=false);

  Buildings.Fluid.Sensors.MassFractionTwoPort senMasFra(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    final allowFlowReversal=allowFlowReversal) if have_sen
    "Mass fraction sensor"
  Buildings.Utilities.Psychrometrics.ToDryAir toDryAir if have_sen
    "Conversion into kg/kg dry air"

  Buildings.Templates.Components.Routing.PassThroughFluid pas(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal) if not have_sen "Pass through"
equation
  connect(port_a, senMasFra.port_a)
  connect(senMasFra.port_b, port_b)
  connect(senMasFra.X, toDryAir.XiTotalAir)

  connect(port_a, pas.port_a)
  connect(pas.port_b, port_b)
  connect(toDryAir.XiDry, y)
end HumidityRatio;


Sensor models

within Buildings.Templates.Components;
package Sensors "Sensor models"
  extends Modelica.Icons.VariantsPackage;
end Sensors;


Specific enthalpy sensor

within Buildings.Templates.Components.Sensors;
model SpecificEnthalpy "Specific enthalpy sensor"
  extends Buildings.Templates.Components.Interfaces.PartialSensor(
    y(final unit="J/kg"),
    final isDifPreSen=false);

  Buildings.Fluid.Sensors.SpecificEnthalpyTwoPort senSpeEnt(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    final allowFlowReversal=allowFlowReversal) if have_sen
    "Specific enthalpy sensor"

  Buildings.Templates.Components.Routing.PassThroughFluid pas(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal) if not have_sen "Pass through"
equation
  connect(port_a,senSpeEnt. port_a)
  connect(senSpeEnt.port_b, port_b)

  connect(port_a, pas.port_a)
  connect(pas.port_b, port_b)
  connect(senSpeEnt.h_out, y)
end SpecificEnthalpy;


Temperature sensor

within Buildings.Templates.Components.Sensors;
model Temperature "Temperature sensor"
  extends Buildings.Templates.Components.Interfaces.PartialSensor(
    y(final unit="K", displayUnit="degC"),
    final isDifPreSen=false);

  parameter Buildings.Templates.Components.Types.SensorTemperature typ=
    Buildings.Templates.Components.Types.SensorTemperature.Standard
    "Type of temperature sensor"

  Buildings.Fluid.Sensors.TemperatureTwoPort senTem(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal) if have_sen
    "Temperature sensor"
  Buildings.Templates.Components.Routing.PassThroughFluid pas(redeclare final
      package Medium = Medium) if not have_sen "Pass through"
equation

  connect(port_a, senTem.port_a)
  connect(senTem.port_b, port_b)
  connect(port_a, pas.port_a)
  connect(pas.port_b, port_b)
  connect(senTem.T, y)
end Temperature;


Volume flow rate sensor

within Buildings.Templates.Components.Sensors;
model VolumeFlowRate "Volume flow rate sensor"
  extends Buildings.Templates.Components.Interfaces.PartialSensor(
    y(final unit="m3/s"),
    final isDifPreSen=false);

  parameter Buildings.Templates.Components.Types.SensorVolumeFlowRate typ
    "Type of volume flow rate sensor"

  Buildings.Fluid.Sensors.VolumeFlowRate senVolFlo(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal) if have_sen
    "Volume flow rate sensor"
  Buildings.Templates.Components.Routing.PassThroughFluid pas(redeclare final
      package Medium = Medium) if not have_sen "Pass through"
equation

  connect(port_a, senVolFlo.port_a)
  connect(senVolFlo.port_b, port_b)
  connect(port_a, pas.port_a)
  connect(pas.port_b, port_b)
  connect(senVolFlo.V_flow, y)
end VolumeFlowRate;


Buffer tank

within Buildings.Templates.Components.Tanks;
model Buffer
  "Buffer tank"
  extends Buildings.Fluid.Interfaces.PartialTwoPortInterface;
  parameter Boolean have_tan=true
    "Set to true for tank, false for direct pass through"
  parameter Modelica.Units.SI.Volume V(
    start=0)
    "Volume"
  // Assumptions
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=Modelica.Fluid.Types.Dynamics.DynamicFreeInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"
  parameter Buildings.Templates.Components.Types.IntegrationPoint icon_pipe=
    Buildings.Templates.Components.Types.IntegrationPoint.None
    "Pipe symbol"
  Buildings.Fluid.MixingVolumes.MixingVolume vol(
    redeclare final package Medium=Medium,
    final V=V,
    final m_flow_nominal=m_flow_nominal,
    final m_flow_small=m_flow_small,
    final energyDynamics=energyDynamics,
    final massDynamics=energyDynamics,
    final mSenFac=1,
    final allowFlowReversal=allowFlowReversal,
    nPorts=2)
    if have_tan
    "Tank"
  Buildings.Templates.Components.Routing.PassThroughFluid pas(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal)
    if not have_tan
    "Direct pass through"
equation
  connect(port_a, vol.ports[1])
  connect(vol.ports[2], port_b)
  connect(port_a, pas.port_a)
  connect(pas.port_b, port_b)
end Buffer;


Tank models

within Buildings.Templates.Components;
package Tanks
  "Tank models"
  extends Modelica.Icons.VariantsPackage;
end Tanks;


Validation model for coil components

within Buildings.Templates.Components.Validation;
model Coils "Validation model for coil components"
  extends Modelica.Icons.Example;

  replaceable package MediumAir=Buildings.Media.Air
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Air medium";
  replaceable package MediumLiq=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "HW or CHW medium";

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

  Fluid.Sources.Boundary_pT bouAirEntCoo(
    redeclare final package Medium = MediumAir,
    X={coiCoo.dat.wAirEnt_nominal/(1 + coiCoo.dat.wAirEnt_nominal),1 - coiCoo.dat.wAirEnt_nominal
        /(1 + coiCoo.dat.wAirEnt_nominal)},
    p=bouAirLvg.p + coiCoo.dat.dpAir_nominal,
    T=coiCoo.dat.TAirEnt_nominal,
    nPorts=2) "Boundary conditions for entering air"
  Fluid.Sources.Boundary_pT bouChiWatEnt(
    redeclare final package Medium = MediumLiq,
    p=bouLiqLvg.p + coiCoo.dat.dpWat_nominal + coiCoo.dat.dpValve_nominal,
    T=coiCoo.dat.TWatEnt_nominal,
    nPorts=1) "Boundary conditions for entering CHW"
  Fluid.Sources.Boundary_pT bouLiqLvg(
    redeclare final package Medium =MediumLiq, nPorts=2)
    "Boundary conditions for leaving liquid"
  Fluid.Sources.Boundary_pT bouAirLvg(
    redeclare final package Medium =MediumAir, nPorts=6) "Boundary conditions for leaving air"

  Buildings.Templates.Components.Coils.WaterBasedCooling coiCoo(
    redeclare final package MediumAir=MediumAir,
    redeclare final package MediumChiWat=MediumLiq,
    dat(
      mAir_flow_nominal=1,
      dpAir_nominal=200,
      mWat_flow_nominal=1,
      dpWat_nominal=2E4,
      dpValve_nominal=coiCoo.dat.dpWat_nominal,
      cap_nominal=-5E4,
      TWatEnt_nominal=280.15,
      TAirEnt_nominal=308.15,
      wAirEnt_nominal=0.017),
    final energyDynamics=energyDynamics,
    val(y_start=0)) "Water-based cooling coil"
  Interfaces.Bus bus "Control bus"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp y(height=1,
    duration=10) "Coil/valve control signal"

  Buildings.Templates.Components.Coils.WaterBasedHeating coiHea(
    redeclare final package MediumAir = MediumAir,
    redeclare final package MediumHeaWat=MediumLiq,
    dat(
      mAir_flow_nominal=1,
      dpAir_nominal=200,
      mWat_flow_nominal=1,
      dpWat_nominal=2E4,
      dpValve_nominal=coiCoo.dat.dpWat_nominal,
      cap_nominal=5E4,
      TWatEnt_nominal=323.15,
      TAirEnt_nominal=263.15),
    final energyDynamics=energyDynamics,
    val(y_start=0)) "Water-based heating"
  Interfaces.Bus bus1 "Control bus"
  Fluid.Sources.Boundary_pT bouAirEntHea(
    redeclare final package Medium = MediumAir,
    p=bouAirLvg.p + coiHea.dat.dpAir_nominal,
    T=coiHea.dat.TAirEnt_nominal,
    nPorts=2) "Boundary conditions for entering air"
  Fluid.Sources.Boundary_pT bouHeaWatEnt(
    redeclare final package Medium = MediumLiq,
    p=bouLiqLvg.p + coiHea.dat.dpWat_nominal + coiHea.dat.dpValve_nominal,
    T=coiHea.dat.TWatEnt_nominal,
    nPorts=1) "Boundary conditions for entering HW"

  Buildings.Templates.Components.Coils.ElectricHeating coiEle(
    redeclare final package MediumAir = MediumAir,
    dat(
    mAir_flow_nominal=1,
    dpAir_nominal=200,
    cap_nominal=5E4),
    final energyDynamics=energyDynamics) "Electric heating"
  Interfaces.Bus bus2 "Control bus"
  Buildings.Templates.Components.Coils.EvaporatorVariableSpeed coiEva(
    redeclare final package MediumAir = MediumAir,
    dat(dpAir_nominal=200),
    final energyDynamics=energyDynamics) "Variable speed evaporator coil"
  BoundaryConditions.WeatherData.Bus weaBus "Weather data bus"
  Interfaces.Bus bus3 "Control bus"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TOut(
    k=coiEva.dat.datCoi.sta[1].nomVal.TConIn_nominal)
    "Outdoor temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant XOut(k=0.015)
    "Water mass fraction in outdoor air"
  Buildings.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBul(redeclare final
      package Medium = MediumAir) "Compute wet bulb temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant pOut(k=101325)
    "Outdoor pressure"
  Fluid.Sources.Boundary_pT bouAirEntCoo1(
    redeclare final package Medium = MediumAir,
    use_Xi_in=true,
    p=bouAirLvg.p + coiEva.dat.dpAir_nominal,
    T=coiEva.dat.datCoi.sta[1].nomVal.TEvaIn_nominal,
    nPorts=2) "Boundary conditions for entering air"
  Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi(use_p_in=false)
    "Compute wet bulb temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TAirEnt(k=coiEva.dat.datCoi.sta[
        1].nomVal.TEvaIn_nominal) "Entering air temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant phiAirEnt(k=coiEva.dat.datCoi.sta[
        1].nomVal.phiIn_nominal) "Enetring air relative humidity"
  Buildings.Templates.Components.Coils.EvaporatorMultiStage coiMul(
    redeclare final package MediumAir = MediumAir,
    dat(
      redeclare
      Buildings.Fluid.DXSystems.Cooling.AirSource.Data.DoubleSpeed.Lennox_SCA240H4B
      datCoi,
      dpAir_nominal=200),
    final energyDynamics=energyDynamics) "Multiple stage evaporator coil"
  Buildings.Controls.OBC.CDL.Integers.Sources.TimeTable y1(
    table=[0,0; 1,1; 2,2],
    timeScale=50,
    period=200) "Coil/valve control signal"
  Interfaces.Bus bus4 "Control bus"
  Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=coiCoo.dat.mAir_flow_nominal,
    final dp_nominal=coiCoo.dat.dpAir_nominal) "Flow resistance"
  Buildings.Templates.Components.Coils.None non(
    redeclare final package MediumAir =MediumAir) "No coilamper"
equation
  connect(bouAirEntCoo.ports[1], coiCoo.port_a)
  connect(coiCoo.port_b, bouAirLvg.ports[1])
  connect(bouChiWatEnt.ports[1], coiCoo.port_aSou)
  connect(bouLiqLvg.ports[1], coiCoo.port_bSou)
  connect(y.y, bus.y)
  connect(bus, coiCoo.bus)
  connect(coiHea.bus, bus1)
  connect(y.y, bus1.y)
  connect(bouAirEntHea.ports[1], coiHea.port_a)
  connect(coiHea.port_b, bouAirLvg.ports[2])
  connect(bouHeaWatEnt.ports[1], coiHea.port_aSou)
  connect(coiHea.port_bSou, bouLiqLvg.ports[2])
  connect(bouAirEntHea.ports[2], coiEle.port_a)
  connect(coiEle.bus, bus2)
  connect(coiEle.port_b, bouAirLvg.ports[3])
  connect(y.y, bus2.y)
  connect(coiEva.port_b, bouAirLvg.ports[4])
  connect(bus3, coiEva.bus)
  connect(weaBus, coiEva.busWea)
  connect(y.y, bus3.y)
  connect(TOut.y, weaBus.TDryBul)
  connect(TOut.y, wetBul.TDryBul)
  connect(pOut.y, wetBul.p)
  connect(wetBul.TWetBul, weaBus.TWetBul)
  connect(XOut.y, wetBul.Xi[1])
  connect(bouAirEntCoo1.ports[1], coiEva.port_a)
  connect(phiAirEnt.y, x_pTphi.phi)
  connect(TAirEnt.y, x_pTphi.T)
  connect(x_pTphi.X[1], bouAirEntCoo1.Xi_in[1])
  connect(coiMul.port_b, bouAirLvg.ports[5])
  connect(bouAirEntCoo1.ports[2], coiMul.port_a)
  connect(weaBus, coiMul.busWea)
  connect(y1.y[1], bus4.y)
        connect(coiMul.bus, bus4)
  connect(res.port_b, non.port_a)
  connect(non.port_b, bouAirLvg.ports[6])
  connect(bouAirEntCoo.ports[2], res.port_a)
end Coils;


Validation model for damper components

within Buildings.Templates.Components.Validation;
model Dampers "Validation model for damper components"
  extends Modelica.Icons.Example;

  replaceable package MediumAir=Buildings.Media.Air
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Air medium";

  Fluid.Sources.Boundary_pT bouAirEnt(
    redeclare final package Medium = MediumAir,
    p=bouAirLvg.p + mod.dat.dp_nominal,
    nPorts=4) "Boundary conditions for entering air"
  Fluid.Sources.Boundary_pT bouAirLvg(
    redeclare final package Medium =MediumAir, nPorts=4)
    "Boundary conditions for leaving air"

  Buildings.Templates.Components.Actuators.Damper mod(
    final typ=Buildings.Templates.Components.Types.Damper.Modulating,
    y_start=0,
    redeclare final package Medium = MediumAir,
    dat(m_flow_nominal=1,
        dp_nominal=50))
    "Modulating damper"
  Interfaces.Bus bus
    "Control bus"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp y(height=1,
    duration=10) "Damper control signal"

  Buildings.Templates.Components.Actuators.Damper pre(
    final typ=Buildings.Templates.Components.Types.Damper.PressureIndependent,
    y_start=0,
    redeclare final package  Medium = MediumAir,
    dat(m_flow_nominal=1, dp_nominal=50))
    "Pressure independent damper"
  Interfaces.Bus bus1
    "Control bus"
  Buildings.Templates.Components.Actuators.Damper two(
    final typ=Buildings.Templates.Components.Types.Damper.TwoPosition,
    y_start=0,
    redeclare final package Medium = MediumAir,
    dat(m_flow_nominal=1, dp_nominal=50)) "Two-position damper"
  Interfaces.Bus bus2
    "Control bus"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,0; 1,1],
    timeScale=10,
    period=200) "Damper control signal"
  Buildings.Templates.Components.Actuators.Damper non(
    final typ=Buildings.Templates.Components.Types.Damper.None,
    redeclare final package Medium = MediumAir)
    "No damper"
  Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=mod.m_flow_nominal,
    final dp_nominal=mod.dp_nominal)     "Flow resistance"
equation
  connect(bouAirEnt.ports[1], mod.port_a)
  connect(mod.port_b, bouAirLvg.ports[1])
  connect(y.y, bus.y)
  connect(bus, mod.bus)
  connect(bouAirEnt.ports[2], pre.port_a)
  connect(pre.port_b, bouAirLvg.ports[2])
  connect(bus1, pre.bus)
  connect(y.y, bus1.y)
  connect(bouAirEnt.ports[3], two.port_a)
  connect(two.port_b, bouAirLvg.ports[3])
  connect(bus2, two.bus)
  connect(y1.y[1], bus2.y1)
  connect(non.port_b, bouAirLvg.ports[4])
  connect(bouAirEnt.ports[4], res.port_a)
  connect(res.port_b, non.port_a)
end Dampers;


Validation model for fans components

within Buildings.Templates.Components.Validation;
model Fans "Validation model for fans components"
  extends Modelica.Icons.Example;

  replaceable package MediumAir=Buildings.Media.Air
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Air medium";

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

  Fluid.Sources.Boundary_pT bou(
    redeclare final package Medium = MediumAir,
    nPorts=8) "Boundary conditions"
  Buildings.Templates.Components.Fans.ArrayVariable arr(
    redeclare final package Medium=MediumAir,
    have_senFlo=true,
    final energyDynamics=energyDynamics,
    dat(m_flow_nominal=1, dp_nominal=1000),
    nFan=4)
    "Fan array"
  Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium=MediumAir,
    final m_flow_nominal=arr.dat.m_flow_nominal,
    final dp_nominal=arr.dat.dp_nominal)
    "Ducts and coils equivalent flow resistance"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp y(height=1, duration=10)
    "Fan control signal"
  Interfaces.Bus bus "Control bus"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,0; 1,1],
    timeScale=10,
    period=100) "Fan start/stop signal"
  Buildings.Templates.Components.Fans.SingleVariable var(
    redeclare final package Medium=MediumAir,
    have_senFlo=true,
    final energyDynamics=energyDynamics,
    dat(m_flow_nominal=1, dp_nominal=1000)) "Variable speed fan"
  Interfaces.Bus bus1 "Control bus"
  Buildings.Templates.Components.Fans.SingleConstant cst(
    redeclare final package Medium=MediumAir,
    have_senFlo=true,
    final energyDynamics=energyDynamics,
    dat(m_flow_nominal=1, dp_nominal=1000)) "Constant speed fan"
  Fluid.FixedResistances.PressureDrop res1(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=cst.dat.m_flow_nominal,
    final dp_nominal=cst.dat.dp_nominal)
    "Ducts and coils equivalent flow resistance"
  Fluid.FixedResistances.PressureDrop res2(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=var.dat.m_flow_nominal,
    final dp_nominal=var.dat.dp_nominal)
    "Ducts and coils equivalent flow resistance"
  Interfaces.Bus bus2
    "Control bus"
  Buildings.Templates.Components.Fans.None non(
    redeclare final package Medium = MediumAir)
    "No fan"
  Fluid.FixedResistances.PressureDrop res3(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=1,
    final dp_nominal=1000)
    "Ducts and coils equivalent flow resistance"
equation
  connect(bou.ports[1], arr.port_a)
  connect(res.port_b, bou.ports[2])
  connect(arr.port_b, res.port_a)
  connect(y.y, bus.y)
  connect(bus, arr.bus)
  connect(y1.y[1], bus1.y1)
  connect(cst.port_b, res1.port_a)
  connect(bou.ports[3], cst.port_a)
  connect(res1.port_b, bou.ports[4])
  connect(res2.port_b, bou.ports[5])
  connect(bou.ports[6], var.port_a)
  connect(var.port_b, res2.port_a)
  connect(bus2, var.bus)
  connect(bus1, cst.bus)
  connect(y.y, bus2.y)
  connect(bou.ports[7], non.port_a)
  connect(non.port_b, res3.port_a)
  connect(res3.port_b, bou.ports[8])
  connect(y1.y[1], bus2.y1)
  connect(y1.y[1], bus.y1)
end Fans;


Package with validation models

within Buildings.Templates.Components;
package Validation "Package with validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.Templates.Components.Validation;
model PumpMultipleRecord "Validation model for parameter propagation with the multiple-pump record"
  extends Modelica.Icons.Example;

  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Fluid medium";

  parameter Integer nPum(
    final min=0,
    start=1)=2
    "Number of pumps"

  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal[nPum](
    each start=1,
    each final min=0)={1, 2}
    "Mass flow rate - Each pump";
  final parameter Modelica.Units.SI.VolumeFlowRate V_flow_nominal[nPum]=
    m_flow_nominal ./ datDef.rho_default
    "Mass flow rate - Each pump";
  parameter Modelica.Units.SI.PressureDifference dp_nominal[nPum](
    each start=0,
    each final min=0)={1, 2} .* 1E4
    "Total pressure rise - Each pump";

  parameter Buildings.Templates.Components.Data.PumpMultiple datDef(
    final typ=Buildings.Templates.Components.Types.Pump.Multiple,
    final nPum=nPum,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dp_nominal)
    "Parameter record - Default bindings for subrecord per"

  parameter Buildings.Templates.Components.Data.PumpMultiple datRed(
    final typ=Buildings.Templates.Components.Types.Pump.Multiple,
    final nPum=nPum,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dp_nominal,
    redeclare Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos80slash1to12 per)
    "Parameter record - Redeclaration of subrecord per"

  parameter Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos80slash1to12 per1;
  parameter Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos50slash1to12 per2;

  parameter Buildings.Templates.Components.Data.PumpMultiple datAss(
    final typ=Buildings.Templates.Components.Types.Pump.Multiple,
    final nPum=nPum,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dp_nominal,
    per={per1, per2})
    "Parameter record - Assignment of subrecord per"

  parameter Buildings.Templates.Components.Data.PumpMultiple datPre(
    final typ=Buildings.Templates.Components.Types.Pump.Multiple,
    final nPum=nPum,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dp_nominal,
    per(pressure(
      V_flow={{0, 2, 4} * m_flow_nominal[i] / datPre.rho_default for i in 1:nPum},
      dp={{2, 1.5, 0.8} * dp_nominal[i] for i in 1:nPum})))
    "Parameter record - Assignment of pressure inside the subrecord per"
end PumpMultipleRecord;


Validation model for pump components

within Buildings.Templates.Components.Validation;
model Pumps "Validation model for pump components"
  extends Modelica.Icons.Example;

  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Liquid medium";
  parameter Data.PumpSingle datPum(
    final typ=pum1.typ,
    m_flow_nominal=1,
    dp_nominal=1E5) "Single pump parameters"
  parameter Data.PumpMultiple datPumMul(
    final typ=pumMul.typ,
    final nPum=pumMul.nPum,
    m_flow_nominal=fill(1, datPumMul.nPum),
    dp_nominal=fill(1E5, datPumMul.nPum))
    "Multiple pump parameters"
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=
    Modelica.Fluid.Types.Dynamics.FixedInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  Buildings.Templates.Components.Pumps.Multiple pumMul(
    final energyDynamics=energyDynamics,
    redeclare final package Medium=Medium,
    nPum=2,
    final dat=datPumMul)
    "Two variable speed pumps in parallel with common speed command signal"
  Buildings.Templates.Components.Pumps.Single pum1(
    final energyDynamics=energyDynamics,
    redeclare final package Medium = Medium,
    final dat=datPum) "Single variable speed pump"
  Buildings.Templates.Components.Pumps.Single pum2(
    final energyDynamics=energyDynamics,
    redeclare final package Medium=Medium,
    final dat=datPum) "Single variable speed pump"
  Fluid.FixedResistances.Junction junInl(
    redeclare final package Medium=Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal) * {1,-1,-1},
    final dp_nominal=fill(0,3))
    "Fluid junction"
  Fluid.FixedResistances.Junction junOut(
    redeclare final package Medium=Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal) * {1,-1,1},
    final dp_nominal=fill(0,3))
    "Fluid junction"
  Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium = Medium,
    final m_flow_nominal=pum1.m_flow_nominal + pum2.m_flow_nominal,
    final dp_nominal=pum1.dp_nominal - pum1.dpValChe_nominal)
    "Fixed flow resistance"

  Fluid.FixedResistances.Junction junInl1(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,-1},
    final dp_nominal=fill(0, 3))
    "Fluid junction"
  Fluid.FixedResistances.Junction junOut1(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,1},
    final dp_nominal=fill(0, 3))
    "Fluid junction"
  Fluid.FixedResistances.PressureDrop resMul(
    redeclare final package Medium = Medium,
    final m_flow_nominal=sum(pumMul.m_flow_nominal),
    final dp_nominal=max(pumMul.dp_nominal .- pumMul.dpValChe_nominal))
    "Fixed flow resistance"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[
      0, 0, 0;
      1, 1, 0;
      2, 1, 1;
      3, 0, 0],
    timeScale=100,
    period=300) "Pump enable signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant y(k=1) "Pump speed command"

  Fluid.Sources.Boundary_pT bou(
    redeclare final package Medium=Medium, nPorts=1)
    "Pressure boundary condition"
  Fluid.Sources.Boundary_pT bou1(redeclare final package Medium = Medium,
      nPorts=1)
    "Pressure boundary condition"
  Buildings.Templates.Components.Pumps.Multiple pumMulCst(
    have_var=false,
    final energyDynamics=energyDynamics,
    redeclare final package Medium = Medium,
    nPum=2,
    final dat=datPumMul) "Two constant speed pumps in parallel"
  Fluid.FixedResistances.Junction junInl2(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,-1},
    final dp_nominal=fill(0, 3))
    "Fluid junction"
  Fluid.FixedResistances.Junction junOut2(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,1},
    final dp_nominal=fill(0, 3))
    "Fluid junction"
  Fluid.FixedResistances.PressureDrop resMulCst(
    redeclare final package Medium = Medium,
    final m_flow_nominal=sum(pumMulCst.m_flow_nominal),
    final dp_nominal=max(pumMulCst.dp_nominal .- pumMulCst.dpValChe_nominal))
    "Fixed flow resistance"
  Fluid.Sources.Boundary_pT bou2(redeclare final package Medium = Medium,
      nPorts=1)
    "Pressure boundary condition"
  Buildings.Templates.Components.Pumps.Multiple pumMulDed(
    have_varCom=false,
    final energyDynamics=energyDynamics,
    redeclare final package Medium = Medium,
    nPum=2,
    final dat=datPumMul)
    "Two variable speed pumps in parallel with dedicated speed command signal"
  Fluid.FixedResistances.Junction junInl3(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,-1},
    final dp_nominal=fill(0, 3))
    "Fluid junction"
  Fluid.FixedResistances.Junction junOut3(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,1},
    final dp_nominal=fill(0, 3))
    "Fluid junction"
  Fluid.FixedResistances.PressureDrop resMulDed(
    redeclare final package Medium = Medium,
    final m_flow_nominal=sum(pumMulDed.m_flow_nominal),
    final dp_nominal=max(pumMulDed.dp_nominal .- pumMulDed.dpValChe_nominal))
    "Fixed flow resistance"
  Fluid.Sources.Boundary_pT bou3(redeclare final package Medium = Medium,
      nPorts=1)
    "Pressure boundary condition"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yDed[pumMulDed.nPum](each k
      =1) "Pump speed command"
protected
  Interfaces.Bus bus "Pump control bus"
  Interfaces.Bus bus1 "Pump control bus"
  Interfaces.Bus bus2 "Pump control bus"
  Interfaces.Bus bus3 "Pump control bus"
  Interfaces.Bus bus4 "Pump control bus"
equation
  connect(pum1.port_b, junOut.port_1)
  connect(junInl.port_2, pum1.port_a)
  connect(junInl.port_3, pum2.port_a)
  connect(pum2.port_b, junOut.port_3)
  connect(junOut.port_2, res.port_a)
  connect(res.port_b, junInl.port_1)
  connect(junOut1.port_2, resMul.port_a)
  connect(junInl1.port_2, pumMul.ports_a[1])
  connect(pumMul.ports_b[1], junOut1.port_1)
  connect(pumMul.ports_b[2], junOut1.port_3)
  connect(junInl1.port_3, pumMul.ports_a[2])
  connect(resMul.port_b, junInl1.port_1)
  connect(bus1, pum2.bus)
  connect(y1.y[2], bus1.y1)
  connect(y.y, bus1.y)
  connect(y1.y[1], bus.y1)
  connect(y.y, bus.y)
  connect(bus, pum1.bus)
  connect(bus2, pumMul.bus)
  connect(y1.y[1:2], bus2.y1)
  connect(y.y, bus2.y)
  connect(bou.ports[1], junInl.port_1)
  connect(bou1.ports[1], junInl1.port_1)
  connect(junOut2.port_2, resMulCst.port_a)
  connect(junInl2.port_2, pumMulCst.ports_a[1])
  connect(pumMulCst.ports_b[1], junOut2.port_1)
  connect(pumMulCst.ports_b[2], junOut2.port_3)
  connect(junInl2.port_3, pumMulCst.ports_a[2])
  connect(resMulCst.port_b, junInl2.port_1)
  connect(bus3, pumMulCst.bus)
  connect(bou2.ports[1],junInl2. port_1)
  connect(y1.y[1:2], bus3.y1)
  connect(junOut3.port_2, resMulDed.port_a)
  connect(junInl3.port_2, pumMulDed.ports_a[1])
  connect(pumMulDed.ports_b[1], junOut3.port_1)
  connect(pumMulDed.ports_b[2], junOut3.port_3)
  connect(junInl3.port_3, pumMulDed.ports_a[2])
  connect(resMulDed.port_b, junInl3.port_1)
  connect(bus4, pumMulDed.bus)
  connect(bou3.ports[1],junInl3. port_1)
  connect(y1.y, bus4.y1)
  connect(yDed.y, bus4.y)
end Pumps;


Validation model for routing components

within Buildings.Templates.Components.Validation;
model Routing "Validation model for routing components"
  extends Modelica.Icons.Example;

  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Medium";
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=
    Modelica.Fluid.Types.Dynamics.FixedInitial
    "Type of energy balance: dynamic (3 initialization options) or steady state"

  Fluid.Sources.Boundary_pT bouLiqEnt(
    redeclare final package Medium = Medium,
    p=bouLiqLvg.p + min(res.dp_nominal),
    nPorts=3) "Boundary conditions for entering liquid"
  Fluid.Sources.Boundary_pT bouLiqLvg(redeclare final package Medium = Medium,
      nPorts=3)
    "Boundary conditions for leaving liquid"
  Fluid.FixedResistances.PressureDrop res[3](
    redeclare final package Medium = Medium,
    each m_flow_nominal=1,
    each dp_nominal=1000) "Flow resistance"
  Buildings.Templates.Components.Routing.MultipleToMultiple mulMul(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    nPorts_a=3,
    m_flow_nominal=3) "Multiple to multiple without common leg"
  Fluid.Sources.Boundary_pT bouLiqEnt1(
    redeclare final package Medium = Medium,
    p=bouLiqLvg.p + min(res1.dp_nominal) + min(res2.dp_nominal),
    nPorts=3) "Boundary conditions for entering liquid"
  Fluid.Sources.Boundary_pT bouLiqLvg1(redeclare final package Medium = Medium,
      nPorts=3)
    "Boundary conditions for leaving liquid"
  Fluid.FixedResistances.PressureDrop res1
                                         [3](
    redeclare final package Medium = Medium,
    each m_flow_nominal=1,
    each dp_nominal=1000) "Flow resistance"
  Buildings.Templates.Components.Routing.MultipleToMultiple mulMulCom(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    nPorts_a=3,
    have_comLeg=true,
    m_flow_nominal=3) "Multiple to multiple with common leg"
  Fluid.FixedResistances.PressureDrop res2[3](
    redeclare final package Medium = Medium,
    each m_flow_nominal=1,
    each dp_nominal=1000) "Flow resistance"
  Fluid.Sources.Boundary_pT bouLiqEnt2(
    redeclare final package Medium = Medium,
    p=bouLiqLvg.p + min(res3.dp_nominal),
    nPorts=3) "Boundary conditions for entering liquid"
  Fluid.Sources.Boundary_pT bouLiqLvg2(redeclare final package Medium = Medium,
      nPorts=1)
    "Boundary conditions for leaving liquid"
  Fluid.FixedResistances.PressureDrop res3
                                         [3](
    redeclare final package Medium = Medium,
    each m_flow_nominal=1,
    each dp_nominal=1000) "Flow resistance"
  Buildings.Templates.Components.Routing.MultipleToSingle mulSin(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    nPorts=3,
    m_flow_nominal=3) "Multiple to single"
  Fluid.Sources.Boundary_pT bouLiqEnt3(
    redeclare final package Medium = Medium,
    p=bouLiqLvg.p + min(res5.dp_nominal),
    nPorts=1) "Boundary conditions for entering liquid"
  Fluid.Sources.Boundary_pT bouLiqLvg3(redeclare final package Medium = Medium,
      nPorts=3)
    "Boundary conditions for leaving liquid"
  Buildings.Templates.Components.Routing.SingleToMultiple sinMul(
    redeclare final package Medium = Medium,
    final energyDynamics=energyDynamics,
    nPorts=3,
    m_flow_nominal=3) "Single to multiple"
  Fluid.FixedResistances.PressureDrop res5[3](
    redeclare final package Medium = Medium,
    each m_flow_nominal=1,
    each dp_nominal=1000) "Flow resistance"
  Fluid.Sources.Boundary_pT bouLiqEnt4(
    redeclare final package Medium = Medium,
    p=bouLiqLvg.p + res4.dp_nominal,
    nPorts=1) "Boundary conditions for entering liquid"
  Fluid.Sources.Boundary_pT bouLiqLvg4(redeclare final package Medium = Medium,
      nPorts=1)
    "Boundary conditions for leaving liquid"
  Buildings.Templates.Components.Routing.PassThroughFluid pas(redeclare final
      package Medium = Medium) "Pass through"
  Fluid.FixedResistances.PressureDrop res4(
    redeclare final package Medium = Medium,
    m_flow_nominal=1,
    dp_nominal=1000) "Flow resistance"
equation
  connect(res.port_b, mulMul.ports_a)
  connect(mulMul.ports_b, bouLiqLvg.ports)
  connect(bouLiqEnt.ports, res.port_a)
  connect(res1.port_b, mulMulCom.ports_a)
  connect(bouLiqEnt1.ports, res1.port_a)
  connect(mulMulCom.ports_b, res2.port_a)
  connect(res2.port_b, bouLiqLvg1.ports)
  connect(res3.port_b, mulSin.ports_a)
  connect(bouLiqEnt2.ports,res3. port_a)
  connect(mulSin.port_b, bouLiqLvg2.ports[1])
  connect(bouLiqEnt3.ports[1], sinMul.port_a)
  connect(sinMul.ports_b, res5.port_a)
  connect(res5.port_b, bouLiqLvg3.ports)
  connect(pas.port_b, bouLiqLvg4.ports[1])
  connect(bouLiqEnt4.ports[1], res4.port_a)
  connect(res4.port_b, pas.port_a)
end Routing;


Validation model for sensor components

within Buildings.Templates.Components.Validation;
model Sensors "Validation model for sensor components"
  extends Modelica.Icons.Example;

  replaceable package MediumAir=Buildings.Media.Air
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Air medium";

  Fluid.Sources.Boundary_pT bouAirEnt(
    redeclare final package Medium = MediumAir,
    p=bouAirLvg.p + res.dp_nominal,
    nPorts=6) "Boundary conditions for entering air"
  Fluid.Sources.Boundary_pT bouAirLvg(redeclare final package Medium =
        MediumAir, nPorts=6)                             "Boundary conditions for leaving air"
  Buildings.Templates.Components.Sensors.HumidityRatio hum(redeclare final
      package Medium = MediumAir, m_flow_nominal=1) "Humidity ratio"
  Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=1,
    final dp_nominal=100) "Flow resistance"
  Fluid.FixedResistances.PressureDrop res1(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=1,
    final dp_nominal=100)                "Flow resistance"
  Buildings.Templates.Components.Sensors.SpecificEnthalpy ent(redeclare final
      package Medium = MediumAir, m_flow_nominal=1) "Specific enthalpy"
  Buildings.Templates.Components.Sensors.DifferentialPressure dp(redeclare
      final package Medium = MediumAir) "Differential pressure"
  Fluid.FixedResistances.PressureDrop res2(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=1,
    final dp_nominal=100)                "Flow resistance"
  Buildings.Templates.Components.Sensors.Temperature tem(redeclare final
      package Medium = MediumAir, m_flow_nominal=1) "Temperature"
  Buildings.Templates.Components.Sensors.VolumeFlowRate vol(redeclare final
      package Medium = MediumAir, m_flow_nominal=1,
      typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.AFMS) "Volume flow rate"
  Fluid.FixedResistances.PressureDrop res3(
    redeclare final package Medium = MediumAir,
    final m_flow_nominal=1,
    final dp_nominal=100)                "Flow resistance"
  Buildings.Templates.Components.Sensors.DifferentialPressure noDp(redeclare
      final package Medium = MediumAir, have_sen=false)
    "No differential pressure sensor"
equation
  connect(bouAirEnt.ports[1], res.port_a)
  connect(res.port_b, hum.port_a)
  connect(hum.port_b, bouAirLvg.ports[1])
  connect(res1.port_b, ent.port_a)
  connect(ent.port_b, bouAirLvg.ports[2])
  connect(bouAirEnt.ports[2], res1.port_a)
  connect(bouAirEnt.ports[3], dp.port_a)
  connect(dp.port_b, bouAirLvg.ports[3])
  connect(res2.port_b, tem.port_a)
  connect(res3.port_b, vol.port_a)
  connect(tem.port_b, bouAirLvg.ports[4])
  connect(vol.port_b, bouAirLvg.ports[5])
  connect(bouAirEnt.ports[4], res2.port_a)
  connect(bouAirEnt.ports[5], res3.port_a)

  connect(bouAirEnt.ports[6], noDp.port_a)
  connect(noDp.port_b, bouAirLvg.ports[6])
end Sensors;


Validation model for tank components

within Buildings.Templates.Components.Validation;
model Tanks
  "Validation model for tank components"
  extends Modelica.Icons.Example;
  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Liquid medium";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=1
    "Nominal mass flow rate";
  parameter Modelica.Units.SI.Volume V=60 * m_flow_nominal / Modelica.Media.Water.ConstantPropertyLiquidWater.d_const
    "Tank volume";
  Fluid.Sources.MassFlowSource_T sou(
    redeclare final package Medium=Medium,
    final m_flow=m_flow_nominal,
    T=303.15,
    nPorts=1)
    "Fluid source"
  Buildings.Templates.Components.Tanks.Buffer tan(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    show_T=true,
    final V=V,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Tank"
  Fluid.Sources.Boundary_pT sin(
    redeclare final package Medium=Medium,
    nPorts=2)
    "Fluid sink"
  Fluid.Sensors.VolumeFlowRate senVolFlo(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal)
    "Volume flow rate"
  Buildings.Utilities.Math.IntegratorWithReset intFlo
    "Volume flow rate integrated over time"
  Fluid.Sources.MassFlowSource_T sou1(
    redeclare final package Medium=Medium,
    final m_flow=m_flow_nominal,
    T=303.15,
    nPorts=1)
    "Fluid source"
  Buildings.Templates.Components.Tanks.Buffer noTan(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    show_T=true,
    have_tan=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "No tank – Direct fluid pass through"
equation
  connect(senVolFlo.port_b, tan.port_a)
  connect(senVolFlo.V_flow, intFlo.u)
  connect(tan.port_b, sin.ports[1])
  connect(sou.ports[1], senVolFlo.port_a)
  connect(sou1.ports[1], noTan.port_a)
  connect(noTan.port_b, sin.ports[2])
end Tanks;


Validation model for valve components

within Buildings.Templates.Components.Validation;
model Valves "Validation model for valve components"
  extends Modelica.Icons.Example;

  replaceable package MediumLiq=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Liquid medium";

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

  Fluid.Sources.Boundary_pT bouLiqEnt(
    redeclare final package Medium = MediumLiq,
    p=bouLiqLvg.p + modThr.dat.dpValve_nominal + modThr.dat.dpFixed_nominal,
    nPorts=7) "Boundary conditions for entering liquid"
  Fluid.Sources.Boundary_pT bouLiqLvg(
    redeclare final package Medium =MediumLiq, nPorts=5)
    "Boundary conditions for leaving liquid"

  Actuators.Valve modThr(
    redeclare final package Medium = MediumLiq,
    typ=Buildings.Templates.Components.Types.Valve.ThreeWayModulating,
    final energyDynamics=energyDynamics,
    dat(
      m_flow_nominal=1,
      dpValve_nominal=5000,
      dpFixed_nominal=5000))
    "Three-way modulating valve"
  Interfaces.Bus bus
    "Control bus"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp y(height=1, duration=10)
    "Damper control signal"

  Actuators.Valve twoThr(
    redeclare final package Medium = MediumLiq,
    typ=Buildings.Templates.Components.Types.Valve.ThreeWayTwoPosition,
    final energyDynamics=energyDynamics,
    dat(
      m_flow_nominal=1,
      dpValve_nominal=5000,
      dpFixed_nominal=5000)) "Three-way two position valve"
  Interfaces.Bus bus1
    "Control bus"

  Actuators.Valve modTwo(
    redeclare final package Medium = MediumLiq,
    typ=Buildings.Templates.Components.Types.Valve.TwoWayModulating,
    final energyDynamics=energyDynamics,
    dat(
      m_flow_nominal=1,
      dpValve_nominal=5000,
      dpFixed_nominal=5000)) "Two-way modulating valve"
  Interfaces.Bus bus2
    "Control bus"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,0; 1,1],
    timeScale=10,
    period=200) "Damper control signal"
  Actuators.Valve twoTwo(
    redeclare final package Medium = MediumLiq,
    typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition,
    final energyDynamics=energyDynamics,
    dat(
      m_flow_nominal=1,
      dpValve_nominal=5000,
      dpFixed_nominal=5000)) "Two-way two-position valve"
  Interfaces.Bus bus3
    "Control bus"
  Actuators.Valve non(
    redeclare final package Medium = MediumLiq,
    typ=Buildings.Templates.Components.Types.Valve.None)
    "No valve"
  Fluid.FixedResistances.PressureDrop res(
    redeclare final package Medium = MediumLiq,
    final m_flow_nominal=modTwo.m_flow_nominal,
    final dp_nominal=modTwo.dpValve_nominal + modTwo.dpFixed_nominal)
                                         "Flow resistance"
equation
  connect(bouLiqEnt.ports[1], modThr.port_a)
  connect(modThr.port_b,bouLiqLvg. ports[1])
  connect(y.y, bus.y)
  connect(bus, modThr.bus)
  connect(bouLiqEnt.ports[3], twoThr.port_a)
  connect(twoThr.port_b, bouLiqLvg.ports[2])
  connect(bus1, twoThr.bus)
  connect(bouLiqEnt.ports[2], modTwo.port_a)
  connect(modTwo.port_b, bouLiqLvg.ports[3])
  connect(bus2, modTwo.bus)
  connect(y.y, bus2.y)
  connect(y1.y[1], bus1.y1)
  connect(bus3, twoTwo.bus)
  connect(y1.y[1],bus3. y1)
  connect(bouLiqEnt.ports[4], twoTwo.port_a)
  connect(twoTwo.port_b, bouLiqLvg.ports[4])
  connect(bouLiqEnt.ports[5], modThr.portByp_a)
  connect(bouLiqEnt.ports[6], twoThr.portByp_a)
  connect(non.port_b, bouLiqLvg.ports[5])
  connect(bouLiqEnt.ports[7], res.port_a)
  connect(res.port_b, non.port_a)
end Valves;


Package with default sizing parameters

within Buildings.Templates.Data;
package Defaults
  "Package with default sizing parameters"
  extends Modelica.Icons.MaterialPropertiesPackage;
  constant Modelica.Units.SI.Temperature TChiWatSup=7 + 273.15
    "CHW supply temperature (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TChiWatSup_min=3.3 + 273.15
    "Minimum CHW supply temperature (typical)";
  constant Modelica.Units.SI.Temperature TChiWatSup_max=16 + 273.15
    "Maximum CHW supply temperature (typical)";
  constant Modelica.Units.SI.Temperature TChiWatRet=12 + 273.15
    "CHW return temperature (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TConWatSup=30 + 273.15
    "CW supply temperature (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TConWatRet=35 + 273.15
    "CW return temperature (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TOutChi=35 + 273.15
    "Outdoor air temperature for air-cooled chiller (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TConEnt_min=13 + 273.15
    "Minimum condenser entering fluid temperature (air or water)";
  constant Modelica.Units.SI.Temperature TConEnt_max=45 + 273.15
    "Maximum condenser entering fluid temperature (air or water)";
  constant Modelica.Units.SI.Temperature TConLvg_min=16 + 273.15
    "Minimum condenser leaving fluid temperature (air or water)";
  constant Modelica.Units.SI.Temperature TConLvg_max=50 + 273.15
    "Maximum condenser leaving fluid temperature (air or water)";
  constant Modelica.Units.SI.Temperature TChiWatEcoEnt=18 + 273.15
    "WSE entering CHW temperature";
  constant Modelica.Units.SI.Temperature TChiWatEcoLvg=11 + 273.15
    "WSE leaving CHW temperature";
  constant Modelica.Units.SI.Temperature TConWatEcoEnt=9 + 273.15
    "WSE entering CW temperature";
  constant Modelica.Units.SI.Temperature TConWatEcoLvg=16 + 273.15
    "WSE leaving CW temperature";
  constant Modelica.Units.SI.Temperature TOutChiWatLck=16 + 273.15
    "Outdoor air lockout temperature below which the CHW system is prevented from operating";
  constant Modelica.Units.SI.TemperatureDifference dTLifChi_min=5
    "Minimum chiller lift at minimum load";
  constant Modelica.Units.SI.Temperature TOutDryCoo=TOutChi
    "Dry cooler entering air drybulb temperature";
  constant Modelica.Units.SI.Temperature TWetBulTowEnt=24 + 273.15
    "CT entering air wetbulb temperature";
  constant Real PFanByFloConWatTow(
    unit="W/(kg/s)")=340
    "CT fan power divided by CW mass flow rate";
  constant Real mConWatFloByAirTow(
    unit="1")=1.45
    "CT CW mass flow rate divided by air mass flow rate";
  constant Modelica.Units.SI.PressureDifference dpConWatFriTow=1E4
    "CW flow-friction losses through open-circuit tower and piping only (without elevation head or valve)";
  constant Modelica.Units.SI.PressureDifference dpConWatStaTow=3E4
    "CW elevation head (for open cooling towers only)";
  constant Modelica.Units.SI.PressureDifference dpConWatTowClo=5E4
    "CW flow-friction losses through closed-circuit tower and piping only (without valve)";
  constant Real mAirFloByCapChi(
    unit="(kg/s)/W")=1E-4
    "Air mass flow rate divided by capacity for air-cooled chiller";
  constant Real COPChiAirCoo(
    unit="1")=2.99
    "Air-cooled chiller COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C OAT)";
  constant Real COPChiWatCoo(
    unit="1")=5.33
    "Water-cooled chiller COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C source LWT)";
  constant Modelica.Units.SI.PressureDifference dpValIso=1E3
    "Isolation or bypass valve pressure drop";
  constant Modelica.Units.SI.PressureDifference dpValBypMin=3E4
    "Minimum flow bypass valve pressure drop at design minimum flow for the largest chiller";
  constant Modelica.Units.SI.PressureDifference dpValChe=1E4
    "Check valve pressure drop";
  constant Modelica.Units.SI.PressureDifference dpChiWatChi=4E4
    "Chiller CHW pressure drop";
  constant Modelica.Units.SI.PressureDifference dpChiWatSet_min=5 * 6894
    "Minimum CHW differential pressure setpoint used in CHW plant reset logic";
  constant Modelica.Units.SI.PressureDifference dpChiWatRemSet_max=5E4
    "Maximum CHW differential pressure setpoint remote from the CHW plant";
  constant Modelica.Units.SI.PressureDifference dpChiWatLocSet_max=15E4
    "Maximum CHW differential pressure setpoint local to the CHW plant";
  constant Modelica.Units.SI.PressureDifference dpConWatChi=4E4
    "Chiller CW pressure drop (water-cooled)";
  constant Modelica.Units.SI.PressureDifference dpAirChi=500
    "Chiller air pressure drop across condenser (air-cooled)";
  constant Modelica.Units.SI.PressureDifference dpChiWatEco=3E4
    "WSE CHW pressure drop";
  constant Modelica.Units.SI.PressureDifference dpConWatEco=3E4
    "WSE CW pressure drop";
  constant Modelica.Units.SI.PressureDifference pChiWat_rel_nominal=1.0E5
    "CHW system gauge pressure at design conditions";
  constant Modelica.Units.SI.PressureDifference pHeaWat_rel_nominal=2.5E5
    "HHW system gauge pressure at design conditions";
  constant Modelica.Units.SI.PressureDifference dpHeaWatBoi=5E3
    "Boiler HW pressure drop";
  constant Modelica.Units.SI.Temperature THeaWatSup=80 + 273.15
    "HW supply temperature";
  constant Modelica.Units.SI.Temperature THeaWatConSup=65 + 273.15
    "HW supply temperature for condensing boilers";
  constant Modelica.Units.SI.Temperature THeaWatRet=55 + 273.15
    "HW return temperature";
  constant Modelica.Units.SI.Temperature TOutHeaWatLck=21 + 273.15
    "Outdoor air lockout temperature above which the HW system is prevented from operating";
  constant Modelica.Units.SI.PressureDifference dpHeaWatSet_min=5 * 6894
    "Minimum HW differential pressure setpoint used in HW plant reset logic";
  constant Modelica.Units.SI.PressureDifference dpHeaWatRemSet_max=5E4
    "Maximum HW differential pressure setpoint remote from the HW plant";
  constant Modelica.Units.SI.PressureDifference dpHeaWatLocSet_max=15E4
    "Maximum HW differential pressure setpoint local to the CHW plant";
  constant Modelica.Units.SI.PressureDifference dpHeaWatHp=3E4
    "Heat pump HW pressure drop across condenser barrel";
  constant Modelica.Units.SI.Temperature THeaWatSupHig=60 + 273.15
    "HW supply temperature - High temperature level (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature THeaWatRetHig=50 + 273.15
    "HW return temperature - High temperature level (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature THeaWatSupMed=50 + 273.15
    "HW supply temperature - Medium temperature level (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature THeaWatRetMed=42 + 273.15
    "HW return temperature - Medium temperature level (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature THeaWatSupLow=40 + 273.15
    "HW supply temperature - Low temperature level (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature THeaWatRetLow=35 + 273.15
    "HW return temperature - Low temperature level (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TOutHpCoo=TOutChi
    "Outdoor air temperature for air-to-water heat pump rating - Cooling (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TOutHpHeaHig=8 + 273.15
    "Outdoor air temperature for air-to-water heat pump rating - High heating (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TOutHpHeaLow=-8 + 273.15
    "Outdoor air temperature for air-to-water heat pump rating - Low heating (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TSouHpCoo=30 + 273.15
    "Source fluid entering temperature for water-to-water heat pump rating - Cooling (AHRI 551/591)";
  constant Modelica.Units.SI.Temperature TSouHpHea=12 + 273.15
    "Source fluid entering temperature for water-to-water heat pump rating - Heating (AHRI 551/591)";
  constant Real COPHpAwHea(
    unit="1")=1.75
    "Air-to-water heat pump heating COP (ASHRAE 90.1 2022 at 50 °C HWST, -8 °C OAT)";
  constant Real COPHpAwCoo(
    unit="1")=2.84
    "Air-to-water heat pump cooling COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C OAT)";
  constant Real COPHpWwHea(
    unit="1")=3.61
    "Water(brine)-to-water heat pump heating COP (ASHRAE 90.1 2022 at 50 °C HWST, 7 °C source LWT)";
  constant Real COPHpWwCoo(
    unit="1")=5.07
    "Water(brine)-to-water heat pump cooling COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C source LWT)";
end Defaults;


within Buildings.Templates;
package Data "Package with classes for storing system parameters"
  extends Modelica.Icons.MaterialPropertiesPackage;
end Data;


Central plants

within Buildings.Templates;
package Plants
  "Central plants"
  extends Modelica.Icons.Package;
end Plants;


Control blocks

within Buildings.Templates.Plants;
package Controls "Control blocks"
end Controls;


Package with type definitions

within Buildings.Templates.Plants.Controls;
package Types
  "Package with type definitions"
  extends Modelica.Icons.TypesPackage;
  type Application = enumeration(
    Cooling
      "Cooling system",
    Heating
      "Heating system")
    "Enumeration to specify the type of application";
  type Actuator = enumeration(
    Modulating
      "Modulating",
    TwoPosition
      "Two-position")
    "Enumeration to specify the type of actuator";
  type EquipmentConnection = enumeration(
    Parallel
      "Parallel piped",
    Series
      "Series piped")
    "Enumeration to specify the type of connection between equipment and primary loop";
end Types;


Plant enable. The plant is enabled when it has been disabled for at least the duration dtRun and:

within Buildings.Templates.Plants.Controls.Enabling;
block Enable
  "Plant enable"
  parameter Buildings.Templates.Plants.Controls.Types.Application typ
    "Type of application"
  parameter Boolean have_inpSch=false
    "Set to true to provide schedule via software input point"
  parameter Real sch[:, 2]=[
    0, 1;
    24 * 3600, 1]
    "Enable schedule"
  parameter Real TOutLck(
    final min=100,
    final unit="K")=if typ == Buildings.Templates.Plants.Controls.Types.Application.Heating
    then 18 + 273.15 else 15 + 273.15
    "Outdoor air lockout temperature";
  parameter Real dTOutLck(
    final min=0,
    final unit="K")=0.5
    "Hysteresis for outdoor air lockout temperature";
  parameter Integer nReqIgn(
    min=0)=0
    "Number of ignored requests";
  parameter Real dtRun(
    final min=0,
    final unit="s")=15 * 60
    "Minimum runtime of enable and disable states";
  parameter Real dtReq(
    final min=0,
    final unit="s")=3 * 60
    "Runtime with low number of request before disabling";
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Sch
    if have_inpSch
    "System enable via schedule"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqPla
    "Number of plant requests"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TOut(
    final unit="K",
    final quantity="ThermodynamicTemperature",
    displayUnit="degC")
    "Outdoor air temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1
    "Enable command"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable schEna(
    final table=sch,
    final period=max(sch[:, 1]))
    if not have_inpSch
    "Enable schedule"
  Buildings.Controls.OBC.CDL.Integers.GreaterThreshold greIgn(
    final t=nReqIgn)
    "Return true if number of requests > number of ignored requests"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greLck(
    final t=TOutLck)
    if typ == Buildings.Templates.Plants.Controls.Types.Application.Cooling
    "Return true if OAT > lockout temperature"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold lesLck(
    final t=TOutLck)
    if typ == Buildings.Templates.Plants.Controls.Types.Application.Heating
    "Return true if OAT < lockout temperature"
  Buildings.Controls.OBC.CDL.Logical.Pre preEna
    "Left limit (in discrete-time) of enable signal"
  Buildings.Controls.OBC.CDL.Logical.Timer timEna(
    final t=dtRun)
    "Return true if system has been enabled for specified duration"
  Buildings.Controls.OBC.CDL.Logical.Not dis
    "Return true if disabled"
  Buildings.Controls.OBC.CDL.Logical.Timer runDis(
    final t=dtRun)
    "Return true if system has been disabled for specified duration"
  Buildings.Controls.OBC.CDL.Logical.MultiAnd mulAnd(
    nin=4)
    "Combine enable conditions"
  Buildings.Controls.OBC.CDL.Logical.MultiOr mulOr(
    nin=3)
    "Combine disable conditions"
  Buildings.Controls.OBC.CDL.Logical.Not disSch
    "Return true if disabled by schedule"
  Buildings.Controls.OBC.CDL.Integers.LessEqualThreshold lowIgn(
    final t=nReqIgn)
    "Return true if number of requests ≤ number of ignored requests"
  Buildings.Controls.OBC.CDL.Logical.Timer timLowReq(
    final t=dtReq)
    "Return true if low number of requests for specified duration"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold lowLckHys(
    final t=TOutLck - dTOutLck)
    if typ == Buildings.Templates.Plants.Controls.Types.Application.Cooling
    "Return true if OAT < lockout temperature - hysteresis"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greLckHys(
    final t=TOutLck + dTOutLck)
    if typ == Buildings.Templates.Plants.Controls.Types.Application.Heating
    "Return true if OAT > lockout temperature + hysteresis"
  Buildings.Controls.OBC.CDL.Logical.And andRun
    "Disable conditions met AND enable minimum runtime exceeded"
  Buildings.Controls.OBC.CDL.Logical.Latch lat
    "Clear enable signal if disable conditions are met"
equation
  connect(nReqPla, greIgn.u)
  connect(TOut, greLck.u)
  connect(TOut, lesLck.u)
  connect(preEna.y, dis.u)
  connect(dis.y, runDis.u)
  connect(preEna.y, timEna.u)
  connect(runDis.passed, mulAnd.u[1])
  connect(schEna.y[1], mulAnd.u[2])
  connect(u1Sch, mulAnd.u[2])
  connect(greIgn.y, mulAnd.u[3])
  connect(schEna.y[1], disSch.u)
  connect(u1Sch, disSch.u)
  connect(disSch.y, mulOr.u[1])
  connect(nReqPla, lowIgn.u)
  connect(lowIgn.y, timLowReq.u)
  connect(timLowReq.passed, mulOr.u[2])
  connect(greLck.y, mulAnd.u[4])
  connect(lesLck.y, mulAnd.u[4])
  connect(TOut, lowLckHys.u)
  connect(lowLckHys.y, mulOr.u[3])
  connect(TOut, greLckHys.u)
  connect(greLckHys.y, mulOr.u[3])
  connect(timEna.passed, andRun.u1)
  connect(mulOr.y, andRun.u2)
  connect(y1, lat.y)
  connect(mulAnd.y, lat.u)
  connect(andRun.y, lat.clr)
  connect(y1, preEna.u)
end Enable;


Plant enable/disable

within Buildings.Templates.Plants.Controls;
package Enabling "Plant enable/disable"
end Enabling;


Validation model for system enabling logic. This model validates

Buildings.Templates.Plants.Controls.Enable.Enable
in a heating configuration, in a cooling configuration, and in
a cooling configuration with the enable schedule provided via
an input point.
All these configurations have the same setting for the minimum number
of ignored requests: nReqIgn=1.

within Buildings.Templates.Plants.Controls.Enabling.Validation;
model Enable
  "Validation model for system enabling logic"
  Buildings.Templates.Plants.Controls.Enabling.Enable enaHea(
    typ=Buildings.Templates.Plants.Controls.Types.Application.Heating,
    nReqIgn=1)
    "Enable heating system"
  Buildings.Controls.OBC.CDL.Integers.Sources.Pulse req(
    amplitude=1,
    period=60 * 20,
    offset=1)
    "System request"
  Buildings.Controls.OBC.CDL.Reals.Sources.Sin TOut(
    y(displayUnit="degC",
      unit="K"),
    final amplitude=12,
    final freqHz=1 /(10000),
    final offset=285.15)
    "Outdoor air temperature"
  Buildings.Templates.Plants.Controls.Enabling.Enable enaCoo(
    typ=Buildings.Templates.Plants.Controls.Types.Application.Cooling,
    nReqIgn=1)
    "Enable cooling system"
  Buildings.Templates.Plants.Controls.Enabling.Enable enaCooSch(
    typ=Buildings.Templates.Plants.Controls.Types.Application.Cooling,
    have_inpSch=true,
    nReqIgn=1)
    "Enable cooling system with input schedule"
  Buildings.Controls.OBC.CDL.Logical.Sources.Pulse sch(
    width=0.4,
    period=120 * 60,
    shift=25 * 60)
    "Enable schedule"
equation
  connect(req.y, enaHea.nReqPla)
  connect(TOut.y, enaHea.TOut)
  connect(req.y, enaCoo.nReqPla)
  connect(TOut.y, enaCoo.TOut)
  connect(TOut.y, enaCooSch.TOut)
  connect(req.y, enaCooSch.nReqPla)
  connect(sch.y, enaCooSch.u1Sch)
end Enable;


Collection of validation models

within Buildings.Templates.Plants.Controls.Enabling;
package Validation "Collection of validation models"
end Validation;