within Buildings.DHC.Plants.Combined.Subsystems;
model ChillerGroup
  "Model of multiple identical chillers in parallel"
  extends Buildings.Fluid.Interfaces.PartialFourPortInterface(
    final m1_flow_nominal = mConWat_flow_nominal,
    final m2_flow_nominal = mChiWat_flow_nominal);

  parameter Integer nUni(final min=1, start=1)
    "Number of units operating at design conditions"
  final parameter Modelica.Units.SI.Temperature TChiWatSup_nominal=
    dat.TEvaLvg_nominal
    "Design (minimum) CHW supply temperature";
  final parameter Modelica.Units.SI.Temperature TConWatLvg_nominal=
    dat.TConLvg_nominal
    "Design (maximum) CW leaving temperature";
  final parameter Modelica.Units.SI.HeatFlowRate QChiWatUni_flow_nominal=
    dat.QEva_flow_nominal
    "Design cooling heat flow rate (each unit, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QConWatUni_flow_nominal=
    -dat.QEva_flow_nominal * (1 + 1 / dat.COP_nominal * dat.etaMotor)
    "Design CW heat flow rate (each unit, >0)"
  final parameter Modelica.Units.SI.HeatFlowRate QChiWat_flow_nominal=
    nUni * QChiWatUni_flow_nominal
    "Design cooling heat flow rate (all units, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QConWat_flow_nominal=
    nUni * QConWatUni_flow_nominal
    "Design CW heat flow rate (all units, >0)"
  final parameter Modelica.Units.SI.MassFlowRate mChiWatUni_flow_nominal(
    final min=0)=dat.mEva_flow_nominal
    "Design chiller CHW mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mConWatUni_flow_nominal(
    final min=0)=dat.mCon_flow_nominal
    "Design chiller CW mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal(
    final min=0)=nUni * mChiWatUni_flow_nominal
    "Design CHW mass flow rate (all units)"
  final parameter Modelica.Units.SI.MassFlowRate mConWat_flow_nominal(
    final min=0)=nUni * mConWatUni_flow_nominal
    "Design CW mass flow rate (all units)"
  parameter Modelica.Units.SI.PressureDifference dpEva_nominal(displayUnit="Pa")
    "Design chiller evaporator pressure drop (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpCon_nominal(displayUnit="Pa")
    "Chiller condenser design pressure drop (each unit)"

  replaceable parameter Fluid.Chillers.Data.ElectricReformulatedEIR.Generic dat
    "Chiller parameters (each unit)"

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

  parameter Boolean use_strokeTime=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Set to true to continuously open and close valve"
  parameter Modelica.Units.SI.Time strokeTime=120
    "Time needed to open or close valve"
  parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput
    "Type of initialization (no init/steady state/initial state/initial output)"
  parameter Real y_start=1 "Initial position of actuator"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1[nUni]
    "Chiller On/Off command"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSet(
    final unit="K", displayUnit="degC")
    "Supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput P(
    final unit="W")
    "Power drawn"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValCon[nUni](
    each final unit="1", each final min=0, each final max=1)
    "Chiller condenser isolation valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValEva[nUni](
    each final unit="1", each final min=0, each final max=1)
    "Chiller evaporator isolation valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TConLvg[nUni](each final
      unit="K", each displayUnit="degC")
    "Chiller condenser leaving temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mCon_flow[nUni](
    each final unit="kg/s")
    "Chiller condenser barrel mass flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TEvaLvg[nUni](each final
      unit="K", each displayUnit="degC")
    "Chiller evaporator leaving temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mEva_flow[nUni](
    each final unit="kg/s")
    "Chiller evaporator barrel mass flow rate"

  Fluid.Chillers.ElectricReformulatedEIR chi(
    PLR1(start=0),
    final per=dat,
    redeclare final package Medium1=Medium1,
    redeclare final package Medium2=Medium2,
    final have_switchover=false,
    final dp1_nominal=0,
    final dp2_nominal=0,
    final allowFlowReversal1=allowFlowReversal1,
    final allowFlowReversal2=allowFlowReversal2,
    final energyDynamics=energyDynamics,
    final show_T=show_T) "Chiller"
  Fluid.BaseClasses.MassFlowRateMultiplier mulConInl(
    redeclare final package Medium = Medium1,
    final allowFlowReversal=allowFlowReversal1,
    final use_input=true)
    "Flow rate multiplier"
  Fluid.BaseClasses.MassFlowRateMultiplier mulConOut(
    redeclare final package Medium = Medium1,
    final allowFlowReversal=allowFlowReversal1,
    final use_input=true)
    "Flow rate multiplier"
  Fluid.BaseClasses.MassFlowRateMultiplier mulEvaInl(
    redeclare final package Medium = Medium2,
    final allowFlowReversal=allowFlowReversal2,
    final use_input=true)
    "Flow rate multiplier"
  Fluid.BaseClasses.MassFlowRateMultiplier mulEvaOut(
    redeclare final package Medium = Medium2,
    final allowFlowReversal=allowFlowReversal2,
    final use_input=true)
    "Flow rate multiplier"
  Buildings.Templates.Components.Controls.MultipleCommands com(
    final nUni=nUni)
    "Convert command signals"
  BaseClasses.MultipleValves valEva(
    redeclare final package Medium = Medium2,
    redeclare final Buildings.Fluid.Actuators.Valves.TwoWayLinear val,
    linearized=true,
    final nUni=nUni,
    final mUni_flow_nominal=mChiWatUni_flow_nominal,
    final dpFixed_nominal=dpEva_nominal,
    dpValve_nominal=1E3,
    final allowFlowReversal=allowFlowReversal2,
    final energyDynamics=energyDynamics,
    final use_strokeTime=use_strokeTime,
    final strokeTime=strokeTime,
    final init=init,
    final y_start=y_start,
    final show_T=show_T) "Chiller evaporator isolation valves"
  BaseClasses.MultipleValves valCon(
    redeclare final package Medium = Medium1,
    redeclare final Buildings.Fluid.Actuators.Valves.TwoWayLinear val,
    linearized=true,
    final nUni=nUni,
    final mUni_flow_nominal=mConWatUni_flow_nominal,
    final dpFixed_nominal=dpCon_nominal,
    dpValve_nominal=1E3,
    final allowFlowReversal=allowFlowReversal1,
    final energyDynamics=energyDynamics,
    final use_strokeTime=use_strokeTime,
    final strokeTime=strokeTime,
    final init=init,
    final y_start=y_start,
    final show_T=show_T) "Chiller condenser isolation valves"
  Buildings.Controls.OBC.CDL.Reals.Multiply mulP "Scale power"
  Fluid.Sensors.TemperatureTwoPort temConLvg(
    redeclare final package Medium = Medium1,
    final m_flow_nominal=mConWatUni_flow_nominal,
    final allowFlowReversal=allowFlowReversal1)
    "Chiller condenser leaving temperature"
  Fluid.Sensors.TemperatureTwoPort temEvaLvg(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=mChiWatUni_flow_nominal,
    final allowFlowReversal=allowFlowReversal2)
    "Chiller evaporator leaving temperature"
  Fluid.Sensors.MassFlowRate floCon(
    redeclare final package Medium =Medium1,
    final allowFlowReversal=allowFlowReversal1)
    "Chiller condenser barrel mass flow rate"
  Fluid.Sensors.MassFlowRate floEva(
    redeclare final package Medium =Medium2,
    final allowFlowReversal=allowFlowReversal2)
    "Chiller evaporator barrel mass flow rate"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep(nout=nUni)
    "Replicate"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep1(nout=nUni)
    "Replicate"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep2(nout=nUni)
    "Replicate"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep3(nout=nUni)
    "Replicate"
equation
  connect(mulEvaInl.port_b,chi. port_a2)
  connect(TSet,chi. TSet)
  connect(mulConOut.uInv, mulConInl.u)
  connect(mulEvaOut.uInv, mulEvaInl.u)
  connect(port_a1, mulConInl.port_a)
  connect(port_a2, mulEvaInl.port_a)
  connect(port_b2, valEva.port_b)
  connect(mulEvaOut.port_b, valEva.port_a)
  connect(y1, com.y1)
  connect(chi.P, mulP.u1)
  connect(com.nUniOn, mulP.u2)
  connect(yValCon, valCon.y)
  connect(yValEva, valEva.y)

  connect(mulConInl.port_b,chi. port_a1)
  connect(mulP.y, P)
  connect(com.nUniOnBou, mulConOut.u)
  connect(mulConInl.uInv, mulEvaOut.u)
  connect(com.y1One,chi. on)
  connect(valCon.port_b, port_b1)
  connect(mulConOut.port_b, valCon.port_a)
  connect(temEvaLvg.port_a, chi.port_b2)
  connect(chi.port_b1, temConLvg.port_a)
  connect(temConLvg.port_b, floCon.port_a)
  connect(floCon.port_b, mulConOut.port_a)
  connect(temEvaLvg.port_b, floEva.port_a)
  connect(floEva.port_b, mulEvaOut.port_a)
  connect(rep.y, TConLvg)
  connect(rep1.y, mCon_flow)
  connect(floCon.m_flow, rep1.u)
  connect(temConLvg.T, rep.u)
  connect(rep3.y, TEvaLvg)
  connect(rep2.y, mEva_flow)
  connect(floEva.m_flow, rep2.u)
  connect(temEvaLvg.T, rep3.u)
end ChillerGroup;


within Buildings.DHC.Plants.Combined.Subsystems;
model ChillerHeatRecoveryGroup
  "Model of multiple identical heat recovery chillers in parallel"
  extends Buildings.Fluid.Interfaces.PartialEightPortInterface(
    redeclare final package Medium1=Medium,
    redeclare final package Medium2=Medium,
    redeclare final package Medium3=Medium,
    redeclare final package Medium4=Medium,
    final m1_flow_nominal = mConWat_flow_nominal,
    final m2_flow_nominal = mChiWat_flow_nominal,
    final m3_flow_nominal = mConWat_flow_nominal,
    final m4_flow_nominal = mChiWat_flow_nominal,
    final allowFlowReversal1=allowFlowReversal,
    final allowFlowReversal2=allowFlowReversal,
    final allowFlowReversal3=allowFlowReversal,
    final allowFlowReversal4=allowFlowReversal);

  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Medium model for all four fluid circuits"

  parameter Integer nUni(final min=1, start=1)
    "Number of units operating at design conditions"
  parameter Modelica.Units.SI.Temperature TCasHeaEnt_nominal=298.15
    "Design evaporator entering temperature in cascading heating mode";
  parameter Modelica.Units.SI.Temperature TCasCooEnt_nominal=288.15
    "Design condenser entering temperature in cascading cooling mode";
  final parameter Modelica.Units.SI.Temperature TChiWatSup_nominal=
    dat.TEvaLvg_nominal
    "Design (minimum) CHW supply temperature";
  final parameter Modelica.Units.SI.Temperature THeaWatSup_nominal=
    dat.TConLvg_nominal
    "Design (maximum) HW supply temperature";
  final parameter Modelica.Units.SI.HeatFlowRate QChiWatUni_flow_nominal=
    dat.QEva_flow_nominal
    "Design cooling heat flow rate (each unit, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QHeaWatUni_flow_nominal=
    -dat.QEva_flow_nominal * (1 + 1 / dat.COP_nominal * dat.etaMotor)
    "Design heating heat flow rate in direct heat recovery mode (each unit, >0)"
  final parameter Modelica.Units.SI.Efficiency COPCasHea_nominal(fixed=false)
    "Coefficient of performance in cascading heating mode";
  final parameter Modelica.Units.SI.Efficiency COPCasCoo_nominal(fixed=false)
    "Coefficient of performance in cascading cooling mode";
  final parameter Modelica.Units.SI.Temperature TCasHeaLvg_nominal(fixed=false)
    "Design value of evaporator leaving temperature in cascading heating mode";
  final parameter Modelica.Units.SI.Temperature TCasCooLvg_nominal(fixed=false)
    "Design value of condenser leaving temperature in cascading cooling mode";
  final parameter Modelica.Units.SI.HeatFlowRate QEvaCasHeaUni_flow_nominal(
    fixed=false,
    start=QChiWatUni_flow_nominal * (1 + 2E-2 * (TCasHeaEnt_nominal -
      (dat.TEvaLvg_nominal - QChiWatUni_flow_nominal / mChiWatUni_flow_nominal / cpCas))))
    "Design evaporator heat flow rate in cascading heating mode (each unit, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QChiWatCasCooUni_flow_nominal(
    fixed=false,
    start=QChiWatUni_flow_nominal * (1 - 2E-2 * (TCasCooEnt_nominal -
      (dat.TConLvg_nominal - QHeaWatUni_flow_nominal / mConWatUni_flow_nominal / cpCas))))
    "Design cooling heat flow rate in cascading cooling mode (each unit, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QHeaWatCasHeaUni_flow_nominal=
    -QEvaCasHeaUni_flow_nominal * (1 + 1 / COPCasHea_nominal * dat.etaMotor)
    "Design heating heat flow rate in cascading heating mode (each unit, >0)"
  final parameter Modelica.Units.SI.HeatFlowRate QConCasCooUni_flow_nominal=
    -QChiWatCasCooUni_flow_nominal * (1 + 1 / COPCasCoo_nominal * dat.etaMotor)
    "Design condenser heat flow rate in cascading cooling mode (each unit, >0)"
  final parameter Modelica.Units.SI.HeatFlowRate QChiWat_flow_nominal=
    nUni * QChiWatUni_flow_nominal
    "Design cooling heat flow rate (all units, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QHeaWat_flow_nominal=
    nUni * QHeaWatUni_flow_nominal
    "Design heating heat flow rate (all units, >0)"
  final parameter Modelica.Units.SI.HeatFlowRate QEvaCasHea_flow_nominal=
    nUni * QEvaCasHeaUni_flow_nominal
    "Design evaporator heat flow rate in cascading heating mode (all units, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QChiWatCasCoo_flow_nominal=
    nUni * QChiWatCasCooUni_flow_nominal
    "Design cooling heat flow rate in cascading cooling mode (all units, <0)"
  final parameter Modelica.Units.SI.HeatFlowRate QHeaWatCasHea_flow_nominal=
    nUni * QHeaWatCasHeaUni_flow_nominal
    "Design heating heat flow rate in cascading heating mode (all units, >0)"
  final parameter Modelica.Units.SI.HeatFlowRate QConCasCoo_flow_nominal=
    nUni * QConCasCooUni_flow_nominal
    "Design condenser heat flow rate in cascading cooling mode (all units, >0)"
  final parameter Modelica.Units.SI.MassFlowRate mChiWatUni_flow_nominal(
    final min=0)=dat.mEva_flow_nominal
    "Design CHW mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mConWatUni_flow_nominal(
    final min=0)=dat.mCon_flow_nominal
    "Design CW mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal(
    final min=0)=nUni * mChiWatUni_flow_nominal
    "Design CHW mass flow rate (all units)"
  final parameter Modelica.Units.SI.MassFlowRate mConWat_flow_nominal(
    final min=0)=nUni * mConWatUni_flow_nominal
    "Design CW mass flow rate (all units)"
  parameter Modelica.Units.SI.PressureDifference dpEva_nominal(displayUnit="Pa")
    "Design evaporator pressure drop (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpCon_nominal(displayUnit="Pa")
    "Design condenser pressure drop (each unit)"

  replaceable parameter Fluid.Chillers.Data.ElectricReformulatedEIR.Generic dat
    "Chiller parameters (each unit)"

  // Assumptions
  parameter Boolean allowFlowReversal = true
    "= false to simplify equations, assuming, but not enforcing, no flow reversal"

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

  parameter Boolean use_strokeTime=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Set to true to continuously open and close valve"
  parameter Modelica.Units.SI.Time strokeTime=120
    "Time needed to open or close valve"
  parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput
    "Type of initialization (no init/steady state/initial state/initial output)"
  parameter Real y_start=1 "Initial position of actuator"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1[nUni]
    "Chiller On/Off command"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1Coo[nUni]
    "Cooling switchover command: true for cooling, false for heating"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSet[nUni](
    each final unit="K", each displayUnit="degC")
    "Supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValConSwi[nUni](
    each final unit="1",
    each final min=0,
    each final max=1) "Chiller condenser switchover valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValEvaSwi[nUni](
    each final unit="1",
    each final min=0,
    each final max=1) "Chiller evaporator switchover valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput P(
    final unit="W") "Power drawn"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValCon[nUni](
    each final unit="1", each final min=0, each final max=1)
    "Chiller condenser isolation valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValEva[nUni](
    each final unit="1", each final min=0, each final max=1)
    "Chiller evaporator isolation valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mEva_flow[nUni](each final
      unit="kg/s") "Chiller evaporator barrel mass flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TEvaLvg[nUni](
    each final unit="K", each displayUnit="degC")
    "Chiller evaporator leaving temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mCon_flow[nUni](
    each final unit="kg/s")
    "Chiller condenser barrel mass flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TConLvg[nUni](
    each final unit="K", each displayUnit="degC")
    "Chiller condenser leaving temperature"

  Fluid.Chillers.ElectricReformulatedEIR chi[nUni](
    PLR1(each start=0),
    each final per=dat,
    redeclare each final package Medium1 = Medium,
    redeclare final package Medium2 = Medium,
    each final have_switchover=true,
    each final dp1_nominal=0,
    each final dp2_nominal=0,
    each final allowFlowReversal1=allowFlowReversal,
    each final allowFlowReversal2=allowFlowReversal,
    each final energyDynamics=energyDynamics,
    each final show_T=show_T) "Chiller"
  Fluid.Actuators.Valves.TwoWayLinear valCon[nUni](
    redeclare each final package Medium = Medium,
    each linearized=true,
    each final CvData=Buildings.Fluid.Types.CvTypes.OpPoint,
    each final m_flow_nominal=mConWatUni_flow_nominal,
    each dpValve_nominal=1E3,
    each final dpFixed_nominal=dpCon_nominal,
    each final allowFlowReversal=allowFlowReversal,
    each final use_strokeTime=use_strokeTime,
    each final strokeTime=strokeTime,
    each final init=init,
    each final y_start=y_start) "Condenser isolation valve"
  Fluid.Actuators.Valves.TwoWayLinear valEva[nUni](
    redeclare each final package Medium = Medium,
    each linearized=true,
    each final CvData=Buildings.Fluid.Types.CvTypes.OpPoint,
    each final m_flow_nominal=mChiWatUni_flow_nominal,
    each dpValve_nominal=1E3,
    each final dpFixed_nominal=dpEva_nominal,
    each final allowFlowReversal=allowFlowReversal,
    each final use_strokeTime=use_strokeTime,
    each final strokeTime=strokeTime,
    each final init=init,
    each final y_start=y_start) "Evaporator isolation valve"
  Fluid.FixedResistances.Junction junConWatEvaOut[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mChiWatUni_flow_nominal*{1,-1,1},
    each final dp_nominal=fill(1E3, 3),
    each final energyDynamics=energyDynamics,
    each final portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering) "Fluid junction"
  Fluid.FixedResistances.Junction junConWatEvaInl[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mChiWatUni_flow_nominal*{1,-1,-1},
    each final dp_nominal=fill(1E3, 3),
    each final energyDynamics=energyDynamics,
    each final portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving) "Fluid junction"
  Fluid.Sensors.TemperatureTwoPort temEvaLvg[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mChiWatUni_flow_nominal,
    each final allowFlowReversal=allowFlowReversal)
    "Chiller evaporator leaving temperature"
  Fluid.FixedResistances.Junction junHeaWatConInl[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mConWatUni_flow_nominal*{1,-1,-1},
    each final dp_nominal=fill(1E3, 3),
    each final energyDynamics=energyDynamics,
    each final portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving) "Fluid junction"
  Fluid.FixedResistances.Junction junHeaWatConOut[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mConWatUni_flow_nominal*{1,-1,1},
    each final dp_nominal=fill(1E3, 3),
    each final energyDynamics=energyDynamics,
    each final portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional,
    each final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering) "Fluid junction"
  Fluid.Sensors.TemperatureTwoPort temConEnt[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mConWatUni_flow_nominal,
    each final allowFlowReversal=allowFlowReversal)
    "Chiller condenser entering temperature"
  Fluid.Sensors.TemperatureTwoPort temConLvg[nUni](
    redeclare each final package Medium = Medium,
    each final m_flow_nominal=mConWatUni_flow_nominal,
    each final allowFlowReversal=allowFlowReversal)
    "Chiller condenser leaving temperature"
  Buildings.Controls.OBC.CDL.Reals.MultiSum mulSum(nin=nUni)
    "Sum up power of all units"
  Fluid.Sensors.MassFlowRate floEva[nUni](
    redeclare each final package Medium =Medium,
    each final allowFlowReversal=allowFlowReversal)
    "Chiller evaporator barrel mass flow rate"
  Fluid.Sensors.MassFlowRate floCon[nUni](
    redeclare each final package Medium =Medium,
    each final allowFlowReversal=allowFlowReversal)
    "Chiller condenser barrel mass flow rate"
  Fluid.Actuators.Valves.TwoWayLinear valConSwi[nUni](
    redeclare each final package Medium = Medium,
    each linearized=true,
    each final CvData=Buildings.Fluid.Types.CvTypes.OpPoint,
    each final m_flow_nominal=mConWatUni_flow_nominal,
    each dpValve_nominal=1E3,
    each final dpFixed_nominal=0,
    each final allowFlowReversal=true,
    each final use_strokeTime=use_strokeTime,
    each final strokeTime=strokeTime,
    each final init=init,
    each final y_start=y_start) "Condenser switchover valve"
  Fluid.Actuators.Valves.TwoWayLinear valEvaSwi[nUni](
    redeclare each final package Medium = Medium,
    each linearized=true,
    each final CvData=Buildings.Fluid.Types.CvTypes.OpPoint,
    each final m_flow_nominal=mChiWatUni_flow_nominal,
    each dpValve_nominal=1E3,
    each final dpFixed_nominal=0,
    each final allowFlowReversal=true,
    each final use_strokeTime=use_strokeTime,
    each final strokeTime=strokeTime,
    each final init=init,
    each final y_start=y_start) "Evaporator switchover valve"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TConEnt[nUni](each final
      unit="K", each displayUnit="degC")
    "Chiller condenser entering temperature"
protected
  parameter Medium.ThermodynamicState staCas=Medium.setState_pTX(
    T=(TCasHeaEnt_nominal + TCasCooEnt_nominal) / 2,
    p=Medium.p_default,
    X=Medium.X_default)
    "State of source medium in cascading mode (at mean source temperature)";
  parameter Modelica.Units.SI.SpecificHeatCapacity cpCas=
    Medium.specificHeatCapacityCp(state=staCas)
    "Heat capacity of source medium in cascading mode";
initial equation
  TCasHeaLvg_nominal = TCasHeaEnt_nominal +
    QEvaCasHeaUni_flow_nominal / cpCas / mConWatUni_flow_nominal;
  TCasCooLvg_nominal = TCasCooEnt_nominal +
    QConCasCooUni_flow_nominal / cpCas / mConWatUni_flow_nominal;
  QEvaCasHeaUni_flow_nominal = dat.QEva_flow_nominal *
    Buildings.Utilities.Math.Functions.biquadratic(
      a=dat.capFunT,
      x1=Modelica.Units.Conversions.to_degC(TCasHeaLvg_nominal),
      x2=Modelica.Units.Conversions.to_degC(THeaWatSup_nominal));
  QChiWatCasCooUni_flow_nominal = dat.QEva_flow_nominal *
    Buildings.Utilities.Math.Functions.biquadratic(
      a=dat.capFunT,
      x1=Modelica.Units.Conversions.to_degC(TChiWatSup_nominal),
      x2=Modelica.Units.Conversions.to_degC(TCasCooLvg_nominal));
  COPCasHea_nominal = dat.COP_nominal /
    Buildings.Utilities.Math.Functions.biquadratic(
      a=dat.EIRFunT,
      x1=Modelica.Units.Conversions.to_degC(TCasCooLvg_nominal),
      x2=Modelica.Units.Conversions.to_degC(THeaWatSup_nominal));
  COPCasCoo_nominal = dat.COP_nominal /
    Buildings.Utilities.Math.Functions.biquadratic(
      a=dat.EIRFunT,
      x1=Modelica.Units.Conversions.to_degC(TChiWatSup_nominal),
      x2=Modelica.Units.Conversions.to_degC(TCasCooLvg_nominal));
equation
  if nUni > 1 then
    connect(junHeaWatConOut[1:nUni - 1].port_1, junHeaWatConOut[2:nUni].port_2)
    connect(valEvaSwi[1:nUni - 1].port_a, junConWatEvaInl[2:nUni].port_2)
    connect(valConSwi[1:nUni - 1].port_a, junHeaWatConInl[2:nUni].port_2)
    connect(junConWatEvaOut[1:nUni - 1].port_1, junConWatEvaOut[2:nUni].port_2)
  end if;
  connect(port_a4, valEvaSwi[nUni].port_a)
  connect(yValConSwi, valConSwi.y)

  connect(y1, chi.on)
  connect(TSet, chi.TSet)
  connect(y1Coo, chi.coo)
  connect(yValCon, valCon.y)
  connect(chi.port_b2, temEvaLvg.port_a)
  connect(yValEva, valEva.y)
  connect(temConEnt.port_b, chi.port_a1)
  connect(chi.port_b1, temConLvg.port_a)
  connect(valCon.port_b, junHeaWatConOut.port_3)
  connect(valEva.port_b,junConWatEvaOut. port_3)
  connect(chi.P, mulSum.u)
  connect(temEvaLvg.port_b, floEva.port_a)
  connect(floEva.port_b, valEva.port_a)
  connect(mulSum.y, P)
  connect(floEva.m_flow, mEva_flow)
  connect(temEvaLvg.T, TEvaLvg)
  connect(temConLvg.port_b, floCon.port_a)
  connect(floCon.port_b, valCon.port_a)
  connect(temConLvg.T, TConLvg)
  connect(floCon.m_flow, mCon_flow)
  connect(junConWatEvaInl.port_3, chi.port_a2)
  connect(yValEvaSwi, valEvaSwi.y)
  connect(junHeaWatConInl.port_3, temConEnt.port_a)

  connect(port_a1, junHeaWatConInl[1].port_2)
  connect(valConSwi.port_b, junHeaWatConInl.port_1)
  connect(junHeaWatConOut[1].port_2, port_b1)
  connect(valEvaSwi.port_b, junConWatEvaInl.port_1)
  connect(port_a2, junConWatEvaInl[1].port_2)
  connect(junHeaWatConOut[nUni].port_1, port_b3)
  connect(junConWatEvaOut[1].port_2, port_b2)
  connect(junConWatEvaOut[nUni].port_1, port_b4)
  connect(valConSwi[nUni].port_a, port_a3)

  connect(temConEnt.T, TConEnt)
end ChillerHeatRecoveryGroup;


within Buildings.DHC.Plants.Combined.Subsystems;
model CoolingTowerGroup "Model of multiple identical cooling towers in parallel"
  extends Buildings.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow_nominal(final min=Modelica.Constants.small)=mConWat_flow_nominal);

  parameter Integer nUni(final min=1, start=1)
    "Number of units operating at design conditions"
  parameter Modelica.Units.SI.MassFlowRate mConWatUni_flow_nominal(
    final min=0)
    "CW design mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mConWat_flow_nominal(
    final min=0)=nUni * mConWatUni_flow_nominal
    "CW design mass flow rate (all units)"
  parameter Modelica.Units.SI.PressureDifference dpConWatFriUni_nominal(
      displayUnit="Pa")
    "CW flow-friction losses through tower and piping only (without elevation head or valve)"
  parameter Modelica.Units.SI.MassFlowRate mAirUni_flow_nominal(
    final min=0,
    start=mConWatUni_flow_nominal / 1.45)
    "Air mass flow rate (each unit)"
  parameter Modelica.Units.SI.Temperature TWetBulEnt_nominal(
    final min=273.15)
    "Entering air wetbulb temperature"
  parameter Modelica.Units.SI.Temperature TConWatRet_nominal(
    final min=273.15)
    "CW return temperature (tower entering)"
  parameter Modelica.Units.SI.Temperature TConWatSup_nominal(
    final min=273.15)
    "CW supply temperature (tower leaving)"
  parameter Modelica.Units.SI.Power PFanUni_nominal(
    final min=0,
    start=340 * mConWatUni_flow_nominal)
    "Fan power (each unit)"
  parameter Real yFan_min(unit="1")=0.1
    "CT fan minimum speed";

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

  parameter Modelica.Units.SI.Time tau=30
    "Time constant of fluid volume for nominal flow, used if energy or mass balance is dynamic"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1[nUni]
    "Cooling tower Start command"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput y(
    final unit="1", final min=0)
    "Cooling tower speed (common to all tower cells)"
  BoundaryConditions.WeatherData.Bus weaBus
    "Bus with weather data"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput P(final unit="W")
    "Power drawn by tower fans"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TConWatSup(
    final unit="K", displayUnit="degC")
    "CW supply temperature (tower leaving)"

  Fluid.BaseClasses.MassFlowRateMultiplier mulInl(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final use_input=false,
    final k=1/nUni)       "Flow rate multiplier"
  Fluid.BaseClasses.MassFlowRateMultiplier mulOut(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final use_input=false,
    final k=nUni)         "Flow rate multiplier"
  Buildings.Templates.Components.Controls.MultipleCommands com(final nUni=nUni)
    "Convert command signals"
  Buildings.Controls.OBC.CDL.Reals.Multiply mulP "Scale power"

  Fluid.HeatExchangers.CoolingTowers.Merkel coo(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatUni_flow_nominal,
    final dp_nominal=dpConWatFriUni_nominal,
    final yMin=yFan_min,
    final ratWatAir_nominal=mConWatUni_flow_nominal/mAirUni_flow_nominal,
    final TAirInWB_nominal=TWetBulEnt_nominal,
    final TWatIn_nominal=TConWatRet_nominal,
    final TWatOut_nominal=TConWatSup_nominal,
    final PFan_nominal=PFanUni_nominal,
    final tau=tau,
    final allowFlowReversal=allowFlowReversal,
    final show_T=show_T,
    final energyDynamics=energyDynamics)
    "Cooling tower"

  Buildings.Controls.OBC.CDL.Logical.Pre preY1[nUni]
    "Left limit of signal avoiding direct feedback of status to controller"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Convert to real"
  Buildings.Controls.OBC.CDL.Reals.Multiply inp
    "Compute pump input signal"
equation
  connect(com.nUniOn, mulP.u2)

  connect(mulP.y, P)
  connect(mulOut.port_b, port_b)
  connect(mulInl.port_b, coo.port_a)
  connect(coo.port_b, mulOut.port_a)
  connect(weaBus.TWetBul, coo.TAir)
  connect(coo.PFan, mulP.u1)
  connect(coo.TLvg, TConWatSup)
  connect(y1, preY1.u)
  connect(preY1.y, com.y1)
  connect(com.y1One, booToRea.u)
  connect(inp.y, coo.y)
  connect(y, inp.u1)
  connect(booToRea.y, inp.u2)
  connect(port_a, mulInl.port_a)
end CoolingTowerGroup;


within Buildings.DHC.Plants.Combined.Subsystems;
model HeatPumpGroup
  "Model of multiple identical air-source heat pumps in parallel"
  extends Buildings.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow_nominal(final min=Modelica.Constants.small)=mHeaWat_flow_nominal);

  replaceable package MediumAir=Buildings.Media.Air
    "Air medium";

  parameter Integer nUni(final min=1, start=1)
    "Number of units operating at design conditions"
  final parameter Modelica.Units.SI.HeatFlowRate capUni_nominal(
    final min=0)=dat.hea.Q_flow
    "Heat pump design capacity (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mHeaWatUni_flow_nominal(
    final min=0)=dat.hea.mLoa_flow
    "HW design mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mAirUni_flow_nominal(
    final min=0)=dat.hea.mSou_flow
    "Air design mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal(
    final min=0)=nUni * mHeaWatUni_flow_nominal
    "HW design mass flow rate (all units)"
  parameter Modelica.Units.SI.PressureDifference dpPumHeaWatUni_nominal(
    final min=0,
    displayUnit="Pa")=dat.dpHeaLoa_nominal
    "HW pump design head (each unit)"

  replaceable parameter Buildings.Fluid.HeatPumps.Data.EquationFitReversible.Generic dat
    "Heat pump parameters (each unit)"
  replaceable parameter Fluid.Movers.Data.Generic datPum
    constrainedby Fluid.Movers.Data.Generic(
      pressure(V_flow={0,1,2}*mHeaWatUni_flow_nominal/rho_nominal,
      dp={1.14,1,0.42}*dpPumHeaWatUni_nominal),
      motorCooledByFluid=false)
    "Condenser pump parameters (each unit)"

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

  parameter Modelica.Units.SI.Time tau=30
    "Time constant of fluid volume for nominal HW flow, used if energy or mass balance is dynamic"

  // Pump speed filter parameters
  parameter Boolean use_riseTime=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Set to true to continuously change motor speed"
  parameter Modelica.Units.SI.Time riseTime=30
    "Time needed to change motor speed"
  parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput
    "Type of initialization (no init/steady state/initial state/initial output)"
  parameter Real y_start=1 "Initial position of actuator"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1[nUni]
    "Heat pump On/Off command"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSet(
    final unit="K", displayUnit="degC")
    "Supply temperature setpoint"
  BoundaryConditions.WeatherData.Bus weaBus
    "Bus with weather data"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PPum(
    final unit="W")
    "Power drawn by HW pumps"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput P(
    final unit="W")
    "Power drawn by heat pumps"

  Fluid.BaseClasses.MassFlowRateMultiplier mulConInl(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final use_input=true)
    "Flow rate multiplier"
  Fluid.BaseClasses.MassFlowRateMultiplier mulConOut(
    redeclare final package Medium = Medium,
    final allowFlowReversal=allowFlowReversal,
    final use_input=true)
    "Flow rate multiplier"
  Buildings.Templates.Components.Controls.MultipleCommands com(final nUni=nUni)
    "Convert command signals"
  Buildings.Controls.OBC.CDL.Reals.Multiply mulP "Scale power"
  Fluid.HeatPumps.EquationFitReversible heaPum(
    redeclare final package Medium1=Medium,
    redeclare final package Medium2=MediumAir,
    final per=dat,
    final tau1=tau,
    final show_T=show_T,
    final energyDynamics=energyDynamics,
    final allowFlowReversal1=allowFlowReversal,
    final allowFlowReversal2=false)
    "Heat pump"
  Fluid.Movers.SpeedControlled_y pum(
    redeclare final package Medium = Medium,
    inputType=Buildings.Fluid.Types.InputType.Continuous,
    final tau=tau,
    final show_T=show_T,
    final allowFlowReversal=allowFlowReversal,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final riseTime=riseTime,
    final init=init,
    final per=datPum,
    addPowerToMedium=false) "HW pump"
  Fluid.Sources.MassFlowSource_WeatherData airSou(
    redeclare final package Medium=MediumAir,
    final use_m_flow_in=true,
    final nPorts=1)
    "Air flow source"
  Fluid.Sources.Boundary_pT airSin(
    redeclare final package Medium=MediumAir,
    final nPorts=1)
    "Air flow sink"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter comFan(
    final k=mAirUni_flow_nominal)
    "Convert On/Off command to air flow setpoint"
  Buildings.Controls.OBC.CDL.Reals.Multiply mulP1 "Scale power"

  Buildings.Controls.OBC.CDL.Logical.Pre preY1[nUni]
    "Left limit of signal avoiding direct feedback of status to controller"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Convert to real"
  Buildings.Controls.OBC.CDL.Reals.Multiply inp
    "Compute pump input signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant cst(final k=1)
    "Constant"
  Buildings.Controls.OBC.CDL.Conversions.RealToInteger reaToInt
    "Convert to integer"
protected
  parameter Medium.ThermodynamicState sta_nominal=Medium.setState_pTX(
    T=dat.hea.TRefLoa,
    p=3E5,
    X=Medium.X_default)
    "State of the medium at the medium default properties";
  parameter Modelica.Units.SI.Density rho_nominal=Medium.density(sta_nominal)
    "Density at the medium default properties";
equation
  connect(mulConOut.uInv, mulConInl.u)
  connect(com.nUniOn, mulP.u2)

  connect(mulP.y, P)
  connect(com.nUniOnBou, mulConOut.u)
  connect(pum.port_b, heaPum.port_a1)
  connect(heaPum.port_b1, mulConOut.port_a)
  connect(mulConInl.port_b, pum.port_a)
  connect(mulConOut.port_b, port_b)
  connect(heaPum.P, mulP.u1)
  connect(port_a, mulConInl.port_a)
  connect(airSou.ports[1], heaPum.port_a2)
  connect(airSin.ports[1], heaPum.port_b2)
  connect(TSet, heaPum.TSet)
  connect(comFan.y, airSou.m_flow_in)
  connect(weaBus, airSou.weaBus)
  connect(mulP1.y, PPum)
  connect(pum.P, mulP1.u1)
  connect(com.nUniOn, mulP1.u2)
  connect(y1, preY1.u)
  connect(preY1.y, com.y1)
  connect(com.y1One, booToRea.u)
  connect(inp.y, pum.y)
  connect(booToRea.y, comFan.u)
  connect(booToRea.y, inp.u2)
  connect(cst.y, inp.u1)
  connect(booToRea.y, reaToInt.u)
  connect(reaToInt.y, heaPum.uMod)
end HeatPumpGroup;


Model of multiple identical pumps in parallel with dp-controlled pump model. This model represents a set of identical dp-controlled
variable speed pumps that are piped in parallel.
An optional check valve in series with each pump is included.

within Buildings.DHC.Plants.Combined.Subsystems;
model MultiplePumpsDp
  "Model of multiple identical pumps in parallel with dp-controlled pump model"
  extends BaseClasses.PartialMultiplePumps(
    final have_var=have_varSet,
    redeclare final Buildings.Fluid.Movers.FlowControlled_dp pum(
      final m_flow_nominal=mPum_flow_nominal,
      final dp_nominal=dpPum_nominal),
    cst(final k=dpPum_nominal));

  parameter Boolean have_varSet = true
    "Set to true for variable setpoint, false for constant setpoint (design value)"

  Buildings.Controls.OBC.CDL.Interfaces.RealInput dp_in(
    final unit="Pa",
    final min=0)
    if have_var
    "Differential pressure setpoint"
equation
  connect(dp_in, inp.u1)
  connect(inp.y, pum.dp_in)
end MultiplePumpsDp;


Model of multiple identical pumps in parallel with flow-controlled pump model. This model represents a set of identical flow-controlled
variable speed pumps that are piped in parallel.
An optional check valve in series with each pump is included.

within Buildings.DHC.Plants.Combined.Subsystems;
model MultiplePumpsFlow
  "Model of multiple identical pumps in parallel with flow-controlled pump model"
  extends BaseClasses.PartialMultiplePumps(
    final have_var=have_varSet,
    redeclare final Buildings.Fluid.Movers.FlowControlled_m_flow pum(
      final m_flow_nominal=mPum_flow_nominal,
      final dp_nominal=dpPum_nominal),
    cst(final k=mPum_flow_nominal));

  parameter Boolean have_varSet = true
    "Set to true for variable setpoint, false for constant setpoint (design value)"

  Buildings.Controls.OBC.CDL.Interfaces.RealInput m_flow_in(
    final unit="kg/s",
    final min=0)
    if have_var
    "Mass flow rate setpoint (total over all pumps)"
  Buildings.Controls.OBC.CDL.Reals.Divide div1
    "Divide total flow setpoint by number of pumps commanded On"
equation
  connect(m_flow_in, div1.u1)
  connect(com.nUniOnBou, div1.u2)
  connect(div1.y, inp.u1)
  connect(inp.y, pum.m_flow_in)
end MultiplePumpsFlow;


Model of multiple identical pumps in parallel with speed-controlled pump model. This model represents a set of identical speed-controlled
pumps that are piped in parallel.
The model may be configured to represent either constant speed
pumps or variable speed pumps.
An optional check valve in series with each pump is included.

within Buildings.DHC.Plants.Combined.Subsystems;
model MultiplePumpsSpeed
  "Model of multiple identical pumps in parallel with speed-controlled pump model"
  extends
    Buildings.DHC.Plants.Combined.Subsystems.BaseClasses.PartialMultiplePumps(
    redeclare final Buildings.Fluid.Movers.SpeedControlled_y pum,
    cst(final k=1));

  Buildings.Controls.OBC.CDL.Interfaces.RealInput y(
    final unit="1",
    final min=0,
    final max=1)
    if have_var
    "Pump speed (common to all pumps)"

equation
  connect(y, inp.u1)
  connect(inp.y, pum.y)
end MultiplePumpsSpeed;


within Buildings.DHC.Plants.Combined;
package Subsystems "Package of models for subsystems of combined plants"
  extends Modelica.Icons.VariantsPackage;
end Subsystems;


within Buildings.DHC.Plants.Combined.Subsystems.BaseClasses;
model MultipleValves
  "Parallel arrangement of identical two-way modulating valves"
  extends Buildings.Fluid.Interfaces.LumpedVolumeDeclarations(
    final massDynamics=energyDynamics,
    final mSenFac=1);
  extends Buildings.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow_nominal(final min=Modelica.Constants.small)=nUni*mUni_flow_nominal,
    show_T=false,
    port_a(
      h_outflow(start=h_outflow_start)),
    port_b(
      h_outflow(start=h_outflow_start),
      p(start=p_start),
      final m_flow(max = if allowFlowReversal then +Modelica.Constants.inf else 0)));

  parameter Integer nUni(
    final min=1,
    start=1)
    "Number of units (branches in the network)"
  parameter Modelica.Units.SI.MassFlowRate mUni_flow_nominal(
    final min=Modelica.Constants.small)
    "Nominal mass flow rate (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpValve_nominal(
    displayUnit="Pa",
    min=0)
    "Nominal pressure drop of fully open valve (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpFixed_nominal(
    displayUnit="Pa",
    min=0) = 0
    "Pressure drop of pipe and other resistances that are in series (each unit)"

  parameter Boolean use_strokeTime=true
    "Set to true to continuously open and close valve using strokeTime"
  parameter Modelica.Units.SI.Time strokeTime=120
    "Time needed to open or close valve"
  parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput
    "Type of initialization (no init/steady state/initial state/initial output)"
  parameter Real y_start=1 "Initial position of actuator"

  parameter Boolean from_dp = false
    "= true, use m_flow = f(dp) else dp = f(m_flow)"
  parameter Boolean linearized = false
    "= true, use linear relation between m_flow and dp for any flow rate"

  Buildings.Controls.OBC.CDL.Interfaces.RealInput y[nUni]
    "Valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y_actual[nUni]
    "Valve returned position"

  Fluid.FixedResistances.Junction junInl[nUni](
    redeclare each final package Medium=Medium,
    each final m_flow_nominal=m_flow_nominal * {1,-1,-1},
    each final dp_nominal=fill(0,3),
    each final energyDynamics=energyDynamics,
    each final portFlowDirection_1=if allowFlowReversal then
      Modelica.Fluid.Types.PortFlowDirection.Bidirectional else
      Modelica.Fluid.Types.PortFlowDirection.Entering,
    each final portFlowDirection_2=if allowFlowReversal then
      Modelica.Fluid.Types.PortFlowDirection.Bidirectional else
      Modelica.Fluid.Types.PortFlowDirection.Leaving,
    each final portFlowDirection_3=if allowFlowReversal then
      Modelica.Fluid.Types.PortFlowDirection.Bidirectional else
      Modelica.Fluid.Types.PortFlowDirection.Leaving)
    "Fluid junction"
  Fluid.FixedResistances.Junction junOut[nUni](
    redeclare each final package Medium=Medium,
    each final m_flow_nominal=m_flow_nominal * {1,-1,1},
    each final dp_nominal=fill(0,3),
    each final energyDynamics=energyDynamics,
    each final portFlowDirection_1=if allowFlowReversal then
      Modelica.Fluid.Types.PortFlowDirection.Bidirectional else
      Modelica.Fluid.Types.PortFlowDirection.Entering,
    each final portFlowDirection_2=if allowFlowReversal then
      Modelica.Fluid.Types.PortFlowDirection.Bidirectional else
      Modelica.Fluid.Types.PortFlowDirection.Leaving,
    each final portFlowDirection_3=if allowFlowReversal then
      Modelica.Fluid.Types.PortFlowDirection.Bidirectional else
      Modelica.Fluid.Types.PortFlowDirection.Entering)
    "Fluid junction"
  replaceable Fluid.Actuators.Valves.TwoWayEqualPercentage val[nUni]
    constrainedby Buildings.Fluid.Actuators.BaseClasses.PartialTwoWayValveKv(
    redeclare each final package Medium = Medium,
    each final from_dp=from_dp,
    each final linearized=linearized,
    each final CvData=Buildings.Fluid.Types.CvTypes.OpPoint,
    each final m_flow_nominal=mUni_flow_nominal,
    each final dpValve_nominal=dpValve_nominal,
    each final dpFixed_nominal=dpFixed_nominal,
    each final allowFlowReversal=allowFlowReversal,
    each final use_strokeTime=use_strokeTime,
    each final strokeTime=strokeTime,
    each final init=init,
    each final y_start=y_start) "Modulating valve"
protected
  final parameter Medium.ThermodynamicState sta_start=Medium.setState_pTX(
    T=T_start,
    p=p_start,
    X=X_start)
    "Medium state at start values";
  final parameter Modelica.Units.SI.SpecificEnthalpy h_outflow_start=
    Medium.specificEnthalpy(sta_start)
    "Start value for outflowing enthalpy";
equation
  if nUni > 1 then
    for i in 1:(nUni - 1) loop
      connect(junOut[i].port_1, junOut[i+1].port_2)
      connect(junInl[i].port_2, junInl[i+1].port_1)
    end for;
  end if;
  connect(junInl.port_3, val.port_a)
  connect(val.port_b, junOut.port_3)
  connect(junOut[1].port_2, port_b)

  connect(port_a, junInl[1].port_1)
  connect(val.y_actual, y_actual)
  connect(y, val.y)
end MultipleValves;


Package with base classes

within Buildings.DHC.Plants.Combined.Subsystems;
package BaseClasses "Package with base classes"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.DHC.Plants.Combined.Subsystems.BaseClasses;
partial model PartialMultiplePumps
  "Base class for modeling multiple identical pumps in parallel"
  extends Buildings.Fluid.Interfaces.LumpedVolumeDeclarations(
    final massDynamics=energyDynamics,
    final mSenFac=1);
  extends Buildings.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow_nominal(final min=Modelica.Constants.small)=nPum * mPum_flow_nominal,
    show_T=false,
    port_a(
      h_outflow(start=h_outflow_start)),
    port_b(
      h_outflow(start=h_outflow_start),
      p(start=p_start),
      final m_flow(max = if allowFlowReversal then +Modelica.Constants.inf else 0)));

  parameter Integer nPum(
    final min=1,
    start=1)
    "Number of pumps"
  parameter Boolean have_var = true
    "Set to true for variable speed pumps, false for constant speed"
  parameter Boolean have_valve = true
    "Set to true for inline check valve"
  parameter Modelica.Units.SI.MassFlowRate mPum_flow_nominal
    "Design mass flow rate (each pump)"
  parameter Modelica.Units.SI.PressureDifference dpPum_nominal(
    displayUnit="Pa")
    "Design head (each pump)"
  parameter Modelica.Units.SI.PressureDifference dpValve_nominal(
    displayUnit="Pa")=10000
    "Pressure drop of check valve fully open"
  replaceable parameter Fluid.Movers.Data.Generic per
    constrainedby Buildings.Fluid.Movers.Data.Generic(
      pressure(
        V_flow={0, 1, 2} * mPum_flow_nominal / rho_default,
        dp={1.14, 1, 0.42} * dpPum_nominal),
      motorCooledByFluid=false) "Pump parameters"

  parameter Modelica.Units.SI.Time tau=1
    "Time constant of fluid volume for nominal flow, used if energy or mass balance is dynamic"

  // Classes used to implement the filtered speed
  parameter Boolean use_riseTime=true
    "Set to true to continuously change motor speed"
  parameter Modelica.Units.SI.Time riseTime=30
    "Time needed to change motor speed between zero and full speed"
  parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput
    "Type of initialization (no init/steady state/initial state/initial output)"

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1[nPum]
    "Start signal (VFD Run or motor starter contact)"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput P(final unit="W")
    "Total power (all pumps)"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1_actual[nPum]
    "Pump status"

  Fluid.BaseClasses.MassFlowRateMultiplier mulOut(
    redeclare final package Medium=Medium,
    final use_input=true)
    "Flow rate multiplier"
  Fluid.BaseClasses.MassFlowRateMultiplier mulInl(
    redeclare final package Medium=Medium,
    final use_input=true)
    "Flow rate multiplier"
  replaceable Fluid.Movers.SpeedControlled_y pum constrainedby
    Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine(
    redeclare final package Medium = Medium,
    final tau=tau,
    final show_T=show_T,
    final allowFlowReversal=allowFlowReversal,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final riseTime=riseTime,
    final init=init,
    final per=per,
    addPowerToMedium=false) "Pump"
  Buildings.Templates.Components.Controls.MultipleCommands com(final nUni=nPum)
    "Convert command signal"

  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Convert to real"
  Buildings.Controls.OBC.CDL.Reals.Multiply mul "Compute total power"
  Buildings.Controls.OBC.CDL.Reals.Multiply inp
    "Compute pump input signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant cst
               if not have_var "Constant setpoint"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isOpe(t=1E-2, h=0.5E-2)
    "Evaluate if pump is operating"
  Fluid.FixedResistances.CheckValve cheVal(
    redeclare final package Medium=Medium,
    final m_flow_nominal=mPum_flow_nominal,
    final dpValve_nominal=dpValve_nominal,
    final show_T=show_T,
    final allowFlowReversal=allowFlowReversal) if have_valve
    "Check valve (optional)"
  Buildings.DHC.Plants.Combined.Subsystems.BaseClasses.PassThroughFluid pas(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal) if not have_valve
    "Direct fluid pass-through (case without check valve)"
  Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rep(
    final nout=nPum)
    "Replicate"
  Buildings.Controls.OBC.CDL.Logical.Pre preY1[nPum]
    "Left limit of signal avoiding direct feedback of status to controller"
protected
  parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
      T=Medium.T_default,
      p=Medium.p_default,
      X=Medium.X_default)
    "State of the medium at the medium default properties";
  parameter Modelica.Units.SI.Density rho_default=Medium.density(sta_default)
    "Density at the medium default properties";
  final parameter Medium.ThermodynamicState sta_start=Medium.setState_pTX(
    T=T_start,
    p=p_start,
    X=X_start)
    "Medium state at start values";
  final parameter Modelica.Units.SI.SpecificEnthalpy h_outflow_start=
    Medium.specificEnthalpy(sta_start)
    "Start value for outflowing enthalpy";
equation
  connect(mulOut.port_b, port_b)
  connect(port_a, mulInl.port_a)
  connect(mulOut.uInv, mulInl.u)
  connect(mulInl.port_b, pum.port_a)
  connect(com.nUniOnBou, mulOut.u)
  connect(com.y1One, booToRea.u)
  connect(mul.y, P)
  connect(com.nUniOn, mul.u1)
  connect(pum.P, mul.u2)
  connect(pum.port_b, cheVal.port_a)
  connect(cheVal.port_b, mulOut.port_a)
  connect(cst.y, inp.u1)
  connect(booToRea.y, inp.u2)
  connect(pum.port_b, pas.port_a)
  connect(pas.port_b, mulOut.port_a)
  connect(pum.y_actual, isOpe.u)
  connect(isOpe.y, rep.u)
  connect(y1, preY1.u)
  connect(preY1.y, com.y1)
  connect(rep.y, y1_actual)
end PartialMultiplePumps;


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

within Buildings.DHC.Plants.Combined.Subsystems.BaseClasses;
model PassThroughFluid "Direct fluid pass-through"
  extends Buildings.Fluid.Interfaces.PartialTwoPort;

equation
  connect(port_a, port_b)
end PassThroughFluid;


Validation of chiller group model

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model ChillerGroup "Validation of chiller group model"
  extends Modelica.Icons.Example;

  replaceable package MediumChiWat=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "CHW medium";
  replaceable package MediumConWat=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "CW medium";

  parameter
    Fluid.Chillers.Data.ElectricReformulatedEIR.ReformEIRChiller_Carrier_19XR_1403kW_7_09COP_VSD
    dat "Chiller parameters"

  Buildings.DHC.Plants.Combined.Subsystems.ChillerGroup chi(
    redeclare final package Medium1 = MediumConWat,
    redeclare final package Medium2 = MediumChiWat,
    show_T=true,
    nUni=2,
    dpEva_nominal=3E5,
    dpCon_nominal=3E5,
    final dat=dat,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Chiller group"

  Fluid.Sources.Boundary_pT retChiWat(
    redeclare final package Medium = MediumChiWat,
    p=supChiWat.p + chi.dpEva_nominal + chi.valEva.dpValve_nominal,
    T=288.15,
    nPorts=1)
    "Boundary conditions for CHW"

  Fluid.Sources.Boundary_pT supConWat(
    redeclare final package Medium = MediumConWat,
    p=retConWat.p + chi.dpCon_nominal + chi.valCon.dpValve_nominal,
    nPorts=1) "Boundary conditions for CW"

  Fluid.Sources.Boundary_pT retConWat(
    redeclare final package Medium = MediumConWat,
    p=200000,
    nPorts=1) "Boundary conditions for CW"
  Fluid.Sources.Boundary_pT supChiWat(
    redeclare final package Medium = MediumChiWat,
    p=200000,
    nPorts=1) "Boundary conditions for CHW"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp TChiWatSupSet(
    y(displayUnit="degC", unit="K"),
    height=+5,
    duration=1000,
    offset=dat.TEvaLvg_nominal) "CHW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,1,1; 0.5,1,1; 0.5,1,0; 0.8,1,0; 0.8,0,0; 1,0,0],
    timeScale=1000,
    period=1000) "Chiller On/Off command"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[chi.nUni]
    "Convert DO to AO"
equation
  connect(chi.port_b1, retConWat.ports[1])
  connect(supConWat.ports[1], chi.port_a1)
  connect(retChiWat.ports[1], chi.port_a2)
  connect(supChiWat.ports[1], chi.port_b2)
  connect(TChiWatSupSet.y, chi.TSet)
  connect(y1.y, chi.y1)
  connect(y1.y, booToRea.u)
  connect(booToRea.y, chi.yValCon)
  connect(booToRea.y, chi.yValEva)
end ChillerGroup;


within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model ChillerHeatRecoveryGroup
  "Validation of heat recovery chiller group model"
  extends Modelica.Icons.Example;

  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Medium model";
  final parameter Integer nChiHea(final min=1, start=1)=2
    "Number of HRCs operating at design conditions"
  parameter
    Fluid.Chillers.Data.ElectricReformulatedEIR.ReformEIRChiller_Carrier_19XR_1403kW_7_09COP_VSD dat(
      EIRFunT={0.0101739374, 0.0607200115, 0.0003348647, 0.003162578, 0.0002388594, -0.0014121289},
      capFunT={0.0387084662, 0.2305017927, 0.0004779504, 0.0178244359, -8.48808e-05, -0.0032406711},
      EIRFunPLR={0.4304252832, -0.0144718912, 5.12039e-05, -0.7562386674, 0.5661683373,
        0.0406987748, 3.0278e-06, -0.3413411197, -0.000469572, 0.0055009208},
      QEva_flow_nominal=-1E6,
      COP_nominal=2.5,
      mEva_flow_nominal=20,
      mCon_flow_nominal=22,
      TEvaLvg_nominal=279.15,
      TEvaLvgMin=277.15,
      TEvaLvgMax=308.15,
      TConLvg_nominal=333.15,
      TConLvgMin=296.15,
      TConLvgMax=336.15)
    "Chiller parameters (each unit)"

  Buildings.DHC.Plants.Combined.Subsystems.ChillerHeatRecoveryGroup
    chi(
    redeclare final package Medium = Medium,
    show_T=true,
    final nUni=nChiHea,
    dpEva_nominal=3E5,
    dpCon_nominal=3E5,
    final dat=dat,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial) "Chiller group"

  Fluid.Sources.Boundary_pT bouChiWat(
    redeclare final package Medium = Medium,
    p=300000,
    nPorts=1) "Pressure boundary condition for CHW"

  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,1,1; 0.8,1,1; 0.8,1,0; 0.9,1,0; 0.9,0,0; 1,0,0],
    timeScale=2000,
    period=2000) "Chiller On/Off command"

  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Coo(
    table=[0,0,0; 0.2,0,0; 0.2,0,1; 0.6,0,1; 0.6,1,1; 1,1,1],
    timeScale=2000,
    period=2000)
    "Cooling mode switchover command"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1HeaCoo(
    table=[0,0,0; 0.4,0,0; 0.4,1,0; 0.6,1,0; 0.6,0,0; 1,0,0],
    timeScale=2000,
    period=2000)
    "Direct heat recovery switchover command"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSet[nChiHea](
      each final k=chi.TChiWatSup_nominal, y(each final unit="K", each
        displayUnit="degC")) "Supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[chi.nUni]
    "Convert DO to AO"
  Fluid.Sensors.TemperatureTwoPort THeaWatSup(
    redeclare final package Medium =
               Medium, final m_flow_nominal=chi.mConWat_flow_nominal)
    "HW supply temperature"
  Fluid.Sensors.MassFlowRate floHeaWat(redeclare final package Medium =
        Medium) "HW flow"
  Fluid.Sensors.MassFlowRate floChiWat(redeclare final package Medium =
        Medium) "CHW flow"
  Fluid.Sensors.TemperatureTwoPort TChiWatSup(redeclare final package Medium =
               Medium, final m_flow_nominal=chi.mChiWat_flow_nominal)
    "CHW supply temperature"
  Buildings.Controls.OBC.CDL.Logical.Or cooOrDir[nChiHea]
    "Return true if cooling OR direct HR"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal yValConSwi[nChiHea]
    "HRC condenser switchover valve commanded position"
  Buildings.Controls.OBC.CDL.Logical.Not hea[nChiHea] "Return true if heating"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nChiHea]
    "Convert"
  Buildings.Controls.OBC.CDL.Integers.MultiSum numHea(nin=nChiHea)
    "Number of HRC connected to HW loop"
  Buildings.Controls.OBC.CDL.Integers.Less intLes[nChiHea]
    "Return true if switchover valve to be open"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant idx[nChiHea](final k={i
        for i in 1:nChiHea}) "HRC index"
  Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator rep(final nout=
        nChiHea) "Replicate"
  Buildings.Controls.OBC.CDL.Logical.Or mul[nChiHea]
    "Return true if cooling OR direct HR"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal yValEvaSwi[nChiHea]
    "HRC evaporator switchover valve commanded position"
  Buildings.Controls.OBC.CDL.Logical.Not heaAndCas[nChiHea]
    "Return true if cascading heating"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1[nChiHea]
    "Convert"
  Buildings.Controls.OBC.CDL.Integers.MultiSum numHeaAndCas(nin=nChiHea)
    "Number of HRC in cascading heating"
  Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator rep1(final nout=
        nChiHea) "Replicate"
  Buildings.Controls.OBC.CDL.Integers.Less intLes1
                                                 [nChiHea]
    "Return true if switchover valve to be open"
  Buildings.Controls.OBC.CDL.Logical.Or mul1
                                           [nChiHea]
    "Return true if cooling OR direct HR"
  Buildings.Controls.OBC.CDL.Reals.Switch TChiHeaSupSet[nChiHea]
    "Switch supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSet[nChiHea](
      each final k=chi.THeaWatSup_nominal, y(each final unit="K", each
        displayUnit="degC")) "Supply temperature setpoint"
  Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pumChiWat(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPum=1,
    have_var=false,
    have_valve=true,
    final mPum_flow_nominal=chi.mChiWat_flow_nominal,
    final dpPum_nominal=chi.dpEva_nominal)
    "CHW pumps"
  Buildings.Controls.OBC.CDL.Logical.MultiOr y1PumConWatCon(nin=2)
    "Start pump if any HRC in cascading cooling"
  Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pumHeaWat(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPum=1,
    have_var=false,
    have_valve=true,
    final mPum_flow_nominal=chi.mConWat_flow_nominal,
    final dpPum_nominal=chi.dpCon_nominal)
    "HW pumps"
  Buildings.Controls.OBC.CDL.Logical.And onAndHea[nChiHea]
    "Return true if On and heating"
  Buildings.Controls.OBC.CDL.Logical.MultiOr y1PumHeaWat(nin=2)
    "Start pump if any HRC On and in heating"
  Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pumConWatCon(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPum=1,
    have_var=false,
    have_valve=true,
    final mPum_flow_nominal=chi.mConWat_flow_nominal,
    final dpPum_nominal=chi.dpCon_nominal)
    "CW pumps serving condenser barrels"
  Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pumConWatEva(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    nPum=1,
    have_var=false,
    have_valve=true,
    final mPum_flow_nominal=chi.mChiWat_flow_nominal,
    final dpPum_nominal=chi.dpEva_nominal)
    "CW pumps serving evaporator barrels"
  Buildings.Controls.OBC.CDL.Integers.GreaterEqualThreshold y1PumConWatEva(t=1)
    "Return true if CW to be operating"
  Buildings.Controls.OBC.CDL.Logical.MultiOr y1PumChiWat(nin=2)
    "Start pump if any HRC in cooling or direct HR mode"
  Fluid.HeatExchangers.SensibleCooler_T disHeaWat(
    redeclare final package Medium = Medium,
    final m_flow_nominal=THeaWatRet.k,
    final dp_nominal=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau=300,
    T_start=chi.THeaWatSup_nominal - 12)
    "Distribution system approximated by prescribed temperature"
  Fluid.HeatExchangers.Heater_T disConWatEva(
    redeclare final package Medium = Medium,
    final m_flow_nominal=chi.mChiWat_flow_nominal,
    final dp_nominal=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau=300,
    T_start=TConWatEvaSup.k)
    "Distribution system approximated by prescribed temperature"
  Fluid.HeatExchangers.SensibleCooler_T disConWatCon(
    redeclare final package Medium = Medium,
    final m_flow_nominal=TConWatConSup.k,
    final dp_nominal=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau=300,
    T_start=chi.TCasCooEnt_nominal)
    "Distribution system approximated by prescribed temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatRet(
    final k=chi.THeaWatSup_nominal - 12,
    y(final unit="K", displayUnit="degC"))
    "Return temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TConWatConSup(final k=
        chi.TCasCooEnt_nominal, y(final unit="K", displayUnit="degC"))
    "Supply temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TConWatEvaSup(final k=
        chi.TCasHeaEnt_nominal, y(final unit="K", displayUnit="degC"))
    "Supply temperature"
  Fluid.HeatExchangers.Heater_T disChiWat(
    redeclare final package Medium = Medium,
    final m_flow_nominal=TChiWatRet.k,
    final dp_nominal=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    tau=300,
    T_start=chi.TChiWatSup_nominal)
    "Distribution system approximated by prescribed temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatRet(
    final k=chi.TChiWatSup_nominal + 6, y(final unit="K", displayUnit="degC"))
    "Return temperature"
  Fluid.Sources.Boundary_pT bouHeaWat(
    redeclare final package Medium = Medium,
    p=300000,
    nPorts=1) "Pressure boundary condition for HW"
equation
  connect(y1.y, chi.y1)
  connect(y1Coo.y, chi.y1Coo)
  connect(y1.y, booToRea.u)
  connect(booToRea.y, chi.yValEva)
  connect(chi.port_b1, THeaWatSup.port_a)
  connect(floChiWat.port_b, chi.port_a4)
  connect(TChiWatSup.port_a, chi.port_b4)
  connect(y1Coo.y, cooOrDir.u1)
  connect(y1HeaCoo.y, cooOrDir.u2)
  connect(y1Coo.y, hea.u)
  connect(hea.y, booToInt.u)
  connect(booToInt.y, numHea.u)
  connect(idx.y, intLes.u1)
  connect(rep.y, intLes.u2)
  connect(intLes.y, mul.u2)
  connect(mul.y, yValConSwi.u)
  connect(yValConSwi.y, chi.yValConSwi)
  connect(y1Coo.y[1:2], mul.u1)
  connect(yValEvaSwi.y, chi.yValEvaSwi)
  connect(numHea.y, rep.u)
  connect(cooOrDir.y, heaAndCas.u)
  connect(heaAndCas.y, booToInt1.u)
  connect(booToInt1.y, numHeaAndCas.u)
  connect(numHeaAndCas.y, rep1.u)
  connect(rep1.y, intLes1.u2)
  connect(idx.y, intLes1.u1)
  connect(cooOrDir.y, mul1.u1)
  connect(intLes1.y, mul1.u2)
  connect(mul1.y, yValEvaSwi.u)
  connect(TChiWatSet.y, TChiHeaSupSet.u1)
  connect(THeaWatSet.y, TChiHeaSupSet.u3)
  connect(y1Coo.y, TChiHeaSupSet.u2)
  connect(TChiHeaSupSet.y, chi.TSet)
  connect(pumChiWat.port_b, floChiWat.port_a)
  connect(y1Coo.y[1:2], y1PumConWatCon.u[1:2])
  connect(pumHeaWat.port_b, floHeaWat.port_a)
  connect(y1.y[1:2], onAndHea.u1)
  connect(hea.y, onAndHea.u2)
  connect(onAndHea.y, y1PumHeaWat.u[1:2])
  connect(y1PumHeaWat.y, pumHeaWat.y1[1])
  connect(THeaWatSup.port_b, pumHeaWat.port_a)
  connect(pumConWatEva.port_b, chi.port_a2)
  connect(chi.port_b3, pumConWatCon.port_a)
  connect(numHeaAndCas.y, y1PumConWatEva.u)
  connect(y1PumConWatEva.y, pumConWatEva.y1[1])
  connect(y1PumConWatCon.y, pumConWatCon.y1[1])
  connect(y1PumChiWat.y, pumChiWat.y1[1])
  connect(cooOrDir.y, y1PumChiWat.u[1:2])
  connect(floHeaWat.port_b, disHeaWat.port_a)
  connect(disHeaWat.port_b, chi.port_a1)
  connect(chi.port_b2, disConWatEva.port_a)
  connect(disConWatEva.port_b, pumConWatEva.port_a)
  connect(pumConWatCon.port_b, disConWatCon.port_a)
  connect(disConWatCon.port_b, chi.port_a3)
  connect(THeaWatRet.y, disHeaWat.TSet)
  connect(TConWatConSup.y, disConWatCon.TSet)
  connect(TConWatEvaSup.y, disConWatEva.TSet)
  connect(disChiWat.port_b, pumChiWat.port_a)
  connect(TChiWatSup.port_b, disChiWat.port_a)
  connect(TChiWatRet.y, disChiWat.TSet)
  connect(bouChiWat.ports[1], pumChiWat.port_a)
  connect(booToRea.y, chi.yValCon)
  connect(bouHeaWat.ports[1], pumHeaWat.port_a)
end ChillerHeatRecoveryGroup;


Validation of cooling tower group model

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model CoolingTowerGroup "Validation of cooling tower group model"
  extends Modelica.Icons.Example;

  replaceable package MediumConWat=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "CW medium";

  Buildings.DHC.Plants.Combined.Subsystems.CoolingTowerGroup coo(
    redeclare final package Medium = MediumConWat,
    show_T=true,
    nUni=2,
    mConWatUni_flow_nominal=1,
    dpConWatFriUni_nominal=1E4,
    mAirUni_flow_nominal=coo.mConWatUni_flow_nominal/1.45,
    TWetBulEnt_nominal=297.05,
    TConWatRet_nominal=308.15,
    TConWatSup_nominal=302.55,
    PFanUni_nominal=340*coo.mConWatUni_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Cooling tower group"

  Fluid.Sources.Boundary_pT bouConWat(
    redeclare final package Medium = MediumConWat,
    T=coo.TConWatRet_nominal,
    nPorts=2)
    "Boundary conditions for CW"

  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp TConWatSupSet(
    height=+3,
    duration=500,
    offset=coo.TConWatSup_nominal,
    startTime=500,
    y(displayUnit="degC", unit="K"))
    "CW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,1,1; 0.4,1,1; 0.4,1,0; 0.8,1,0; 0.8,0,0; 1,0,0],
    timeScale=1000,
    period=1000)
    "On/Off command"
  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource(
    "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Outdoor conditions"
  Fluid.Sensors.TemperatureTwoPort TConWatSup(
    redeclare package Medium =MediumConWat,
    final m_flow_nominal=coo.mConWat_flow_nominal)
    "CW supply temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatRet(
    redeclare package Medium =MediumConWat,
    final m_flow_nominal=coo.mConWat_flow_nominal)
    "CW return temperature"
  ETS.Combined.Controls.PIDWithEnable ctl(
    k=1,
    Ti=60,
    reverseActing=false) "Controller"
  Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pum(
    redeclare package Medium =MediumConWat,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final nPum=coo.nUni,
    have_var=false,
    have_valve=false,
    final mPum_flow_nominal=coo.mConWatUni_flow_nominal,
    final dpPum_nominal=coo.dpConWatFriUni_nominal)
    "CW pumps"
equation
  connect(y1.y, coo.y1)
  connect(weaDat.weaBus, coo.weaBus)
  connect(coo.port_b, TConWatSup.port_a)
  connect(bouConWat.ports[1],TConWatRet. port_a)
  connect(TConWatRet.port_b, coo.port_a)
  connect(coo.TConWatSup, ctl.u_m)
  connect(y1.y[1], ctl.uEna)
  connect(TConWatSupSet.y, ctl.u_s)
  connect(ctl.y, coo.y)
  connect(pum.port_b, bouConWat.ports[2])
  connect(TConWatSup.port_b, pum.port_a)
  connect(y1.y, pum.y1)
end CoolingTowerGroup;


Validation of heat pump group model

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model HeatPumpGroup "Validation of heat pump group model"
  extends Modelica.Icons.Example;

  replaceable package MediumHeaWat=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "CHW medium";
  replaceable package MediumAir=Buildings.Media.Air
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "CW medium";

  parameter Fluid.HeatPumps.Data.EquationFitReversible.Generic dat(
    dpHeaLoa_nominal=50000,
    dpHeaSou_nominal=100,
    hea(
      mLoa_flow=dat.hea.Q_flow / 10 / 4186,
      mSou_flow=1E-4 * dat.hea.Q_flow,
      Q_flow=1E6,
      P=dat.hea.Q_flow / 2.2,
      coeQ={-5.64420084,  1.95212447,  9.96663913,  0.23316322, -5.64420084},
      coeP={-3.96682255,  6.8419453,   1.99606939,  0.01393387, -3.96682255},
      TRefLoa=298.15,
      TRefSou=253.15),
    coo(
      mLoa_flow=0,
      mSou_flow=0,
      Q_flow=-1,
      P=0,
      coeQ=fill(0, 5),
      coeP=fill(0, 5),
      TRefLoa=273.15,
      TRefSou=273.15))
    "Heat pump parameters (each unit)"

  Buildings.DHC.Plants.Combined.Subsystems.HeatPumpGroup heaPum(
    redeclare final package Medium = MediumHeaWat,
    redeclare final package MediumAir = MediumAir,
    show_T=true,
    nUni=2,
    final dat=dat,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Heat pump group"

  Fluid.Sources.Boundary_pT bouHeaWat(
    redeclare final package Medium = MediumHeaWat,
    use_T_in=true,
    nPorts=2)
    "Boundary conditions for HW"

  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet(
    k=dat.hea.TRefLoa+ 10,
    y(displayUnit="degC", unit="K")) "HW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1(
    table=[0,1,1; 0.5,1,1; 0.5,1,0; 0.8,1,0; 0.8,0,0; 1,0,0],
    timeScale=1000,
    period=1000)
    "Heat pump On/Off command"

  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(
    filNam=Modelica.Utilities.Files.loadResource(
    "modelica://Buildings/Resources/weatherdata/USA_IL_Chicago-OHare.Intl.AP.725300_TMY3.mos"))
    "Outdoor conditions"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp THeaWatRetBou(
    y(displayUnit="degC", unit="K"),
    height=+5,
    duration=1000,
    offset=dat.hea.TRefLoa) "HW return temperature"
  Fluid.Sensors.TemperatureTwoPort THeaWatSup(
    redeclare package Medium = MediumHeaWat,
    final m_flow_nominal=heaPum.mHeaWat_flow_nominal)
    "HW supply temperature"
  Fluid.Sensors.TemperatureTwoPort THeaWatRet(
    redeclare package Medium = MediumHeaWat,
    final m_flow_nominal=heaPum.mHeaWat_flow_nominal)
    "HW return temperature"
equation
  connect(THeaWatSupSet.y,heaPum. TSet)
  connect(y1.y,heaPum. y1)
  connect(weaDat.weaBus,heaPum. weaBus)
  connect(THeaWatRetBou.y, bouHeaWat.T_in)
  connect(heaPum.port_b, THeaWatSup.port_a)
  connect(THeaWatSup.port_b, bouHeaWat.ports[1])
  connect(bouHeaWat.ports[2], THeaWatRet.port_a)
  connect(THeaWatRet.port_b, heaPum.port_a)
end HeatPumpGroup;


Validation of multiple pumps model with dp-controlled pump model. This model validates

Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsDp
by comparing an instance of that model with two instances of

Buildings.Fluid.Movers.FlowControlled_dp
connected in parallel.
The two pumps are commanded On one after the other as they receive
an increasing differential pressure setpoint and work
against a two-way modulating valve that gets progressively opened.

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model MultiplePumpsDp
  "Validation of multiple pumps model with dp-controlled pump model"
  extends BaseClasses.PartialMultiplePumps(
    redeclare final Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsDp pum,
    redeclare final Buildings.Fluid.Movers.FlowControlled_dp pum1(
      final m_flow_nominal=mPum_flow_nominal,
      final dp_nominal=dpPum_nominal),
    redeclare final Buildings.Fluid.Movers.FlowControlled_dp pum2(
      final m_flow_nominal=mPum_flow_nominal,
      final dp_nominal=dpPum_nominal));

  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp dpSet(
    height=dpPum_nominal, duration=500)
    "Differential pressure setpoint"
equation
  connect(dpSet.y, inp1.u1)
  connect(dpSet.y, inp2.u1)
  connect(inp1.y, pum1.dp_in)
  connect(inp2.y, pum2.dp_in)
  connect(dpSet.y, pum.dp_in)
end MultiplePumpsDp;


Validation of multiple pumps model with flow-controlled pump model. This model validates

Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsFlow
by comparing an instance of that model with two instances of

Buildings.Fluid.Movers.FlowControlled_m_flow
connected in parallel.
The two pumps are commanded On one after the other as they receive
an increasing flow setpoint and work against a two-way modulating
valve that gets progressively opened.

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model MultiplePumpsFlow
  "Validation of multiple pumps model with flow-controlled pump model"
  extends BaseClasses.PartialMultiplePumps(
    redeclare final Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsFlow pum,
    redeclare final Buildings.Fluid.Movers.FlowControlled_m_flow pum1(
      final m_flow_nominal=mPum_flow_nominal,
      final dp_nominal=dpPum_nominal),
    redeclare final Buildings.Fluid.Movers.FlowControlled_m_flow pum2(
      final m_flow_nominal=mPum_flow_nominal,
      final dp_nominal=dpPum_nominal));

  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp floSet(height=
        mPum_flow_nominal, duration=500) "Mass flow rate setpoint (each pump)"
  Buildings.Controls.OBC.CDL.Reals.Add floTotSet
    "Compute total flow rate setpoint (all pumps)"
equation
  connect(floSet.y, inp1.u1)
  connect(floSet.y, inp2.u1)
  connect(inp2.y, pum2.m_flow_in)
  connect(inp1.y, pum1.m_flow_in)
  connect(floTotSet.y, pum.m_flow_in)
  connect(inp1.y, floTotSet.u1)
  connect(inp2.y, floTotSet.u2)
end MultiplePumpsFlow;


Validation of multiple pumps model with speed-controlled pump model. This model validates

Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed
by comparing an instance of that model with two instances of

Buildings.Fluid.Movers.SpeedControlled_y
connected in parallel.
The two pumps are commanded On one after the other as they receive
an increasing speed signal and work against a two-way modulating valve
that gets progressively opened.

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model MultiplePumpsSpeed
  "Validation of multiple pumps model with speed-controlled pump model"
  extends BaseClasses.PartialMultiplePumps(
    redeclare final Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pum,
    redeclare final Fluid.Movers.SpeedControlled_y pum1,
    redeclare final Fluid.Movers.SpeedControlled_y pum2);

  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp spe(duration=500)
    "Pump speed signal"
equation
  connect(spe.y, pum.y)
  connect(spe.y, inp1.u1)
  connect(spe.y, inp2.u1)
  connect(inp1.y, pum1.y)
  connect(inp2.y, pum2.y)
end MultiplePumpsSpeed;


Package with validation models

within Buildings.DHC.Plants.Combined.Subsystems;
package Validation "Package with validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;


within Buildings.DHC.Plants.Combined.Subsystems.Validation;
model ValveOpeningFlowBalancing
  "Validation model for the computation of the valve opening ensuring flow balancing"
  extends Modelica.Icons.Example;
  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "CHW medium";

  parameter Real m1_flow = 1
    "Valve #1 design mass flow rate";
  parameter Real m2_flow = 1.5
    "Valve #2 design mass flow rate";
  parameter Real dpv1 = 1E3
    "Valve #1 design pressure drop";
  parameter Real dpv2 = 1E3
    "Valve #2 design pressure drop";
  parameter Real dpf1 = 3E4
    "Design pressure drop of fixed flow resistance in series with valve #1";
  parameter Real dpf2 = 5E4
    "Design pressure drop of fixed flow resistance in series with valve #2";
  parameter Real dps = 20E4;

  parameter Real y1 = if dpf2 + dpv2 - dpf1 <= 0 then 1 else
    (dpv1 / (dpf2 + dpv2 - dpf1))^0.5
    "Valve #1 opening";
  parameter Real y2 = if dpf1 + dpv1 - dpf2 <= 0 then 1 else
    (dpv2 / (dpf1 + dpv1 - dpf2))^0.5
    "Valve #2 opening";

  Fluid.Actuators.Valves.TwoWayLinear val1(
    redeclare package Medium = Medium,
    m_flow_nominal=m1_flow,
    linearized=true,
    dpValve_nominal=dpv1,
    use_strokeTime=false,
    dpFixed_nominal=dpf1)
    "Valve #1"
  Fluid.Actuators.Valves.TwoWayLinear val2(
    redeclare package Medium=Medium,
    m_flow_nominal=m2_flow,
    linearized=true,
    dpValve_nominal=dpv2,
    use_strokeTime=false,
    dpFixed_nominal=dpf2)
    "Valve #1"
  Fluid.Sources.Boundary_pT bou(
    p=Medium.p_default + dps,  nPorts=2,
    redeclare package Medium=Medium)
    "Pressure boundary condition"
  Fluid.Sources.Boundary_pT bou1(nPorts=2,
    redeclare package Medium=Medium)
    "Pressure boundary condition"
  Modelica.Blocks.Sources.RealExpression y[2](y={y1, y2})
    "Valve opening signal"
equation
  connect(bou.ports[1], val1.port_a)
  connect(val1.port_b, bou1.ports[1])
  connect(bou.ports[2],val2. port_a)
  connect(val2.port_b, bou1.ports[2])
  connect(y[1].y, val1.y)
  connect(y[2].y,val2. y)
end ValveOpeningFlowBalancing;


Package with base classes

within Buildings.DHC.Plants.Combined.Subsystems.Validation;
package BaseClasses "Package with base classes"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.DHC.Plants.Combined.Subsystems.Validation.BaseClasses;
partial model PartialMultiplePumps
  "Base class for validating the multiple pumps model"
  extends Modelica.Icons.Example;

  package Medium = Buildings.Media.Water
    "Medium model for hot water";

  parameter Integer nPum(
    final min=1)=2
    "Number of pumps"
  parameter Modelica.Units.SI.MassFlowRate mPum_flow_nominal=1
    "Pump mass flow rate (each pump)"
  parameter Modelica.Units.SI.PressureDifference dpPum_nominal = 1E5
    "Pump head (each pump)"
  final parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=
    nPum * mPum_flow_nominal
    "Circuit mass flow rate at design conditions";
  parameter Modelica.Units.SI.Pressure p_min = 2E5
    "Circuit minimum pressure";
  parameter Modelica.Units.SI.PressureDifference dp_nominal = dpPum_nominal
    "Circuit total pressure drop at design conditions";

  Fluid.Sources.Boundary_pT bou(
    redeclare final package Medium = Medium,
    final p=p_min,
    nPorts=2)
    "Pressure boundary condition"
  replaceable Buildings.DHC.Plants.Combined.Subsystems.MultiplePumpsSpeed pum
    constrainedby
    Buildings.DHC.Plants.Combined.Subsystems.BaseClasses.PartialMultiplePumps(
    redeclare final package Medium = Medium,
    final nPum=nPum,
    final mPum_flow_nominal=mPum_flow_nominal,
    final dpPum_nominal=dpPum_nominal,
    use_riseTime=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Multiple pumps in parallel - Speed controlled"

  Fluid.Sensors.RelativePressure senRelPre(redeclare package Medium = Medium)
    "Differential pressure sensor"
  Fluid.Sensors.MassFlowRate senMasFlo(redeclare package Medium = Medium)
    "Mass flow rate sensor"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ope(
    height=0.8,
    duration=300,
    offset=0.2,
    startTime=200)
    "Valve opening signal"
  Fluid.Actuators.Valves.TwoWayEqualPercentage val(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dpValve_nominal=5000,
    dpFixed_nominal=dp_nominal - val.dpValve_nominal)
    "Modulating valve"

  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Pum(
    table=[0,0,0; 1,0,0; 1,1,0; 4,1,1; 4,1,1; 10,1,1],
    timeScale=100,
    period=1000) "Pump Start signal"
  replaceable Fluid.Movers.SpeedControlled_y pum1 constrainedby
    Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine(
    redeclare final package Medium = Medium,
    final energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    use_riseTime=false,
    final per=pum.per,
    addPowerToMedium=false) "Pump"
  Fluid.FixedResistances.CheckValve cheVal1(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mPum_flow_nominal,
    final dpValve_nominal=pum.dpValve_nominal)
    "Check valve"
  replaceable Fluid.Movers.SpeedControlled_y pum2 constrainedby
    Buildings.Fluid.Movers.BaseClasses.PartialFlowMachine(
    redeclare final package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    use_riseTime=false,
    final per=pum.per,
    addPowerToMedium=false) "Pump"
  Fluid.FixedResistances.CheckValve cheVal2(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mPum_flow_nominal,
    final dpValve_nominal=pum.dpValve_nominal)
    "Check valve"
  Fluid.Actuators.Valves.TwoWayEqualPercentage val1(
    redeclare package Medium = Medium,
    m_flow_nominal=m_flow_nominal,
    dpValve_nominal=5000,
    dpFixed_nominal=dp_nominal - val.dpValve_nominal)
    "Modulating valve"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[2]
    "Convert to real"
  Fluid.Sensors.RelativePressure senRelPre1(redeclare package Medium = Medium)
    "Differential pressure sensor"
  Fluid.Sensors.MassFlowRate senMasFlo1(redeclare package Medium = Medium)
    "Mass flow rate sensor"
  Buildings.Controls.OBC.CDL.Reals.Multiply inp1
    "Compute pump input signal"
  Buildings.Controls.OBC.CDL.Reals.Multiply inp2
    "Compute pump input signal"
equation
  connect(bou.ports[1], pum.port_a)
  connect(val.port_b, pum.port_a)
  connect(pum.port_b, senRelPre.port_a)
  connect(ope.y, val.y)
  connect(y1Pum.y, pum.y1)
  connect(pum.port_b, senMasFlo.port_a)
  connect(senMasFlo.port_b, val.port_a)
  connect(senRelPre.port_b, pum.port_a)
  connect(pum1.port_b, cheVal1.port_a)
  connect(pum2.port_b, cheVal2.port_a)
  connect(val1.port_b, pum2.port_a)
  connect(val1.port_b, pum1.port_a)
  connect(val1.port_b, bou.ports[2])
  connect(y1Pum.y, booToRea.u)
  connect(cheVal2.port_b, senMasFlo1.port_a)
  connect(senMasFlo1.port_b, val1.port_a)
  connect(cheVal1.port_b, senMasFlo1.port_a)
  connect(senRelPre1.port_a, senMasFlo1.port_a)
  connect(senRelPre1.port_b, pum2.port_a)
  connect(booToRea[1].y, inp1.u2)
  connect(ope.y, val1.y)
  connect(booToRea[2].y, inp2.u2)
end PartialMultiplePumps;


Validation of all-electric plant model

within Buildings.DHC.Plants.Combined.Validation;
model AllElectricCWStorage "Validation of all-electric plant model"
  extends Modelica.Icons.Example;

  replaceable package Medium=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Main medium (common to CHW, HW and CW)";
  replaceable package MediumConWatCoo=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Medium in cooler circuit";

  replaceable parameter
    Fluid.Chillers.Data.ElectricReformulatedEIR.ReformEIRChiller_Carrier_19XR_1403kW_7_09COP_VSD datChi(
      EIRFunT={0.0101739374, 0.0607200115, 0.0003348647, 0.003162578, 0.0002388594, -0.0014121289},
      capFunT={0.0387084662, 0.2305017927, 0.0004779504, 0.0178244359, -8.48808e-05, -0.0032406711},
      EIRFunPLR={0.4304252832, -0.0144718912, 5.12039e-05, -0.7562386674, 0.5661683373,
        0.0406987748, 3.0278e-06, -0.3413411197, -0.000469572, 0.0055009208},
      QEva_flow_nominal=-1E6,
      COP_nominal=2.5,
    mEva_flow_nominal=-datChi.QEva_flow_nominal/5/4186,
      mCon_flow_nominal=-datChi.QEva_flow_nominal * (1 + 1/datChi.COP_nominal) / 10 / 4186,
    TEvaLvg_nominal=279.15,
    TEvaLvgMin=277.15,
    TEvaLvgMax=308.15,
    TConLvg_nominal=333.15,
    TConLvgMin=296.15,
    TConLvgMax=336.15)
    constrainedby Buildings.Fluid.Chillers.Data.BaseClasses.Chiller
    "Chiller parameters (each unit)"
  replaceable parameter Fluid.Chillers.Data.ElectricReformulatedEIR.Generic datChiHea=
    datChi
    constrainedby Buildings.Fluid.Chillers.Data.BaseClasses.Chiller
    "Chiller parameters (each unit)"
  replaceable parameter Fluid.HeatPumps.Data.EquationFitReversible.Generic datHeaPum(
    dpHeaLoa_nominal=50000,
    dpHeaSou_nominal=100,
    hea(
      mLoa_flow=datHeaPum.hea.Q_flow / 10 / 4186,
      mSou_flow=1E-4 * datHeaPum.hea.Q_flow,
      Q_flow=1E6,
      P=datHeaPum.hea.Q_flow / 2.2,
      coeQ={-5.64420084,  1.95212447,  9.96663913,  0.23316322, -5.64420084},
      coeP={-3.96682255,  6.8419453,   1.99606939,  0.01393387, -3.96682255},
      TRefLoa=298.15,
      TRefSou=253.15),
    coo(
      mLoa_flow=0,
      mSou_flow=0,
      Q_flow=-1,
      P=0,
      coeQ=fill(0, 5),
      coeP=fill(0, 5),
      TRefLoa=273.15,
      TRefSou=273.15))
    "Heat pump parameters (each unit)"

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

  Buildings.DHC.Plants.Combined.AllElectricCWStorage pla(
    redeclare final package Medium = Medium,
    redeclare package MediumHea_b = Medium,
    redeclare final package MediumConWatCoo = MediumConWatCoo,
    allowFlowReversal=true,
    dpConWatCooFri_nominal=1E4,
    mAirCooUni_flow_nominal=pla.mConWatCoo_flow_nominal/pla.nCoo/1.45,
    TWetBulCooEnt_nominal=297.05,
    PFanCoo_nominal=340*pla.mConWatCoo_flow_nominal/pla.nCoo,
    chi(show_T=true),
    chiHea(show_T=true),
    heaPum(show_T=true),
    final datChi=datChi,
    final datChiHea=datChiHea,
    final datHeaPum=datHeaPum,
    nChi=2,
    dpChiWatSet_max=20E4,
    nChiHea=2,
    dpHeaWatSet_max=20E4,
    nHeaPum=2,
    dInsTan=0.05,
    nCoo=3,
    final energyDynamics=energyDynamics)
    "CHW and HW plant"

  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSupSet(final k=pla.TChiWatSup_nominal,
    y(final unit="K", displayUnit="degC"))
                   "Source signal for setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet(final k=pla.THeaWatSup_nominal,
    y(final unit="K", displayUnit="degC"))
                   "Source signal for setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpHeaWatSet_max(
    k=pla.dpHeaWatSet_max,
    y(final unit="Pa")) "Source signal for setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpChiWatSet_max(
    k=pla.dpChiWatSet_max,
    y(final unit="Pa")) "Source signal for setpoint"
  BoundaryConditions.WeatherData.ReaderTMY3 weaDat(filNam=
        Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos"))
    "Outdoor conditions"
  Fluid.HeatExchangers.SensibleCooler_T disHeaWat(
    redeclare final package Medium = Medium,
    final m_flow_nominal=pla.mHeaWat_flow_nominal,
    final dp_nominal=0,
    final energyDynamics=energyDynamics,
    tau=300)
    "Distribution system approximated by prescribed return temperature"
  Fluid.HeatExchangers.Heater_T disChiWat(
    redeclare final package Medium = Medium,
    final m_flow_nominal=pla.mChiWat_flow_nominal,
    show_T=true,
    final dp_nominal=0,
    final energyDynamics=energyDynamics,
    tau=300)
    "Distribution system approximated by prescribed return temperature"

  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatRet(k=pla.THeaWatRet_nominal,
              y(final unit="K", displayUnit="degC"))
    "Source signal for HW return temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatRet(k=pla.TChiWatRet_nominal,
              y(final unit="K", displayUnit="degC"))
    "Source signal for CHW return temperature"
  Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1(
    table=[0,0,0; 4,1,1; 72,0,1; 96,0,0],
    timeScale=3600,
    period=96*3600) "Plant enable signal: y[1] for cooling, y[2] for heating"
  Fluid.Actuators.Valves.TwoWayPressureIndependent valDisHeaWat(
    redeclare final package Medium = Medium,
    m_flow_nominal=pla.mHeaWat_flow_nominal,
    dpValve_nominal=1E4,
    dpFixed_nominal=pla.dpHeaWatSet_max - valDisHeaWat.dpValve_nominal)
    "Distribution system approximated by variable flow resistance"
  Fluid.Actuators.Valves.TwoWayPressureIndependent valDisChiWat(
    redeclare final package Medium = Medium,
    m_flow_nominal=pla.mChiWat_flow_nominal,
    dpValve_nominal=1E4,
    dpFixed_nominal=pla.dpChiWatSet_max - valDisChiWat.dpValve_nominal)
    "Distribution system approximated by variable flow resistance"
  Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratFlo(table=[0,0,0;
        6,0,0; 10,0.3,0.1; 15,1,0.1; 24,0.1,0.1; 30,0.1,1; 39,1,0.3; 48,0.1,0.1;
        54,0.1,1; 63,0.1,0.3; 72,0,0; 78,0,1; 96,0,0],
                                    timeScale=3600)
    "Source signal: y[1] for cooling load, y[2] for heating load"
equation
  connect(TChiWatSupSet.y, pla.TChiWatSupSet)
  connect(THeaWatSupSet.y, pla.THeaWatSupSet)
  connect(dpChiWatSet_max.y, pla.dpChiWatSet)
  connect(dpHeaWatSet_max.y, pla.dpHeaWatSet)

  connect(weaDat.weaBus, pla.weaBus)
  connect(pla.port_bSerHea, disHeaWat.port_a)
  connect(pla.port_bSerCoo, disChiWat.port_a)
  connect(THeaWatRet.y, disHeaWat.TSet)
  connect(TChiWatRet.y, disChiWat.TSet)
  connect(u1.y[1], pla.u1Coo)
  connect(disHeaWat.port_b, valDisHeaWat.port_a)
  connect(valDisHeaWat.port_b, pla.port_aSerHea)
  connect(disChiWat.port_b, valDisChiWat.port_a)
  connect(valDisChiWat.port_b, pla.port_aSerCoo)
  connect(ratFlo.y[2], valDisHeaWat.y)
  connect(ratFlo.y[1], valDisChiWat.y)
  connect(u1.y[2], pla.u1Hea)
end AllElectricCWStorage;


Package with validation models

within Buildings.DHC.Plants.Combined;
package Validation "Package with validation models"
  extends Modelica.Icons.ExamplesPackage;
end Validation;