within Buildings.DHC.Plants.Combined;
model AllElectricCWStorage
  "All-electric CHW and HW plant with CW storage"
  extends BaseClasses.PartialPlant(
    final typ=Buildings.DHC.Types.DistrictSystemType.CombinedGeneration2to4,
    final have_weaBus=true,
    final have_fan=true,
    final have_pum=true,
    final have_eleHea=true,
    final have_eleCoo=true);

  replaceable package MediumAir=Buildings.Media.Air
    "Air medium";
  replaceable package MediumConWatCoo=Buildings.Media.Water
    constrainedby Modelica.Media.Interfaces.PartialMedium
    "Medium model for cooling tower circuit"

  // CHW loop and cooling-only chillers
  parameter Integer nChi(final min=1, start=1)
    "Number of units operating at design conditions"
  parameter Integer nPumChiWat(final min=1, start=1)=max(nChi, nChiHea)
    "Number of CHW pumps operating at design conditions"
  final parameter Modelica.Units.SI.MassFlowRate mChiWatChi_flow_nominal(
    final min=0)=datChi.mEva_flow_nominal
    "Design chiller CHW mass flow rate (each unit)"
  parameter Modelica.Units.SI.MassFlowRate mChiWatChi_flow_min(
    final min=0)=0.6 * mChiWatChi_flow_nominal
    "Chiller CHW minimum mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mConWatChi_flow_nominal(
    final min=0)=datChi.mCon_flow_nominal
    "Design chiller CW mass flow rate (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpChiWatSet_max(
    final min=0,
    displayUnit="Pa")
    "Design (maximum) CHW differential pressure setpoint"
  parameter Modelica.Units.SI.PressureDifference dpEvaChi_nominal(
    final min=0,
    displayUnit="Pa")=5E4
    "Design evaporator pressure drop (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpConChi_nominal(
    final min=0,
    displayUnit="Pa")=5E4
    "Design condenser pressure drop (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpPumChiWat_nominal(
    final min=0,
    displayUnit="Pa")=1.1 * (dpChiWatSet_max + max(
      dpEvaChi_nominal + chi.valEva.dpValve_nominal,
      dpEvaChiHea_nominal + max(chiHea.valEva.dpValve_nominal) + sum(chiHea.valEvaSwi.dpValve_nominal)))
    "Design head of CHW pump(each unit)"

  replaceable parameter Fluid.Chillers.Data.ElectricReformulatedEIR.Generic datChi
    constrainedby Buildings.Fluid.Chillers.Data.BaseClasses.Chiller
    "Chiller parameters (each unit)"

  final parameter Modelica.Units.SI.Temperature TChiWatSup_nominal=
    max(chi.TChiWatSup_nominal, chiHea.TChiWatSup_nominal)
    "Design (minimum) CHW supply temperature"
  final parameter Modelica.Units.SI.Temperature TChiWatRet_nominal=
    TChiWatSup_nominal - QChiWat_flow_nominal / mChiWat_flow_nominal / cp_default
    "Design (maximum) CHW return temperature"
  // Plant capacity computed with HRCs in direct heat recovery mode, see
  // Buildings.DHC.Plants.Combined.Controls.BaseClasses.StagingPlant.
  final parameter Modelica.Units.SI.HeatFlowRate QChiWat_flow_nominal=
    chi.QChiWat_flow_nominal + chiHea.QChiWat_flow_nominal
    "Design plant cooling heat flow rate (all units)";
  final parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal(
    final min=0)=
    nChi * mChiWatChi_flow_nominal + nChiHea * mChiWatChiHea_flow_nominal
    "Design CHW mass flow rate (all units)"

  parameter Modelica.Units.SI.TemperatureDifference dTLifChi_min=10
    "Minimum chiller lift at minimum load"
  parameter Modelica.Units.SI.TemperatureDifference dTLifChi_nominal=
    TTanSet[1, 2] + 5 - TChiWatSup_nominal
    "Design chiller lift"

  // HW loop and heat recovery chillers
  parameter Integer nChiHea(final min=1, start=1)
    "Number of units operating at design conditions"
  parameter Integer nPumHeaWat(final min=1, start=1) = nChiHea
    "Number of HW pumps operating at design conditions"
  final parameter Modelica.Units.SI.MassFlowRate mChiWatChiHea_flow_nominal=
    datChiHea.mEva_flow_nominal
    "Design HRC CHW mass flow rate (each unit)"
  parameter Modelica.Units.SI.MassFlowRate mChiWatChiHea_flow_min(
    final min=0)=0.6 * mChiWatChiHea_flow_nominal
    "HRC CHW minimum mass flow rate (each unit)"
  parameter Modelica.Units.SI.MassFlowRate mHeaWatChiHea_flow_min(
    final min=0)=0.6 * mConWatChiHea_flow_nominal
    "HRC HW minimum mass flow rate (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mConWatChiHea_flow_nominal=
    datChiHea.mCon_flow_nominal
    "Design HRC CW mass flow rate (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpHeaWatSet_max(
    final min=0,
    displayUnit="Pa")
    "Design (maximum) HW differential pressure setpoint"
  parameter Modelica.Units.SI.PressureDifference dpEvaChiHea_nominal(
    final min=0,
    displayUnit="Pa")=5E4
    "Design evaporator  pressure drop (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpConChiHea_nominal(
    final min=0,
    displayUnit="Pa")=5E4
    "Design condenser pressure drop (each unit)"

  parameter Modelica.Units.SI.PressureDifference dpPumHeaWat_nominal(
    final min=0,
    displayUnit="Pa")=1.1 * (dpHeaWatSet_max +
      dpConChiHea_nominal + max(chiHea.valCon.dpValve_nominal) +
      sum(chiHea.valConSwi.dpValve_nominal))
    "Design head of HW pump(each unit)"

  replaceable parameter Fluid.Chillers.Data.ElectricReformulatedEIR.Generic datChiHea
    constrainedby Buildings.Fluid.Chillers.Data.BaseClasses.Chiller
    "HRC parameters (each unit)"

  final parameter Modelica.Units.SI.Temperature THeaWatSup_nominal=
    chiHea.THeaWatSup_nominal
    "Design (maximum) HW supply temperature"
  final parameter Modelica.Units.SI.Temperature THeaWatRet_nominal=
    THeaWatSup_nominal - QHeaWat_flow_nominal / mHeaWat_flow_nominal / cp_default
    "Design (minimum) HW return temperature"

  // TCasHeaEnt_nominal computed in second cycle of TES tank.
  final parameter Modelica.Units.SI.Temperature TCasHeaEnt_nominal=
    TTanSet[2, 2]
    "Design evaporator entering temperature in cascading heating mode"
  // TCasCooEnt_nominal computed in Heat Rejection mode.
  final parameter Modelica.Units.SI.Temperature TCasCooEnt_nominal=
    TConWatCooSup_nominal + dTHexCoo_nominal
    "Design condenser entering temperature in cascading cooling mode"
  final parameter Modelica.Units.SI.HeatFlowRate QHeaWat_flow_nominal=
    chiHea.QHeaWat_flow_nominal
    "Design heating heat flow rate (all units)"
  final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal=
    chiHea.mConWat_flow_nominal
    "Design HW mass flow rate (all units)"

  // CW loop, TES tank and heat pumps
  parameter Integer nHeaPum(final min=1, start=1)
    "Number of heat pumps operating at design conditions"
  parameter Integer nPumConWatCon(final min=1, start=1)=max(nChi, nChiHea)
    "Number of CW pumps serving condenser barrels at design conditions"
  parameter Integer nPumConWatEva(final min=1, start=1)=nChiHea
    "Number of CW pumps serving evaporator barrels at design conditions"
  parameter Modelica.Units.SI.PressureDifference dpConWatConSet_max(
    final min=0,
    displayUnit="Pa")=max(
     dpConChi_nominal + chi.valCon.dpValve_nominal,
     dpConChiHea_nominal + max(chiHea.valCon.dpValve_nominal) + sum(chiHea.valConSwi.dpValve_nominal))
    "Design (maximum) CW condenser loop differential pressure setpoint"
  parameter Modelica.Units.SI.PressureDifference dpConWatEvaSet_max(
    final min=0,
    displayUnit="Pa")=
    dpEvaChiHea_nominal + max(chiHea.valEva.dpValve_nominal) + sum(chiHea.valEvaSwi.dpValve_nominal)
    "Design (maximum) CW evaporator loop differential pressure setpoint"
  parameter Modelica.Units.SI.PressureDifference dpPumConWatCon_nominal(
    final min=0,
    displayUnit="Pa")=1.1 * (dpConWatConSet_max + max(dpHexCoo_nominal, dpTan_nominal))
    "Design head of CW pump serving condenser barrels (each unit)"
  parameter Modelica.Units.SI.PressureDifference dpPumConWatEva_nominal(
    final min=0,
    displayUnit="Pa")=1.1 * (dpConWatEvaSet_max + dpTan_nominal)
    "Design head of CW pump serving evaporator barrels (each unit)"
  final parameter Modelica.Units.SI.MassFlowRate mConWatCon_flow_nominal(
    final min=0)=chi.mConWat_flow_nominal + chiHea.mConWat_flow_nominal
    "Design total CW mass flow rate through condenser barrels (all units)";
  final parameter Modelica.Units.SI.MassFlowRate mConWatEva_flow_nominal(
    final min=0)=chiHea.mChiWat_flow_nominal
    "Design total CW mass flow rate through evaporator barrels (all units)"
  parameter Modelica.Units.SI.Volume VTan=
    -chiHea.QEvaCasHea_flow_nominal * 3 * 3600 / (max(TTanSet) - min(TTanSet)) /
    cp_default / rho_default
    "Tank volume"
  parameter Modelica.Units.SI.Length hTan = (16 * VTan / Modelica.Constants.pi)^(1/3)
    "Height of tank (without insulation)"
  // Default considering 1 m high thermmocline and 1 m high section below and above diffusers.
  // Thermocline only useless during last tank cycle, hence the scale factor.
  parameter Real fraUslTan(final unit="1", final min=0, final max=1, start=0.1) =
    ((max(TTanSet[2]) - min(TTanSet)) / (max(TTanSet) - min(TTanSet)) * 1 + 1) / hTan
    "Useless fraction of TES"
  parameter Modelica.Units.SI.Length dInsTan
    "Thickness of insulation"
  parameter Modelica.Units.SI.ThermalConductivity kInsTan=0.04
    "Specific heat conductivity of insulation"
  parameter Integer nSegTan(min=2) = 10
    "Number of volume segments"
  parameter Modelica.Units.SI.Temperature TTanSet[2, 2] = {
    {15 + 273.15, 25 + 273.15},
    {TChiWatSup_nominal, 15 + 273.15}}
    "Tank temperature setpoints: 2 cycles with 2 setpoints"
  // Default TES tank pressure drop without PSV, otherwise ~ 20E3
  parameter Modelica.Units.SI.PressureDifference dpTan_nominal(displayUnit="Pa")=1E3
    "Design pressure drop through TES tank"
  replaceable parameter Fluid.HeatPumps.Data.EquationFitReversible.Generic datHeaPum
    "Heat pump parameters (each unit)"

  // Buildings.DHC.Plants.Cooling tower loop
  parameter Integer nCoo(final min=1, start=1)
    "Number of cooling tower cells operating at design conditions"
  parameter Modelica.Units.SI.MassFlowRate mConWatCoo_flow_nominal(
    final min=0)=mConWatCon_flow_nominal
    "Design CT CW mass flow rate (all units)"
  parameter Modelica.Units.SI.PressureDifference dpConWatCooFri_nominal(
    displayUnit="Pa",
    start=1E4,
    final min=0)
    "Design CW flow-friction losses through tower and piping only (without elevation head or valve)"
  parameter Modelica.Units.SI.MassFlowRate mAirCooUni_flow_nominal(
    final min=0,
    start=mConWatCoo_flow_nominal / nCoo / 1.45)
    "Design CT air mass flow rate (each unit)"
  parameter Modelica.Units.SI.Temperature TWetBulCooEnt_nominal(
    final min=273.15)
    "Design CT entering air wetbulb temperature"
  parameter Modelica.Units.SI.Temperature TConWatCooRet_nominal(
    final min=273.15)=TConWatCooSup_nominal +
    abs(QHexCoo_flow_nominal) / mConWatCoo_flow_nominal / cpConWatCoo_default
    "Design CT CW return temperature (tower entering)"
  parameter Modelica.Units.SI.Temperature TConWatCooSup_nominal(
    final min=273.15)=TWetBulCooEnt_nominal + 3
    "Design CT CW supply temperature (tower leaving)"
  parameter Modelica.Units.SI.Power PFanCoo_nominal(
    final min=0,
    start=340 * mConWatCoo_flow_nominal / nCoo)
    "CT fan power (each unit)"

  parameter Integer nPumConWatCoo(final min=1, start=1)=nCoo
    "Number of CW pumps serving cooling towers at design conditions"
  parameter Modelica.Units.SI.PressureDifference dpPumConWatCoo_nominal=
    1.1 * (dpHexCoo_nominal + dpConWatCooFri_nominal)
    "Design head of CW pump serving cooling towers (each unit)"

  parameter Modelica.Units.SI.TemperatureDifference dTHexCoo_nominal=2
    "Design heat exchanger approach"
  parameter Modelica.Units.SI.PressureDifference dpHexCoo_nominal=3E4
    "Design pressure drop through heat exchanger (same on both sides)"

  // HX sized with all HRCs in cascading cooling mode.
  parameter Modelica.Units.SI.HeatFlowRate QHexCoo_flow_nominal=
    -(chi.QConWat_flow_nominal + chiHea.QConCasCoo_flow_nominal)
    "Design cooling heat flow rate of heat exchanger (<0)"

  // 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
    "Time needed to open or close valve"

  parameter Boolean use_riseTime=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState
    "Time needed to change motor speed"
  // Outside connectors

  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Coo
    "Cooling enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Hea
    "Heating enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSupSet(
    final unit="K",
    displayUnit="degC")
    "CHW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput dpChiWatSet(
    final unit="Pa",
    final min=0)
    "CHW differential pressure setpoint (for local dp sensor)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatSupSet(
    final unit="K",
    displayUnit="degC")
    "HW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHeaWatSet(
    final unit="Pa",
    final min=0)
    "HW differential pressure setpoint (for local dp sensor)"

  // Components - CHW loop and cooling-only chillers
  Subsystems.ChillerGroup chi(
    redeclare final package Medium1=Medium,
    redeclare final package Medium2=Medium,
    final dat=datChi,
    final nUni=nChi,
    final dpEva_nominal=dpEvaChi_nominal,
    final dpCon_nominal=dpConChi_nominal,
    final energyDynamics=energyDynamics,
    final use_strokeTime=use_strokeTime,
    final allowFlowReversal1=allowFlowReversal,
    final allowFlowReversal2=allowFlowReversal)
    "Cooling-only chillers"
  Subsystems.MultiplePumpsSpeed pumChiWat(
    redeclare final package Medium=Medium,
    final nPum=nPumChiWat,
    final have_var=true,
    final have_valve=true,
    final mPum_flow_nominal=mChiWat_flow_nominal / nPumChiWat,
    final dpPum_nominal=dpPumChiWat_nominal,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final allowFlowReversal=allowFlowReversal)
    "Primary CHW pumps"
  Fluid.FixedResistances.Junction junChiWatSup(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mChiWat_flow_nominal * {1, -1, -1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal
      then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
      else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal
      then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
      else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal
      then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
      else Modelica.Fluid.Types.PortFlowDirection.Leaving)
    "Fluid junction"
  Fluid.FixedResistances.Junction junChiWatRet(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mChiWat_flow_nominal * {1, -1, 1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal
      then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
      else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal
      then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
      else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal
      then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
       else Modelica.Fluid.Types.PortFlowDirection.Entering)
   "Fluid junction"
  Fluid.FixedResistances.Junction junChiWatChiHeaRet(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mChiWat_flow_nominal * {1,-1,-1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving) "Fluid junction"
  Fluid.FixedResistances.Junction junChiWatChiHeaSup(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mChiWat_flow_nominal*{1,-1,1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering) "Fluid junction"
  // PICV model sized at design flow (instead of minimum flow) for convenience.
  Fluid.Actuators.Valves.TwoWayLinear valChiWatMinByp(
    redeclare final package Medium=Medium,
    final m_flow_nominal=max(mChiWatChi_flow_min, mChiWatChiHea_flow_min),
    from_dp=true,
    linearized=true,
    dpValve_nominal=1E3,
    final use_strokeTime=use_strokeTime,
    final allowFlowReversal=allowFlowReversal)
    "CHW minimum flow bypass valve"
  Fluid.Sensors.RelativePressure dpChiWat(
    redeclare final package Medium=Medium)
    "CHW differential pressure (local sensor hardwired to plant controller)"
  Fluid.Sensors.TemperatureTwoPort TChiWatPriRet(
    redeclare final package Medium=Medium,
    final m_flow_nominal=mChiWat_flow_nominal,
    final allowFlowReversal=allowFlowReversal) "Primary CHW return temperature"
  Fluid.Sensors.MassFlowRate mChiWatPri_flow(
    redeclare final package Medium =Medium,
    final allowFlowReversal=allowFlowReversal) "Primary CHW mass flow rate"
  Fluid.Sensors.TemperatureTwoPort TChiWatSup(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mChiWat_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "CHW supply temperature"

  // Components - HW loop and heat recovery chillers
  Subsystems.ChillerHeatRecoveryGroup chiHea(
    redeclare final package Medium = Medium,
    final dat=datChiHea,
    final nUni=nChiHea,
    final TCasCooEnt_nominal=TCasCooEnt_nominal,
    final TCasHeaEnt_nominal=TCasHeaEnt_nominal,
    final dpEva_nominal=dpEvaChiHea_nominal,
    final dpCon_nominal=dpConChiHea_nominal,
    final allowFlowReversal=allowFlowReversal,
    final use_strokeTime=use_strokeTime,
    final energyDynamics=energyDynamics)
    "Heat recovery chillers"

  Subsystems.MultiplePumpsSpeed pumHeaWat(
    redeclare final package Medium=Medium,
    final nPum=nPumHeaWat,
    final have_var=true,
    final have_valve=true,
    final mPum_flow_nominal=mHeaWat_flow_nominal/nPumHeaWat,
    final dpPum_nominal=dpPumHeaWat_nominal,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final allowFlowReversal=allowFlowReversal)
    "Primary HW pumps"
  Fluid.FixedResistances.Junction junHeaWatSup(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mHeaWat_flow_nominal * {1,-1,-1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving) "Fluid junction"
  Fluid.FixedResistances.Junction junHeaWatRet(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mHeaWat_flow_nominal * {1,-1,1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
       else Modelica.Fluid.Types.PortFlowDirection.Entering) "Fluid junction"
  // PICV model sized at design flow (instead of minimum flow) for convenience.
  Fluid.Actuators.Valves.TwoWayLinear valHeaWatMinByp(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mHeaWatChiHea_flow_min,
    from_dp=true,
    linearized=true,
    dpValve_nominal=1E3,
    final use_strokeTime=use_strokeTime,
    final allowFlowReversal=allowFlowReversal) "HW minimum flow bypass valve"
  Fluid.Sensors.RelativePressure dpHeaWat(
    redeclare final package Medium =Medium)
    "HW differential pressure (local sensor hardwired to plant controller)"
  Fluid.Sensors.TemperatureTwoPort THeaWatPriRet(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mHeaWat_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "Primary HW return temperature"
  Fluid.Sensors.TemperatureTwoPort THeaWatSup(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mHeaWat_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "HW supply temperature"
  Fluid.Sensors.MassFlowRate mHeaWatPri_flow(
    redeclare final package Medium =Medium,
    final allowFlowReversal=allowFlowReversal)
    "Primary HW mass flow rate"

  // Components - CW loop and heat pumps
  Subsystems.MultiplePumpsSpeed pumConWatCon(
    redeclare final package Medium = Medium,
    final nPum=nPumConWatCon,
    final have_var=true,
    final have_valve=true,
    final mPum_flow_nominal=mConWatCon_flow_nominal / nPumConWatCon,
    final dpPum_nominal=dpPumConWatCon_nominal,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final allowFlowReversal=allowFlowReversal)
    "CW pumps serving condenser barrels"
  Subsystems.MultiplePumpsSpeed pumConWatEva(
    redeclare final package Medium = Medium,
    final nPum=nPumConWatEva,
    final have_var=true,
    final have_valve=true,
    final mPum_flow_nominal=mConWatEva_flow_nominal / nPumConWatEva,
    final dpPum_nominal=dpPumConWatEva_nominal,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final allowFlowReversal=allowFlowReversal)
    "CW pumps serving evaporator barrels"
  Fluid.FixedResistances.Junction junConWatEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal*{1,-1,-1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving) "Fluid junction"
  Fluid.Storage.Stratified tan(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final VTan=VTan,
    final hTan=hTan,
    final dIns=dInsTan,
    final kIns=kInsTan,
    final nSeg=nSegTan)
    "TES tank"
  Fluid.Sources.Boundary_pT bouConWat(
    redeclare final package Medium = Medium,
    final p=hTan * rho_default * Modelica.Constants.g_n,
    final nPorts=1)
    "CW pressure boundary condition prescribed by tank operating level"
  Fluid.FixedResistances.Junction junConWatTanEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal*{1,-1,-1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=Modelica.Fluid.Types.PortFlowDirection.Bidirectional)
    "Fluid junction"
  Fluid.FixedResistances.Junction junConWatLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal*{1,-1,1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering) "Fluid junction"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor TTan[nSegTan](
    T(each displayUnit="degC"))
    "TES tank temperature sensor gateway"
  HeatTransfer.Sources.PrescribedTemperature out "Outdoor temperature"
  Fluid.FixedResistances.Junction junConWatHeaPumEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal*{1,-1,-1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving)
    "Fluid junction"
  Fluid.FixedResistances.Junction junConWatHeaPumLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal*{1,-1,1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering)
    "Fluid junction"
  Subsystems.HeatPumpGroup heaPum(
    redeclare final package Medium = Medium,
    redeclare final package MediumAir = MediumAir,
    final nUni=nHeaPum,
    final dat=datHeaPum,
    final energyDynamics=energyDynamics,
    final use_riseTime=use_riseTime,
    final allowFlowReversal=allowFlowReversal)
    "Heat pumps"
  Fluid.FixedResistances.Junction junConWatTanLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal*{1,-1,1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering) "Fluid junction"
  Fluid.HeatExchangers.PlateHeatExchangerEffectivenessNTU hexCoo(
    redeclare final package Medium1=MediumConWatCoo,
    redeclare final package Medium2=Medium,
    final m1_flow_nominal=mConWatCoo_flow_nominal,
    final m2_flow_nominal=mConWatCon_flow_nominal,
    final dp1_nominal=0,
    final dp2_nominal=0,
    final Q_flow_nominal=QHexCoo_flow_nominal,
    final T_a1_nominal=TConWatCooSup_nominal,
    final T_a2_nominal=TConWatCooRet_nominal + dTHexCoo_nominal,
    final allowFlowReversal1=allowFlowReversal,
    final allowFlowReversal2=allowFlowReversal,
    final configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow)
    "Heat exchanger with cooling tower circuit"
  Subsystems.CoolingTowerGroup coo(
    redeclare final package Medium=Medium,
    final nUni=nCoo,
    final mConWatUni_flow_nominal=mConWatCoo_flow_nominal / nCoo,
    final dpConWatFriUni_nominal=dpConWatCooFri_nominal + dpHexCoo_nominal,
    final mAirUni_flow_nominal=mAirCooUni_flow_nominal,
    final TWetBulEnt_nominal=TWetBulCooEnt_nominal,
    final TConWatRet_nominal=TConWatCooRet_nominal,
    final TConWatSup_nominal=TConWatCooSup_nominal,
    final PFanUni_nominal=PFanCoo_nominal,
    final energyDynamics=energyDynamics,
    final allowFlowReversal=allowFlowReversal)
    "Cooling towers"
  Fluid.Actuators.Valves.ThreeWayLinear valBypTan(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final energyDynamics=energyDynamics,
    dpValve_nominal=1E3,
    dpFixed_nominal={dpTan_nominal,dpHexCoo_nominal})
    "TES tank bypass valve"
  Fluid.Sources.Boundary_pT bouConWatCoo(
    redeclare final package Medium = Medium,
    final p=130000,
    nPorts=1)
    "CW pressure boundary condition prescribed by CT elevation head"
  Subsystems.MultiplePumpsSpeed pumConWatCoo(
    redeclare final package Medium = Medium,
    final nPum=nPumConWatCoo,
    final have_var=true,
    have_valve=false,
    final mPum_flow_nominal=mConWatCoo_flow_nominal / nPumConWatCoo,
    final dpPum_nominal=dpPumConWatCoo_nominal,
    final energyDynamics=energyDynamics,
    final allowFlowReversal=allowFlowReversal) "Cooling tower pumps"
  Fluid.Sensors.TemperatureTwoPort TConWatEvaEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatEva_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "HRC evaporator entering CW temperature"

  // Controls
  Buildings.DHC.Plants.Combined.Controls.Controller ctl(
    final nChi=nChi,
    final nPumChiWat=nPumChiWat,
    final QHeaPum_flow_nominal=datHeaPum.hea.Q_flow*nHeaPum,
    final dTLifChi_min=dTLifChi_min,
    final dTLifChi_nominal=dTLifChi_nominal,
    final nChiHea=nChiHea,
    final nPumHeaWat=nPumHeaWat,
    final nHeaPum=nHeaPum,
    final nPumConWatCon=nPumConWatCon,
    final nPumConWatEva=nPumConWatEva,
    final TTanSet=TTanSet,
    final nCoo=nCoo,
    final nPumConWatCoo=nPumConWatCoo,
    final THeaWatSup_nominal=THeaWatSup_nominal,
    final TChiWatSup_nominal=TChiWatSup_nominal,
    final mChiWat_flow_nominal=mChiWat_flow_nominal,
    final mHeaWat_flow_nominal=mHeaWat_flow_nominal,
    final mConWatCon_flow_nominal=mConWatCon_flow_nominal,
    final mConWatEva_flow_nominal=mConWatEva_flow_nominal,
    final mChiWatChi_flow_nominal=mChiWatChi_flow_nominal,
    final mChiWatChi_flow_min=mChiWatChi_flow_min,
    final mConWatChi_flow_nominal=mConWatChi_flow_nominal,
    final mChiWatChiHea_flow_nominal=mChiWatChiHea_flow_nominal,
    final mChiWatChiHea_flow_min=mChiWatChiHea_flow_min,
    final mConWatChiHea_flow_nominal=mConWatChiHea_flow_nominal,
    final mHeaWatChiHea_flow_min=mHeaWatChiHea_flow_min,
    final dpChiWatSet_max=dpChiWatSet_max,
    final dpHeaWatSet_max=dpHeaWatSet_max,
    final dpConWatConSet_max=dpConWatConSet_max,
    final dpConWatEvaSet_max=dpConWatEvaSet_max,
    final dpEvaChi_nominal=dpEvaChi_nominal,
    final dpValEvaChi_nominal=chi.valEva.dpValve_nominal,
    final dpEvaChiHea_nominal=dpEvaChiHea_nominal,
    final dpValEvaChiHea_nominal=max(chiHea.valEva.dpValve_nominal),
    final QChiWatChi_flow_nominal=chi.QChiWat_flow_nominal,
    final QChiWatCasCoo_flow_nominal=chiHea.QChiWatCasCoo_flow_nominal,
    final QChiWatCasCoo_flow_nominal_approx=chiHea.QChiWat_flow_nominal,
    final QHeaWat_flow_nominal=QHeaWat_flow_nominal,
    final cp_default=cp_default,
    final fraUslTan=fraUslTan,
    final dTHexCoo_nominal=dTHexCoo_nominal,
    final nTTan=nSegTan)
    "Controller"

  // Miscellaneous
  Modelica.Blocks.Sources.RealExpression sumPHea(
    final y=heaPum.P + sum({
      if ctl.y1CooChiHea[i] or ctl.y1HeaCooChiHea[i] then 0 else chiHea.chi[i].P
      for i in 1:nChiHea}))
    "Sum up power drawn from all subsystems"
  Modelica.Blocks.Sources.RealExpression sumPCoo(
    final y=chi.P + sum({
      if ctl.y1CooChiHea[i] or ctl.y1HeaCooChiHea[i] then chiHea.chi[i].P else 0
      for i in 1:nChiHea}))
    "Sum up power drawn from all subsystems"
  Modelica.Blocks.Sources.RealExpression sumPFan(y=coo.P)
    "Sum up power drawn from all subsystems"
  Modelica.Blocks.Sources.RealExpression sumPPum(
    final y=pumChiWat.P + pumHeaWat.P + pumConWatCon.P + pumConWatEva.P + pumConWatCoo.P + heaPum.PPum)
    "Sum up power drawn from all subsystems"

  Fluid.Sensors.RelativePressure dpConWatEva(redeclare final package Medium =
        Medium) "CW evaporator loop differential pressure "
  Fluid.Sensors.RelativePressure dpConWatCon(redeclare final package Medium =
        Medium) "CW condenser loop differential pressure "
  Fluid.Sensors.MassFlowRate mConWatEva_flow(redeclare final package Medium =
        Medium, final allowFlowReversal=allowFlowReversal)
    "CW evaporator loop mass flow rate"
  Fluid.Sensors.MassFlowRate mConWatCon_flow(redeclare final package Medium =
        Medium, final allowFlowReversal=allowFlowReversal)
    "CW condenser loop mass flow rate"
  Fluid.Sensors.MassFlowRate mConWatOutTan_flow(redeclare final package Medium =
        Medium, final allowFlowReversal=allowFlowReversal)
    "Mass flow rate out of lower port of TES tank (>0 when charging)"
  Fluid.Sensors.TemperatureTwoPort TConWatConChiLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "Chiller and HRC leaving CW temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatConChiEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "Chiller and HRC entering CW temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatCooSup(
    redeclare final package Medium = MediumConWatCoo,
    final m_flow_nominal=mConWatCoo_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "Cooling tower loop CW supply temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatCooRet(
    redeclare final package Medium = MediumConWatCoo,
    final m_flow_nominal=mConWatCoo_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "Cooling tower loop CW return temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatHexCooEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal) "HX entering CW temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatHexCooLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal) "HX leaving CW temperature"
  Fluid.Actuators.Valves.ThreeWayLinear valConWatEvaMix(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatEva_flow_nominal,
    final energyDynamics=energyDynamics,
    dpValve_nominal=1E3,
    final dpFixed_nominal=fill(0, 2)) "HRC evaporator CW mixing valve"
  Fluid.FixedResistances.Junction junConWatEvaLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatEva_flow_nominal*{1,-1,-1},
    final dp_nominal=fill(0, 3),
    final energyDynamics=energyDynamics,
    final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Entering,
    final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving,
    final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional
         else Modelica.Fluid.Types.PortFlowDirection.Leaving)
    "Fluid junction"
  Fluid.Sensors.TemperatureTwoPort TConWatConRet(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal)
    "Condenser loop CW return temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatHeaPumEnt(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal) "HP entering CW temperature"
  Fluid.Sensors.TemperatureTwoPort TConWatHeaPumLvg(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    final allowFlowReversal=allowFlowReversal) "HP leaving CW temperature"
protected
  final parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default)
    "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
    Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";
  final parameter Modelica.Units.SI.Density rho_default=
    Medium.density(sta_default)
    "Density of the fluid";
  final parameter MediumConWatCoo.ThermodynamicState staConWatCoo_default=
    MediumConWatCoo.setState_pTX(
    T=MediumConWatCoo.T_default,
    p=MediumConWatCoo.p_default,
    X=MediumConWatCoo.X_default)
    "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cpConWatCoo_default=
    MediumConWatCoo.specificHeatCapacityCp(staConWatCoo_default)
    "Specific heat capacity of the fluid";
public
  Fluid.Sensors.MassFlowRate mConWatHexCoo_flow(redeclare final package Medium =
        Medium, final allowFlowReversal=allowFlowReversal)
    "CW mass flow rate through secondary (plant) side of HX"
  Fluid.Actuators.Valves.TwoWayLinear valConWatByp(
    redeclare final package Medium = Medium,
    final m_flow_nominal=mConWatCon_flow_nominal,
    from_dp=true,
    linearized=true,
    dpValve_nominal=1E3,
    final use_strokeTime=use_strokeTime,
    final allowFlowReversal=allowFlowReversal)
    "CW chiller bypass valve"
equation
  connect(junChiWatSup.port_2, port_bSerCoo)
  connect(junChiWatSup.port_3, valChiWatMinByp.port_a)
  connect(valChiWatMinByp.port_b, junChiWatRet.port_3)
  connect(junChiWatSup.port_2, dpChiWat.port_a)
  connect(TChiWatPriRet.port_a, junChiWatRet.port_2)
  connect(port_aSerCoo, junChiWatRet.port_1)
  connect(dpChiWat.port_b, junChiWatRet.port_1)
  connect(junHeaWatSup.port_3, valHeaWatMinByp.port_a)
  connect(valHeaWatMinByp.port_b, junHeaWatRet.port_3)
  connect(THeaWatPriRet.port_a, junHeaWatRet.port_2)
  connect(dpHeaWat.port_b, junHeaWatRet.port_1)
  connect(junHeaWatSup.port_2, port_bSerHea)
  connect(ctl.y1Chi, chi.y1)
  connect(ctl.yValConChi, chi.yValCon)
  connect(TChiWatSupSet, chi.TSet)
  connect(ctl.y1PumChiWat, pumChiWat.y1)
  connect(ctl.y1PumHeaWat, pumHeaWat.y1)
  connect(ctl.yValChiWatMinByp, valChiWatMinByp.y)
  connect(ctl.yValHeaWatMinByp, valHeaWatMinByp.y)
  connect(THeaWatPriRet.port_b, mHeaWatPri_flow.port_a)
  connect(TChiWatPriRet.port_b, mChiWatPri_flow.port_a)
  connect(ctl.y1PumConWatEva, pumConWatEva.y1)
  connect(ctl.yPumConWatEva, pumConWatEva.y)
  connect(sumPHea.y, PHea)
  connect(sumPCoo.y, PCoo)
  connect(sumPFan.y, PFan)
  connect(sumPPum.y, PPum)
  connect(junHeaWatSup.port_2, dpHeaWat.port_a)
  connect(pumChiWat.port_b, TChiWatSup.port_a)
  connect(TChiWatSup.port_b, junChiWatSup.port_1)
  connect(tan.heaPorVol, TTan.port)
  connect(out.port, tan.heaPorTop)
  connect(out.port, tan.heaPorSid)
  connect(out.port, tan.heaPorBot)
  connect(pumHeaWat.port_b, THeaWatSup.port_a)
  connect(THeaWatSup.port_b, junHeaWatSup.port_1)
  connect(junConWatHeaPumEnt.port_2, junConWatHeaPumLvg.port_1)
  connect(weaBus.TDryBul, out.T)
  connect(weaBus, heaPum.weaBus)
  connect(ctl.y1HeaPum, heaPum.y1)
  connect(ctl.THeaPumSet, heaPum.TSet)
  connect(bouConWat.ports[1], tan.port_b)
  connect(ctl.yPumChiWat, pumChiWat.y)
  connect(ctl.yPumHeaWat, pumHeaWat.y)
  connect(mChiWatPri_flow.port_b,junChiWatChiHeaRet. port_1)
  connect(junChiWatChiHeaRet.port_2, chi.port_a2)
  connect(port_aSerHea, junHeaWatRet.port_1)
  connect(junConWatTanEnt.port_2, valBypTan.port_2)
  connect(valBypTan.port_1, tan.port_a)
  connect(ctl.yValBypTan, valBypTan.y)
  connect(bouConWatCoo.ports[1], pumConWatCoo.port_a)
  connect(coo.port_b, pumConWatCoo.port_a)
  connect(weaBus, coo.weaBus)
  connect(ctl.yCoo, coo.y)
  connect(ctl.y1PumConWatCoo, pumConWatCoo.y1)
  connect(chi.port_b1, junConWatLvg.port_3)
  connect(chiHea.port_b1, pumHeaWat.port_a)
  connect(mHeaWatPri_flow.port_b, chiHea.port_a1)
  connect(junChiWatChiHeaRet.port_3, chiHea.port_a4)
  connect(junConWatEnt.port_2, chiHea.port_a3)
  connect(chiHea.port_b3, junConWatLvg.port_1)
  connect(ctl.yValEvaChiHea, chiHea.yValEva)
  connect(ctl.y1CooChiHea, chiHea.y1Coo)
  connect(ctl.y1ChiHea, chiHea.y1)
  connect(ctl.yValConChiHea, chiHea.yValCon)
  connect(ctl.TChiHeaSet, chiHea.TSet)
  connect(ctl.yValEvaChi, chi.yValEva)
  connect(junChiWatChiHeaSup.port_2, pumChiWat.port_a)
  connect(chi.port_b2, junChiWatChiHeaSup.port_1)
  connect(chiHea.port_b4, junChiWatChiHeaSup.port_3)
  connect(TConWatEvaEnt.port_b, chiHea.port_a2)
  connect(TChiWatSupSet, ctl.TChiWatSupSet)
  connect(dpChiWatSet, ctl.dpChiWatSet)
  connect(THeaWatSupSet, ctl.THeaWatSupSet)
  connect(dpHeaWatSet, ctl.dpHeaWatSet)
  connect(u1Coo, ctl.u1Coo)
  connect(u1Hea, ctl.u1Hea)
  connect(mChiWatPri_flow.m_flow, ctl.mChiWatPri_flow)
  connect(dpChiWat.p_rel, ctl.dpChiWat)
  connect(mHeaWatPri_flow.m_flow, ctl.mHeaWatPri_flow)
  connect(dpHeaWat.p_rel, ctl.dpHeaWat)
  connect(pumConWatEva.port_b, dpConWatEva.port_a)
  connect(pumConWatEva.port_b, mConWatEva_flow.port_a)
  connect(mConWatEva_flow.port_b, TConWatEvaEnt.port_a)
  connect(junConWatTanLvg.port_2, mConWatCon_flow.port_a)
  connect(mConWatCon_flow.port_b, pumConWatCon.port_a)
  connect(mConWatCon_flow.m_flow, ctl.mConWatCon_flow)
  connect(mConWatEva_flow.m_flow, ctl.mConWatEva_flow)
  connect(dpConWatEva.p_rel, ctl.dpConWatEva)
  connect(dpConWatCon.p_rel, ctl.dpConWatCon)
  connect(TChiWatPriRet.T, ctl.TChiWatPriRet)
  connect(THeaWatPriRet.T, ctl.THeaWatPriRet)
  connect(TTan.T, ctl.TTan)
  connect(tan.port_b, mConWatOutTan_flow.port_a)
  connect(mConWatHexCoo_flow.m_flow, ctl.mConWatHexCoo_flow)
  connect(mConWatOutTan_flow.m_flow, ctl.mConWatOutTan_flow)
  connect(junConWatEnt.port_3, chi.port_a1)
  connect(chi.mCon_flow, ctl.mConChi_flow)
  connect(chi.mEva_flow, ctl.mEvaChi_flow)
  connect(chiHea.mCon_flow, ctl.mConChiHea_flow)
  connect(chiHea.mEva_flow, ctl.mEvaChiHea_flow)
  connect(ctl.yValConSwiChiHea, chiHea.yValConSwi)
  connect(ctl.yValEvaSwiHea, chiHea.yValEvaSwi)
  connect(TChiWatSup.T, ctl.TChiWatSup)
  connect(chiHea.TEvaLvg, ctl.TEvaLvgChiHea)
  connect(junConWatLvg.port_2, TConWatConChiLvg.port_a)
  connect(TConWatConChiLvg.port_b, junConWatHeaPumEnt.port_1)
  connect(THeaWatSup.T, ctl.THeaWatSup)
  connect(TConWatConChiEnt.port_b, junConWatEnt.port_1)
  connect(pumConWatCoo.port_b, TConWatCooSup.port_a)
  connect(TConWatCooSup.port_b, hexCoo.port_a1)
  connect(hexCoo.port_b1, TConWatCooRet.port_a)
  connect(TConWatCooRet.port_b, coo.port_a)
  connect(valBypTan.port_3, TConWatHexCooEnt.port_a)
  connect(TConWatHexCooEnt.port_b, hexCoo.port_a2)
  connect(hexCoo.port_b2, TConWatHexCooLvg.port_a)
  connect(TConWatHexCooLvg.port_b, mConWatHexCoo_flow.port_a)
  connect(TConWatConChiLvg.T, ctl.TConWatConChiLvg)
  connect(TConWatConChiEnt.T, ctl.TConWatConChiEnt)
  connect(TConWatCooSup.T, ctl.TConWatCooSup)
  connect(TConWatCooRet.T, ctl.TConWatCooRet)
  connect(TConWatHexCooEnt.T, ctl.TConWatHexCooEnt)
  connect(TConWatHexCooLvg.T, ctl.TConWatHexCooLvg)
  connect(ctl.yPumConWatCoo, pumConWatCoo.y)
  connect(chiHea.TConLvg, ctl.TConLvgChiHea)
  connect(chiHea.TConEnt, ctl.TConEntChiHea)
  connect(junConWatTanEnt.port_3, valConWatEvaMix.port_1)
  connect(valConWatEvaMix.port_2, pumConWatEva.port_a)
  connect(junConWatEvaLvg.port_3, valConWatEvaMix.port_3)
  connect(junConWatEvaLvg.port_3, dpConWatEva.port_b)
  connect(chiHea.port_b2, junConWatEvaLvg.port_1)
  connect(junConWatEvaLvg.port_2, junConWatTanLvg.port_3)
  connect(TConWatEvaEnt.T, ctl.TConWatEvaEnt)
  connect(ctl.yValConWatEvaMix, valConWatEvaMix.y)
  connect(junConWatHeaPumLvg.port_2, TConWatConRet.port_a)
  connect(TConWatConRet.port_b, junConWatTanEnt.port_1)
  connect(TConWatConRet.T, ctl.TConWatConRet)
  connect(chi.TConLvg, ctl.TConLvgChi)
  connect(junConWatHeaPumEnt.port_3, TConWatHeaPumEnt.port_a)
  connect(TConWatHeaPumEnt.port_b, heaPum.port_a)
  connect(heaPum.port_b, TConWatHeaPumLvg.port_a)
  connect(TConWatHeaPumLvg.port_b, junConWatHeaPumLvg.port_3)
  connect(ctl.y1Coo, coo.y1)
  connect(mConWatHexCoo_flow.port_b, junConWatTanLvg.port_1)
  connect(mConWatOutTan_flow.port_b, junConWatTanLvg.port_1)
  connect(ctl.yPumConWatCon, pumConWatCon.y)
  connect(ctl.y1PumConWatCon, pumConWatCon.y1)
  connect(pumConWatCon.port_b, valConWatByp.port_b)
  connect(ctl.yValConWatByp, valConWatByp.y)
  connect(pumConWatCon.port_b, TConWatConChiEnt.port_a)
  connect(pumConWatCon.port_b, dpConWatCon.port_a)
  connect(valConWatByp.port_a, TConWatConChiLvg.port_a)
  connect(dpConWatCon.port_b, TConWatConChiLvg.port_a)
end AllElectricCWStorage;


within Buildings.DHC.Plants;
package Combined "Package of models for central plants that provide heating and cooling"
  extends Modelica.Icons.VariantsPackage;
end Combined;


Plant controller. This block implements the following control functions.

within Buildings.DHC.Plants.Combined.Controls;
block Controller "Plant controller"
  extends BaseClasses.PartialController;

  Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator repHeaPum(
    final nout=nHeaPum) "Replicate signal"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal cvtValBypTan
    "Convert DO to AO"
  Buildings.Controls.OBC.CDL.Reals.Switch TChiHeaSupSet[nChiHea]
    "Switch supply temperature setpoint"
  BaseClasses.StagingPump staPumChiWat(
    final nPum=nPumChiWat,
    final m_flow_nominal=mChiWat_flow_nominal)
    "CHW pump staging"
  ETS.Combined.Controls.PIDWithEnable pumChiWat(
    k=0.1,
    Ti=60,
    r=dpChiWatSet_max,
    y_reset=1,
    y_neutral=0)
    "Pump speed controller"
  ETS.Combined.Controls.PIDWithEnable pumHeaWat(
    k=0.1,
    Ti=60,
    r=dpHeaWatSet_max,
    y_reset=1,
    y_neutral=0)
    "Pump speed controller"
  BaseClasses.StagingPump staPumHeaWat(
    final nPum=nPumHeaWat,
    final m_flow_nominal=mHeaWat_flow_nominal)
    "HW pump staging"
  BaseClasses.StagingPump staPumConWatCon(
    final nPum=nPumConWatCon,
    final m_flow_nominal=mConWatCon_flow_nominal)
    "CW pump staging"
  ETS.Combined.Controls.PIDWithEnable pumConWatCon(
    k=0.1,
    Ti=60,
    final r=dpConWatConSet_max,
    y_reset=1,
    y_neutral=0)
    "Pump speed controller"
  ETS.Combined.Controls.PIDWithEnable pumConWatEva(
    k=0.1,
    Ti=60,
    final r=dpConWatEvaSet_max,
    y_reset=1,
    y_neutral=0)
    "Pump speed controller"
  BaseClasses.StagingPump staPumConWatEva(
    final nPum=nPumConWatEva,
    final m_flow_nominal=mConWatEva_flow_nominal)
    "CW pump staging"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpConNom(final k=
        dpConWatConSet_max) "Constant"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpEvaNom(final k=
        dpConWatEvaSet_max) "Constant"
  BaseClasses.StagingPlant staPla(
    final nChi=nChi,
    final QChiWatChi_flow_nominal=QChiWatChi_flow_nominal,
    final nChiHea=nChiHea,
    final QChiWatCasCoo_flow_nominal=QChiWatCasCoo_flow_nominal,
    final QChiWatCasCoo_flow_nominal_approx=QChiWatCasCoo_flow_nominal_approx,
    final QHeaWat_flow_nominal=QHeaWat_flow_nominal,
    final cp_default=cp_default) "Plant staging"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator repTSet(nout=nChiHea)
    "Replicate signal"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator repTSet1(nout=nChiHea)
    "Replicate signal"
  BaseClasses.ModeCondenserLoop modConLoo(
    final mConWatHexCoo_flow_nominal=mConWatCon_flow_nominal,
    final QHeaPum_flow_nominal=QHeaPum_flow_nominal,
    final TTanSet=TTanSet,
    final fraUslTan=fraUslTan,
    final ratFraChaTanLim=ratFraChaTanLim,
    final cp_default=cp_default,
    nTTan=nTTan) "Condenser loop operating mode"
  BaseClasses.TankCycle cycTan(
    mConWatHexCoo_flow_nominal=mConWatCon_flow_nominal,
                               final TTanSet=TTanSet, nTTan=nTTan)
    "Determine tank cycle"
  Buildings.Controls.OBC.CDL.Integers.Equal isModChaAss
    "Return true if charge assist mode is active"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant chaAss(
    final k=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.chargeAssist)
    "Charge assist mode index"
  Buildings.Controls.OBC.CDL.Logical.And assAndPum
    "Charge assist mode and any CW pump On"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaPumSetVal[2](
    final k={max(TTanSet[i]) + 3 for i in 1:2})
    "HP supply temperature setpoint for each tank cycle"
  Buildings.Controls.OBC.CDL.Routing.RealExtractor extIndRea(final nin=2)
    "Extract active setpoint"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant heaRej(
    final k=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.heatRejection)
    "Heat rejection mode index"
  Buildings.Controls.OBC.CDL.Integers.Equal isModHeaRej
    "Return true if heat rejection mode is active"
  Buildings.Controls.OBC.CDL.Logical.Not isModNotHeaRej
    "Return true if heat rejection mode is NOT active"
  BaseClasses.ValveCondenserEvaporator valConEva(
    final nChi=nChi,
    final nChiHea=nChiHea,
    final mChiWatChi_flow_nominal=mChiWatChi_flow_nominal,
    final mChiWatChi_flow_min=mChiWatChi_flow_min,
    final mConWatChi_flow_nominal=mConWatChi_flow_nominal,
    final dpEvaChi_nominal=dpEvaChi_nominal,
    final dpValEvaChi_nominal=dpValEvaChi_nominal,
    final mChiWatChiHea_flow_nominal=mChiWatChiHea_flow_nominal,
    final mChiWatChiHea_flow_min=mChiWatChiHea_flow_min,
    final mConWatChiHea_flow_nominal=mConWatChiHea_flow_nominal,
    final mHeaWatChiHea_flow_min=mHeaWatChiHea_flow_min,
    final dpEvaChiHea_nominal=dpEvaChiHea_nominal,
    final dpValEvaChiHea_nominal=dpValEvaChiHea_nominal,
    final TTanSet=TTanSet)
    "Controller for chiller and HRC condenser and evaporator valves"
  Buildings.DHC.Plants.Combined.Controls.BaseClasses.DirectHeatRecovery dirHeaCoo(
    final nChi=nChi,
    final nChiHea=nChiHea,
    final mChiWatChi_flow_nominal=mChiWatChi_flow_nominal,
    final mChiWatChi_flow_min=mChiWatChi_flow_min,
    final mChiWatChiHea_flow_nominal=mChiWatChiHea_flow_nominal,
    final mChiWatChiHea_flow_min=mChiWatChiHea_flow_min)
    "Control logic for HRC in direct HR mode"
  BaseClasses.CoolingTowerLoop coo(
    final mConWatHexCoo_flow_nominal=mConWatCon_flow_nominal,
    final nCoo=nCoo,
    final nPumConWatCoo=nPumConWatCoo,
    final QChiWat_flow_nominal=QChiWat_flow_nominal,
    final dTLifChi_min=dTLifChi_min,
    final dTLifChi_nominal=dTLifChi_nominal,
    final TTanSet=TTanSet,
    final dTHexCoo_nominal=dTHexCoo_nominal) "Cooling tower loop"
  Buildings.Controls.OBC.CDL.Logical.Or u1CooOrHea
    "Plant Enable signal: either cooling or heating is enabled"
equation
  connect(repHeaPum.y, y1HeaPum)
  connect(cvtValBypTan.y, yValBypTan)
  connect(staPumChiWat.y1, y1PumChiWat)
  connect(pumChiWat.y, yPumChiWat)
  connect(dpChiWatSet, pumChiWat.u_s)
  connect(staPumHeaWat.y1, y1PumHeaWat)
  connect(pumHeaWat.y, yPumHeaWat)
  connect(dpHeaWatSet, pumHeaWat.u_s)
  connect(pumConWatEva.y, yPumConWatEva)
  connect(pumConWatCon.y, yPumConWatCon)
  connect(staPumConWatCon.y1, y1PumConWatCon)
  connect(staPumConWatEva.y1, y1PumConWatEva)
  connect(dpHeaWat, pumHeaWat.u_m)
  connect(mHeaWatPri_flow, staPumHeaWat.m_flow)
  connect(dpChiWat, pumChiWat.u_m)
  connect(mConWatEva_flow, staPumConWatEva.m_flow)
  connect(mConWatCon_flow, staPumConWatCon.m_flow)
  connect(mChiWatPri_flow, staPumChiWat.m_flow)
  connect(dpConNom.y, pumConWatCon.u_s)
  connect(dpEvaNom.y, pumConWatEva.u_s)
  connect(mHeaWatPri_flow, staPla.mHeaWatPri_flow)
  connect(THeaWatSupSet, staPla.THeaWatSupSet)
  connect(mChiWatPri_flow, staPla.mChiWatPri_flow)
  connect(u1Coo, staPla.u1Coo)
  connect(u1Hea, staPla.u1Hea)
  connect(TChiWatSupSet, staPla.TChiWatSupSet)
  connect(TChiWatPriRet, staPla.TChiWatPriRet)
  connect(THeaWatPriRet, staPla.THeaWatPriRet)
  connect(repTSet1.y, TChiHeaSupSet.u3)
  connect(repTSet.y, TChiHeaSupSet.u1)
  connect(staPla.y1CooChiHea, TChiHeaSupSet.u2)
  connect(TChiHeaSupSet.y, TChiHeaSet)
  connect(TChiWatSupSet, repTSet.u)
  connect(THeaWatSupSet, repTSet1.u)
  connect(mConWatHexCoo_flow, modConLoo.mConWatHexCoo_flow)
  connect(mConWatOutTan_flow, modConLoo.mConWatOutTan_flow)
  connect(TTan, modConLoo.TTan)
  connect(TTan, cycTan.TTan)
  connect(mConWatOutTan_flow, cycTan.mConWatOutTan_flow)
  connect(chaAss.y, isModChaAss.u2)
  connect(modConLoo.mode, isModChaAss.u1)
  connect(assAndPum.y, repHeaPum.u)
  connect(isModChaAss.y, assAndPum.u1)
  connect(THeaPumSetVal.y, extIndRea.u)
  connect(extIndRea.y, THeaPumSet)
  connect(cycTan.idxCycTan, extIndRea.index)
  connect(heaRej.y, isModHeaRej.u1)
  connect(modConLoo.mode, isModHeaRej.u2)
  connect(isModNotHeaRej.y, cvtValBypTan.u)
  connect(isModHeaRej.y, isModNotHeaRej.u)
  connect(mEvaChi_flow,valConEva. mEvaChi_flow)
  connect(mConChi_flow,valConEva. mConChi_flow)
  connect(mEvaChiHea_flow,valConEva. mEvaChiHea_flow)
  connect(mConChiHea_flow,valConEva. mConChiHea_flow)
  connect(staPla.y1Chi,valConEva. u1Chi)
  connect(staPla.y1ChiHea,valConEva. u1ChiHea)
  connect(staPla.y1CooChiHea,valConEva. u1CooChiHea)
  connect(staPla.y1HeaCooChiHea,valConEva. u1HeaCooChiHea)
  connect(valConEva.yValEvaChi, yValEvaChi)
  connect(valConEva.yValConChi, yValConChi)
  connect(valConEva.yValConSwiChiHea, yValConSwiChiHea)
  connect(valConEva.yValEvaSwiChiHea, yValEvaSwiHea)
  connect(valConEva.yValConChiHea, yValConChiHea)
  connect(valConEva.yValEvaChiHea, yValEvaChiHea)
  connect(dpConWatEva, pumConWatEva.u_m)
  connect(dpConWatCon, pumConWatCon.u_m)
  connect(cycTan.idxCycTan,valConEva. idxCycTan)
  connect(modConLoo.mode,valConEva. mode)
  connect(TChiWatSup, staPla.TChiWatSup)
  connect(dpChiWatSet, staPla.dpChiWatSet)
  connect(dpChiWat, staPla.dpChiWat)
  connect(valConEva.y1PumChiWat, staPumChiWat.y1Ena)
  connect(pumChiWat.y, staPumChiWat.y)
  connect(pumHeaWat.y, staPumHeaWat.y)
  connect(valConEva.y1PumHeaWat, staPumHeaWat.y1Ena)
  connect(pumConWatCon.y, staPumConWatCon.y)
  connect(pumConWatEva.y, staPumConWatEva.y)
  connect(valConEva.y1PumConWatEva, staPumConWatEva.y1Ena)
  connect(valConEva.y1PumConWatCon, staPumConWatCon.y1Ena)
  connect(staPla.y1Chi, y1Chi)
  connect(staPla.y1ChiHea, y1ChiHea)
  connect(staPla.y1CooChiHea, y1CooChiHea)
  connect(staPla.y1HeaCooChiHea, y1HeaCooChiHea)
  connect(staPla.y1ChiHea, dirHeaCoo.y1)
  connect(staPla.y1HeaCooChiHea, dirHeaCoo.y1HeaCoo)
  connect(TChiWatSupSet, dirHeaCoo.TChiWatSupSet)
  connect(TEvaLvgChiHea, dirHeaCoo.TEvaLvg)
  connect(THeaWatPriRet, dirHeaCoo.THeaWatPriRet)
  connect(dirHeaCoo.mEvaChiSet_flow,valConEva. mEvaChiSet_flow)
  connect(dirHeaCoo.mEvaChiHeaSet_flow,valConEva. mEvaChiHeaSet_flow)
  connect(dpHeaWatSet, staPla.dpHeaWatSet)
  connect(dpHeaWat, staPla.dpHeaWat)
  connect(THeaWatSup, staPla.THeaWatSup)
  connect(coo.y1PumConWatCoo, y1PumConWatCoo)
  connect(coo.yPumConWatCoo, yPumConWatCoo)
  connect(coo.y1Coo, y1Coo)
  connect(coo.yCoo, yCoo)
  connect(cycTan.idxCycTan, coo.idxCycTan)
  connect(modConLoo.mode, coo.mode)
  connect(TChiWatSupSet, coo.TChiWatSupSet)
  connect(TConWatConChiEnt, coo.TConWatConChiEnt)
  connect(TConWatConChiLvg, coo.TConWatConChiLvg)
  connect(TConWatCooSup, coo.TConWatCooSup)
  connect(TConWatCooRet, coo.TConWatCooRet)
  connect(TConWatHexCooEnt, coo.TConWatHexCooEnt)
  connect(TConWatHexCooLvg, coo.TConWatHexCooLvg)
  connect(staPla.QCooReq_flow, coo.QCooReq_flow)
  connect(mConWatHexCoo_flow, coo.mConWatHexCoo_flow)
  connect(cvtValBypTan.y, coo.yValBypTan)
  connect(dirHeaCoo.TConEntChiHeaSet,valConEva. TConEntChiHeaSet)
  connect(TConEntChiHea,valConEva. TConEntChiHea)
  connect(staPumConWatCon.y1Any, pumConWatCon.uEna)
  connect(staPumConWatEva.y1Any, pumConWatEva.uEna)
  connect(staPumConWatCon.y1Any, assAndPum.u2)
  connect(staPumHeaWat.y1Any, pumHeaWat.uEna)
  connect(staPumChiWat.y1Any, pumChiWat.uEna)
  connect(valConEva.yValConWatEvaMix, yValConWatEvaMix)
  connect(TEvaLvgChiHea, valConEva.TEvaLvgChiHea)
  connect(TConWatEvaEnt, valConEva.TConWatEvaEnt)
  connect(TConLvgChiHea, valConEva.TConLvgChiHea)
  connect(TConLvgChi, valConEva.TConLvgChi)
  connect(TConWatConRet, valConEva.TConWatConRet)
  connect(valConEva.yValChiWatMinByp, yValChiWatMinByp)
  connect(valConEva.yValHeaWatMinByp, yValHeaWatMinByp)
  connect(valConEva.yValConWatByp, yValConWatByp)
  connect(mConWatCon_flow, modConLoo.mConWatCon_flow)
  connect(TConWatConChiLvg, modConLoo.TConWatConChiLvg)
  connect(TConWatConRet, modConLoo.TConWatConRet)
  connect(u1Coo, u1CooOrHea.u1)
  connect(u1Hea, u1CooOrHea.u2)
  connect(u1CooOrHea.y, valConEva.u1CooOrHea)
end Controller;


within Buildings.DHC.Plants.Combined;
package Controls "Package of control blocks for combined plants"
  extends Modelica.Icons.VariantsPackage;
end Controls;


Cooling tower loop control. This block implements the control logic for the CT pumps and
CT fans.

within Buildings.DHC.Plants.Combined.Controls.BaseClasses;
block CoolingTowerLoop "Cooling tower loop control"

  parameter Modelica.Units.SI.MassFlowRate mConWatHexCoo_flow_nominal
    "Design total CW mass flow rate through condenser barrels (all units)";
  parameter Integer nCoo(final min=1, start=1)
    "Number of cooling tower cells operating at design conditions"
  parameter Integer nPumConWatCoo(final min=1, start=1)
    "Number of CW pumps serving cooling towers at design conditions"
  parameter Modelica.Units.SI.HeatFlowRate QChiWat_flow_nominal
    "Design plant cooling heat flow rate (all units)";
  parameter Modelica.Units.SI.TemperatureDifference dTLifChi_min
    "Minimum chiller lift at minimum load";
  parameter Modelica.Units.SI.TemperatureDifference dTLifChi_nominal
    "Design chiller lift";
  parameter Modelica.Units.SI.Temperature TTanSet[2, 2]
    "Tank temperature setpoints: 2 cycles with 2 setpoints";
  parameter Modelica.Units.SI.TemperatureDifference dTHexCoo_nominal
    "Design heat exchanger approach";
  parameter Real yPumConWatCoo_min[nPumConWatCoo](each final unit="1")=
    {0.2/i for i in 1:nPumConWatCoo}
    "Tower pump speed needed to maintain minimum tower flow (each pump stage)";

  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput mode(
    final min=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.tankCharge,
    final max=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.heatRejection)
    "Condenser loop operating mode"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput idxCycTan(
    final min=1,
    final max=2)
    "Index of active tank cycle"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatCooSup(final unit="K",
      displayUnit="degC") "Cooling tower loop CW supply temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mConWatHexCoo_flow(
    final unit="kg/s")
    "CW mass flow rate through secondary side of HX"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput  QCooReq_flow(
    final unit="W")
    "Plant required cooling capacity (>0)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatConChiEnt(final unit=
        "K", displayUnit="degC") "Chiller and HRC entering CW temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatConChiLvg(final unit=
        "K", displayUnit="degC") "Chiller and HRC leaving CW temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSupSet(final unit="K",
      displayUnit="degC") "CHW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatCooRet(final unit="K",
      displayUnit="degC") "Cooling tower loop CW return temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValBypTan(final unit="1")
    "TES tank bypass valve commanded position"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatHexCooEnt(final unit=
        "K", displayUnit="degC") "HX entering CW temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatHexCooLvg(final unit=
        "K", displayUnit="degC") "HX leaving CW temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumConWatCoo[
    nPumConWatCoo] "Cooling tower pump Start command"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCoo
    "Cooling tower fan speed command"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumConWatCoo
    "Cooling tower pump speed command"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Coo[nCoo]
    "Cooling tower Start command"
  Buildings.Controls.OBC.CDL.Reals.Subtract delTemCon "Compute CW deltaT"
  Buildings.Controls.OBC.CDL.Reals.MovingAverage mea(delta=5*60)
    "Moving mean"
  Buildings.Controls.OBC.CDL.Reals.Subtract delTem1 "Compute deltaT"
  Buildings.Controls.OBC.CDL.Reals.Add lifPlu "Add target lift"
  Buildings.Controls.OBC.CDL.Reals.AddParameter subApp(final p=-
        dTHexCoo_nominal) "Substract HX approach"
  Buildings.Controls.OBC.CDL.Reals.Switch TSupSetUnb(y(unit="K",
        displayUnit="degC"))
    "Compute tower supply temperature setpoint, unbounded"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant modRej(
    final k=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.heatRejection)
    "Heat rejection mode index"
  Buildings.Controls.OBC.CDL.Integers.Equal isModRej "Heat rejection mode"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant setOth[2](final k=
        TTanSet[:, 1] .- dTHexCoo_nominal)
    "Target setpoint in any mode other than heat rejection"
  Buildings.Controls.OBC.CDL.Routing.RealExtractor extSet(final nin=2)
    "Extract setpoint value based on current mode"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter ratDes(final k=abs(1
        /QChiWat_flow_nominal)) "Ratio to design capacity"
  Buildings.Controls.OBC.CDL.Reals.Line lif "Compute target chiller lift"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xLif[2](k={0.1,1})
    "x-value for lift reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yLif[2](final k={
        dTLifChi_min,dTLifChi_nominal}) "y-value for lift reset"
  StagingPump staPum(
    nPum=nPumConWatCoo,
    have_flowCriterion=false,
    yDow=0.4,
    yUp=0.8)
    "Stage pumps"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold cmpFlo(t=0.025*
        mConWatHexCoo_flow_nominal, h=0.025*mConWatHexCoo_flow_nominal/2)
    "Flow criterion to enable lead pump"
  Buildings.Controls.OBC.CDL.Logical.Timer timFlo(t=60)
    "Timer for flow exceeding triggering limit"
  Buildings.Controls.OBC.CDL.Logical.Timer timFlo1(t=5*60)
    "Timer for flow exceeding triggering limit"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold cmpOpe(t=0.99, h=0.005)
    "Valve opening criterion to enable lead pump"
  Buildings.Controls.OBC.CDL.Logical.Timer timOpe(t=60)
    "Timer for valve opening exceeding triggering limit"
  Buildings.Controls.OBC.CDL.Logical.Timer timOpe1(t=60)
    "Timer for valve opening exceeding triggering limit"
  Buildings.Controls.OBC.CDL.Logical.Not not1
    "Valve opening criterion to disable lead pump"
  Buildings.Controls.OBC.CDL.Logical.Or dis "Disable condition"
  Buildings.Controls.OBC.CDL.Logical.And ena "Enable condition"
  Buildings.Controls.OBC.CDL.Logical.Latch enaLea "Enable lead pump"
  Buildings.Controls.OBC.CDL.Reals.Subtract delTem2 "Compute deltaT"
  Buildings.Controls.OBC.CDL.Reals.Subtract delTem3 "Compute deltaT"
  Buildings.Controls.OBC.CDL.Reals.AddParameter addOff(final p=-1)
    "Add offset"
  Buildings.Controls.OBC.CDL.Reals.AddParameter addApp(final p=
        dTHexCoo_nominal) "Add HX approach"
  ETS.Combined.Controls.PIDWithEnable ctlPum1(
    k=0.01,
    Ti=60,
    final reverseActing=false) "Pump control loop #1"
  ETS.Combined.Controls.PIDWithEnable ctlPum2(
    k=0.01,
    Ti=60,
    final reverseActing=false)
                              "Pump control loop #1"
  Buildings.Controls.OBC.CDL.Reals.Min minCtlPum "Minimum loop output"
  Buildings.Controls.OBC.CDL.Reals.Line pum "Pump speed command"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xPum[2](k={0,1})
    "x-value for pump speed reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant one(final k=1)
    "Constant"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumMin[nPumConWatCoo](
     final k=yPumConWatCoo_min) "Minimum pump speed"
  Buildings.Controls.OBC.CDL.Routing.RealExtractor extYPumMin(final nin=
        nPumConWatCoo)
    "Extract minimum pump speed value based on current pump stage"
  Modelica.Blocks.Sources.IntegerExpression nPumBou(y=max(1, staPum.nPumEna))
    "Number of pumps commanded on, bounded by 1"
  Buildings.Controls.OBC.CDL.Reals.Line fanMax "Compute maximum fan speed"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xFan[2](k={0,0.5})
    "x-value for maximum fan speed reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yFan[2](final k={0.7,1.0})
    "y-value for maximum fan speed reset"
  ETS.Combined.Controls.PIDWithEnable ctlFan(
    k=0.05,
    Ti=60,
    final reverseActing=false) "Fan control loop"
  Buildings.Controls.OBC.CDL.Logical.Pre pre1
    "Left limit of signal to avoid direct feedback"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant setMax(k=25 + 273.15)
    "Maximum setpoint"
  Buildings.Controls.OBC.CDL.Reals.Min TSupSet(
    y(unit="K", displayUnit="degC"))
    "Compute tower supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Reals.Line fan "Compute fan speed"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xFan1
                                                             [2](k={0,1})
    "x-value for fan speed reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yFan1(final k=0)
    "y-value for fan speed reset"
  Buildings.Controls.OBC.CDL.Logical.Not not2
    "Flow criterion to disable lead pump"
  Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rep(final nout=
        nCoo) "Replicate"
  Buildings.Controls.OBC.CDL.Logical.Not notDis "Not disabled"
  Buildings.Controls.OBC.CDL.Logical.And enaAndNotDis
    "Reset enable condition when disable is true to trigger latch block when (enable, disable) becomes (true, false) again"
equation
  connect(QCooReq_flow, ratDes.u)
  connect(ratDes.y, lif.u)
  connect(xLif[1].y, lif.x1)
  connect(xLif[2].y, lif.x2)
  connect(yLif[1].y, lif.f1)
  connect(yLif[2].y, lif.f2)
  connect(TConWatConChiLvg, delTemCon.u1)
  connect(TConWatConChiEnt, delTemCon.u2)
  connect(delTemCon.y, mea.u)
  connect(lif.y, lifPlu.u1)
  connect(TChiWatSupSet, lifPlu.u2)
  connect(lifPlu.y, delTem1.u1)
  connect(mea.y, delTem1.u2)
  connect(delTem1.y,subApp. u)
  connect(mode, isModRej.u1)
  connect(modRej.y, isModRej.u2)
  connect(isModRej.y, TSupSetUnb.u2)
  connect(subApp.y, TSupSetUnb.u1)
  connect(setOth.y,extSet. u)
  connect(extSet.y, TSupSetUnb.u3)
  connect(mConWatHexCoo_flow, cmpFlo.u)
  connect(cmpFlo.y, timFlo.u)
  connect(yValBypTan, cmpOpe.u)
  connect(not1.y, timOpe1.u)
  connect(cmpOpe.y, timOpe.u)
  connect(cmpOpe.y, not1.u)
  connect(timFlo.passed, ena.u1)
  connect(timOpe.passed, ena.u2)
  connect(timFlo1.passed, dis.u1)
  connect(timOpe1.passed, dis.u2)
  connect(dis.y,enaLea. clr)
  connect(enaLea.y, staPum.y1Ena)
  connect(TConWatCooRet, delTem3.u1)
  connect(TConWatCooSup, delTem3.u2)
  connect(TConWatHexCooEnt, delTem2.u1)
  connect(delTem2.y, addOff.u)
  connect(addApp.y, ctlPum1.u_s)
  connect(delTem3.y, ctlPum2.u_m)
  connect(addOff.y, ctlPum2.u_s)
  connect(ctlPum1.y, minCtlPum.u1)
  connect(ctlPum2.y, minCtlPum.u2)
  connect(xPum[1].y, pum.x1)
  connect(xPum[2].y, pum.x2)
  connect(pum.y, yPumConWatCoo)
  connect(one.y, pum.f2)
  connect(minCtlPum.y, pum.u)
  connect(idxCycTan,extSet. index)
  connect(yPumMin.y, extYPumMin.u)
  connect(nPumBou.y, extYPumMin.index)
  connect(extYPumMin.y, pum.f1)
  connect(xFan[1].y, fanMax.x1)
  connect(xFan[2].y, fanMax.x2)
  connect(yFan[1].y, fanMax.f1)
  connect(yFan[2].y, fanMax.f2)
  connect(ratDes.y, fanMax.u)
  connect(enaLea.y, pre1.u)
  connect(TConWatCooSup, ctlFan.u_m)
  connect(pum.y, staPum.y)
  connect(pre1.y, ctlPum1.uEna)
  connect(pre1.y, ctlPum2.uEna)
  connect(staPum.y1, y1PumConWatCoo)
  connect(setMax.y, TSupSet.u2)
  connect(TSupSetUnb.y, TSupSet.u1)
  connect(TSupSet.y, ctlFan.u_s)
  connect(TSupSet.y, addApp.u)
  connect(TConWatHexCooLvg, delTem2.u2)
  connect(TConWatHexCooLvg, ctlPum1.u_m)
  connect(xFan1[1].y, fan.x1)
  connect(xFan1[2].y, fan.x2)
  connect(yFan1.y, fan.f1)
  connect(ctlFan.y, fan.u)
  connect(fan.y, yCoo)
  connect(fanMax.y, fan.f2)
  connect(enaLea.y, ctlFan.uEna)
  connect(cmpFlo.y, not2.u)
  connect(not2.y, timFlo1.u)
  connect(rep.y, y1Coo)
  connect(enaLea.y, rep.u)
  connect(ena.y, enaAndNotDis.u1)
  connect(notDis.y, enaAndNotDis.u2)
  connect(enaAndNotDis.y, enaLea.u)
  connect(dis.y, notDis.u)
end CoolingTowerLoop;


Block controlling HRC in direct heat recovery mode. In direct heat recovery mode, the HRC is internally controlled in heating mode
and tracks a HW supply temperature setpoint.
The CHW supply temperature setpoint is maintained by means of supervisory controls
that act on the evaporator flow rate and condenser entering water temperature as
described below.

within Buildings.DHC.Plants.Combined.Controls.BaseClasses;
block DirectHeatRecovery
  "Block controlling HRC in direct heat recovery mode"

  parameter Integer nChi(final min=1, start=1)
    "Number of units operating at design conditions"
  parameter Integer nChiHea(final min=1, start=1)
    "Number of units operating at design conditions"
  parameter Modelica.Units.SI.MassFlowRate mChiWatChi_flow_nominal
    "Chiller CHW design mass flow rate (value will be used for each unit)"
  parameter Modelica.Units.SI.MassFlowRate mChiWatChi_flow_min
    "Chiller CHW minimum mass flow rate (value will be used for each unit)"
  parameter Modelica.Units.SI.MassFlowRate mChiWatChiHea_flow_nominal
    "HRC CHW design mass flow rate (value will be used for each unit)"
  parameter Modelica.Units.SI.MassFlowRate mChiWatChiHea_flow_min
    "HRC CHW minimum mass flow rate (value will be used for each unit)"

  parameter Real k(min=0)=0.01
    "Gain of controller"
  parameter Modelica.Units.SI.Time Ti=60
    "Time constant of integrator block"
  parameter Real y_reset=0.5
    "Value to which the controller output is reset if the boolean trigger has a rising edge"
  parameter Real y_neutral=0.5
    "Value to which the controller output is reset when the controller is disabled"

  Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSupSet(final unit="K",
      displayUnit="degC") "CHW supply temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TEvaLvg[nChiHea](each final unit="K",
    each  displayUnit="degC") "Evaporator barrel leaving temperature (each HRC)"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1HeaCoo[nChiHea]
    "Direct HR command"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1[nChiHea]
    "On/Off command"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mEvaChiSet_flow(
    final unit="kg/s") "Chiller evaporator flow setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TConEntChiHeaSet(
    final unit="K", displayUnit="degC")
    "HRC condenser entering temperature setpoint"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatPriRet(final unit="K",
      displayUnit="degC") "Primary HW return temperature"

  Buildings.Controls.OBC.CDL.Logical.And heaCooAndOn[nChiHea]
    "Return true if direct HR AND On"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep(
    final nout=nChiHea) "Replicate"
  ETS.Combined.Controls.PIDWithEnable ctl[nChiHea](
    each final k=k,
    each final Ti=Ti,
    each final reverseActing=false,
    each final y_reset=y_reset,
    each final y_neutral=y_neutral)
    "CHW supply temperature control"
  Buildings.Controls.OBC.CDL.Reals.Line chiFloRes[nChiHea]
    "Chiller evaporator flow reset"
  Buildings.Controls.OBC.CDL.Reals.MultiMin min(nin=nChiHea)
    "Minimum evaporator flow setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xFlo[nChiHea,2](
    final k=fill({0,0.33}, nChiHea))
    "x-value for flow reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yFlo[nChiHea,2](
    final k=fill(1.2 .* {mChiWatChi_flow_min,mChiWatChi_flow_nominal}, nChiHea))
    "y-value for flow reset"
  Buildings.Controls.OBC.CDL.Reals.Line chiHeaFloRes[nChiHea]
    "HRC evaporator flow reset"
  Buildings.Controls.OBC.CDL.Reals.MultiMin min1(nin=nChiHea)
    "Minimum evaporator flow setpoint"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xFlo1
                                                             [nChiHea, 2](final k=
        fill({0.33,0.67}, nChiHea))
    "x-value for flow reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant yFlo1
                                                             [nChiHea, 2](final k=
        fill(1.2 .* {mChiWatChiHea_flow_nominal,mChiWatChiHea_flow_min}, nChiHea))
    "y-value for flow reset"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mEvaChiHeaSet_flow(final
      unit="kg/s") "HRC evaporator flow setpoint"
  Buildings.Controls.OBC.CDL.Reals.Line chiHeaConTemRes[nChiHea]
    "HRC condenser entering temperature reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant xFlo2
                                                             [nChiHea, 2](final k=
        fill({0.67,1.0}, nChiHea))
    "x-value for flow reset"

  Buildings.Controls.OBC.CDL.Reals.AddParameter addOff(final p=0.5)
    "Add offset"
  Buildings.Controls.OBC.CDL.Reals.AddParameter addOff1(final p=-15)
    "Add offset"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep1(final nout=
        nChiHea) "Replicate"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep2(final nout=
        nChiHea) "Replicate"
  Buildings.Controls.OBC.CDL.Routing.RealExtractor extIndRea(final nin=nChiHea)
    "Keep reset value from HRC in direct HR with higher index"
  Modelica.Blocks.Sources.IntegerExpression idxHig(final y=max({if heaCooAndOn[
        i].y then i else 1 for i in 1:nChiHea}))
    "Highest index of HRC in direct HR (defaulted to 1 if all false)"
  Buildings.Controls.OBC.CDL.Reals.MovingAverage mea(delta=5*60)
    "Moving average"
equation
  connect(TChiWatSupSet, rep.u)
  connect(y1, heaCooAndOn.u1)
  connect(y1HeaCoo, heaCooAndOn.u2)
  connect(rep.y, ctl.u_s)
  connect(TEvaLvg, ctl.u_m)
  connect(heaCooAndOn.y, ctl.uEna)
  connect(chiFloRes.y, min.u)
  connect(yFlo[:, 2].y, chiFloRes.f2)
  connect(yFlo[:, 1].y, chiFloRes.f1)
  connect(ctl.y, chiFloRes.u)
  connect(xFlo[:, 1].y, chiFloRes.x1)
  connect(xFlo[:, 2].y, chiFloRes.x2)
  connect(min.y, mEvaChiSet_flow)
  connect(chiHeaFloRes.y, min1.u)
  connect(yFlo1[:, 2].y, chiHeaFloRes.f2)
  connect(yFlo1[:, 1].y, chiHeaFloRes.f1)
  connect(ctl.y, chiHeaFloRes.u)
  connect(xFlo1[:, 1].y, chiHeaFloRes.x1)
  connect(xFlo1[:, 2].y, chiHeaFloRes.x2)
  connect(min1.y, mEvaChiHeaSet_flow)
  connect(ctl.y, chiHeaConTemRes.u)
  connect(xFlo2[:, 1].y, chiHeaConTemRes.x1)
  connect(xFlo2[:, 2].y, chiHeaConTemRes.x2)
  connect(addOff.y, rep1.u)
  connect(addOff1.y, rep2.u)
  connect(rep2.y, chiHeaConTemRes.f2)
  connect(rep1.y, chiHeaConTemRes.f1)
  connect(extIndRea.y, TConEntChiHeaSet)
  connect(chiHeaConTemRes.y, extIndRea.u)
  connect(idxHig.y, extIndRea.index)
  connect(addOff.u, mea.y)
  connect(THeaWatPriRet, mea.u)
  connect(mea.y, addOff1.u)
end DirectHeatRecovery;


Block that holds the value of an integer array for a given time. This blocks updates the value of the output array to
match the value of the input array only if the time
since the last update exceeds holdDuration.
Otherwise, the value of the output array is kept equal
to its value at the time of the last update.
At initial time, the value of the output array is set
to the value of the input array, and this is considered
as the first update time.

within Buildings.DHC.Plants.Combined.Controls.BaseClasses;
block IntegerArrayHold
  "Block that holds the value of an integer array for a given time"
  parameter Integer nin=0
    "Array dimension"
  final parameter Integer nout=nin
    "Output array dimension";
  parameter Real holdDuration(
    final quantity="Time",
    final unit="s")=1
    "Hold duration";

 Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u[nin]
    "Connector of Real input signal"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y[nout]
    "Connector of Integer output signal"
protected
  Real time_change;
initial algorithm
  y := u;
  time_change := time;
algorithm
  when Modelica.Math.BooleanVectors.anyTrue({
    u[i] <> pre(y[i]) for i in 1:nin}) and time - time_change > holdDuration then
    y := u;
    time_change := time;
  end when;
end IntegerArrayHold;


Block that determines the condenser loop mode.

within Buildings.DHC.Plants.Combined.Controls.BaseClasses;
block ModeCondenserLoop
  "Block that determines the condenser loop mode"

  parameter Modelica.Units.SI.MassFlowRate mConWatHexCoo_flow_nominal
    "Design total CW mass flow rate through condenser barrels (all units)";
  parameter Modelica.Units.SI.HeatFlowRate QHeaPum_flow_nominal
    "Design heat flow from heat pumps (all units)";
  parameter Modelica.Units.SI.Temperature TTanSet[2, 2]
    "Tank temperature setpoints: 2 cycles with 2 setpoints"
  parameter Real fraUslTan(unit="1")
    "Useless fraction of TES"
  parameter Integer nTTan=2
    "Number of tank temperature points"
  parameter Real ratFraChaTanLim[5](each final unit="1/h")=
    {-0.3, -0.2, -0.15, -0.10, -0.08}
    "Rate of change of tank charge fraction (over 10, 30, 120, 240, and 360') that triggers Charge Assist (<0)";
  parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
    Buildings.Utilities.Psychrometrics.Constants.cpWatLiq
    "Specific heat capacity of the fluid";

  Buildings.Controls.OBC.CDL.Interfaces.RealInput mConWatOutTan_flow(
    final unit="kg/s")
    "Mass flow rate out of lower port of TES tank (>0 when charging)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TTan[nTTan](
    each final unit="K",
    each displayUnit="degC")
    "TES tank temperature"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput mode(
    final min=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.tankCharge,
    final max=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.heatRejection)
    "Condenser loop operating mode"

  Real fraChaTanIns(final unit="1")=
    (sum(TTan .- min(TTanSet)) / (max(TTanSet) - min(TTanSet)) / nTTan - fraUslTan) /
    (1 - fraUslTan)
    "Tank charge fraction (instantaneous value)";
  Real ratFraChaTan[5](each final unit="1/h")=
    {(fraChaTan.y - delay(fraChaTan.y, x)) / x * 3600  for x in
    {10, 30, 120, 240, 360} .* 60}
    "Rate of change of tank charge fraction (over 10, 30, 120, 240, and 360')";
  Real nHouToWarUp(final unit="h") = noEvent(
    if mod(time, 24 * 3600) > 4 * 3600
      then 4 + 24 - mod(time, 24 * 3600) / 3600
    else 4 - mod(time, 24 * 3600) / 3600)
    "Number of hours between next warmup period (set at 4 AM by default)";

  Modelica.Blocks.Sources.RealExpression ratFraChaTanVal[5](final y=ratFraChaTan)
    "Rate of change of tank charge fraction"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold lesThr[5](
    final t=ratFraChaTanLim, each h=1E-4)
    "Compare rate of change to threshold"
  Buildings.Controls.OBC.CDL.Logical.Timer tim[5](each t=5*60)
    "Condition is true for given time"
  Buildings.Controls.OBC.CDL.Logical.MultiOr anyEnaTru(nin=6)
    "Any of the enable conditions is true"
  Modelica.Blocks.Sources.RealExpression varCriWarUp(y=1 - fraChaTan.y)
    "Compute variable used to evaluate warmup criterion"
  Buildings.Controls.OBC.CDL.Reals.Greater criWarUp(h=1e-3)
    "Enable criterion based on time to warmup"
  Buildings.Controls.OBC.CDL.Logical.And criWarUpAndChaLow
    "Both enable criteria met"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold criChaLow(t=0.97, h=1e-3)
    "Low charge fraction criterion"
  Buildings.Controls.OBC.CDL.Logical.Not enaFal[6]
    "True if enabling condition is false"
  Buildings.Controls.OBC.CDL.Logical.MultiAnd noEnaTruAndRatCon(nin=7)
    "None of the enable conditions is true AND HR rate condition true"
  Buildings.Controls.OBC.CDL.Logical.Timer tim2(t=15*60)
    "None of the enabling conditions is true for given time"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold criFlo(t=1E-3*
        mConWatHexCoo_flow_nominal, h=1E-3*mConWatHexCoo_flow_nominal/2)
    "Disable criterion based on flow rate"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold criTem(t=max(TTanSet)
         - 2, h=1e-3)
    "Disable criterion based on temperature"
  Buildings.Controls.OBC.CDL.Logical.And criFloAndTem
    "Flow criterion and temperature criterion both true"
  Buildings.Controls.OBC.CDL.Logical.Timer timCriFlo(t=5*60)
    "Criterion true for given time"
  Buildings.Controls.OBC.CDL.Logical.Or disCha
    "Any of the disabling conditions is true"
  Buildings.Controls.OBC.CDL.Logical.Latch enaCha "Enable charge assist mode"
  Buildings.Controls.OBC.CDL.Logical.Timer timNotCha(t=5*60)
  Buildings.Controls.OBC.CDL.Logical.Timer timCriTem(t=5*60)
    "Criterion true for given time"
  Buildings.Controls.OBC.CDL.Logical.Not criFraChaHig
    "High charge fraction criterion"
  Buildings.Controls.OBC.CDL.Logical.And allEnaTru "All enable criteria true"
  Buildings.Controls.OBC.CDL.Logical.And criTemOrCriChaHigAndTimCriFlo
    "Temperature or high charge fraction criterion true and given time criterion true"
  Buildings.Controls.OBC.CDL.Logical.Timer timCriFraChaHig(t=5*60)
  Buildings.Controls.OBC.CDL.Logical.Or criTemOrCriChaHig
    "Temperature criterion or high charge fraction criterion true"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mConWatHexCoo_flow(final unit="kg/s")
  "CW mass flow rate through secondary (plant) side of HX"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold criFlo1(t=-1E-3*
        mConWatHexCoo_flow_nominal, h=1E-3*mConWatHexCoo_flow_nominal/2)
  Buildings.Controls.OBC.CDL.Logical.Timer timCriFlo1(t=60)
    "Criterion true for given time"
  Buildings.Controls.OBC.CDL.Logical.Latch enaRej "Enable heat rejection mode"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant modTan(
    final k=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.tankCharge)
    "Tank Charge/Discharge mode"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant modRej(
    final k=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.heatRejection)
    "Heat rejection mode"
  Buildings.Controls.OBC.CDL.Integers.Sources.Constant modCha(
    final k=Buildings.DHC.Plants.Combined.Controls.ModeCondenserLoop.chargeAssist)
    "Charge assist mode"
  Buildings.Controls.OBC.CDL.Integers.Switch intSwi
  Buildings.Controls.OBC.CDL.Integers.Switch intSwi1
  Modelica.Blocks.Sources.RealExpression varCriWarUp1(
    final y=0.08*abs(nHouToWarUp - 2))
    "Compute variable used to evaluate warmup criterion"
  Buildings.Controls.OBC.CDL.Logical.Not isChaDis "Charge assist mode disabled"
  Buildings.Controls.OBC.CDL.Logical.And enaAndNotDis
    "Reset enable condition when disable is true to trigger latch block when (enable, disable) becomes (true, false) again"
  Buildings.Controls.OBC.CDL.Logical.Not notDis "Not disabled"
  Buildings.Controls.OBC.CDL.Logical.And enaAndNotDis1
    "Reset enable condition when disable is true to trigger latch block when (enable, disable) becomes (true, false) again"
  Buildings.Controls.OBC.CDL.Logical.Not notDis1 "Not disabled"
  Buildings.Controls.OBC.CDL.Reals.MovingAverage fraChaTan(delta=5*60)
    "Moving mean of tank charge fraction used for control logic"
  Modelica.Blocks.Sources.RealExpression fraChaTanVal(y=fraChaTanIns)
    "Instantaneous tank charge fraction"
  Buildings.Controls.OBC.CDL.Logical.Timer tim1(t=5*60)
    "Condition is true for given time"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mConWatCon_flow(final unit="kg/s")
                "CW condenser loop mass flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatConChiLvg(final unit="K",
      displayUnit="degC")        "Chiller and HRC leaving CW temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatConRet(final unit="K",
      displayUnit="degC")       "CWC return temperature"
  Buildings.Controls.OBC.CDL.Reals.Subtract delTem "Compute Delta-T"
  Buildings.Controls.OBC.CDL.Reals.Multiply floOutHeaPum
    "Compute HP heat flow rate output "
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter floCap(final k=
        cp_default)
    "Compute capacity flow rate"
  Buildings.Controls.OBC.CDL.Reals.Subtract delTem1 "Compute Delta-T"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter floCap1(final k=
        cp_default)
    "Compute capacity flow rate"
  Buildings.Controls.OBC.CDL.Reals.Multiply floChaTan
    "Compute tank charge rate"
  Buildings.Controls.OBC.CDL.Reals.Subtract ratHeaRec
    "Compute heat recovery rate"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold criRatHeaRec(final t=
        1E-4*(mConWatHexCoo_flow_nominal*(TTanSet[1, 2] - TTanSet[1, 1])*4184
         - QHeaPum_flow_nominal), final h=1E-4*(mConWatHexCoo_flow_nominal*(
        TTanSet[1, 2] - TTanSet[1, 1])*4184 - QHeaPum_flow_nominal)/2)
             "Disable criterion based on heat recovery rate"
equation
  connect(ratFraChaTanVal.y, lesThr.u)
  connect(criWarUp.y, criWarUpAndChaLow.u1)
  connect(criChaLow.y, criWarUpAndChaLow.u2)
  connect(noEnaTruAndRatCon.y, tim2.u)
  connect(disCha.y, enaCha.clr)
  connect(criTem.y, timCriTem.u)
  connect(criFlo.y, timCriFlo.u)
  connect(timCriFlo.passed, criFloAndTem.u1)
  connect(timCriTem.passed, criFloAndTem.u2)
  connect(criChaLow.y, criFraChaHig.u)
  connect(criFloAndTem.y, disCha.u1)
  connect(timNotCha.passed, allEnaTru.u1)
  connect(criFraChaHig.y, timCriFraChaHig.u)
  connect(timCriTem.passed, criTemOrCriChaHig.u1)
  connect(timCriFraChaHig.passed, criTemOrCriChaHig.u2)
  connect(criFlo1.y, timCriFlo1.u)
  connect(timCriFlo1.passed,enaRej. clr)
  connect(enaRej.y, intSwi1.u2)
  connect(modRej.y, intSwi1.u1)
  connect(modTan.y, intSwi1.u3)
  connect(intSwi.y, mode)
  connect(enaCha.y, intSwi.u2)
  connect(modCha.y, intSwi.u1)
  connect(intSwi1.y, intSwi.u3)
  connect(varCriWarUp1.y, criWarUp.u2)
  connect(varCriWarUp.y, criWarUp.u1)
  connect(TTan[nTTan], criTem.u)
  connect(isChaDis.y, timNotCha.u)
  connect(enaCha.y, isChaDis.u)
  connect(mConWatHexCoo_flow, criFlo1.u)
  connect(mConWatOutTan_flow, criFlo.u)
  connect(disCha.y, notDis.u)
  connect(notDis.y, enaAndNotDis.u1)
  connect(enaAndNotDis.y, enaCha.u)
  connect(enaAndNotDis1.y, enaRej.u)
  connect(allEnaTru.y, enaAndNotDis1.u1)
  connect(notDis1.y, enaAndNotDis1.u2)
  connect(timCriFlo1.passed, notDis1.u)
  connect(fraChaTanVal.y, fraChaTan.u)
  connect(fraChaTan.y, criChaLow.u)
  connect(lesThr.y, tim.u)
  connect(criWarUpAndChaLow.y, tim1.u)
  connect(enaAndNotDis.u2, anyEnaTru.y)
  connect(tim.passed, anyEnaTru.u[1:5])
  connect(tim1.passed, anyEnaTru.u[6])
  connect(lesThr.y, enaFal[1:5].u)
  connect(criWarUpAndChaLow.y, enaFal[6].u)
  connect(enaFal.y, noEnaTruAndRatCon.u[1:6])
  connect(TConWatConRet, delTem.u1)
  connect(TConWatConChiLvg, delTem.u2)
  connect(mConWatCon_flow, floCap.u)
  connect(floCap.y, floOutHeaPum.u1)
  connect(delTem.y, floOutHeaPum.u2)
  connect(mConWatOutTan_flow, floCap1.u)
  connect(floCap1.y,floChaTan. u1)
  connect(delTem1.y,floChaTan. u2)
  connect(TTan[1], delTem1.u1)
  connect(TTan[nTTan], delTem1.u2)
  connect(floOutHeaPum.y, ratHeaRec.u2)
  connect(floChaTan.y, ratHeaRec.u1)
  connect(criRatHeaRec.y, noEnaTruAndRatCon.u[7])
  connect(tim2.passed, disCha.u2)
  connect(ratHeaRec.y, criRatHeaRec.u)
  connect(criTemOrCriChaHig.y, criTemOrCriChaHigAndTimCriFlo.u2)
  connect(timCriFlo.passed, criTemOrCriChaHigAndTimCriFlo.u1)
  connect(criTemOrCriChaHigAndTimCriFlo.y, allEnaTru.u2)
end ModeCondenserLoop;


Block that computes the cascading cooling and direct HR switchover signals. This block computes the command signals to the HRCs to initiate
the switchover into either cascading cooling mode (with the evaporator
indexed to the CHW loop and the condenser indexed to the CW loop)
or direct heat recovery mode (with the evaporator
indexed to the CHW loop and the condenser indexed to the HW loop).
Switching a HRC to cascading cooling mode is done starting from the unit nearest
to the CW interconnection, that is the unit with the highest index.
Switching a HRC to direct heat recovery mode is done starting from the unit nearest
to the CW interconnection and that is not operating in cascading cooling,
that is the unit with the highest index below the lowest index of HRCs operating
in cascading cooling mode.

within Buildings.DHC.Plants.Combined.Controls.BaseClasses;
block ModeHeatRecoveryChiller
  "Block that computes the cascading cooling and direct HR switchover signals"

  parameter Integer nChiHea
    "Number of HRC"

  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nCasCoo
    "Number of units required to be operating in cascading cooling mode"
  Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nHeaCoo
    "Number of HRC required to be operating in direct HR mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Coo[nChiHea]
    "Command signal for cascading cooling mode"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1HeaCoo[nChiHea]
    "Command signal for direct HR mode"
protected
  Integer lasTruIdx;
  Integer counter;
algorithm
  y1Coo := fill(false, nChiHea);
  y1HeaCoo := fill(false, nChiHea);
  lasTruIdx := 0;
  counter := 1;
  for i in 1:nChiHea loop
    if counter > nHeaCoo then
      break;
    end if;
    if i > nCasCoo then
      y1HeaCoo[nChiHea - i + 1] := true;
      counter := counter + 1;
    end if;
  end for;
  for i in 1:nChiHea loop
    if y1HeaCoo[i] then
      lasTruIdx := i;
    end if;
  end for;
  counter := 1;
  for i in 1:nChiHea loop
    if counter > nCasCoo then
      break;
    end if;
    y1Coo[nChiHea - i + 1] := true;
    counter := counter + 1;
  end for;
end ModeHeatRecoveryChiller;


Package with base classes

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