within Buildings.DHC.ETS.BaseClasses;
model PartialIndirect
  "Partial indirect energy transfer station for district energy systems"
  extends
    Buildings.DHC.ETS.BaseClasses.PartialETS(
    final have_weaBus=false,
    final have_hotWat=false,
    final have_eleHea=false,
    final nFue=0,
    final have_eleCoo=false,
    final have_pum=false,
    final have_fan=false);
  // mass flow rates
  parameter Modelica.Units.SI.MassFlowRate mDis_flow_nominal(
    final min=0)
    "Nominal mass flow rate of district side"
  parameter Modelica.Units.SI.MassFlowRate mBui_flow_nominal(
    final min=0)
    "Nominal mass flow rate of building side"
  // Primary supply control valve
  parameter Modelica.Units.SI.PressureDifference dpConVal_nominal(
    final min=0,
    displayUnit="Pa")=6000
    "Nominal pressure drop of fully open control valve"
  // Heat exchanger
  parameter Modelica.Units.SI.PressureDifference dp1_nominal(
    final min=0,
    displayUnit="Pa")
    "Nominal pressure difference on primary side"
  parameter Modelica.Units.SI.PressureDifference dp2_nominal(
    final min=0,
    displayUnit="Pa")
    "Nominal pressure difference on secondary side"
  parameter Boolean use_Q_flow_nominal=true
    "Set to true to specify Q_flow_nominal and temeratures, or to false to specify effectiveness"
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat transfer (positive for heat transfer from district to building)"
  parameter Modelica.Units.SI.Temperature T_a1_nominal(
    final min=273.15,
    final max=373.15)
    "Nominal temperature at port a1 (district supply)"
  parameter Modelica.Units.SI.Temperature T_a2_nominal(
    final min=273.15,
    final max=373.15)
    "Nominal temperature at port a2 (building return)"
  parameter Modelica.Units.SI.Efficiency eta(
    final min=0,
    final max=1)=0.8
    "Constant effectiveness"
   //Controller parameters
  parameter Modelica.Blocks.Types.SimpleController controllerType=Modelica.Blocks.Types.SimpleController.PI
    "Type of controller"
  parameter Real k(
    final min=0,
    final unit="1")=1
    "Gain of controller"
  parameter Modelica.Units.SI.Time Ti(
    final min=Modelica.Constants.small)=120
    "Time constant of integrator block"
  parameter Modelica.Units.SI.Time Td(
    final min=0)=0.1
    "Time constant of derivative block"
  parameter Real yMax=1
    "Upper limit of output"
  parameter Real yMin=0.01
    "Lower limit of output"
  Modelica.Blocks.Interfaces.RealInput TBuiSupSet
    "Setpoint temperature for building supply"
  Modelica.Blocks.Interfaces.RealOutput Q_flow(
    final quantity="HeatFlowRate",
    final unit="W",
    displayUnit="kW")
    "Measured heating demand at the ETS"
  Modelica.Blocks.Interfaces.RealOutput Q(
    final quantity="Energy",
    final unit="J",
    displayUnit="kW.h")
    "Measured energy consumption at the ETS"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTDisSup(
    redeclare final package Medium=MediumSer,
    final m_flow_nominal=mDis_flow_nominal)
    "District supply temperature sensor"
  Buildings.Fluid.Sensors.MassFlowRate senMasFlo(
    redeclare final package Medium=MediumSer)
    "District supply mass flow rate sensor"
  Buildings.Fluid.Actuators.Valves.TwoWayEqualPercentage conVal(
    redeclare final package Medium=MediumSer,
    final m_flow_nominal=mDis_flow_nominal,
    final dpValve_nominal=dpConVal_nominal,
    strokeTime(displayUnit="s") = 10,
    y_start=0)
    "Control valve"
  Buildings.Fluid.HeatExchangers.PlateHeatExchangerEffectivenessNTU hex(
    redeclare package Medium1 = MediumSer,
    redeclare package Medium2 = MediumBui,
    final m1_flow_nominal=mDis_flow_nominal,
    final m2_flow_nominal=mBui_flow_nominal,
    final dp1_nominal=dp1_nominal,
    final dp2_nominal=dp2_nominal,
    final configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    final Q_flow_nominal=Q_flow_nominal,
    final T_a1_nominal=T_a1_nominal,
    final T_a2_nominal=T_a2_nominal)
    "Heat exchanger"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTDisRet(
    redeclare final package Medium=MediumSer,
    final m_flow_nominal=mDis_flow_nominal)
    "District return temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTBuiRet(
    redeclare final package Medium=MediumBui,
    final m_flow_nominal=mBui_flow_nominal)
    "Building return temperature sensor"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTBuiSup(
    redeclare final package Medium=MediumBui,
    final m_flow_nominal=mBui_flow_nominal)
    "Building supply temperature sensor"
  Controls.OBC.CDL.Reals.PID con(
    final controllerType=controllerType,
    final k=k,
    final Ti=Ti,
    final Td=Td,
    final yMax=yMax,
    final yMin=yMin)
    "Building supply temperature controller"

  Modelica.Blocks.Math.Add dTDis(
    final k1=-1)
  "Temperature difference on the district side"
  Modelica.Blocks.Math.Product pro
  "product"
  Modelica.Blocks.Math.Gain cp(
    final k=cp_default)
    "Specific heat multiplier to calculate heat flow rate"
  Modelica.Blocks.Continuous.Integrator int(
    final k=1)
    "Integration"
protected
  final parameter MediumSer.ThermodynamicState sta_default=MediumSer.setState_pTX(
    T=MediumSer.T_default,
    p=MediumSer.p_default,
    X=MediumSer.X_default)
    "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=MediumSer.specificHeatCapacityCp(
    sta_default)
    "Specific heat capacity of the fluid";
equation
  connect(senTDisSup.port_b, senMasFlo.port_a)
  connect(senMasFlo.port_b, conVal.port_a)
  connect(conVal.port_b, hex.port_a1)
  connect(hex.port_b1, senTDisRet.port_a)
  connect(senTBuiRet.port_b, hex.port_a2)
  connect(hex.port_b2, senTBuiSup.port_a)
  connect(senTBuiSup.T, con.u_m)
  connect(TBuiSupSet, con.u_s)
  connect(con.y, conVal.y)
  connect(senTDisSup.T,dTDis. u2)
  connect(senTBuiRet.T,dTDis. u1)
  connect(senMasFlo.m_flow, pro.u2)
  connect(dTDis.y, pro.u1)
  connect(pro.y, cp.u)
  connect(cp.y, Q_flow)
  connect(cp.y, int.u)
  connect(int.y, Q)
end PartialIndirect;


Pump with prescribed mass flow rate. This is a steady-state model of a pump with ideally controlled
mass flow rate as input signal, and no heat added to the medium.

within Buildings.DHC.ETS.BaseClasses;
model Pump_m_flow
  "Pump with prescribed mass flow rate"
  extends Buildings.Fluid.Movers.Preconfigured.FlowControlled_m_flow(
    addPowerToMedium=false,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    use_riseTime=false);
end Pump_m_flow;


Stratified buffer tank model

within Buildings.DHC.ETS.BaseClasses;
model StratifiedTank
  "Stratified buffer tank model"
  replaceable package Medium=Modelica.Media.Interfaces.PartialMedium
    "Medium model"
  final parameter Boolean allowFlowReversal=true
    "= true to allow flow reversal, false restricts to design direction (port_a -> port_b)"
  parameter Modelica.Units.SI.Volume VTan "Tank volume";
  parameter Modelica.Units.SI.Length hTan "Height of tank (without insulation)";
  parameter Modelica.Units.SI.Length dIns "Thickness of insulation";
  parameter Modelica.Units.SI.ThermalConductivity kIns=0.04
    "Specific heat conductivity of insulation";
  parameter Integer nSeg(
    min=2)=3
    "Number of volume segments";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Nominal mass flow rate"
  // IO CONNECTORS
  Modelica.Fluid.Interfaces.FluidPort_a port_aTop(
    redeclare final package Medium=Medium,
    m_flow(
      min=
        if allowFlowReversal then
          -Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Inlet fluid port at tank top"
  Modelica.Fluid.Interfaces.FluidPort_b port_bBot(
    redeclare final package Medium=Medium,
    m_flow(
      max=
        if allowFlowReversal then
          +Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Outlet fluid port at tank bottom"
  Modelica.Fluid.Interfaces.FluidPort_a port_aBot(
    redeclare final package Medium=Medium,
    m_flow(
      min=
        if allowFlowReversal then
          -Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Inlet fluid port at tank bottom"
  Modelica.Fluid.Interfaces.FluidPort_b port_bTop(
    redeclare final package Medium=Medium,
    m_flow(
      max=
        if allowFlowReversal then
          +Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Outlet fluid port at tank top"
  Modelica.Blocks.Interfaces.RealOutput Ql_flow(
    final unit="W")
    "Heat loss of tank (positive if heat flows from tank to ambient)"
  Modelica.Blocks.Interfaces.RealOutput TTop(
    final unit="K",
    displayUnit="degC")
    "Fluid temperature at tank top"
  Modelica.Blocks.Interfaces.RealOutput TBot(
    final unit="K",
    displayUnit="degC")
    "Fluid temperature at tank bottom"
  Modelica.Thermal.HeatTransfer.Interfaces.HeatPort_a heaPorAmb
    "Heat port at interface with ambient (outside insulation)"
  // COMPONENTS
  Fluid.Storage.Stratified tan(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    final VTan=VTan,
    final hTan=hTan,
    final dIns=dIns,
    final kIns=kIns,
    final nSeg=nSeg)
    "Stratified tank"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTBot
    "Tank bottom temperature"
  Modelica.Thermal.HeatTransfer.Sensors.TemperatureSensor senTTop
    "Tank top temperature"
protected
  Modelica.Thermal.HeatTransfer.Components.ThermalCollector theCol(
    m=3)
    "Connector to assign multiple heat ports to one heat port"
equation
  connect(port_aTop,tan.port_a)
  connect(port_bTop,tan.fluPorVol[1])
  connect(tan.port_b,port_bBot)
  connect(port_aBot,tan.fluPorVol[nSeg])
  connect(tan.Ql_flow,Ql_flow)
  connect(tan.heaPorVol[nSeg],senTBot.port)
  connect(tan.heaPorVol[1],senTTop.port)
  connect(senTTop.T,TTop)
  connect(senTBot.T,TBot)
  connect(heaPorAmb,theCol.port_b)
  connect(theCol.port_a[1],tan.heaPorTop)
  connect(theCol.port_a[2],tan.heaPorSid)
  connect(theCol.port_a[3],tan.heaPorBot)
end StratifiedTank;


within Buildings.DHC.ETS.BaseClasses.Validation;
model CollectorDistributor
  "Validation of collector distributor model"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Source side medium";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=1
    "Nominal mass flow rate";
  Fluid.Movers.FlowControlled_m_flow sou1(
    redeclare package Medium=Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_start=273.15+40,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true)
    "Primary supply"
  Fluid.Movers.FlowControlled_m_flow sou2_1(
    redeclare package Medium=Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_start=273.15+30,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true)
    "Secondary pump"
  Fluid.Sources.Boundary_pT bou1(
    redeclare package Medium=Medium,
    use_T_in=true,
    nPorts=2)
    "Boundary pressure"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp m1(
    height=1.1,
    duration=1000,
    startTime=0)
    "Primary flow"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T1(
    k=40+273.15)
    "Primary supply temperature"
  Fluid.Sensors.TemperatureTwoPort senT2_1Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT1_1Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Primary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT1_1Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Primary return temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT2_1Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary return temperature (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo1_1(
    redeclare final package Medium=Medium)
    "Primary mass flow rate (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo2_1(
    redeclare final package Medium=Medium)
    "Secondary mass flow rate (measured)"
  Fluid.MixingVolumes.MixingVolume vol2_1(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15+30,
    final prescribedHeatFlowRate=true,
    redeclare final package Medium=Medium,
    V=1,
    final mSenFac=1,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)
    "Volume for fluid stream"
  Fluid.HeatExchangers.HeaterCooler_u coo(
    redeclare final package Medium=Medium,
    dp_nominal=1,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=-1E5)
    "Heat exchange with water stream"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2_1Ret(
    k=30+273.15)
    "First secondary return temperature"
  Buildings.Controls.OBC.CDL.Reals.PID conTChiWat1(
    k=0.1,
    Ti=10,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    yMin=0,
    reverseActing=false)
    "PI controller for chilled water supply"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp m2_1(
    height=0.5,
    duration=1000,
    offset=0.5,
    startTime=2000)
    "First secondary flow signal"
  Fluid.Movers.FlowControlled_m_flow sou2_2(
    redeclare package Medium=Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_start=273.15+30,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true)
    "Secondary pump"
  Fluid.Sensors.TemperatureTwoPort senT2_2Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT2_2Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary return temperature (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo2_2(
    redeclare final package Medium=Medium)
    "Secondary mass flow rate (measured)"
  Fluid.MixingVolumes.MixingVolume vol2(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15+30,
    final prescribedHeatFlowRate=true,
    redeclare final package Medium=Medium,
    V=1,
    final mSenFac=1,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)
    "Volume for fluid stream"
  Fluid.HeatExchangers.HeaterCooler_u coo1(
    redeclare final package Medium=Medium,
    dp_nominal=1,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=-1E5)
    "Heat exchange with water stream"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2_2Ret(
    k=35+273.15)
    "Second secondary return temperature"
  Buildings.Controls.OBC.CDL.Reals.PID conTChiWat2(
    k=0.1,
    Ti=10,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    yMin=0,
    reverseActing=false)
    "PI controller for chilled water supply"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant m2_2(
    k=0.5)
    "Second secondary mass flow rate signal"
  Buildings.DHC.ETS.BaseClasses.CollectorDistributor colDis(
    redeclare final package Medium=Medium,
    mCon_flow_nominal=fill(
      m_flow_nominal,
      2),
    nCon=2)
    "Collector/distributor"
  Fluid.Movers.FlowControlled_m_flow sou2(
    redeclare package Medium=Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_start=273.15+40,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true,
    dp_nominal=50E3)
    "Primary supply"
  Fluid.Sources.Boundary_pT bou2(
    redeclare package Medium=Medium,
    use_T_in=true,
    nPorts=2)
    "Boundary pressure"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2(
    k=40+273.15)
    "Primary supply temperature"
  Fluid.Sensors.TemperatureTwoPort senT2_3Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT1_2Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Primary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT1_2Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Primary return temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT2_3Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary return temperature (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo1_2(
    redeclare final package Medium=Medium)
    "Primary mass flow rate (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo2_3(
    redeclare final package Medium=Medium)
    "Secondary mass flow rate (measured)"
  Fluid.MixingVolumes.MixingVolume vol2_2(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15+30,
    final prescribedHeatFlowRate=true,
    redeclare final package Medium=Medium,
    V=1,
    final mSenFac=1,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)
    "Volume for fluid stream"
  Fluid.HeatExchangers.HeaterCooler_u coo2(
    redeclare final package Medium=Medium,
    dp_nominal=1,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=-1E5)
    "Heat exchange with water stream"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2_1Ret1(
    k=30+273.15)
    "First secondary return temperature"
  Buildings.Controls.OBC.CDL.Reals.PID conTChiWat3(
    k=0.1,
    Ti=10,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    yMin=0,
    reverseActing=false)
    "PI controller for chilled water supply"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp m2_3(
    height=0.5,
    duration=1000,
    offset=0.5,
    startTime=2000)
    "First secondary flow signal"
  Fluid.Sensors.TemperatureTwoPort senT2_4Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT2_4Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary return temperature (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo2_4(
    redeclare final package Medium=Medium)
    "Secondary mass flow rate (measured)"
  Fluid.MixingVolumes.MixingVolume vol1(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15+30,
    final prescribedHeatFlowRate=true,
    redeclare final package Medium=Medium,
    V=1,
    final mSenFac=1,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)
    "Volume for fluid stream"
  Fluid.HeatExchangers.HeaterCooler_u coo3(
    redeclare final package Medium=Medium,
    dp_nominal=1,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=-1E5)
    "Heat exchange with water stream"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2_2Ret1(
    k=35+273.15)
    "Second secondary return temperature"
  Buildings.Controls.OBC.CDL.Reals.PID conTChiWat4(
    k=0.1,
    Ti=10,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    yMin=0,
    reverseActing=false)
    "PI controller for chilled water supply"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant m2_4(
    k=0.5)
    "Second secondary mass flow rate signal"
  Buildings.DHC.ETS.BaseClasses.CollectorDistributor colDis1(
    redeclare final package Medium=Medium,
    mCon_flow_nominal=fill(
      m_flow_nominal,
      2),
    nCon=2)
    "Collector/distributor"
  Fluid.Actuators.Valves.TwoWayEqualPercentage val2_1(
    redeclare package Medium=Medium,
    m_flow_nominal=m_flow_nominal,
    dpValve_nominal=3000,
    dpFixed_nominal=7000)
    "Secondary control valve"
  Fluid.Actuators.Valves.TwoWayEqualPercentage val2_2(
    redeclare package Medium=Medium,
    m_flow_nominal=m_flow_nominal,
    dpValve_nominal=3000,
    dpFixed_nominal=7000)
    "Secondary control valve"
  Fluid.Movers.FlowControlled_m_flow sou2_3(
    redeclare package Medium=Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_start=273.15+30,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true)
    "Secondary pump"
  Fluid.Sources.Boundary_pT bou3(
    redeclare package Medium=Medium,
    use_T_in=true,
    nPorts=2)
    "Boundary pressure"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T3(
    k=40+273.15)
    "Primary supply temperature"
  Fluid.Sensors.TemperatureTwoPort senT2_5Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT1_3Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Primary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT1_3Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Primary return temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT2_5Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary return temperature (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo1_3(
    redeclare final package Medium=Medium)
    "Primary mass flow rate (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo2_5(
    redeclare final package Medium=Medium)
    "Secondary mass flow rate (measured)"
  Fluid.MixingVolumes.MixingVolume vol2_3(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15+30,
    final prescribedHeatFlowRate=true,
    redeclare final package Medium=Medium,
    V=1,
    final mSenFac=1,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)
    "Volume for fluid stream"
  Fluid.HeatExchangers.HeaterCooler_u coo4(
    redeclare final package Medium=Medium,
    dp_nominal=1,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=-1E5)
    "Heat exchange with water stream"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2_1Ret2(
    k=30+273.15)
    "First secondary return temperature"
  Buildings.Controls.OBC.CDL.Reals.PID conTChiWat5(
    k=0.1,
    Ti=10,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    yMin=0,
    reverseActing=false)
    "PI controller for chilled water supply"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp m2_5(
    height=0.5,
    duration=1000,
    offset=0.5,
    startTime=2000)
    "First secondary flow signal"
  Fluid.Movers.FlowControlled_m_flow sou2_4(
    redeclare package Medium=Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    T_start=273.15+30,
    m_flow_nominal=m_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true)
    "Secondary pump"
  Fluid.Sensors.TemperatureTwoPort senT2_6Sup(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary supply temperature (measured)"
  Fluid.Sensors.TemperatureTwoPort senT2_6Ret(
    redeclare final package Medium=Medium,
    m_flow_nominal=m_flow_nominal)
    "Secondary return temperature (measured)"
  Fluid.Sensors.MassFlowRate senMasFlo2_6(
    redeclare final package Medium=Medium)
    "Secondary mass flow rate (measured)"
  Fluid.MixingVolumes.MixingVolume vol3(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=273.15+30,
    final prescribedHeatFlowRate=true,
    redeclare final package Medium=Medium,
    V=1,
    final mSenFac=1,
    final m_flow_nominal=m_flow_nominal,
    nPorts=2)
    "Volume for fluid stream"
  Fluid.HeatExchangers.HeaterCooler_u coo5(
    redeclare final package Medium=Medium,
    dp_nominal=1,
    m_flow_nominal=m_flow_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    Q_flow_nominal=-1E5)
    "Heat exchange with water stream"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant T2_2Ret2(
    k=35+273.15)
    "Second secondary return temperature"
  Buildings.Controls.OBC.CDL.Reals.PID conTChiWat6(
    k=0.1,
    Ti=10,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    yMin=0,
    reverseActing=false)
    "PI controller for chilled water supply"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant m2_6(
    k=0.5)
    "Second secondary mass flow rate signal"
  Buildings.DHC.ETS.BaseClasses.CollectorDistributor colDis2(
    redeclare final package Medium=Medium,
    mCon_flow_nominal=fill(
      m_flow_nominal,
      2),
    nCon=2)
    "Collector/distributor"
equation
  connect(m1.y,sou1.m_flow_in)
  connect(senMasFlo1_1.port_b,senT1_1Sup.port_a)
  connect(senT2_1Sup.port_b,senMasFlo2_1.port_a)
  connect(sou1.port_b,senMasFlo1_1.port_a)
  connect(coo.port_b,senT2_1Ret.port_a)
  connect(T2_1Ret.y,conTChiWat1.u_s)
  connect(conTChiWat1.y,coo.u)
  connect(senT2_1Ret.T,conTChiWat1.u_m)
  connect(vol2_1.ports[1],sou2_1.port_a)
  connect(senMasFlo2_1.port_b,vol2_1.ports[2])
  connect(m2_1.y,sou2_1.m_flow_in)
  connect(bou1.ports[1],sou1.port_a)
  connect(T1.y,bou1.T_in)
  connect(senT2_2Sup.port_b,senMasFlo2_2.port_a)
  connect(coo1.port_b,senT2_2Ret.port_a)
  connect(T2_2Ret.y,conTChiWat2.u_s)
  connect(conTChiWat2.y,coo1.u)
  connect(senT2_2Ret.T,conTChiWat2.u_m)
  connect(vol2.ports[1],sou2_2.port_a)
  connect(senMasFlo2_2.port_b,vol2.ports[2])
  connect(sou2_2.port_b,coo1.port_a)
  connect(senT1_1Ret.port_b,bou1.ports[2])
  connect(sou2_1.port_b,coo.port_a)
  connect(m2_2.y,sou2_2.m_flow_in)
  connect(senT1_1Sup.port_b,colDis.port_aDisSup)
  connect(senT1_1Ret.port_a,colDis.port_bDisRet)
  connect(colDis.ports_bCon[1],senT2_1Sup.port_a)
  connect(colDis.ports_bCon[2],senT2_2Sup.port_a)
  connect(senT2_1Ret.port_b,colDis.ports_aCon[1])
  connect(senT2_2Ret.port_b,colDis.ports_aCon[2])
  connect(colDis.port_bDisSup,colDis.port_aDisRet)
  connect(senMasFlo1_2.port_b,senT1_2Sup.port_a)
  connect(senT2_3Sup.port_b,senMasFlo2_3.port_a)
  connect(sou2.port_b,senMasFlo1_2.port_a)
  connect(coo2.port_b,senT2_3Ret.port_a)
  connect(T2_1Ret1.y,conTChiWat3.u_s)
  connect(conTChiWat3.y,coo2.u)
  connect(senT2_3Ret.T,conTChiWat3.u_m)
  connect(senMasFlo2_3.port_b,vol2_2.ports[1])
  connect(bou2.ports[1],sou2.port_a)
  connect(T2.y,bou2.T_in)
  connect(senT2_4Sup.port_b,senMasFlo2_4.port_a)
  connect(coo3.port_b,senT2_4Ret.port_a)
  connect(T2_2Ret1.y,conTChiWat4.u_s)
  connect(conTChiWat4.y,coo3.u)
  connect(senT2_4Ret.T,conTChiWat4.u_m)
  connect(senMasFlo2_4.port_b,vol1.ports[1])
  connect(senT1_2Ret.port_b,bou2.ports[2])
  connect(senT1_2Sup.port_b,colDis1.port_aDisSup)
  connect(senT1_2Ret.port_a,colDis1.port_bDisRet)
  connect(colDis1.ports_bCon[1],senT2_3Sup.port_a)
  connect(colDis1.ports_bCon[2],senT2_4Sup.port_a)
  connect(senT2_3Ret.port_b,colDis1.ports_aCon[1])
  connect(senT2_4Ret.port_b,colDis1.ports_aCon[2])
  connect(vol2_2.ports[2],val2_1.port_a)
  connect(val2_1.port_b,coo2.port_a)
  connect(m2_3.y,val2_1.y)
  connect(vol1.ports[2],val2_2.port_a)
  connect(val2_2.port_b,coo3.port_a)
  connect(m2_4.y,val2_2.y)
  connect(senMasFlo1_3.port_b,senT1_3Sup.port_a)
  connect(senT2_5Sup.port_b,senMasFlo2_5.port_a)
  connect(coo4.port_b,senT2_5Ret.port_a)
  connect(T2_1Ret2.y,conTChiWat5.u_s)
  connect(conTChiWat5.y,coo4.u)
  connect(senT2_5Ret.T,conTChiWat5.u_m)
  connect(vol2_3.ports[1],sou2_3.port_a)
  connect(senMasFlo2_5.port_b,vol2_3.ports[2])
  connect(m2_5.y,sou2_3.m_flow_in)
  connect(T3.y,bou3.T_in)
  connect(senT2_6Sup.port_b,senMasFlo2_6.port_a)
  connect(coo5.port_b,senT2_6Ret.port_a)
  connect(T2_2Ret2.y,conTChiWat6.u_s)
  connect(conTChiWat6.y,coo5.u)
  connect(senT2_6Ret.T,conTChiWat6.u_m)
  connect(vol3.ports[1],sou2_4.port_a)
  connect(senMasFlo2_6.port_b,vol3.ports[2])
  connect(sou2_4.port_b,coo5.port_a)
  connect(sou2_3.port_b,coo4.port_a)
  connect(m2_6.y,sou2_4.m_flow_in)
  connect(colDis2.ports_bCon[1],senT2_5Sup.port_a)
  connect(colDis2.ports_bCon[2],senT2_6Sup.port_a)
  connect(senT2_5Ret.port_b,colDis2.ports_aCon[1])
  connect(senT2_6Ret.port_b,colDis2.ports_aCon[2])
  connect(bou3.ports[1],senMasFlo1_3.port_a)
  connect(senT1_3Sup.port_b,colDis2.port_aDisSup)
  connect(senT1_3Ret.port_a,colDis2.port_bDisRet)
  connect(m1.y,sou2.m_flow_in)
  connect(bou3.ports[2],senT1_3Ret.port_b)
end CollectorDistributor;


Collection of validation models

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


within Buildings.DHC.ETS.Combined;
model ChillerBorefield "ETS model for 5GDHC systems with heat recovery chiller and optional borefield"
  extends Buildings.DHC.ETS.Combined.BaseClasses.PartialParallel(
    final have_eleCoo=true,
    final have_fan=false,
    redeclare replaceable Buildings.DHC.ETS.Combined.Controls.Supervisory conSup
      constrainedby Buildings.DHC.ETS.Combined.Controls.Supervisory(
        final controllerType=controllerType,
        final kHot=kHot,
        final kCol=kCol,
        final TiHot=TiHot,
        final TiCol=TiCol,
        final THeaWatSupSetMin=THeaWatSupSetMin,
        final TChiWatSupSetMin=TChiWatSupSetMin),
    nSysHea=1,
    nSouAmb=
      if have_borFie then
        2
      else
        1,
    VTanHeaWat=datChi.PLRMin*datChi.mCon_flow_nominal*5*60/1000,
    VTanChiWat=datChi.PLRMin*datChi.mEva_flow_nominal*5*60/1000,
    colChiWat(
      mCon_flow_nominal={colAmbWat.mDis_flow_nominal,datChi.mEva_flow_nominal}),
    colHeaWat(
      mCon_flow_nominal={colAmbWat.mDis_flow_nominal,datChi.mCon_flow_nominal}),
    colAmbWat(
      mCon_flow_nominal=
        if have_borFie then
          {hex.m2_flow_nominal,datBorFie.conDat.mBorFie_flow_nominal}
        else
          {hex.m2_flow_nominal}),
    totPPum(
      nin=3),
    totPHea(
      nin=1),
    totPCoo(
      nin=1),
    nPorts_bChiWat=1,
    nPorts_aHeaWat=1,
    nPorts_aChiWat=1,
    nPorts_bHeaWat=1);
  parameter Boolean have_borFie=false
    "Set to true in case a borefield is used in addition of the district HX"
  parameter Boolean have_WSE=false
    "Set to true in case a waterside economizer is used"
  parameter Modelica.Units.SI.PressureDifference dpCon_nominal(displayUnit="Pa")
    "Nominal pressure drop accross condenser"
  parameter Modelica.Units.SI.PressureDifference dpEva_nominal(displayUnit="Pa")
    "Nominal pressure drop accross evaporator"
  replaceable parameter Fluid.Chillers.Data.ElectricEIR.Generic datChi
    "Chiller performance data"
  parameter Modelica.Units.SI.PressureDifference dp1WSE_nominal(displayUnit=
        "Pa") = 40E3
    "Nominal pressure drop across heat exchanger on district side"
  parameter Modelica.Units.SI.PressureDifference dp2WSE_nominal(displayUnit=
        "Pa") = 40E3
    "Nominal pressure drop across heat exchanger on building side"
  parameter Modelica.Units.SI.HeatFlowRate QWSE_flow_nominal=0
    "Nominal heat flow rate through heat exchanger (<=0)"
  parameter Modelica.Units.SI.Temperature T_a1WSE_nominal=279.15
    "Nominal water inlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_b1WSE_nominal=284.15
    "Nominal water outlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_a2WSE_nominal=288.15
    "Nominal water inlet temperature on building side"
  parameter Modelica.Units.SI.Temperature T_b2WSE_nominal=281.15
    "Nominal water outlet temperature on building side"
  parameter Real y1WSEMin(unit="1")=0.05
    "Minimum pump flow rate or valve opening for temperature measurement (fractional)"
  final parameter Modelica.Units.SI.MassFlowRate m1WSE_flow_nominal=abs(
      QWSE_flow_nominal/4200/(T_b1WSE_nominal - T_a1WSE_nominal))
    "WSE primary mass flow rate"
  parameter Modelica.Units.SI.Temperature TBorWatEntMax=313.15
    "Maximum value of borefield water entering temperature"
  parameter Real spePumBorMin(unit="1")=0.1
    "Borefield pump minimum speed"
  parameter Modelica.Units.SI.Pressure dpBorFie_nominal(displayUnit="Pa") = 5E4
    "Pressure losses for the entire borefield (control valve excluded)"
  replaceable parameter Fluid.Geothermal.Borefields.Data.Borefield.Example datBorFie
    constrainedby Fluid.Geothermal.Borefields.Data.Borefield.Template
    "Borefield parameters"
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType=
    Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real kHot(
    min=0)=0.05
    "Gain of controller on hot side"
  parameter Real kCol(
    min=0)=0.1
    "Gain of controller on cold side"
  parameter Modelica.Units.SI.Time TiHot(min=Buildings.Controls.OBC.CDL.Constants.small)
     = 300 "Time constant of integrator block on hot side"
  parameter Modelica.Units.SI.Time TiCol(min=Buildings.Controls.OBC.CDL.Constants.small)
     = 120 "Time constant of integrator block on cold side"
  parameter Modelica.Units.SI.Temperature THeaWatSupSetMin(displayUnit="degC")
     = datChi.TConEntMin + 5
    "Minimum value of heating water supply temperature set point"
  parameter Modelica.Units.SI.Temperature TChiWatSupSetMin(displayUnit="degC")
     = datChi.TEvaLvgMin
    "Minimum value of chilled water supply temperature set point"

  replaceable
    Buildings.DHC.ETS.Combined.Subsystems.Chiller
    chi(
    redeclare final package Medium = MediumBui,
    final dpCon_nominal=dpCon_nominal,
    final dpEva_nominal=dpEva_nominal,
    final dat=datChi) "Chiller"
  replaceable
    Buildings.DHC.ETS.Combined.Subsystems.Borefield
    borFie(
    redeclare final package Medium = MediumBui,
    final datBorFie=datBorFie,
    final TBorWatEntMax=TBorWatEntMax,
    final spePumBorMin=spePumBorMin,
    final dp_nominal=dpBorFie_nominal) if have_borFie "Borefield"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zerPPum(
    final k=0) if not have_borFie
    "Zero power"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zerPHea(
    final k=0)
    "Zero power"
  Buildings.DHC.Networks.BaseClasses.DifferenceEnthalpyFlowRate dHFloHeaWat(
    redeclare final package Medium1 = MediumBui,
    final m_flow_nominal=colHeaWat.mDis_flow_nominal)
    "Variation of enthalpy flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput dHHeaWat_flow(final unit="W")
    "Heating water distributed energy flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput dHChiWat_flow(final unit="W")
    "Chilled water distributed energy flow rate"
  Buildings.DHC.Networks.BaseClasses.DifferenceEnthalpyFlowRate dHFloChiWat(
    redeclare final package Medium1 = MediumBui,
    final m_flow_nominal=colChiWat.mDis_flow_nominal)
    "Variation of enthalpy flow rate"
  Buildings.DHC.ETS.Combined.Subsystems.WatersideEconomizer
    WSE(
    redeclare final package Medium1 = MediumSer,
    redeclare final package Medium2 = MediumBui,
    final allowFlowReversal1=allowFlowReversalSer,
    final allowFlowReversal2=allowFlowReversalBui,
    final conCon=conCon,
    final dp1Hex_nominal=dp1WSE_nominal,
    final dp2Hex_nominal=dp2WSE_nominal,
    final Q_flow_nominal=QWSE_flow_nominal,
    final T_a1_nominal=T_a1WSE_nominal,
    final T_b1_nominal=T_b1WSE_nominal,
    final T_a2_nominal=T_a2WSE_nominal,
    final T_b2_nominal=T_b2WSE_nominal,
    final y1Min=y1WSEMin) if have_WSE "Waterside economizer"
  Buildings.DHC.ETS.BaseClasses.Junction splWSE(
    redeclare final package Medium = MediumSer,
    final m_flow_nominal={
      hex.m1_flow_nominal + m1WSE_flow_nominal,
      -hex.m1_flow_nominal,
      -m1WSE_flow_nominal})
    "Flow splitter for WSE"
  Buildings.DHC.ETS.BaseClasses.Junction mixWSE(
    redeclare final package Medium = MediumSer,
    final m_flow_nominal={
      hex.m1_flow_nominal,
      -hex.m1_flow_nominal - m1WSE_flow_nominal,
      m1WSE_flow_nominal})
    "Flow mixer for WSE"

equation
  if not have_WSE then
    connect(tanChiWat.port_aTop, dHFloChiWat.port_b2)
  end if;

  connect(chi.port_bHeaWat,colHeaWat.ports_aCon[2])
  connect(chi.port_aHeaWat,colHeaWat.ports_bCon[2])
  connect(chi.port_bChiWat,colChiWat.ports_aCon[2])
  connect(colChiWat.ports_bCon[2],chi.port_aChiWat)
  connect(conSup.TChiWatSupSet,chi.TChiWatSupSet)
  connect(chi.PPum,totPPum.u[2])
  connect(colAmbWat.ports_aCon[2],borFie.port_b)
  connect(colAmbWat.ports_bCon[2],borFie.port_a)
  connect(conSup.yAmb[1],borFie.u)
  connect(valIsoCon.y_actual,borFie.yValIso_actual[1])
  connect(valIsoEva.y_actual,borFie.yValIso_actual[2])
  connect(borFie.PPum,totPPum.u[3])
  connect(zerPPum.y,totPPum.u[3])
  connect(zerPHea.y,totPHea.u[1])
  connect(chi.PChi,totPCoo.u[1])
  connect(uHea,conSup.uHea)
  connect(conSup.yHea,chi.uHea)
  connect(conSup.yCoo,chi.uCoo)
  connect(valIsoCon.y_actual,conSup.yValIsoCon_actual)
  connect(valIsoEva.y_actual,conSup.yValIsoEva_actual)
  connect(dHFloHeaWat.dH_flow,dHHeaWat_flow)
  connect(dHFloChiWat.dH_flow,dHChiWat_flow)
  connect(dHFloChiWat.port_a1, tanChiWat.port_bBot)
  connect(dHFloChiWat.port_b1, ports_bChiWat[1])
  connect(tanHeaWat.port_bTop, dHFloHeaWat.port_a1)
  connect(tanHeaWat.port_aBot, dHFloHeaWat.port_b2)
  connect(dHFloHeaWat.port_a2, ports_aHeaWat[1])
  connect(ports_aChiWat[1], dHFloChiWat.port_a2)
  connect(dHFloHeaWat.port_b1, ports_bHeaWat[1])
  connect(splWSE.port_2, hex.port_a1)
  connect(dHFloChiWat.port_b2, WSE.port_a2)
  connect(WSE.port_b2, tanChiWat.port_aTop)
  connect(mixWSE.port_2, port_bSerAmb)
  connect(splWSE.port_3, WSE.port_a1)
  connect(WSE.port_b1, mixWSE.port_3)
  connect(hex.port_b1, mixWSE.port_1)
  connect(conSup.yCoo, WSE.uCoo)
  connect(valIsoEva.y_actual, WSE.yValIsoEva_actual)
  connect(port_aSerAmb, splWSE.port_1)
end ChillerBorefield;


within Buildings.DHC.ETS.Combined;
model HeatPumpHeatExchanger
  "Model of a substation with heat pump for heating, heat pump for domestic hot water, and compressor-less cooling"
  extends
    Buildings.DHC.ETS.Combined.BaseClasses.PartialHeatPumpHeatExchanger(
      volMix_a(nPorts=4),
      volMix_b(nPorts=4));
  Buildings.DHC.ETS.Combined.Subsystems.HeatPump proHotWat(
    redeclare final package Medium1 = MediumBui,
    redeclare final package Medium2 = MediumSer,
    final COP_nominal=COPHotWat_nominal,
    final TCon_nominal=THotWatSup_nominal,
    final TEva_nominal=TDisWatMin - dT_nominal,
    dT_nominal=dT_nominal,
    final Q1_flow_nominal=QHotWat_flow_nominal,
    final allowFlowReversal1=allowFlowReversalBui,
    final allowFlowReversal2=allowFlowReversalSer,
    final dp1_nominal=dp_nominal,
    final dp2_nominal=dp_nominal) if have_hotWat
    "Subsystem for hot water production"
  Buildings.Fluid.Sources.Boundary_pT      souColWat(
    redeclare final package Medium = MediumBui,
    use_T_in=true,
    nPorts=1) if have_hotWat
    "Source for cold water"
  Buildings.Fluid.Sources.Boundary_pT sinSHW(redeclare final package Medium = MediumBui,
      nPorts=1)
               if have_hotWat
    "Sink for service hot water"
  Buildings.Controls.OBC.CDL.Reals.Divide div1 if have_hotWat
    "Compute mass flow rate from load"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai(final k=
        cpBui_default) if have_hotWat "Times Cp"
  Buildings.Controls.OBC.CDL.Reals.Subtract delT if have_hotWat
    "Compute DeltaT needed on condenser side"
equation
  connect(souColWat.ports[1], proHotWat.port_a1)
  connect(sinSHW.ports[1], proHotWat.port_b1)
  connect(THotWatSupSet, proHotWat.TSupSet)
  connect(enaSHW.y, proHotWat.uEna)
  connect(proHotWat.PPum, PPumHeaTot.u[2])
  connect(proHotWat.mEva_flow, masFloHeaTot.u[2])
  connect(proHotWat.mEva_flow, masFloHea.u2)
  connect(proHotWat.PHea, PHeaTot.u[2])
  connect(TColWat, souColWat.T_in)
  connect(proHotWat.port_a2, volMix_a.ports[4])
  connect(proHotWat.port_b2, volMix_b.ports[4])
  connect(gai.y,div1. u2)
  connect(QReqHotWat_flow,div1. u1)
  connect(delT.y,gai. u)
  connect(TColWat,delT. u2)
  connect(THotWatSupSet,delT. u1)
  connect(div1.y, proHotWat.m1_flow)
end HeatPumpHeatExchanger;


within Buildings.DHC.ETS.Combined;
model HeatPumpHeatExchangerDHWTank
  "Model of a substation with heat pump for heating, heat pump with storage tank for domestic hot water, and compressor-less cooling"
  extends
    Buildings.DHC.ETS.Combined.BaseClasses.PartialHeatPumpHeatExchanger(
    volMix_b(nPorts=4),
    volMix_a(nPorts=4));
  Buildings.Fluid.Sources.Boundary_pT souDCW(
    redeclare final package Medium = MediumBui,
    use_T_in=true,
    nPorts=1)  if have_hotWat "Source for domestic cold water"
  Buildings.DHC.ETS.Combined.Subsystems.HeatPumpDHWTank proHotWat(
    redeclare final package Medium1 = MediumBui,
    redeclare final package Medium2 = MediumSer,
    final COP_nominal=COPHotWat_nominal,
    TCon_nominal=THotWatSup_nominal,
    TEva_nominal=TDisWatMin - dT_nominal,
    QHotWat_flow_nominal=QHotWat_flow_nominal,
    dT_nominal=dT_nominal,
    final allowFlowReversal1=allowFlowReversalBui,
    final allowFlowReversal2=allowFlowReversalSer,
    dp1_nominal=6000,
    dp2_nominal=6000,
    datWatHea=datWatHea) if have_hotWat
    "Subsystem for hot water production"
  parameter Buildings.DHC.Loads.HotWater.Data.GenericDomesticHotWaterWithHeatExchanger
    datWatHea "Performance data"
  Buildings.DHC.Loads.HotWater.ThermostaticMixingValve theMixVal(
    redeclare package Medium = MediumBui,
    mMix_flow_nominal=QHotWat_flow_nominal/cpBui_default/(THotWatSup_nominal - TColWat_nominal))
     if have_hotWat
     "Thermostatic mixing valve"
  Buildings.DHC.ETS.BaseClasses.Junction dcwSpl(
      redeclare final package Medium = MediumBui, final m_flow_nominal=
        datWatHea.mDom_flow_nominal*{1,-1,-1})
                                             "Splitter for domestic cold water"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai(
    k=1/QHotWat_flow_nominal) if have_hotWat
equation

  connect(proHotWat.port_b2, volMix_b.ports[4])
  connect(proHotWat.PHea, PHeaTot.u[2])
  connect(proHotWat.PPum, PPumHeaTot.u[2])
  connect(proHotWat.mEva_flow, masFloHeaTot.u[2])
  connect(proHotWat.mEva_flow, masFloHea.u2)
  connect(proHotWat.port_a2, volMix_a.ports[4])
  connect(souDCW.ports[1], dcwSpl.port_1)
  connect(dcwSpl.port_3, proHotWat.port_a1)
  connect(dcwSpl.port_2, theMixVal.port_col)
  connect(proHotWat.port_b1, theMixVal.port_hot)
  connect(souDCW.T_in, TColWat)
  connect(THotWatSupSet, theMixVal.TMixSet)
  connect(QReqHotWat_flow, gai.u)
  connect(gai.y, theMixVal.yMixSet)
  connect(enaSHW.y, proHotWat.uEna)
end HeatPumpHeatExchangerDHWTank;


within Buildings.DHC.ETS;
package Combined "Package of models for DHC energy transfer stations"
  extends Modelica.Icons.VariantsPackage;
end Combined;


Package with base classes

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


within Buildings.DHC.ETS.Combined.BaseClasses;
model PartialHeatPumpHeatExchanger
  "Partial model of a substation with heat pump and compressor-less cooling"
  extends
    Buildings.DHC.ETS.BaseClasses.PartialETS(
    final typ=Buildings.DHC.Types.DistrictSystemType.CombinedGeneration5,
    final have_weaBus=false,
    final have_chiWat=true,
    final have_heaWat=true,
    have_hotWat=false,
    final have_eleHea=true,
    final nFue=0,
    final have_eleCoo=false,
    final have_pum=true,
    final have_fan=false,
    nPorts_aHeaWat=1,
    nPorts_aChiWat=1);
  // SYSTEM GENERAL
  parameter Boolean have_varFloCon = true
    "Set to true for heat pumps with variable condenser flow"
  parameter Boolean have_varFloEva = true
    "Set to true for heat pumps with variable evaporator flow"
  parameter Real ratFloMin(
    final unit="1",
    final min=0,
    final max=1)=0.3
    "Minimum condenser mass flow rate (ratio to nominal)"
  parameter Modelica.Units.SI.Temperature TDisWatMin
    "District water minimum temperature"
  parameter Modelica.Units.SI.Temperature TDisWatMax
    "District water maximum temperature"
  parameter Modelica.Units.SI.TemperatureDifference dT_nominal(min=0) = 5
    "Water temperature drop/increase accross load and source-side HX (always positive)"
  parameter Modelica.Units.SI.Temperature TChiWatSup_nominal=291.15
    "Chilled water supply temperature"
  final parameter Modelica.Units.SI.Temperature TChiWatRet_nominal=
      TChiWatSup_nominal + dT_nominal "Chilled water return temperature"
  parameter Modelica.Units.SI.Temperature THeaWatSup_nominal=313.15
    "Heating water supply temperature"
  final parameter Modelica.Units.SI.Temperature THeaWatRet_nominal=
      THeaWatSup_nominal - dT_nominal "Heating water return temperature"
  parameter Modelica.Units.SI.Temperature THotWatSup_nominal=336.15
    "Domestic hot water supply temperature to fixtures"
  parameter Modelica.Units.SI.Temperature TColWat_nominal=288.15
    "Cold water temperature (for hot water production)"
  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa") = 50000
    "Pressure difference at nominal flow rate (for each flow leg)"
  final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal(min=0)=
    abs(QHeaWat_flow_nominal/cpBui_default/(THeaWatSup_nominal - THeaWatRet_nominal))
    "Heating water mass flow rate"
  final parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal(min=0)=
    abs(QChiWat_flow_nominal/cpBui_default/(TChiWatSup_nominal - TChiWatRet_nominal))
    "Chilled water mass flow rate"
  final parameter Modelica.Units.SI.MassFlowRate mEvaHotWat_flow_nominal(min=0)=
       QHotWat_flow_nominal*(COPHotWat_nominal - 1)/COPHotWat_nominal/cpSer_default/dT_nominal
       "Evaporator water mass flow rate of heat pump for hot water production"
  final parameter Modelica.Units.SI.MassFlowRate mSerWat_flow_nominal(min=0)=
    max(proHeaWat.mCon_flow_nominal + mEvaHotWat_flow_nominal, hexChi.m1_flow_nominal)
    "Service water mass flow rate"
  constant Modelica.Units.SI.SpecificHeatCapacity cpBui_default=
    MediumBui.specificHeatCapacityCp(MediumBui.setState_pTX(
      p=MediumBui.p_default,
      T=MediumBui.T_default)) "Specific heat capacity of the fluid";
  constant Modelica.Units.SI.SpecificHeatCapacity cpSer_default=
    MediumBui.specificHeatCapacityCp(MediumSer.setState_pTX(
      p=MediumSer.p_default,
      T=MediumSer.T_default)) "Specific heat capacity of the fluid";
  // Heat pump for heating water production
  parameter Real COPHeaWat_nominal(final unit="1")
    "COP of heat pump for heating water production"
  // Heat pump for hot water production
  parameter Real COPHotWat_nominal(final unit="1")
    "COP of heat pump for hot water production"
  // District HX
  final parameter Modelica.Units.SI.MassFlowRate m1HexChi_flow_nominal(min=0)=
       abs(QChiWat_flow_nominal/cpSer_default/dT_nominal)
    "CHW HX primary mass flow rate"
  final parameter Modelica.Units.SI.MassFlowRate m2HexChi_flow_nominal(min=0)=
       abs(QChiWat_flow_nominal/cpSer_default/(THeaWatSup_nominal -
    THeaWatRet_nominal)) "CHW HX secondary mass flow rate"
  // Dynamics
  parameter Modelica.Fluid.Types.Dynamics mixingVolumeEnergyDynamics=
    Modelica.Fluid.Types.Dynamics.FixedInitial
    "Formulation of energy balance for mixing volume at inlet and outlet"
  // IO CONNECTORS
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uCoo
    "Cooling enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uHea
    "Heating enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uSHW if have_hotWat
    "SHW production enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Heating water supply temperature set point"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THotWatSupSet(
    final unit="K",
    displayUnit="degC") if have_hotWat
    "Domestic hot water temperature set point for supply to fixtures"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TColWat(
    final unit="K",
    displayUnit="degC") if have_hotWat
    "Cold water temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput QReqHotWat_flow(
    final unit="W") if have_hotWat "Service hot water load"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSupSet(final unit="K",
      displayUnit="degC")
    "Chilled water supply temperature set point"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mHea_flow(final unit="kg/s")
    "District water mass flow rate used for heating service"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mCoo_flow(final unit="kg/s")
    "District water mass flow rate used for cooling service"
  // COMPONENTS
  Buildings.Fluid.Delays.DelayFirstOrder volMix_a(
    redeclare final package Medium = MediumSer,
    final m_flow_nominal=mSerWat_flow_nominal,
    tau=600,
    final energyDynamics=mixingVolumeEnergyDynamics)
    "Mixing volume to break algebraic loops and to emulate the delay of the substation"
  Buildings.Fluid.Delays.DelayFirstOrder volMix_b(
    redeclare final package Medium = MediumSer,
    final m_flow_nominal=mSerWat_flow_nominal,
    tau=600,
    final energyDynamics=mixingVolumeEnergyDynamics)
    "Mixing volume to break algebraic loops and to emulate the delay of the substation"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow pum1HexChi(
    redeclare final package Medium = MediumSer,
    final m_flow_nominal=m1HexChi_flow_nominal,
    final allowFlowReversal=allowFlowReversalSer,
    dp_nominal=dp_nominal)
    "Chilled water HX primary pump"
  Buildings.Fluid.HeatExchangers.DryCoilEffectivenessNTU hexChi(
    redeclare final package Medium1 = MediumSer,
    redeclare final package Medium2 = MediumBui,
    final m1_flow_nominal=m1HexChi_flow_nominal,
    final m2_flow_nominal=m2HexChi_flow_nominal,
    final dp1_nominal=dp_nominal/2,
    final dp2_nominal=dp_nominal/2,
    configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    final Q_flow_nominal=QChiWat_flow_nominal,
    final T_a1_nominal=TDisWatMax,
    final T_a2_nominal=TChiWatRet_nominal,
    final allowFlowReversal1=allowFlowReversalSer,
    final allowFlowReversal2=allowFlowReversalBui)
    "Chilled water HX"
  Buildings.Fluid.Delays.DelayFirstOrder volHeaWatRet(
    redeclare final package Medium = MediumBui,
    final m_flow_nominal=proHeaWat.mCon_flow_nominal,
    tau=60,
    final energyDynamics=mixingVolumeEnergyDynamics,
    T_start=THeaWatSup_nominal,
    nPorts=3) "Mixing volume representing building HHW primary"
  Buildings.Fluid.Sensors.MassFlowRate senMasFloHeaWat(
    redeclare final package Medium = MediumBui,
    final allowFlowReversal=allowFlowReversalBui)
    "Heating water mass flow rate"
  Buildings.Fluid.Delays.DelayFirstOrder volChiWat(
    redeclare final package Medium = MediumBui,
    final m_flow_nominal=m1HexChi_flow_nominal,
    tau=60,
    final energyDynamics=mixingVolumeEnergyDynamics,
    T_start=TChiWatSup_nominal,
    nPorts=3) "Mixing volume representing building CHW primary"
  Buildings.Fluid.Sensors.MassFlowRate senMasFloChiWat(
    redeclare final package Medium = MediumBui,
    final allowFlowReversal=allowFlowReversalBui)
    "Chilled water mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai2(final k=
        m1HexChi_flow_nominal)
  Buildings.DHC.ETS.Combined.Controls.PIDWithEnable conTChiWat(
    k=0.05,
    Ti=120,
    yMax=1,
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    reverseActing=false,
    yMin=0) "PI controller for district HX primary side"
  Buildings.Controls.OBC.CDL.Reals.MultiSum PPumHeaTot(nin=2)
    "Total pump power for heating applications"
  Buildings.Fluid.Sources.Boundary_pT bouHeaWat(
    redeclare final package Medium = MediumBui,
    nPorts=1)
    "Pressure boundary condition representing the expansion vessel"
  Buildings.Fluid.Sources.Boundary_pT bouChiWat(
    redeclare final package Medium = MediumBui,
    nPorts=1)
    "Pressure boundary condition representing the expansion vessel"
  Buildings.Controls.OBC.CDL.Reals.MultiSum PPumCooTot(nin=1)
    "Total pump power for space cooling"
  Buildings.Controls.OBC.CDL.Reals.MultiSum PPumTot(nin=2)
    "Total pump power"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTHeaWatSup(
    redeclare final package Medium=MediumBui,
    final allowFlowReversal=allowFlowReversalBui,
    final m_flow_nominal=mHeaWat_flow_nominal)
    "Heating water supply temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTChiWatSup(
    redeclare final package Medium=MediumBui,
    final allowFlowReversal=allowFlowReversalBui,
    final m_flow_nominal=mChiWat_flow_nominal)
    "Chilled water supply temperature"
  Buildings.DHC.ETS.Combined.Subsystems.SwitchBox
    swiFlo(
    redeclare final package Medium = MediumSer,
    final m_flow_nominal=mSerWat_flow_nominal,
    dpValve_nominal=1e-4)                      "Flow switch box"
  Buildings.DHC.ETS.BaseClasses.Junction bypHeaWatSup(
    redeclare final package Medium = MediumBui, final m_flow_nominal=proHeaWat.mCon_flow_nominal
        *{1,-1,-1}) "Bypass heating water (supply)"
  Buildings.DHC.ETS.BaseClasses.Junction bypHeaWatRet(
    redeclare final package Medium = MediumBui, final m_flow_nominal=proHeaWat.mCon_flow_nominal
        *{1,-1,1})
    "Bypass heating water (return)"
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold enaHea(
    trueHoldDuration=15*60) "Enable heating"
  Buildings.DHC.ETS.Combined.Subsystems.HeatPump proHeaWat(
    redeclare final package Medium1 = MediumBui,
    redeclare final package Medium2 = MediumSer,
    dT_nominal=dT_nominal,
    final have_varFloCon=have_varFloCon,
    final COP_nominal=COPHeaWat_nominal,
    final TCon_nominal=THeaWatSup_nominal,
    final TEva_nominal=TDisWatMin - dT_nominal,
    final Q1_flow_nominal=QHeaWat_flow_nominal,
    final allowFlowReversal1=allowFlowReversalBui,
    final allowFlowReversal2=allowFlowReversalSer,
    final dp1_nominal=dp_nominal,
    final dp2_nominal=dp_nominal) "Subsystem for heating water production"
  Buildings.Controls.OBC.CDL.Reals.MultiSum masFloHeaTot(nin=2)
    "Compute district water mass flow rate used for heating service"
  Modelica.Blocks.Sources.Constant zer(final k=0) if not have_hotWat
    "Replacement variable"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTHeaWatRet(
    redeclare final package Medium = MediumBui,
    final allowFlowReversal=allowFlowReversalBui,
    final m_flow_nominal=mHeaWat_flow_nominal)
    "Heating water return temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTChiWatRet(
    redeclare final package Medium = MediumBui,
    final allowFlowReversal=allowFlowReversalBui,
    final m_flow_nominal=mChiWat_flow_nominal)
    "Chilled water return temperature"
  Buildings.Fluid.Sensors.MassFlowRate senMasFloHeaWatPri(redeclare final
      package                                                                     Medium =
        MediumBui, final allowFlowReversal=allowFlowReversalBui)
    "Primary heating water mass flow rate"
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold enaSHW(
    trueHoldDuration=15*60) if have_hotWat "Enable SHW production"
  Modelica.Blocks.Sources.Constant zer1(k=0) if not have_hotWat
    "Replacement variable"
  Buildings.Controls.OBC.CDL.Reals.Add masFloHea
    "Service water mass flow rate for heating applications"
  Buildings.Controls.OBC.CDL.Reals.MultiSum PHeaTot(nin=2)
    "Total power used for heating and hot water production"
  Buildings.Controls.OBC.CDL.Reals.Subtract dTHHW
    "Heating hot water DeltaT"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter capFloHHW(
    final k=cpBui_default) if have_varFloEva or have_varFloCon "Capacity flow rate"
  Buildings.DHC.ETS.Combined.Controls.PrimaryVariableFlow conFloConHHW(
    final Q_flow_nominal=QHeaWat_flow_nominal,
    final dT_nominal=dT_nominal,
    final ratFloMin=ratFloMin,
    final cp=cpBui_default) if have_varFloCon
    "Mass flow rate control"
  Buildings.Controls.OBC.CDL.Reals.Max priOve if have_varFloCon
    "Ensure primary overflow"
  Buildings.Controls.OBC.CDL.Reals.Multiply loaHHW
    if have_varFloEva or have_varFloCon "Heating load"

  Fluid.Sensors.MassFlowRate senMasFlo1HexChi(redeclare package Medium =
        MediumSer) "Chilled water HX primary mass flow rate"
equation
  connect(TChiWatSupSet, conTChiWat.u_s)
  connect(pum1HexChi.P, PPumCooTot.u[1])
  connect(PPumHeaTot.y, PPumTot.u[1])
  connect(PPumCooTot.y, PPumTot.u[2])
  connect(pum1HexChi.m_flow_actual, mCoo_flow)
  connect(volMix_a.ports[1], swiFlo.port_bSup)
  connect(swiFlo.port_aRet, volMix_b.ports[1])
  connect(volMix_b.ports[2], pum1HexChi.port_a)
  connect(hexChi.port_b1, volMix_a.ports[2])
  connect(gai2.y, pum1HexChi.m_flow_in)
  connect(PPumTot.y, PPum)
  connect(ports_aHeaWat[1], senMasFloHeaWat.port_a)
  connect(bypHeaWatSup.port_2, senTHeaWatSup.port_a)
  connect(senTHeaWatSup.port_b, ports_bHeaWat[1])
  connect(bypHeaWatRet.port_2, volHeaWatRet.ports[1])
  connect(bouHeaWat.ports[1], volHeaWatRet.ports[2])
  connect(ports_aChiWat[1], senMasFloChiWat.port_a)
  connect(senTChiWatSup.port_b, ports_bChiWat[1])
  connect(bypHeaWatRet.port_3, bypHeaWatSup.port_3)
  connect(volHeaWatRet.ports[3], proHeaWat.port_a1)
  connect(proHeaWat.port_b2, volMix_b.ports[3])
  connect(volMix_a.ports[3], proHeaWat.port_a2)
  connect(enaHea.y, proHeaWat.uEna)
  connect(THeaWatSupSet, proHeaWat.TSupSet)
  connect(proHeaWat.PPum, PPumHeaTot.u[1])
  connect(masFloHeaTot.y, mHea_flow)
  connect(zer.y, masFloHeaTot.u[2])
  connect(proHeaWat.mEva_flow, masFloHeaTot.u[1])
  connect(zer.y, PPumHeaTot.u[2])
  connect(senMasFloHeaWat.port_b, senTHeaWatRet.port_a)
  connect(senTHeaWatRet.port_b, bypHeaWatRet.port_1)
  connect(senMasFloChiWat.port_b, senTChiWatRet.port_a)
  connect(proHeaWat.port_b1, senMasFloHeaWatPri.port_a)
  connect(senMasFloHeaWatPri.port_b, bypHeaWatSup.port_1)
  connect(port_aSerAmb, swiFlo.port_aSup)
  connect(swiFlo.port_bRet, port_bSerAmb)
  connect(uHea, enaHea.u)
  connect(conTChiWat.y, gai2.u)
  connect(uCoo, conTChiWat.uEna)
  connect(uSHW, enaSHW.u)
  connect(senTChiWatRet.port_b, volChiWat.ports[1])
  connect(volChiWat.ports[2], hexChi.port_a2)
  connect(hexChi.port_b2, senTChiWatSup.port_a)
  connect(bouChiWat.ports[1], volChiWat.ports[3])
  connect(senTChiWatSup.T, conTChiWat.u_m)
  connect(zer1.y, masFloHea.u2)
  connect(proHeaWat.mEva_flow, masFloHea.u1)
  connect(masFloHea.y, swiFlo.mPos_flow)
  connect(proHeaWat.PHea, PHeaTot.u[1])
  connect(zer.y, PHeaTot.u[2])
  connect(PHeaTot.y, PHea)
  connect(senTHeaWatRet.T, dTHHW.u2)
  connect(senTHeaWatSup.T, dTHHW.u1)
  connect(senMasFloHeaWat.m_flow, capFloHHW.u)
  connect(senMasFloHeaWat.m_flow, priOve.u1)
  connect(conFloConHHW.m_flow, priOve.u2)
  connect(priOve.y, proHeaWat.m1_flow)
  connect(capFloHHW.y, loaHHW.u2)
  connect(dTHHW.y, loaHHW.u1)
  connect(loaHHW.y, conFloConHHW.loa)
  connect(pum1HexChi.port_b, senMasFlo1HexChi.port_a)
  connect(senMasFlo1HexChi.port_b, hexChi.port_a1)
  connect(senMasFlo1HexChi.m_flow, swiFlo.mRev_flow)
end PartialHeatPumpHeatExchanger;


within Buildings.DHC.ETS.Combined.BaseClasses;
model PartialParallel
  "Partial ETS model with district heat exchanger and parallel connection of production systems"
  extends Buildings.DHC.ETS.BaseClasses.PartialETS(
    final typ=Buildings.DHC.Types.DistrictSystemType.CombinedGeneration5,
    final have_heaWat=true,
    final have_chiWat=true,
    final have_pum=true,
    have_hotWat=false,
    have_eleHea=false,
    have_weaBus=false);

  parameter Buildings.DHC.ETS.Types.ConnectionConfiguration conCon=
      Buildings.DHC.ETS.Types.ConnectionConfiguration.Pump
    "District connection configuration"
  parameter Integer nSysHea
    "Number of heating systems"
  parameter Integer nSysCoo=nSysHea
    "Number of cooling systems"
  parameter Integer nSouAmb=1
    "Number of ambient sources"
  parameter Modelica.Units.SI.PressureDifference dpValIso_nominal(displayUnit=
        "Pa") = 2E3 "Nominal pressure drop of ambient circuit isolation valves"
  parameter Modelica.Units.SI.PressureDifference dp1Hex_nominal(displayUnit=
        "Pa") "Nominal pressure drop across heat exchanger on district side"
  parameter Modelica.Units.SI.PressureDifference dp2Hex_nominal(displayUnit=
        "Pa") "Nominal pressure drop across heat exchanger on building side"
  parameter Modelica.Units.SI.HeatFlowRate QHex_flow_nominal
    "Nominal heat flow rate through heat exchanger (from district to building)"
  parameter Modelica.Units.SI.Temperature T_a1Hex_nominal
    "Nominal water inlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_b1Hex_nominal
    "Nominal water outlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_a2Hex_nominal
    "Nominal water inlet temperature on building side"
  parameter Modelica.Units.SI.Temperature T_b2Hex_nominal
    "Nominal water outlet temperature on building side"
  parameter Real spePum1HexMin(
    final unit="1",
    min=0)=0.1
    "Heat exchanger primary pump minimum speed (fractional)"
  parameter Real spePum2HexMin(
    final unit="1",
    min=0.01)=0.1
    "Heat exchanger secondary pump minimum speed (fractional)"
  parameter Modelica.Units.SI.Volume VTanHeaWat "Heating water tank volume"
  parameter Modelica.Units.SI.Length hTanHeaWat=(VTanHeaWat*16/Modelica.Constants.pi)
      ^(1/3) "Heating water tank height (assuming twice the diameter)"
  parameter Modelica.Units.SI.Length dInsTanHeaWat=0.1
    "Heating water tank insulation thickness"
  parameter Modelica.Units.SI.Volume VTanChiWat "Chilled water tank volume"
  parameter Modelica.Units.SI.Length hTanChiWat=(VTanChiWat*16/Modelica.Constants.pi)
      ^(1/3) "Chilled water tank height (without insulation)"
  parameter Modelica.Units.SI.Length dInsTanChiWat=0.1
    "Chilled water tank insulation thickness"
  parameter Integer nSegTan=3
    "Number of volume segments for tanks"
  // IO VARIABLES
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uHea
    "Heating enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uCoo
    "Cooling enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Heating water supply temperature set point"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Chilled water supply temperature set point"
  // COMPONENTS
  replaceable Buildings.DHC.ETS.Combined.Controls.BaseClasses.PartialSupervisory conSup
    constrainedby Buildings.DHC.ETS.Combined.Controls.BaseClasses.PartialSupervisory(
      final nSouAmb=nSouAmb)
    "Supervisory controller"
  Buildings.Fluid.Actuators.Valves.TwoWayLinear valIsoEva(
    redeclare final package Medium = MediumBui,
    final dpValve_nominal=dpValIso_nominal,
    final m_flow_nominal=colAmbWat.mDis_flow_nominal,
    use_strokeTime=false) "Evaporator to ambient loop isolation valve"
  Buildings.Fluid.Actuators.Valves.TwoWayLinear valIsoCon(
    redeclare final package Medium = MediumBui,
    final dpValve_nominal=dpValIso_nominal,
    final m_flow_nominal=colAmbWat.mDis_flow_nominal,
    use_strokeTime=false) "Condenser to ambient loop isolation valve"
  Buildings.DHC.ETS.Combined.Subsystems.HeatExchanger hex(
    redeclare final package Medium1=MediumSer,
    redeclare final package Medium2=MediumBui,
    final allowFlowReversal1=allowFlowReversalSer,
    final allowFlowReversal2=allowFlowReversalBui,
    final conCon=conCon,
    final dp1Hex_nominal=dp1Hex_nominal,
    final dp2Hex_nominal=dp2Hex_nominal,
    final Q_flow_nominal=QHex_flow_nominal,
    final T_a1_nominal=T_a1Hex_nominal,
    final T_b1_nominal=T_b1Hex_nominal,
    final T_a2_nominal=T_a2Hex_nominal,
    final T_b2_nominal=T_b2Hex_nominal,
    final spePum1Min=spePum1HexMin,
    final spePum2Min=spePum2HexMin) "District heat exchanger"
  Buildings.DHC.ETS.BaseClasses.StratifiedTank tanChiWat(
    redeclare final package Medium = MediumBui,
    final m_flow_nominal=colChiWat.mDis_flow_nominal,
    final VTan=VTanChiWat,
    final hTan=hTanChiWat,
    final dIns=dInsTanChiWat,
    final nSeg=nSegTan) "Chilled water tank"
  Buildings.DHC.ETS.BaseClasses.StratifiedTank tanHeaWat(
    redeclare final package Medium = MediumBui,
    final m_flow_nominal=colHeaWat.mDis_flow_nominal,
    final VTan=VTanHeaWat,
    final hTan=hTanHeaWat,
    final dIns=dInsTanHeaWat,
    final nSeg=nSegTan) "Heating water tank"
  Buildings.DHC.ETS.BaseClasses.CollectorDistributor colChiWat(
    redeclare final package Medium = MediumBui,
    final nCon=1 + nSysCoo,
    mCon_flow_nominal={colAmbWat.mDis_flow_nominal})
    "Collector/distributor for chilled water"
  Buildings.DHC.ETS.BaseClasses.CollectorDistributor colHeaWat(
    redeclare final package Medium = MediumBui,
    final nCon=1 + nSysHea,
    mCon_flow_nominal={colAmbWat.mDis_flow_nominal})
    "Collector/distributor for heating water"
  Buildings.DHC.ETS.BaseClasses.CollectorDistributor colAmbWat(
    redeclare final package Medium = MediumBui,
    final nCon=nSouAmb,
    mCon_flow_nominal={hex.m2_flow_nominal})
    "Collector/distributor for ambient water"
  Buildings.Controls.OBC.CDL.Reals.MultiSum totPPum(
    nin=1)
    "Total pump power"
  Buildings.Controls.OBC.CDL.Reals.MultiSum totPHea(
    nin=1)
    "Total power drawn by heating system"
  Buildings.Controls.OBC.CDL.Reals.MultiSum totPCoo(
    nin=1)
    "Total power drawn by cooling system"
  Buildings.Fluid.Sources.Boundary_pT bou(redeclare final package Medium =
        MediumBui, nPorts=1)
    "Pressure boundary condition representing expansion vessel (common to HHW and CHW)"
protected
  parameter Boolean have_val1Hex=
    conCon == DHC.ETS.Types.ConnectionConfiguration.TwoWayValve
    "True in case of control valve on district side, false in case of a pump";
equation
  connect(hex.PPum,totPPum.u[1])
  connect(THeaWatSupSet,conSup.THeaWatSupPreSet)
  connect(tanHeaWat.TTop,conSup.THeaWatTop)
  connect(tanChiWat.TBot,conSup.TChiWatBot)
  connect(hex.port_b2,colAmbWat.ports_aCon[1])
  connect(hex.port_a2,colAmbWat.ports_bCon[1])
  connect(totPPum.y,PPum)
  connect(hex.yValIso_actual[1],valIsoCon.y_actual)
  connect(hex.yValIso_actual[2],valIsoEva.y_actual)
  connect(valIsoEva.port_b,colAmbWat.port_bDisSup)
  connect(valIsoCon.port_b,colAmbWat.port_aDisSup)
  connect(TChiWatSupSet,conSup.TChiWatSupPreSet)
  connect(uCoo,conSup.uCoo)
  connect(uHea,conSup.uHea)
  connect(valIsoEva.port_a,colChiWat.ports_aCon[1])
  connect(colAmbWat.port_aDisRet,colChiWat.ports_bCon[1])
  connect(conSup.yValIsoEva,valIsoEva.y)
  connect(conSup.yValIsoCon,valIsoCon.y)
  connect(conSup.yAmb[nSouAmb],hex.u)
  connect(colChiWat.port_bDisRet,tanChiWat.port_aBot)
  connect(colChiWat.port_aDisSup,tanChiWat.port_bTop)
  connect(colHeaWat.port_bDisRet,tanHeaWat.port_aTop)
  connect(tanHeaWat.port_bBot,colHeaWat.port_aDisSup)
  connect(valIsoCon.port_a,colHeaWat.ports_aCon[1])
  connect(colAmbWat.port_bDisRet,colHeaWat.ports_bCon[1])
  connect(totPHea.y,PHea)
  connect(totPCoo.y,PCoo)
  connect(bou.ports[1], colChiWat.port_aDisSup)
end PartialParallel;


Borefield controller. This block implements the control logic for the borefield system.
The main control signal u is yielded by the hot side
or cold side controller, see for instance

Buildings.DHC.ETS.Combined.Controls.SideHot.

within Buildings.DHC.ETS.Combined.Controls;
model Borefield
  "Borefield controller"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.Temperature TBorWatEntMax(displayUnit="degC")
    "Maximum value of borefield water entering temperature";
  parameter Real spePumBorMin(
    final unit="1")=0.1
    "Borefield pump minimum speed";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIso_actual[2]
    "Isolation valves return position (fractional)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Control signal from supervisory"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPum(
    final unit="kg/s")
    "Control signal for borefield pump"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValMix(
    final unit="1")
    "Control signal for borefield mixing valve"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TBorWatEnt(
    final unit="K",
    displayUnit="degC")
    "Borefield water entering temperature"
  Buildings.Controls.OBC.CDL.Reals.PIDWithReset conMix(
    final yMin=0,
    final yMax=1,
    final reverseActing=true,
    y_reset=0,
    k=0.1,
    final controllerType=Modelica.Blocks.Types.SimpleController.PI,
    Ti(
      displayUnit="s")=120)
    "Mixing valve controller"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant maxTBorWatEnt(
    y(final unit="K",
      displayUnit="degC"),
    final k=TBorWatEntMax)
    "Maximum value of borefield water entering temperature"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold opeVal(
    final t=0.9,
    final h=0.1)
    "True if at least one isolation valve is open"
  Buildings.Controls.OBC.CDL.Reals.MultiMax multiMax1(
    final nin=2)
    "Maximum opening"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold enaSup(
    final t=0.05,
    final h=0.025)
    "Borefield enabled from supervisory"
  Buildings.Controls.OBC.CDL.Reals.Switch runBor
    "Enable borefield system pump"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant limVal(
    final k=0.3)
    "Control signal value for full opening of the valve"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant speMin(
    final k=spePumBorMin)
    "Minimum pump speed"
  Buildings.Controls.OBC.CDL.Logical.And enaBor
    "Borefield enable signal"
  Buildings.Controls.OBC.CDL.Reals.Line mapSpe
    "Mapping function for pump speed"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant one(
    final k=1)
    "One"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer(
    final k=0)
    "Zero"
  Buildings.Controls.OBC.CDL.Reals.Line mapVal
    "Mapping function for valve opening"
  Buildings.Controls.OBC.CDL.Reals.Min min1
    "Minimum"
equation
  connect(multiMax1.y,opeVal.u)
  connect(yValIso_actual,multiMax1.u)
  connect(u,enaSup.u)
  connect(enaSup.y,enaBor.u1)
  connect(opeVal.y,enaBor.u2)
  connect(enaBor.y,conMix.trigger)
  connect(maxTBorWatEnt.y,conMix.u_s)
  connect(runBor.y,yPum)
  connect(TBorWatEnt,conMix.u_m)
  connect(enaBor.y,runBor.u2)
  connect(mapSpe.y,runBor.u1)
  connect(u,mapSpe.u)
  connect(speMin.y,mapSpe.f1)
  connect(min1.y,yValMix)
  connect(conMix.y,min1.u2)
  connect(mapVal.y,min1.u1)
  connect(one.y,mapSpe.x2)
  connect(one.y,mapSpe.f2)
  connect(one.y,mapVal.f2)
  connect(zer.y,mapVal.x1)
  connect(limVal.y,mapVal.x2)
  connect(u,mapVal.u)
  connect(limVal.y,mapSpe.x1)
  connect(zer.y,mapVal.f1)
  connect(zer.y,runBor.u3)
end Borefield;


Chiller controller. This is a controller for the chiller system, which includes the dedicated
condenser and evaporator pumps.

within Buildings.DHC.ETS.Combined.Controls;
model Chiller
  "Chiller controller"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.Temperature TConWatEntMin(displayUnit="degC")
    "Minimum value of condenser water entering temperature";
  parameter Modelica.Units.SI.Temperature TEvaWatEntMax(displayUnit="degC")
    "Maximum value of evaporator water entering temperature";
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uCoo
    "Cooling enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uHea
    "Heating enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TConWatEnt(
    final unit="K",
    displayUnit="degC")
    "Condenser water entering temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TEvaWatEnt(
    final unit="K",
    displayUnit="degC")
    "Evaporator water entering temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValCon
    "Condenser mixing valve control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValEva
    "Evaporator mixing valve control signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yChi
    "Chiller enable signal"
  Buildings.Controls.OBC.CDL.Logical.Or heaOrCoo
    "Heating or cooling enabled"
  PIDWithEnable conValEva(
    final controllerType=Modelica.Blocks.Types.SimpleController.PI,
    final yMax=1,
    final yMin=0,
    y_reset=0,
    k=0.1,
    Ti(
      displayUnit="s")=60,
    final reverseActing=true)
    "Evaporator three-way valve control"
  PIDWithEnable conValCon(
    final controllerType=Modelica.Blocks.Types.SimpleController.PI,
    final yMax=1,
    final yMin=0,
    y_reset=0,
    k=0.1,
    Ti(
      displayUnit="s")=60,
    final reverseActing=false)
    "Condenser three-way valve control"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant maxTEvaWatEnt(
    y(final unit="K",
      displayUnit="degC"),
    final k=TEvaWatEntMax)
    "Maximum value of evaporator water entering temperature"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant minTConWatEnt(
    y(final unit="K",
      displayUnit="degC"),
    final k=TConWatEntMin)
    "Minimum value of condenser water entering temperature"
equation
  connect(TEvaWatEnt,conValEva.u_m)
  connect(TConWatEnt,conValCon.u_m)
  connect(heaOrCoo.y,yChi)
  connect(uHea,heaOrCoo.u1)
  connect(uCoo,heaOrCoo.u2)
  connect(maxTEvaWatEnt.y,conValEva.u_s)
  connect(minTConWatEnt.y,conValCon.u_s)
  connect(conValEva.y,yValEva)
  connect(heaOrCoo.y,conValEva.uEna)
  connect(heaOrCoo.y,conValCon.uEna)
  connect(conValCon.y,yValCon)
end Chiller;


District heat exchanger controller. This block implements the control logic for the district heat exchanger,
which realizes the interface between the building system and the district system.

within Buildings.DHC.ETS.Combined.Controls;
model HeatExchanger
  "District heat exchanger controller"
  extends Modelica.Blocks.Icons.Block;
  parameter DHC.ETS.Types.ConnectionConfiguration conCon
    "District connection configuration"
  parameter Real spePum1Min(
    final unit="1",
    min=0)=0.1
    "Heat exchanger primary pump minimum speed (fractional)"
  parameter Real spePum2Min(
    final unit="1",
    min=0.01)=0.1
    "Heat exchanger secondary pump minimum speed (fractional)";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIso[2]
    "Isolation valves return position (index 1 for condenser)"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y1(final unit="1")
    "District heat exchanger primary control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPum2(
    final unit="1")
    "District heat exchanger secondary pump control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yVal2(
    final unit="1")
    "District heat exchanger secondary valve control signal"
  Buildings.Controls.OBC.CDL.Reals.Max max1
    "Maximum between control signal and minimum speed or opening"
  Buildings.Controls.OBC.CDL.Reals.Switch swiOff1
    "Output zero if not enabled"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant min1(
    final k=if have_val1 then 0 else spePum1Min)
    "Minimum pump speed or actuator opening"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Control signal for secondary side (from supervisory)"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr(
    final t=0.01,
    final h=0.005)
    "Check for heat or cold rejection demand"
  Buildings.Controls.OBC.CDL.Logical.And and2
    "At least one valve is open and HX circuit is enabled"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold heaRej(
    final t=0.9,
    final h=0.1)
    "Heat rejection if condenser isolation valve is open"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold cooRej(
    final t=0.9,
    final h=0.1)
    "Cold rejection if evaporator isolation valve is open"
  Buildings.Controls.OBC.CDL.Logical.Or or1
    "At least one valve is open "
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant speMin(
    final k=spePum2Min)
    "Minimum pump speed"
  Buildings.Controls.OBC.CDL.Reals.Switch swiOff2
    "Output zero if not enabled"
  Buildings.Controls.OBC.CDL.Reals.Line mapSpe
    "Mapping function for pump speed"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant one(
    final k=1)
    "One"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer(
    final k=0)
    "Zero"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant hal(
    final k=0.3)
    "Control signal value for full opening of the valve"
  Buildings.Controls.OBC.CDL.Reals.Line mapVal
    "Mapping function for valve opening"
protected
  parameter Boolean have_val1=conCon ==
    DHC.ETS.Types.ConnectionConfiguration.TwoWayValve
    "True in case of control valve on district side, false in case of a pump";
equation
  connect(swiOff1.y, y1)
  connect(max1.y,swiOff1.u1)
  connect(u,greThr.u)
  connect(greThr.y,and2.u1)
  connect(and2.y,swiOff1.u2)
  connect(cooRej.y,or1.u2)
  connect(heaRej.y,or1.u1)
  connect(or1.y,and2.u2)
  connect(min1.y,max1.u2)
  connect(swiOff2.y,yPum2)
  connect(one.y,mapSpe.x2)
  connect(one.y,mapSpe.f2)
  connect(u,mapSpe.u)
  connect(speMin.y,mapSpe.f1)
  connect(mapSpe.y,swiOff2.u1)
  connect(zer.y,swiOff2.u3)
  connect(zer.y,swiOff1.u3)
  connect(hal.y,mapSpe.x1)
  connect(u,mapVal.u)
  connect(zer.y,mapVal.x1)
  connect(zer.y,mapVal.f1)
  connect(one.y,mapVal.f2)
  connect(hal.y,mapVal.x2)
  connect(mapVal.y,yVal2)
  connect(and2.y,swiOff2.u2)
  connect(u, max1.u1)
  connect(yValIso[1], heaRej.u)
  connect(yValIso[2], cooRej.u)
end HeatExchanger;


within Buildings.DHC.ETS.Combined;
package Controls "Package of control blocks for fifth generation DHC ETS"
  extends Modelica.Icons.VariantsPackage;
end Controls;


PID controller with enable signal. This is an update of

Buildings.Controls.OBC.CDL.Reals.PIDWithReset
with an additional Boolean input representing an enable signal.

within Buildings.DHC.ETS.Combined.Controls;
block PIDWithEnable
  "PID controller with enable signal"
  extends Modelica.Blocks.Icons.Block;
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller";
  parameter Real k(
    min=0)=1
    "Gain of controller";
  parameter Modelica.Units.SI.Time Ti(min=Buildings.Controls.OBC.CDL.Constants.small)
     = 0.5 "Time constant of integrator block"
  parameter Modelica.Units.SI.Time Td(min=0) = 0.1
    "Time constant of derivative block"
  parameter Real r(
    min=100*Modelica.Constants.eps)=1
    "Typical range of control error, used for scaling the control error";
  parameter Real yMin=0
    "Lower limit of output";
  parameter Real yMax=1
    "Upper limit of output";
  parameter Boolean reverseActing=true
    "Set to true for reverse acting, or false for direct acting control action";
  parameter Real y_reset=yMin
    "Value to which the controller output is reset if the boolean trigger has a rising edge";
  parameter Real y_neutral=y_reset
    "Value to which the controller output is reset when the controller is disabled";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u_s
    "Connector of setpoint input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u_m
    "Connector of measurement input signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y
    "Connector of actuator output signal"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uEna
    "Enable signal"
  Buildings.Controls.OBC.CDL.Reals.PIDWithReset conPID(
    final k=k,
    final Ti=Ti,
    final Td=Td,
    final r=r,
    final controllerType=controllerType,
    final yMin=yMin,
    final yMax=yMax,
    final reverseActing=reverseActing,
    final y_reset=y_reset)
  Buildings.Controls.OBC.CDL.Reals.Switch swi
  Buildings.Controls.OBC.CDL.Reals.Switch swi1
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant valDis(
    final k=y_neutral)
    "Value when disabled"
equation
  connect(conPID.u_s,swi.y)
  connect(uEna,swi.u2)
  connect(u_s,swi.u1)
  connect(u_m,swi.u3)
  connect(uEna,conPID.trigger)
  connect(u_m,conPID.u_m)
  connect(conPID.y,swi1.u1)
  connect(swi1.y,y)
  connect(uEna,swi1.u2)
  connect(valDis.y,swi1.u3)
end PIDWithEnable;


Block that predicts heat exchanger leaving water temperature. This block computes the predicted heat exchanger leaving water temperature
as used in

Buildings.DHC.ETS.Combined.Controls.WatersideEconomizer.

within Buildings.DHC.ETS.Combined.Controls;
model PredictLeavingTemperature
  "Block that predicts heat exchanger leaving water temperature"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.TemperatureDifference dTApp_nominal
    "Heat exchanger approach"
  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal
    "Heat exchanger secondary mass flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput T1WatEnt(
    final unit="K",
    displayUnit="degC")
    "Heat exchanger primary water entering temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput T2WatLvg(
    final unit="K",
    displayUnit="degC")
    "Heat exchanger secondary water leaving temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput m2_flow(
    final unit="kg/s")
    "Heat exchanger secondary mass flow rate"
protected
  Real ratLoa "Part load ratio";
equation
  ratLoa = min(1, abs(m2_flow / m2_flow_nominal));
  T2WatLvg = T1WatEnt + dTApp_nominal * ratLoa;
end PredictLeavingTemperature;


Ideal control of condenser or evaporator variable flow rate. This block implements an ideal control of the evaporator (or condenser) water
mass flow rate.
The control intent aims to maintain a constant water temperature difference
dT_nominal across the heat exchanger, within the limit of a
minimum mass flow rate ratio ratFloMin.
For computational performance and to avoid the use of a PI controller,
the required mass flow rate is computed based on a signal representative of
the load.

within Buildings.DHC.ETS.Combined.Controls;
block PrimaryVariableFlow
  "Ideal control of condenser or evaporator variable flow rate"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Heat flow rate at nominal conditions (>0 for condenser)";
  parameter Modelica.Units.SI.TemperatureDifference dT_nominal(min=if
        Q_flow_nominal > 0 then Modelica.Constants.eps else -100, max=if
        Q_flow_nominal < 0 then -Modelica.Constants.eps else 100)
    "DeltaT at nominal conditions (>0 for condenser)";
  parameter Real ratFloMin(
    final unit="1",
    final min=0,
    final max=1)=0.3
    "Minimum mass flow rate (ratio to nominal)";
  constant Modelica.Units.SI.SpecificHeatCapacity cp=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq
    "Specific heat capacity";
  final parameter Modelica.Units.SI.MassFlowRate m_flow_nominal(min=0)=
    Q_flow_nominal/cp/dT_nominal "Mass flow rate at nominal conditions";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput loa(final unit="W")
    "Signal approximating the load on condenser or evaporator"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput m_flow(final unit="kg/s")
    "Mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant masFloMin(
    final k=ratFloMin*m_flow_nominal)
    "Minimum mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter masFlo_dT(final k=1
        /cp/dT_nominal) "Mass flow rate for constant DeltaT"
  Buildings.Controls.OBC.CDL.Reals.Max masFlo "Mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.Abs abs1 "Absolute value"
equation
  connect(loa, masFlo_dT.u)
  connect(masFloMin.y, masFlo.u1)
  connect(masFlo.y, m_flow)
  connect(masFlo_dT.y, abs1.u)
  connect(abs1.y, masFlo.u2)
end PrimaryVariableFlow;


Supervisory supply temperature reset. This block implements the supervisory reset of the heating water
supply temperature.
The heating water supply temperature is reset down whenever the
heating demand signal yielded by the building automation system
is false.
This enables operating the chiller at a reduced lift whenever
there is no requirement on the water temperature supplied to the
building system.

within Buildings.DHC.ETS.Combined.Controls;
model Reset
  "Supervisory supply temperature reset"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.Temperature THeaWatSupSetMin(displayUnit="degC")
    "Minimum value of heating water supply temperature set point";
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uHea
    "Heating enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatSupPreSet(
    final unit="K",
    displayUnit="degC")
    "Heating water supply temperature set point"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput THeaWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Heating water supply temperature set point after reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant minSet(
    k=THeaWatSupSetMin)
    "Minimum value of HW set point"
  Buildings.Controls.OBC.CDL.Reals.Switch swiHea
    "Switch"
  Buildings.Controls.OBC.CDL.Reals.LimitSlewRate ramLimHea(raisingSlewRate
      =0.1) "Limit the rate of change"
equation
  connect(THeaWatSupPreSet,swiHea.u1)
  connect(minSet.y,swiHea.u3)
  connect(uHea,swiHea.u2)
  connect(swiHea.y,ramLimHea.u)
  connect(ramLimHea.y,THeaWatSupSet)
end Reset;


Control block for cold side. This block serves as the controller for the cold side of the ETS in

Buildings.DHC.ETS.Combined.Controls.Supervisory.
It computes the following control signals.

within Buildings.DHC.ETS.Combined.Controls;
model SideCold
  "Control block for cold side"
  extends Modelica.Blocks.Icons.Block;
  parameter Integer nSouAmb=1
    "Number of ambient sources to control"
  parameter Modelica.Units.SI.Temperature TChiWatSupSetMin(displayUnit="degC")
    "Minimum value of chilled water supply temperature set point";
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real k(
    min=0)=0.1
    "Gain of controller";
  parameter Modelica.Units.SI.Time Ti(
    min=Buildings.Controls.OBC.CDL.Constants.small)=120
    "Time constant of integrator block"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput uCol
    "Cold rejection control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput TChiWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Chilled water supply temperature set point"
  Buildings.Controls.OBC.CDL.Reals.Line mapFun[nSouAmb]
    "Mapping functions for ambient source control"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant x1[nSouAmb](
    final k={(i-1) for i in 1:nSouAmb})
    "x1"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep(
    final nout=nSouAmb)
    "Replicate control signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant f1[nSouAmb](
    each final k=0)
    "f1"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant f2[nSouAmb](
    each final k=1)
    "f2"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant x2[nSouAmb](
    final k={(i) for i in 1:nSouAmb})
    "x2"
  Combined.Controls.PIDWithEnable conTChiWatSup(
    final k=k,
    final Ti=Ti,
    final controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    final yMin=0,
    final yMax=1,
    final reverseActing=false)
    "Controller for CHWST"
  Buildings.Controls.OBC.CDL.Reals.Line mapFunTChiSupSet
    "Mapping function for CHWST reset"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant minTChiWatSup(
    y(final unit="K",
      displayUnit="degC"),
    final k=TChiWatSupSetMin)
    "Minimum value of chilled water supply temperature"
  Buildings.Controls.OBC.CDL.Reals.AddParameter addPar(
    p=nSouAmb)
    "One minus control loop output"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai(
    k=-nSouAmb)
    "Gain factor"
  Buildings.Controls.OBC.CDL.Reals.Max max1
    "CHWST reset signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer(
    k=0)
    "Zero"
  Buildings.Controls.OBC.CDL.Reals.AddParameter subNumSou(
    p=-nSouAmb)
    "Control signal minus nSouAmb"
  Buildings.Controls.OBC.CDL.Reals.Min min1
    "Ambient source control signal"
  Buildings.Controls.OBC.CDL.Reals.LimitSlewRate ramLimHea(
    raisingSlewRate=0.1) "Limit the rate of change"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uHeaCoo
    "Enable signal for heating or cooling"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSet(
    final unit="K",
    displayUnit="degC")
    "Supply temperature set point (heating or chilled water)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TBot(
    final unit="K",
    displayUnit="degC")
    "Temperature at bottom of tank"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yAmb[nSouAmb](
    each final unit="1")
    "Control signal for ambient sources"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValIso(
    final unit="1")
    "Ambient loop isolation valve control signal"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Convert DO to AO signal"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr(
    t=0.01)
    "Control signal is non zero (with 1% tolerance)"
  Modelica.Blocks.Discrete.ZeroOrderHold zeroOrderHold(
    samplePeriod=60)
equation
  connect(x1.y,mapFun.x1)
  connect(rep.y,mapFun.u)
  connect(f1.y,mapFun.f1)
  connect(f2.y,mapFun.f2)
  connect(x2.y,mapFun.x2)
  connect(TSet,conTChiWatSup.u_s)
  connect(TBot,conTChiWatSup.u_m)
  connect(f2[1].y,mapFunTChiSupSet.x2)
  connect(minTChiWatSup.y,mapFunTChiSupSet.f2)
  connect(TSet,mapFunTChiSupSet.f1)
  connect(uCol,subNumSou.u)
  connect(max1.y,mapFunTChiSupSet.u)
  connect(uCol,min1.u1)
  connect(addPar.y,min1.u2)
  connect(min1.y,rep.u)
  connect(mapFun.y,yAmb)
  connect(ramLimHea.y,TChiWatSupSet)
  connect(uHeaCoo,conTChiWatSup.uEna)
  connect(zer.y,mapFunTChiSupSet.x1)
  connect(uCol,greThr.u)
  connect(greThr.y,booToRea.u)
  connect(booToRea.y,zeroOrderHold.u)
  connect(zeroOrderHold.y,yValIso)
  connect(mapFunTChiSupSet.y,ramLimHea.u)
  connect(zer.y,max1.u2)
  connect(subNumSou.y,max1.u1)
  connect(conTChiWatSup.y, gai.u)
  connect(gai.y, addPar.u)
end SideCold;


Control block for hot side. This block serves as the controller for the hot side of the ETS in

Buildings.DHC.ETS.Combined.Controls.Supervisory.
It computes the following control signals.

within Buildings.DHC.ETS.Combined.Controls;
block SideHot
  "Control block for hot side"
  extends Modelica.Blocks.Icons.Block;
  parameter Integer nSouAmb=1
    "Number of ambient sources to control"
  parameter Modelica.Units.SI.TemperatureDifference dTDea(min=0) = 1
    "Temperature difference band between set point tracking and heat rejection (absolute value)";
  parameter Modelica.Units.SI.TemperatureDifference dTLoc(min=0) = dTDea + 2
    "Temperature difference between set point tracking and cold rejection lockout (absolute value)";
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real k(
    min=0)=0.1
    "Gain of controller";
  parameter Modelica.Units.SI.Time Ti(min=Buildings.Controls.OBC.CDL.Constants.small)=
       120 "Time constant of integrator block"
  PIDWithEnable conColRej(
    final k=k,
    final Ti=Ti,
    final controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    final yMin=0,
    final yMax=nSouAmb+1,
    final reverseActing=true)
    "Controller for cold rejection"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yCol(
    final unit="1")
    "Control signal for cold side"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr(
    final t=0.01)
    "Control signal is non zero (with 1% tolerance)"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Convert DO to AO signal"
  PIDWithEnable conHeaRej(
    final k=k,
    final Ti=Ti,
    final controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI,
    final yMin=0,
    final yMax=nSouAmb,
    final reverseActing=false)
    "Controller for heat rejection"
  Buildings.Controls.OBC.CDL.Reals.Line mapFun[nSouAmb]
    "Mapping functions for controlled systems"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant x1[nSouAmb](
    final k={(i-1) for i in 1:nSouAmb})
    "x1"
  Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep(
    final nout=nSouAmb)
    "Replicate control signal"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant f1[nSouAmb](
    each final k=0)
    "f1"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant f2[nSouAmb](
    each final k=1)
    "f2"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant x2[nSouAmb](
    final k={(i) for i in 1:nSouAmb})
    "x2"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uHeaCoo
    "Enable signal for heating or cooling"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSet(
    final unit="K",
    displayUnit="degC")
    "Supply temperature set point (heating or chilled water)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TTop(
    final unit="K",
    displayUnit="degC")
    "Temperature at top of tank"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yAmb[nSouAmb](
    each final unit="1")
    "Control signal for ambient sources"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValIso(
    final unit="1")
    "Ambient loop isolation valve control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIsoCon_actual(
    final unit="1")
    "Return position of condenser to ambient loop isolation valve"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIsoEva_actual(
    final unit="1")
    "Return position of evaporator to ambient loop isolation valve"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold isValIsoConClo(
    final t=1E-6,
    h=0.5E-6)
    "Check if isolation valve is closed"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold isValIsoEvaClo(
    final t=1E-6,
    h=0.5E-6)
    "At least one signal is non zero"
  Buildings.Controls.OBC.CDL.Logical.MultiAnd mulAnd(
    nin=3)
  Buildings.Controls.OBC.CDL.Reals.AddParameter addDea(
    p=dTDea)
    "Add dead band"
  Modelica.Blocks.Discrete.ZeroOrderHold zeroOrderHold(
    samplePeriod=60)
  Buildings.Controls.OBC.CDL.Reals.AddParameter addLoc(
    p=dTLoc)
    "Add temperature difference for lockout"
  Buildings.Controls.OBC.CDL.Reals.Less isBelLoc(
    h=0.1)
    "Check if temperature is below cold rejection lockout"
equation
  connect(mapFun.y,yAmb)
  connect(TSet,conColRej.u_s)
  connect(TTop,conColRej.u_m)
  connect(conHeaRej.y,greThr.u)
  connect(x1.y,mapFun.x1)
  connect(conHeaRej.y,rep.u)
  connect(rep.y,mapFun.u)
  connect(f1.y,mapFun.f1)
  connect(f2.y,mapFun.f2)
  connect(x2.y,mapFun.x2)
  connect(conColRej.y,yCol)
  connect(TTop,conHeaRej.u_m)
  connect(yValIsoCon_actual,isValIsoConClo.u)
  connect(yValIsoEva_actual,isValIsoEvaClo.u)
  connect(mulAnd.y,conColRej.uEna)
  connect(isValIsoEvaClo.y,conHeaRej.uEna)
  connect(TSet,addDea.u)
  connect(addDea.y,conHeaRej.u_s)
  connect(greThr.y,booToRea.u)
  connect(booToRea.y,zeroOrderHold.u)
  connect(zeroOrderHold.y,yValIso)
  connect(TSet,addLoc.u)
  connect(TTop,isBelLoc.u1)
  connect(addLoc.y,isBelLoc.u2)
  connect(uHeaCoo,mulAnd.u[1])
  connect(isValIsoConClo.y,mulAnd.u[2])
  connect(isBelLoc.y,mulAnd.u[3])
end SideHot;


Supervisory controller. This block implements the supervisory control functions of the ETS model

Buildings.DHC.ETS.Combined.ChillerBorefield.

within Buildings.DHC.ETS.Combined.Controls;
model Supervisory
  "Supervisory controller"
  extends Buildings.DHC.ETS.Combined.Controls.BaseClasses.PartialSupervisory;
  parameter Buildings.Controls.OBC.CDL.Types.SimpleController
    controllerType=Buildings.Controls.OBC.CDL.Types.SimpleController.PI
    "Type of controller"
  parameter Real kHot(
    min=0)=0.05
    "Gain of controller on hot side";
  parameter Real kCol(
    min=0)=0.1
    "Gain of controller on cold side";
  parameter Modelica.Units.SI.Time TiHot(min=Buildings.Controls.OBC.CDL.Constants.small)
     = 300 "Time constant of integrator block on hot side"
  parameter Modelica.Units.SI.Time TiCol(min=Buildings.Controls.OBC.CDL.Constants.small)
     = 120 "Time constant of integrator block on cold side"
  parameter Modelica.Units.SI.Temperature THeaWatSupSetMin(displayUnit="degC")
    "Minimum value of heating water supply temperature set point";
  parameter Modelica.Units.SI.Temperature TChiWatSupSetMin(displayUnit="degC")
    "Minimum value of chilled water supply temperature set point";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIsoCon_actual(
    final unit="1")
    "Return position of condenser to ambient loop isolation valve"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIsoEva_actual(
    final unit="1")
    "Return position of evaporator to ambient loop isolation valve"
  Combined.Controls.SideHot conHot(
    final k=kHot,
    final Ti=TiHot,
    final nSouAmb=nSouAmb,
    final controllerType=controllerType)
    "Hot side controller"
  SideCold conCol(
    final k=kCol,
    final Ti=TiCol,
    final nSouAmb=nSouAmb,
    final controllerType=controllerType,
    final TChiWatSupSetMin=TChiWatSupSetMin)
    "Cold side controller"
  Buildings.Controls.OBC.CDL.Reals.Max max1[nSouAmb]
    "Maximum of output control signals"
  Reset resTSup(
    final THeaWatSupSetMin=THeaWatSupSetMin)
    "Supply temperature reset"
equation
  connect(conHot.yAmb,max1.u1)
  connect(conCol.yAmb,max1.u2)
  connect(conHot.yCol,conCol.uCol)
  connect(resTSup.THeaWatSupSet,conHot.TSet)
  connect(THeaWatTop,conHot.TTop)
  connect(max1.y,yAmb)
  connect(TChiWatBot,conCol.TBot)
  connect(THeaWatSupPreSet,resTSup.THeaWatSupPreSet)
  connect(conHot.yValIso,yValIsoCon)
  connect(conCol.yValIso,yValIsoEva)
  connect(resTSup.THeaWatSupSet,THeaWatSupSet)
  connect(conCol.TChiWatSupSet,TChiWatSupSet)
  connect(TChiWatSupPreSet,conCol.TSet)
  connect(uHeaHol.y,conHot.uHeaCoo)
  connect(uCooHol.y,conCol.uHeaCoo)
  connect(uHeaHol.y,resTSup.uHea)
  connect(uHeaHol.y,yHea)
  connect(uCooHol.y,yCoo)
  connect(yValIsoCon_actual,conHot.yValIsoCon_actual)
  connect(yValIsoEva_actual,conHot.yValIsoEva_actual)
end Supervisory;