Controller for flow switch box. This block implements a control logic preventing flow reversal in the
service line, for instance with the hydronic configuration of

Buildings.DHC.ETS.Combined.HeatPumpHeatExchanger.
The block requires two input signals representing the mass flow rate contributing
to a positive flow direction mPos_flow and the mass flow contributing
to a reverse flow direction mRev_flow.
The output signal y switches to maintain mPos_flow ≥ mRev_flow
with a temporization avoiding short cycling.
Due to the temporization, the mass flow rate may transiently change direction as
illustrated in

Buildings.DHC.ETS.Combined.Subsystems.Validation.SwitchBox.

within Buildings.DHC.ETS.Combined.Controls;
block SwitchBox "Controller for flow switch box"
  extends Modelica.Blocks.Icons.Block;
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Nominal mass flow rate, used for scaling to avoid chattering"
  parameter Real trueHoldDuration(
    final quantity="Time",
    final unit="s")
    "true hold duration";
  parameter Real falseHoldDuration(
    final quantity="Time",
    final unit="s") = trueHoldDuration
    "false hold duration";
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mPos_flow(final unit="kg/s")
    "Service water mass flow rate in positive direction"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mRev_flow(final unit="kg/s")
    "Service water mass flow rate in reverse direction"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y(final unit="1")
    "Control output signal"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold posDom(final t, h=0.001*m_flow_nominal)
    "Output true in case of dominating positive flow"
  Modelica.Blocks.Logical.Switch swi "Switch to select the mode"
  Modelica.Blocks.Sources.Constant posModOn(final k=1)
    "Output signal in case of dominating positive flow"
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold truFalHol(
    final trueHoldDuration=trueHoldDuration,
    final falseHoldDuration=falseHoldDuration)
    "True/false hold to remove the risk of chattering"
  Modelica.Blocks.Sources.Constant revModOn(final k=0)
    "Output signal in case of dominating reverse flow"
  Buildings.Controls.OBC.CDL.Reals.Subtract sub
    "Flow difference"
  Buildings.Controls.OBC.CDL.Reals.MovingAverage movAve(delta=trueHoldDuration/10)
    "Rolling average of flow difference"
equation
  connect(posModOn.y, swi.u1)
  connect(swi.y, y)
  connect(posDom.y, truFalHol.u)
  connect(truFalHol.y, swi.u2)
  connect(revModOn.y, swi.u3)
  connect(mPos_flow, sub.u1)
  connect(mRev_flow, sub.u2)
  connect(posDom.u, movAve.y)
  connect(movAve.u, sub.y)
end SwitchBox;


Waterside economizer controller. This block implements the control logic for the waterside economizer.

within Buildings.DHC.ETS.Combined.Controls;
model WatersideEconomizer
  "Waterside economizer controller"
  extends Modelica.Blocks.Icons.Block;

  parameter Modelica.Units.SI.MassFlowRate m2_flow_nominal
    "Heat exchanger secondary mass flow rate"
  parameter Modelica.Units.SI.Temperature T_a1_nominal
    "Nominal water inlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_b2_nominal
    "Nominal water outlet temperature on building side"
  parameter Real y1Min(final unit="1")=0.05
    "Minimum pump flow rate or valve opening for temperature measurement (fractional)"
  parameter Modelica.Units.SI.TemperatureDifference dTEna=1
    "Minimum delta-T above predicted heat exchanger leaving water temperature to enable WSE"
  parameter Modelica.Units.SI.TemperatureDifference dTDis=0.5
    "Minimum delta-T across heat exchanger before disabling WSE"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput T1WatEnt(
    final unit="K",
    displayUnit="degC") "Heat exchanger primary water entering temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput m2_flow(
    final unit="kg/s")
    "Heat exchanger secondary mass flow rate"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput T2WatLvg(
    final unit="K", displayUnit="degC")
    "Heat exchanger secondary water leaving temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput T2WatEnt(
    final unit="K", displayUnit="degC")
    "Heat exchanger secondary water entering temperature"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput y1(final unit="1")
    "Primary control signal (pump or valve)"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yVal2(
    final unit="1")
    "Secondary valve control signal"
  Buildings.Controls.OBC.CDL.Reals.AddParameter addDelTem(
    final p=dTEna)
    "Add threshold for enabling WSE"
  Modelica.StateGraph.InitialStepWithSignal iniSta(nIn=1, nOut=1)
                                                   "Initial state "
  Modelica.StateGraph.TransitionWithSignal ena "Transition to enabled state"
  Modelica.StateGraph.StepWithSignal actSta(nIn=1, nOut=1)
                                            "Active WSE"
  Modelica.StateGraph.TransitionWithSignal dis "Transition to disabled state"
  Buildings.Controls.OBC.CDL.Reals.Subtract delT1 "Add delta-T"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold delTemDis(t=dTDis)
    "Compare to threshold for disabling WSE"
  PredictLeavingTemperature calTemLvg(
    final dTApp_nominal=abs(T_a1_nominal - T_b2_nominal),
    final m2_flow_nominal=m2_flow_nominal)
    "Compute predicted leaving water temperature"
  Buildings.Controls.OBC.CDL.Reals.Less delTemDis1
    "Compare to threshold for enabling WSE"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea(
    final realTrue=1,
    final realFalse=0)
    "Convert to real signal (close bypass valve when WSE enabled)"
  inner Modelica.StateGraph.StateGraphRoot stateGraphRoot "Root of state graph"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant min1(
    final k=y1Min)
    "Minimum signal"
  Buildings.Controls.OBC.CDL.Reals.Line lin
    "Linear variation bounded by minimum and 1"
  Buildings.Controls.OBC.CDL.Reals.Switch swiOff1
    "Output zero if cooling not enabled or isolation valve open (cold rejection)"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer(final k=0) "Zero"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uCoo
    "Cooling enable signal"
  Buildings.Controls.OBC.CDL.Logical.MultiAnd mulAnd(nin=4)
    "Enable if cooling enabled and temperature criterion verified"
  Buildings.Controls.OBC.CDL.Logical.MultiOr or1(nin=3)
    "Cooling disabled or temperature criterion verified"
  Buildings.Controls.OBC.CDL.Logical.Not not2 "Cooling disabled"
  Buildings.Controls.OBC.CDL.Logical.Timer tim(t=1200)
    "True when WSE active for more than t"
  Buildings.Controls.OBC.CDL.Logical.Timer tim1(t=1200)
    "True when WSE inactive for more than t"
  Buildings.Controls.OBC.CDL.Logical.And and2
    "Cooling disabled or temperature criterion verified"
  Buildings.Controls.OBC.CDL.Reals.LessThreshold isValIsoEvaClo(
    final t=1E-6, h=0.5E-6)
    "True if valve closed"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIsoEva_actual(final unit="1")
    "Return position of evaporator to ambient loop isolation valve"
  Buildings.Controls.OBC.CDL.Logical.Not not1 "True if valve open"
  Buildings.Controls.OBC.CDL.Logical.And and1 "Cooling disabled or temperature criterion verified"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter nor2(
    k=1/m2_flow_nominal) "Normalize"
  Buildings.Controls.OBC.CDL.Reals.Switch swiOff2
    "Switch between enabled and disabled mode"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant one(final k=1) "One"
equation
  connect(T2WatEnt, delT1.u1)
  connect(T2WatLvg, delT1.u2)
  connect(delT1.y, delTemDis.u)
  connect(T1WatEnt, calTemLvg.T1WatEnt)
  connect(calTemLvg.T2WatLvg, addDelTem.u)
  connect(addDelTem.y, delTemDis1.u1)
  connect(T2WatEnt, delTemDis1.u2)
  connect(iniSta.outPort[1], ena.inPort)
  connect(ena.outPort, actSta.inPort[1])
  connect(actSta.outPort[1], dis.inPort)
  connect(dis.outPort, iniSta.inPort[1])
  connect(booToRea.y, yVal2)
  connect(zer.y, swiOff1.u3)
  connect(mulAnd.y, ena.condition)
  connect(uCoo, not2.u)
  connect(actSta.active, booToRea.u)
  connect(delTemDis1.y, mulAnd.u[1])
  connect(iniSta.active, tim1.u)
  connect(tim1.passed, mulAnd.u[2])
  connect(uCoo, mulAnd.u[3])
  connect(actSta.active, tim.u)
  connect(tim.passed, and2.u1)
  connect(or1.y, and2.u2)
  connect(and2.y, dis.condition)
  connect(m2_flow, calTemLvg.m2_flow)
  connect(yValIsoEva_actual,isValIsoEvaClo.u)
  connect(isValIsoEvaClo.y, mulAnd.u[4])
  connect(isValIsoEvaClo.y, not1.u)
  connect(delTemDis.y, or1.u[1])
  connect(not2.y, or1.u[2])
  connect(not1.y, or1.u[3])
  connect(uCoo, and1.u1)
  connect(and1.y, swiOff1.u2)
  connect(isValIsoEvaClo.y, and1.u2)
  connect(m2_flow, nor2.u)
  connect(min1.y, swiOff1.u1)
  connect(swiOff2.y, y1)
  connect(swiOff1.y, swiOff2.u1)
  connect(iniSta.active, swiOff2.u2)
  connect(lin.y, swiOff2.u3)
  connect(nor2.y, lin.u)
  connect(one.y, lin.x2)
  connect(one.y, lin.f2)
  connect(zer.y, lin.x1)
  connect(min1.y, lin.f1)
end WatersideEconomizer;


Package with base classes

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


Partial model for supervisory controller. This is a base class for the ETS supervisory controller.

within Buildings.DHC.ETS.Combined.Controls.BaseClasses;
partial block PartialSupervisory
  "Partial model for supervisory controller"
  extends Modelica.Blocks.Icons.Block;
  parameter Integer nSouAmb
    "Number of ambient sources to control"
  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 TChiWatSupPreSet(
    final unit="K",
    displayUnit="degC")
    "Chilled water supply temperature set point"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatBot(
    final unit="K",
    displayUnit="degC")
    "Chilled water temperature at tank bottom"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatTop(
    final unit="K",
    displayUnit="degC")
    "Heating water temperature at tank top"
  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.Interfaces.RealOutput TChiWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Chilled water supply temperature set point after reset"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValIsoEva(
    final unit="1")
    "Evaporator to ambient loop isolation valve control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yValIsoCon(
    final unit="1")
    "Condenser to ambient loop isolation valve control signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput yAmb[nSouAmb](
    each final unit="1")
    "Control output for ambient sources"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yHea
    "Tank in heating demand"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yCoo
    "Tank in cooling demand"
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold uHeaHol(
    trueHoldDuration=900)
    "Hold heating enable signal"
  Buildings.Controls.OBC.CDL.Logical.TrueFalseHold uCooHol(
    trueHoldDuration=900)
    "Hold cooling enable signal"
equation
  connect(uHea,uHeaHol.u)
  connect(uCoo,uCooHol.u)
end PartialSupervisory;


Example of the ETS model with heat recovery chiller and borefield. This model validates

Buildings.DHC.ETS.Combined.ChillerBorefield
in a system configuration including a geothermal borefield.
See

Buildings.DHC.ETS.Combined.Examples.ChillerOnly
for the description of the main modeling assumptions.

within Buildings.DHC.ETS.Combined.Examples;
model ChillerBorefield
  "Example of the ETS model with heat recovery chiller and borefield"
  extends ChillerOnly(
    ets(
      have_borFie=true,
      datBorFie=datBorFie));
  parameter Integer nBorHol=64
    "Number of boreholes (must be a square number)";
  parameter Modelica.Units.SI.Distance dxy=6
    "Distance in x-axis (and y-axis) between borehole axes";
  final parameter Modelica.Units.SI.Distance cooBor[nBorHol,2]=
    Buildings.DHC.ETS.BaseClasses.computeCoordinates(nBorHol, dxy)
    "Coordinates of boreholes";
  parameter Fluid.Geothermal.Borefields.Data.Borefield.Example datBorFie(
    conDat=Fluid.Geothermal.Borefields.Data.Configuration.Example(
      cooBor=cooBor,
      dp_nominal=0))
    "Borefield design data"
end ChillerBorefield;


Example of the ETS model with heat recovery chiller. This model validates

Buildings.DHC.ETS.Combined.ChillerBorefield
in a system configuration with no geothermal borefield.

within Buildings.DHC.ETS.Combined.Examples;
model ChillerOnly
  "Example of the ETS model with heat recovery chiller"
  extends Buildings.DHC.ETS.Combined.Validation.BaseClasses.PartialChillerBorefield(
    TDisWatSup(
      table=[
        0,11;
        1,12;
        2,13;
        3,14;
        4,15;
        5,16;
        6,17;
        7,18;
        8,20;
        9,18;
        10,16;
        11,13;
        12,11],
      timeScale=2592000),
    loa(
      tableOnFile=true,
      fileName=Modelica.Utilities.Files.loadResource(
        filNam),
      timeScale=1),
    QCoo_flow_nominal=Buildings.DHC.Loads.BaseClasses.getPeakLoad(
      string="#Peak space cooling load",
      filNam=Modelica.Utilities.Files.loadResource(filNam)),
    QHea_flow_nominal=Buildings.DHC.Loads.BaseClasses.getPeakLoad(
      string="#Peak space heating load",
      filNam=Modelica.Utilities.Files.loadResource(filNam)));
  parameter String filNam="modelica://Buildings/Resources/Data/DHC/Loads/Examples/MediumOffice-90.1-2010-5A.mos"
    "File name with thermal loads as time series";
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter loaNorHea(
    final k=1/ets.QHeaWat_flow_nominal)
    "Normalize by nominal"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter loaNorCoo(
    final k=1/ets.QChiWat_flow_nominal) "Normalize by nominal"
equation
  connect(loa.y[2],loaNorHea.u)
  connect(loa.y[1],loaNorCoo.u)
  connect(loaNorHea.y,heaLoaNor.u)
  connect(loaNorCoo.y,loaCooNor.u)
  connect(TDisWatSup.y[1],disWat.T_in)
end ChillerOnly;


within Buildings.DHC.ETS.Combined;
package Examples "Example models integrating multiple components"
  extends Modelica.Icons.ExamplesPackage;
end Examples;


within Buildings.DHC.ETS.Combined.Subsystems;
model Borefield
  "Base subsystem with geothermal borefield"
  extends Buildings.Fluid.Interfaces.PartialTwoPortInterface(
    final m_flow_nominal=datBorFie.conDat.mBorFie_flow_nominal);
  replaceable model BorefieldType=Fluid.Geothermal.Borefields.OneUTube
    constrainedby Fluid.Geothermal.Borefields.BaseClasses.PartialBorefield(
      redeclare package Medium=Medium,
      allowFlowReversal=allowFlowReversal,
      borFieDat=datBorFie,
      energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Wall heat transfer"
  replaceable parameter Fluid.Geothermal.Borefields.Data.Borefield.Example datBorFie(
    conDat=Buildings.Fluid.Geothermal.Borefields.Data.Configuration.Example())
    constrainedby Fluid.Geothermal.Borefields.Data.Borefield.Template(
      conDat(
        dp_nominal=0))
    "Borefield parameters"
  parameter Modelica.Units.SI.Pressure dp_nominal(displayUnit="Pa")
    "Pressure losses for the entire borefield (control valve excluded)"
  parameter Modelica.Units.SI.Pressure dpValBorFie_nominal=dp_nominal/2
    "Nominal pressure drop of control valve";
  parameter Modelica.Units.SI.Temperature TBorWatEntMax(displayUnit="degC")
    "Maximum value of borefield water entering temperature";
  parameter Real spePumBorMin=0.1
    "Borefield pump minimum speed";
  // IO VARIABLES
  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"
  // COMPONENTS
  Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear val(
    redeclare final package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=false,
    use_strokeTime=false,
    final m_flow_nominal=m_flow_nominal,
    final dpValve_nominal=dpValBorFie_nominal,
    final dpFixed_nominal=fill(dp_nominal, 2))
    "Mixing valve controlling entering temperature"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow pum(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal,
    final dp_nominal=dpValBorFie_nominal+dp_nominal)
    "Pump with prescribed mass flow rate"
  Fluid.Sensors.TemperatureTwoPort senTEnt(
    final tau=
      if allowFlowReversal then
        1
      else
        0,
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=m_flow_nominal)
    "Entering temperature"
  BorefieldType borFie
    "Geothermal borefield"
  Buildings.DHC.ETS.BaseClasses.Junction spl(
    redeclare final package Medium=Medium,
    final m_flow_nominal=m_flow_nominal .* {1,-1,-1})
    "Flow splitter"
  Fluid.Sensors.TemperatureTwoPort senTLvg(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=m_flow_nominal)
    "Leaving temperature"
  Buildings.DHC.ETS.Combined.Controls.Borefield con(
    final TBorWatEntMax=TBorWatEntMax,
    final spePumBorMin=spePumBorMin)
    "Controller"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PPum(
    final unit="W")
    "Pump power"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai1(final k=
        m_flow_nominal) "Scale to nominal mass flow rate"
initial equation
  assert(
    abs(
      datBorFie.conDat.dp_nominal) < Modelica.Constants.eps,
    "In "+getInstanceName()+": dp_nominal in the parameter record should be set to zero as the nominal
    pressure drop is lumped in the valve model. Use the exposed parameter
    dp_nominal instead.",
    level=AssertionLevel.warning);
equation
  connect(pum.port_b,senTEnt.port_a)
  connect(senTEnt.port_b,borFie.port_a)
  connect(port_b,spl.port_2)
  connect(spl.port_1,senTLvg.port_b)
  connect(borFie.port_b,senTLvg.port_a)
  connect(spl.port_3,val.port_3)
  connect(u,con.u)
  connect(yValIso_actual,con.yValIso_actual)
  connect(con.yValMix,val.y)
  connect(port_a,val.port_1)
  connect(val.port_2,pum.port_a)
  connect(senTEnt.T,con.TBorWatEnt)
  connect(pum.P,PPum)
  connect(con.yPum,gai1.u)
  connect(gai1.y,pum.m_flow_in)
end Borefield;


within Buildings.DHC.ETS.Combined.Subsystems;
model Chiller
  "Base subsystem with heat recovery chiller"
  replaceable package Medium=Modelica.Media.Interfaces.PartialMedium
    "Medium model"
  parameter Boolean allowFlowReversal=false
    "= true to allow flow reversal, false restricts to design direction (port_a -> port_b)"
  replaceable parameter Buildings.Fluid.Chillers.Data.ElectricEIR.Generic dat
    "Chiller performance data"
  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"
  parameter Modelica.Units.SI.Pressure dpValCon_nominal=dpCon_nominal/2
    "Nominal pressure drop accross control valve on condenser side"
  parameter Modelica.Units.SI.Pressure dpValEva_nominal=dpEva_nominal/2
    "Nominal pressure drop accross control valve on evaporator side"
  parameter Modelica.Units.SI.Temperature TConWatEntMin(displayUnit="degC")=
    dat.TConEntMin "Minimum value of condenser water entering temperature"
  parameter Modelica.Units.SI.Temperature TEvaWatEntMax(displayUnit="degC")=
    dat.TEvaLvgMax - dat.QEva_flow_nominal/cp_default/dat.mEva_flow_nominal
    "Maximum value of evaporator water entering temperature"
  // IO CONNECTORS
  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 TChiWatSupSet(
    final unit="K",
    displayUnit="degC")
    "Chilled water supply temperature set point (may be reset down)"
  Modelica.Fluid.Interfaces.FluidPort_a port_aChiWat(
    redeclare final package Medium=Medium,
    m_flow(
      min=
        if allowFlowReversal then
          -Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Fluid port for chilled water return"
  Modelica.Fluid.Interfaces.FluidPort_b port_bChiWat(
    redeclare final package Medium=Medium,
    m_flow(
      max=
        if allowFlowReversal then
          +Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Fluid port for chilled water supply"
  Modelica.Fluid.Interfaces.FluidPort_a port_aHeaWat(
    redeclare final package Medium=Medium,
    m_flow(
      min=
        if allowFlowReversal then
          -Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Fluid port for heating water return"
  Modelica.Fluid.Interfaces.FluidPort_b port_bHeaWat(
    redeclare final package Medium=Medium,
    m_flow(
      max=
        if allowFlowReversal then
          +Modelica.Constants.inf
        else
          0),
    h_outflow(
      start=Medium.h_default,
      nominal=Medium.h_default))
    "Fluid port for heating water supply"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PChi(
    final unit="W")
    "Chiller power"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PPum(
    final unit="W")
    "Pump power"
  // COMPONENTS
  Fluid.Chillers.ElectricEIR chi(
    redeclare final package Medium1=Medium,
    redeclare final package Medium2=Medium,
    final allowFlowReversal1=allowFlowReversal,
    final allowFlowReversal2=allowFlowReversal,
    final dp1_nominal=0,
    final dp2_nominal=0,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    final per=dat)
    "Water cooled chiller (ports indexed 1 are on condenser side)"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow pumCon(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=dat.mCon_flow_nominal,
    final dp_nominal=dpCon_nominal+dpValCon_nominal)
    "Condenser pump"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow pumEva(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=dat.mEva_flow_nominal,
    final dp_nominal=dpEva_nominal+dpValEva_nominal)
    "Evaporator pump"
  Buildings.DHC.ETS.Combined.Controls.Chiller con(
    final TConWatEntMin=TConWatEntMin,
    final TEvaWatEntMax=TEvaWatEntMax)
    "Controller"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTConLvg(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=dat.mCon_flow_nominal)
    "Condenser water leaving temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTConEnt(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=dat.mCon_flow_nominal)
    "Condenser water entering temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTEvaEnt(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=dat.mEva_flow_nominal)
    "Evaporator water entering temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTEvaLvg(
    redeclare final package Medium=Medium,
    final allowFlowReversal=allowFlowReversal,
    final m_flow_nominal=dat.mEva_flow_nominal)
    "Evaporator water leaving temperature"
  Buildings.DHC.ETS.BaseClasses.Junction splEva(
    redeclare final package Medium=Medium,
    final m_flow_nominal=dat.mEva_flow_nominal .* {1,-1,-1})
    "Flow splitter for the evaporator water circuit"
  Buildings.DHC.ETS.BaseClasses.Junction splConMix(
    redeclare final package Medium=Medium,
    final m_flow_nominal=dat.mCon_flow_nominal .* {1,-1,-1})
    "Flow splitter"
  Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valEva(
    redeclare final package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=false,
    use_strokeTime=false,
    final m_flow_nominal=dat.mEva_flow_nominal,
    final dpValve_nominal=dpValEva_nominal,
    final dpFixed_nominal=fill(dpEva_nominal, 2))
    "Control valve for maximum evaporator water entering temperature"
  Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valCon(
    redeclare final package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=false,
    use_strokeTime=false,
    final m_flow_nominal=dat.mCon_flow_nominal,
    final dpValve_nominal=dpValCon_nominal,
    final dpFixed_nominal=fill(dpCon_nominal, 2))
    "Control valve for minimum condenser water entering temperature"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
    "Constant speed primary pumps control signal"
  Buildings.Controls.OBC.CDL.Reals.Add add2
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai1(final k=dat.mCon_flow_nominal)
    "Scale to nominal mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai2(final k=dat.mEva_flow_nominal)
    "Scale to nominal mass flow rate"
protected
  final parameter Medium.ThermodynamicState sta_default=Medium.setState_pTX(
    T=Medium.T_default,
    p=Medium.p_default,
    X=Medium.X_default[1:Medium.nXi])
    "Medium state at default properties";
  final parameter Modelica.Units.SI.SpecificHeatCapacity cp_default=
      Medium.specificHeatCapacityCp(sta_default)
    "Specific heat capacity of the fluid";
equation
  connect(splConMix.port_3,valCon.port_3)
  connect(valCon.port_2,pumCon.port_a)
  connect(pumEva.port_b,splEva.port_1)
  connect(splEva.port_3,valEva.port_3)
  connect(con.yValEva,valEva.y)
  connect(con.yValCon,valCon.y)
  connect(con.yChi,chi.on)
  connect(uHea,con.uHea)
  connect(uCoo,con.uCoo)
  connect(senTConEnt.T,con.TConWatEnt)
  connect(senTEvaEnt.T,con.TEvaWatEnt)
  connect(splConMix.port_2,port_bHeaWat)
  connect(splEva.port_2,port_bChiWat)
  connect(port_aHeaWat,valCon.port_1)
  connect(port_aChiWat,valEva.port_1)
  connect(valEva.port_2,senTEvaEnt.port_a)
  connect(senTEvaLvg.port_b,pumEva.port_a)
  connect(senTEvaLvg.port_a,chi.port_b2)
  connect(senTEvaEnt.port_b,chi.port_a2)
  connect(chi.port_b1,senTConLvg.port_a)
  connect(senTConLvg.port_b,splConMix.port_1)
  connect(pumCon.port_b,senTConEnt.port_a)
  connect(senTConEnt.port_b,chi.port_a1)
  connect(chi.P,PChi)
  connect(add2.y,PPum)
  connect(pumEva.P,add2.u2)
  connect(pumCon.P,add2.u1)
  connect(con.yChi,booToRea.u)
  connect(booToRea.y,gai2.u)
  connect(gai2.y,pumEva.m_flow_in)
  connect(gai1.y,pumCon.m_flow_in)
  connect(booToRea.y,gai1.u)
  connect(TChiWatSupSet,chi.TSet)
end Chiller;


within Buildings.DHC.ETS.Combined.Subsystems;
model HeatExchanger
  "Base subsystem with district heat exchanger"
  extends Buildings.Fluid.Interfaces.PartialFourPortInterface(
    final m1_flow_nominal=abs(Q_flow_nominal/4200/(T_b1_nominal - T_a1_nominal)),
    final m2_flow_nominal=abs(Q_flow_nominal/4200/(T_b2_nominal - T_a2_nominal)));
  parameter DHC.ETS.Types.ConnectionConfiguration conCon
    "District connection configuration"
  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.PressureDifference dpVal1_nominal(displayUnit=
        "Pa") = dp1Hex_nominal/2
    "Nominal pressure drop of primary control valve"
  parameter Modelica.Units.SI.PressureDifference dpVal2_nominal(displayUnit=
        "Pa") = dp2Hex_nominal/2
    "Nominal pressure drop of secondary control valve"
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat flow rate (from district to building)"
  parameter Modelica.Units.SI.Temperature T_a1_nominal
    "Nominal water inlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_b1_nominal
    "Nominal water outlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_a2_nominal
    "Nominal water inlet temperature on building side"
  parameter Modelica.Units.SI.Temperature T_b2_nominal
    "Nominal water outlet temperature on building side"
  parameter Real spePum1Min(unit="1")=0.1
    "Heat exchanger primary pump minimum speed (fractional)"
  parameter Real spePum2Min(unit="1")=0.1
    "Heat exchanger secondary pump minimum speed (fractional)"
  // IO CONNECTORS
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIso_actual[2]
    "Isolation valves return position (index 1 for condenser)"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput u
    "Control signal for secondary side (from supervisory)"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PPum(
    final unit="W")
    "Power drawn by pump motors"
  // COMPONENTS
  Buildings.DHC.ETS.Combined.Controls.HeatExchanger con(
    final conCon=conCon,
    final spePum1Min=spePum1Min,
    final spePum2Min=spePum2Min)
    "District heat exchanger loop controller"
  Buildings.Fluid.HeatExchangers.PlateHeatExchangerEffectivenessNTU hex(
    redeclare final package Medium1 = Medium1,
    redeclare final package Medium2 = Medium2,
    final use_Q_flow_nominal=true,
    configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    final allowFlowReversal1=allowFlowReversal1,
    final allowFlowReversal2=allowFlowReversal2,
    final dp1_nominal=if have_val1 then 0 else dp1Hex_nominal,
    final dp2_nominal=0,
    final m1_flow_nominal=m1_flow_nominal,
    final m2_flow_nominal=m2_flow_nominal,
    final Q_flow_nominal=Q_flow_nominal,
    final T_a1_nominal=T_a1_nominal,
    final T_a2_nominal=T_a2_nominal)
    "Heat exchanger"

  DHC.ETS.BaseClasses.Pump_m_flow pum1(
    redeclare final package Medium = Medium1,
    final m_flow_nominal=m1_flow_nominal,
    final dp_nominal=dp1Hex_nominal,
    final allowFlowReversal=allowFlowReversal1) if not have_val1
    "District heat exchanger primary pump"
  DHC.ETS.BaseClasses.Pump_m_flow pum2(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=m2_flow_nominal,
    final dp_nominal=dp2Hex_nominal + dpVal2_nominal,
    final allowFlowReversal=allowFlowReversal2)
    "Secondary pump"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2WatEnt(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=m2_flow_nominal,
    final allowFlowReversal=allowFlowReversal2)
    "Heat exchanger secondary water entering temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2WatLvg(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=m2_flow_nominal,
    final allowFlowReversal=allowFlowReversal2)
    "Heat exchanger secondary water leaving temperature"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai2(final k=
        m2_flow_nominal) "Scale to nominal mass flow rate"
  Fluid.Actuators.Valves.TwoWayPressureIndependent val1(
    redeclare final package Medium = Medium1,
    final m_flow_nominal=m1_flow_nominal,
    from_dp=true,
    final dpValve_nominal=dpVal1_nominal,
    use_strokeTime=false,
    final dpFixed_nominal=dp1Hex_nominal) if have_val1
    "Heat exchanger primary control valve"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai1(final k=
        m1_flow_nominal) if not have_val1 "Scale to nominal mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.MultiSum totPPum(
    final nin=
      if have_val1 then
        1
      else
        2)
    "Total pump power"
  Buildings.Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear val2(
    redeclare final package Medium = Medium2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    from_dp=false,
    use_strokeTime=false,
    final m_flow_nominal=m2_flow_nominal,
    final dpValve_nominal=dpVal2_nominal,
    final dpFixed_nominal=fill(dp2Hex_nominal, 2)) "Control valve"
  DHC.ETS.BaseClasses.Junction spl(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=m2_flow_nominal .* {1,-1,-1})
    "Flow splitter"
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
  if have_val1 then
    connect(port_a1, hex.port_a1)
  else
    connect(hex.port_b1, port_b1)
  end if;
  connect(gai2.y,pum2.m_flow_in)
  connect(port_a1,pum1.port_a)
  connect(val1.port_b,port_b1)
  connect(pum2.port_b,senT2WatEnt.port_a)
  connect(senT2WatEnt.port_b,hex.port_a2)
  connect(con.y1, val1.y)
  connect(con.y1, gai1.u)
  connect(gai1.y,pum1.m_flow_in)
  connect(pum1.P,totPPum.u[2])
  connect(pum2.P,totPPum.u[1])
  connect(totPPum.y,PPum)
  connect(yValIso_actual,con.yValIso)
  connect(con.yPum2,gai2.u)
  connect(u,con.u)
  connect(hex.port_b2,senT2WatLvg.port_a)
  connect(val2.port_2,pum2.port_a)
  connect(port_a2,val2.port_1)
  connect(spl.port_1,senT2WatLvg.port_b)
  connect(spl.port_2,port_b2)
  connect(spl.port_3,val2.port_3)
  connect(con.yVal2,val2.y)
  connect(hex.port_b1, val1.port_a)
  connect(pum1.port_b, hex.port_a1)
end HeatExchanger;


Base subsystem with water-to-water heat pump. This model represents a water-to-water heat pump, an evaporator water pump,
and a condenser water pump.
The heat pump model is described in

Buildings.Fluid.HeatPumps.Carnot_TCon.
By default, a variable speed condenser pump is considered, but a constant speed
pump may also be represented by setting have_varFloCon to false.
The evaporator hydronics and control are described in

Buildings.DHC.ETS.Combined.Subsystems.BaseClasses.PartialHeatPump.

within Buildings.DHC.ETS.Combined.Subsystems;
model HeatPump "Base subsystem with water-to-water heat pump"
  extends
    Buildings.DHC.ETS.Combined.Subsystems.BaseClasses.PartialHeatPump(
        heaPum(QCon_flow_nominal=Q1_flow_nominal));
  parameter Boolean have_varFloCon = true
    "Set to true for a variable condenser flow"
  parameter Modelica.Units.SI.HeatFlowRate Q1_flow_nominal(min=0)
    "Heating heat flow rate"
  // IO CONNECTORS
  Buildings.Controls.OBC.CDL.Interfaces.RealInput TSupSet(
    final unit="K",
    displayUnit="degC")
    "Supply temperature set point"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput m1_flow(
    final unit="kg/s") if have_varFloCon
    "Condenser mass flow rate"
  // COMPONENTS
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant floConNom(
    final k=mCon_flow_nominal) if not have_varFloCon
    "Nominal flow rate"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea
  Buildings.Controls.OBC.CDL.Reals.Multiply floCon
    "Zero flow rate if not enabled"
equation
  connect(booToRea.y, floCon.u1)
  connect(m1_flow, floCon.u2)
  connect(floConNom.y, floCon.u2)
  connect(port_a1, heaPum.port_a1)
  connect(pumCon.port_b, port_b1)
  connect(TSupSet, heaPum.TSet)
  connect(floCon.y, pumCon.m_flow_in)
  connect(conPI.trigger, floEva.u)
  connect(addPPum.y, PPum)
  connect(uEna, booToRea.u)
  connect(uEna, floEva.u)
end HeatPump;


within Buildings.DHC.ETS.Combined.Subsystems;
model HeatPumpDHWTank
  "Base subsystem with water-to-water heat pump with storage tank for domestic hot water"
  extends
    Buildings.DHC.ETS.Combined.Subsystems.BaseClasses.PartialHeatPump(
      heaPum(
        QCon_flow_nominal=QHotWat_flow_nominal,
        QCon_flow_max=QHotWat_flow_nominal),
    pumCon(use_riseTime=true),
    pumEva(use_riseTime=true));
  parameter Buildings.DHC.Loads.HotWater.Data.GenericDomesticHotWaterWithHeatExchanger
    datWatHea "Performance data"
  parameter Modelica.Units.SI.HeatFlowRate QHotWat_flow_nominal(min=0)
    "Nominal capacity of heat pump condenser for hot water production system (>=0)"

  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal floCon(realTrue=
        mCon_flow_nominal) "Condenser mass flow rate"
  Buildings.DHC.Loads.HotWater.StorageTankWithExternalHeatExchanger heaPumTan(
    redeclare package MediumDom = Medium1,
    redeclare package MediumHea = Medium2,
    final dat=datWatHea)
    "Heat pump with storage tank for domestic hot water"

  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THotSouSet(
    k=datWatHea.TDom_nominal)
    "Set point of water in hot water tank"
  Buildings.Fluid.Sources.Boundary_pT preRef(
    redeclare package Medium = Medium2,
    p(displayUnit="bar"),
    nPorts=1) "Reference pressure for loop"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTemHeaPumRet(
    redeclare package Medium = Medium1,
    allowFlowReversal=false,
    m_flow_nominal=mCon_flow_nominal,
    tau=0) "Sensor for return temperature to heat pump"
  Buildings.Controls.OBC.CDL.Reals.AddParameter addPar(
    p=dT_nominal) "dT for heater"
  Modelica.Blocks.Math.Add addPPum1 "Electricity use for pumps"
  Buildings.Controls.OBC.CDL.Logical.And and2
    "Outputs true if boiler needs to be charged and plant is enabled"
equation
  connect(THotSouSet.y, heaPumTan.TDomSet)
  connect(heaPumTan.port_bHea, senTemHeaPumRet.port_a)
  connect(senTemHeaPumRet.T, addPar.u)
  connect(floCon.y, pumCon.m_flow_in)
  connect(heaPumTan.port_aHea, pumCon.port_b)
  connect(senTemHeaPumRet.port_b, heaPum.port_a1)
  connect(addPPum.y, addPPum1.u1)
  connect(heaPumTan.PEle, addPPum1.u2)
  connect(addPPum1.y, PPum)
  connect(addPar.y, heaPum.TSet)
  connect(heaPumTan.port_bDom, port_b1)
  connect(port_a1, heaPumTan.port_aDom)
  connect(uEna, and2.u1)
  connect(heaPumTan.charge, and2.u2)
  connect(and2.y, floEva.u)
  connect(and2.y, floCon.u)
  connect(and2.y, conPI.trigger)
  connect(preRef.ports[1], heaPum.port_b1)
end HeatPumpDHWTank;


within Buildings.DHC.ETS.Combined;
package Subsystems "Package of models for subsystems of fifth generation DHC ETS"
  extends Modelica.Icons.VariantsPackage;
end Subsystems;


within Buildings.DHC.ETS.Combined.Subsystems;
model SwitchBox
  "Model for mass flow rate redirection with three-port two-position directional valves"
  replaceable package Medium = Modelica.Media.Interfaces.PartialMedium
    "Medium model";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal
    "Nominal mass flow rate"
  parameter Modelica.Units.SI.PressureDifference dpValve_nominal(
    min=0,
    displayUnit="Pa") = 5000 "Valve pressure drop at nominal conditions"
  parameter Real trueHoldDuration(
    final unit="s") = 60
    "true hold duration";
  parameter Real falseHoldDuration(
    final unit="s") = trueHoldDuration
    "false hold duration";
  parameter Modelica.Fluid.Types.Dynamics energyDynamics=
    Modelica.Fluid.Types.Dynamics.FixedInitial
    "Type of energy balance (except for the pump always modeled in steady state)"
  // IO CONECTORS
  Modelica.Fluid.Interfaces.FluidPort_b port_bSup(
    redeclare package Medium = Medium)
    "Supply line outlet port"
  Modelica.Fluid.Interfaces.FluidPort_b port_bRet(
    redeclare final package Medium = Medium)
    "Return line outlet port"
  Modelica.Fluid.Interfaces.FluidPort_a port_aSup(
    redeclare final package Medium = Medium)
    "Supply line inlet port"
  Modelica.Fluid.Interfaces.FluidPort_a port_aRet(
    redeclare final package Medium = Medium)
    "Return line inlet port"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mRev_flow(final unit="kg/s")
    "Service water mass flow rate in reverse direction"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput mPos_flow(final unit="kg/s")
    "Service water mass flow rate in positive direction"
  // COMPONENTS
  Buildings.DHC.ETS.BaseClasses.Junction splSup(
    redeclare final package Medium = Medium,
    m_flow_nominal={1,1,1}*m_flow_nominal)
    "Flow splitter"
  Buildings.DHC.ETS.BaseClasses.Junction splRet(
    redeclare final package Medium = Medium,
    m_flow_nominal={1,1,1}*m_flow_nominal)
    "Flow splitter"
  Buildings.DHC.ETS.Combined.Controls.SwitchBox con(
    final m_flow_nominal=m_flow_nominal,
    final trueHoldDuration=trueHoldDuration,
    final falseHoldDuration=falseHoldDuration)
    "Switch box controller"
  Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valSup(
    redeclare package Medium = Medium,
    dpValve_nominal=dpValve_nominal,
    use_strokeTime=false,
    m_flow_nominal=m_flow_nominal,
    linearized={true,true},
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Directional valve"
  Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valRet(
    redeclare package Medium = Medium,
    dpValve_nominal=dpValve_nominal,
    use_strokeTime=false,
    m_flow_nominal=m_flow_nominal,
    linearized={true,true},
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState)
    "Directional valve"
equation
  connect(port_bSup, splSup.port_2)
  connect(mRev_flow, con.mRev_flow)
  connect(splRet.port_1, port_aRet)
  connect(valSup.port_1, splSup.port_1)
  connect(valSup.port_3, splRet.port_3)
  connect(splRet.port_2, valRet.port_1)
  connect(splSup.port_3, valRet.port_3)
  connect(valRet.port_2, port_bRet)
  connect(valSup.port_2, port_aSup)
  connect(con.y, valRet.y)
  connect(mPos_flow, con.mPos_flow)
  connect(con.y, valSup.y)
end SwitchBox;


within Buildings.DHC.ETS.Combined.Subsystems;
model WatersideEconomizer
  "Base subsystem with waterside economizer"
  extends Buildings.Fluid.Interfaces.PartialFourPortInterface(
    final m1_flow_nominal=abs(Q_flow_nominal/4200/(T_b1_nominal - T_a1_nominal)),
    final m2_flow_nominal=abs(Q_flow_nominal/4200/(T_b2_nominal - T_a2_nominal)));
  parameter DHC.ETS.Types.ConnectionConfiguration conCon
    "District connection configuration"
  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.PressureDifference dpVal1_nominal(displayUnit=
        "Pa") = if have_val1 then dp1Hex_nominal/2 else 0
    "Nominal pressure drop of primary control valve"
  parameter Modelica.Units.SI.PressureDifference dpVal2_nominal(displayUnit=
        "Pa") = dp2Hex_nominal/10
    "Nominal pressure drop of heat exchanger bypass valve"
  parameter Modelica.Units.SI.HeatFlowRate Q_flow_nominal
    "Nominal heat flow rate (from district to building)"
  parameter Modelica.Units.SI.Temperature T_a1_nominal
    "Nominal water inlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_b1_nominal
    "Nominal water outlet temperature on district side"
  parameter Modelica.Units.SI.Temperature T_a2_nominal
    "Nominal water inlet temperature on building side"
  parameter Modelica.Units.SI.Temperature T_b2_nominal
    "Nominal water outlet temperature on building side"
  parameter Real y1Min(final unit="1")=0.05
    "Minimum pump flow rate or valve opening for temperature measurement (fractional)"
  parameter Modelica.Units.SI.TemperatureDifference dTEna=1
    "Minimum delta-T above predicted heat exchanger leaving water temperature to enable WSE"
  parameter Modelica.Units.SI.TemperatureDifference dTDis=0.5
    "Minimum delta-T across heat exchanger before disabling WSE"
  parameter Real k(
    min=0)=1
    "Gain of controller"
  parameter Modelica.Units.SI.Time Ti(min=Buildings.Controls.OBC.CDL.Constants.small)=
       60 "Time constant of integrator block"
  // IO CONNECTORS
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PPum(
    final unit="W") if not have_val1
    "Power drawn by pump motors"
  // COMPONENTS
  Buildings.DHC.ETS.Combined.Controls.WatersideEconomizer conWSE(
    final m2_flow_nominal=m2_flow_nominal,
    final y1Min=y1Min,
    final T_a1_nominal=T_a1_nominal,
    final T_b2_nominal=T_b2_nominal,
    final dTEna=dTEna,
    final dTDis=dTDis)
    "District heat exchanger loop controller"
  Buildings.Fluid.HeatExchangers.PlateHeatExchangerEffectivenessNTU hex(
    redeclare final package Medium1 = Medium1,
    redeclare final package Medium2 = Medium2,
    final use_Q_flow_nominal=true,
    configuration=Buildings.Fluid.Types.HeatExchangerConfiguration.CounterFlow,
    final allowFlowReversal1=allowFlowReversal1,
    final allowFlowReversal2=allowFlowReversal2,
    final dp1_nominal=if have_val1 then 0 else dp1Hex_nominal,
    final dp2_nominal=0,
    final m1_flow_nominal=m1_flow_nominal,
    final m2_flow_nominal=m2_flow_nominal,
    final Q_flow_nominal=Q_flow_nominal,
    final T_a1_nominal=T_a1_nominal,
    final T_a2_nominal=T_a2_nominal)
    "Heat exchanger"
  DHC.ETS.BaseClasses.Pump_m_flow pum1(
    redeclare final package Medium = Medium1,
    final m_flow_nominal=m1_flow_nominal,
    final dp_nominal=dp1Hex_nominal,
    final allowFlowReversal=allowFlowReversal1) if not have_val1
    "District heat exchanger primary pump"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2WatEnt(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=m2_flow_nominal,
    final allowFlowReversal=allowFlowReversal2)
    "Heat exchanger secondary water entering temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2WatLvg(
    redeclare final package Medium = Medium2,
    final m_flow_nominal=m2_flow_nominal,
    final allowFlowReversal=allowFlowReversal2)
    "Heat exchanger secondary water leaving temperature"
  Buildings.Fluid.Actuators.Valves.TwoWayPressureIndependent val1(
    redeclare final package Medium = Medium1,
    final m_flow_nominal=m1_flow_nominal,
    from_dp=true,
    final dpValve_nominal=dpVal1_nominal,
    final dpFixed_nominal=dp1Hex_nominal,
    use_strokeTime=false) if have_val1 "Heat exchanger primary control valve"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai1(final k=
        m1_flow_nominal) if not have_val1 "Scale to nominal mass flow rate"
  Buildings.Fluid.Actuators.Valves.ThreeWayLinear val2(
    redeclare final package Medium = Medium2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    use_strokeTime=false,
    final m_flow_nominal=m2_flow_nominal,
    final dpValve_nominal=dpVal2_nominal,
    final dpFixed_nominal={dp2Hex_nominal,0},
    fraK=1) "Heat exchanger secondary control valve"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1WatEnt(
    redeclare final package Medium = Medium1,
    final m_flow_nominal=m1_flow_nominal,
    final allowFlowReversal=allowFlowReversal1)
    "Heat exchanger primary water entering temperature"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uCoo
    "Cooling enable signal"
  Buildings.Controls.OBC.CDL.Interfaces.RealInput yValIsoEva_actual(final unit="1")
    "Return position of evaporator to ambient loop isolation valve"
  Buildings.Fluid.Sensors.MassFlowRate senMasFlo2(redeclare final package
      Medium = Medium2, final allowFlowReversal=allowFlowReversal2)
    "Heat exchanger secondary mass flow rate"
protected
  parameter Boolean have_val1=
    conCon ==Buildings.DHC.ETS.Types.ConnectionConfiguration.TwoWayValve
    "True in case of control valve on district side, false in case of a pump";
equation
  if not have_val1 then
    connect(hex.port_b1, port_b1)
  else
    connect(port_a1, senT1WatEnt.port_a)
  end if;
  connect(port_a1,pum1.port_a)
  connect(val1.port_b,port_b1)
  connect(conWSE.y1, val1.y)
  connect(conWSE.y1, gai1.u)
  connect(gai1.y,pum1.m_flow_in)
  connect(PPum, pum1.P)
  connect(conWSE.yVal2, val2.y)
  connect(port_a2, senT2WatEnt.port_a)
  connect(hex.port_b2, senT2WatLvg.port_a)
  connect(senT1WatEnt.port_b, hex.port_a1)
  connect(senT1WatEnt.port_a, pum1.port_b)
  connect(hex.port_b1, val1.port_a)
  connect(uCoo, conWSE.uCoo)
  connect(senT1WatEnt.T, conWSE.T1WatEnt)
  connect(conWSE.T2WatEnt, senT2WatEnt.T)
  connect(senT2WatLvg.T, conWSE.T2WatLvg)
  connect(yValIsoEva_actual, conWSE.yValIsoEva_actual)
  connect(val2.port_3, senT2WatLvg.port_a)
  connect(val2.port_1, hex.port_a2)
  connect(val2.port_2, senT2WatEnt.port_b)
  connect(port_b2, senMasFlo2.port_b)
  connect(senMasFlo2.port_a, senT2WatLvg.port_b)
  connect(senMasFlo2.m_flow, conWSE.m2_flow)
end WatersideEconomizer;


Contains base classes for Subsystems

within Buildings.DHC.ETS.Combined.Subsystems;
package BaseClasses "Contains base classes for Subsystems"
  extends Modelica.Icons.BasesPackage;
end BaseClasses;


within Buildings.DHC.ETS.Combined.Subsystems.BaseClasses;
model PartialHeatPump
  "Partial base class for subsystems containing a heat pump"
  replaceable package Medium1=Modelica.Media.Interfaces.PartialMedium
    "Medium model on condenser side"
  replaceable package Medium2=Modelica.Media.Interfaces.PartialMedium
    "Medium model on evaporator side"
  parameter Real COP_nominal(final unit="1")
    "Heat pump COP"
  parameter Modelica.Units.SI.Temperature TCon_nominal
    "Condenser outlet temperature used to compute COP_nominal"
  parameter Modelica.Units.SI.Temperature TEva_nominal
    "Evaporator outlet temperature used to compute COP_nominal"

  parameter Modelica.Units.SI.TemperatureDifference dT_nominal(min=0) = 5
    "Water temperature drop/increase accross load and source-side HX (always positive)"
  final parameter Modelica.Units.SI.MassFlowRate mCon_flow_nominal = heaPum.m1_flow_nominal
    "Condenser mass flow rate";
  final parameter Modelica.Units.SI.MassFlowRate mEva_flow_nominal = heaPum.m2_flow_nominal
    "Evaporator mass flow rate";

  parameter Boolean allowFlowReversal1=false
    "Set to true to allow flow reversal on condenser side"
  parameter Boolean allowFlowReversal2=false
    "Set to true to allow flow reversal on evaporator side"
  parameter Modelica.Units.SI.Pressure dp1_nominal(displayUnit="Pa")
    "Pressure difference over condenser"
  parameter Modelica.Units.SI.Pressure dp2_nominal(displayUnit="Pa")
    "Pressure difference over evaporator"
  // IO CONNECTORS
  Modelica.Fluid.Interfaces.FluidPort_a port_a2(
    redeclare final package Medium = Medium2,
    m_flow(min=if allowFlowReversal2 then -Modelica.Constants.inf else 0),
    h_outflow(start=Medium2.h_default, nominal=Medium2.h_default))
    "Fluid port for entering evaporator water"
  Modelica.Fluid.Interfaces.FluidPort_b port_b2(
    redeclare final package Medium = Medium2,
    m_flow(max=if allowFlowReversal2 then +Modelica.Constants.inf else 0),
    h_outflow(start=Medium2.h_default, nominal=Medium2.h_default))
    "Fluid port for leaving evaporator water"
  Modelica.Fluid.Interfaces.FluidPort_a port_a1(
    redeclare final package Medium = Medium1,
    m_flow(min=if allowFlowReversal1 then -Modelica.Constants.inf else 0),
    h_outflow(start=Medium1.h_default, nominal=Medium1.h_default))
    "Fluid port for cold domestic water"
  Modelica.Fluid.Interfaces.FluidPort_b port_b1(
    redeclare final package Medium = Medium1,
    m_flow(max=if allowFlowReversal1 then +Modelica.Constants.inf else 0),
    h_outflow(start=Medium1.h_default, nominal=Medium1.h_default))
    "Fluid port for heated domestic hot water"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PHea(
    final unit="W") "Heat pump power"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput PPum(
    final unit="W") "Pump power"
  Buildings.Controls.OBC.CDL.Interfaces.RealOutput mEva_flow(final unit="kg/s")
    "Evaporator water mass flow rate"
  // COMPONENTS
  Buildings.Fluid.HeatPumps.Carnot_TCon heaPum(
    redeclare package Medium1 = Medium1,
    redeclare package Medium2 = Medium2,
    allowFlowReversal1=false,
    allowFlowReversal2=false,
    dTEva_nominal=-dT_nominal,
    dTCon_nominal=dT_nominal,
    use_eta_Carnot_nominal=false,
    COP_nominal=COP_nominal,
    TCon_nominal=TCon_nominal,
    TEva_nominal=TEva_nominal,
    final dp1_nominal=dp1_nominal,
    final dp2_nominal=dp2_nominal,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial)
    "Domestic hot water heat pump"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow
                                     pumCon(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    redeclare package Medium = Medium2,
    m_flow_nominal=mCon_flow_nominal,
    riseTime=10,
    dp_nominal=dp1_nominal)
                 "Pump for heat pump condenser"

  Buildings.Fluid.Movers.Preconfigured.SpeedControlled_y pumEva(
    redeclare final package Medium = Medium2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    final allowFlowReversal=allowFlowReversal2,
    addPowerToMedium=false,
    use_riseTime=false,
    m_flow_nominal=mEva_flow_nominal,
    dp_nominal=dp2_nominal + 6000) "Heat pump evaporator water pump"

  Modelica.Blocks.Math.Add addPPum "Electricity use for pumps"
  Buildings.Controls.OBC.CDL.Conversions.BooleanToReal floEva
                           "Evaporator mass flow rate"
  Fluid.Actuators.Valves.ThreeWayEqualPercentageLinear valHeaPumEva(
    redeclare package Medium = Medium2,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyState,
    m_flow_nominal=mEva_flow_nominal,
    dpValve_nominal=6000) "Valve at heat pump evaporator"
  Fluid.Sensors.TemperatureTwoPort senTEvaRet(
    redeclare final package Medium = Medium2,
    final allowFlowReversal=allowFlowReversal1,
    final m_flow_nominal=mEva_flow_nominal,
    tau=0)
    "Evaporator return temperature sensor"
  Fluid.Sensors.TemperatureTwoPort senTDisSup(
    redeclare final package Medium = Medium2,
    final allowFlowReversal=allowFlowReversal1,
    final m_flow_nominal=mEva_flow_nominal,
    tau=0)
    "District supply temperature sensor"
  Buildings.Controls.OBC.CDL.Reals.Subtract dT_supRet
    "Temperature difference over heat pump connection"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant dTSet(k=dT_nominal)
    "Set point for temperature difference over heat pump"
  Buildings.Controls.OBC.CDL.Reals.PIDWithReset conPI(
    k=0.1,
    Ti=120,                                                  xi_start=0.2,
    reverseActing=false)
    "Controller to ensure dT_nominal over heat pump connection"
  Fluid.Sensors.MassFlowRate senMasFlo(redeclare package Medium = Medium2)
    "Mass flow rate drawn from ETS"
  Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uEna(start=false)
    "Enable signal"
  Buildings.DHC.ETS.BaseClasses.Junction
    junction(redeclare package Medium = Medium2, m_flow_nominal={
        mEva_flow_nominal,-mEva_flow_nominal,mEva_flow_nominal})
equation
  connect(heaPum.port_b1,pumCon. port_a)
  connect(heaPum.P, PHea)
  connect(senTDisSup.T, dT_supRet.u1)
  connect(valHeaPumEva.port_1, senTDisSup.port_b)
  connect(conPI.u_s, dTSet.y)
  connect(dT_supRet.y, conPI.u_m)
  connect(conPI.y, valHeaPumEva.y)
  connect(senTDisSup.port_a, senMasFlo.port_b)
  connect(senMasFlo.port_a, port_a2)
  connect(senMasFlo.m_flow, mEva_flow)
  connect(pumCon.P, addPPum.u1)
  connect(addPPum.u2, pumEva.P)
  connect(heaPum.port_b2, senTEvaRet.port_a)
  connect(senTEvaRet.T, dT_supRet.u2)
  connect(heaPum.port_a2, pumEva.port_b)
  connect(junction.port_2, port_b2)
  connect(junction.port_1, senTEvaRet.port_b)
  connect(valHeaPumEva.port_2, pumEva.port_a)
  connect(junction.port_3, valHeaPumEva.port_3)
  connect(floEva.y, pumEva.y)
end PartialHeatPump;


within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model Borefield
  "Validation of the base subsystem model with geothermal borefield"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  parameter Integer nBorHol=100
    "Number of boreholes (must be a square number)";
  parameter Modelica.Units.SI.Distance dxy=6
    "Distance in x-axis (and y-axis) between borehole axes";
  final parameter Modelica.Units.SI.Distance cooBor[nBorHol,2]=
      Buildings.DHC.ETS.BaseClasses.computeCoordinates(
      nBorHol, dxy) "Coordinates of boreholes";
  Buildings.DHC.ETS.Combined.Subsystems.Borefield borFie(
    redeclare final package Medium=Medium,
    final datBorFie=datBorFie,
    dp_nominal=5E4,
    TBorWatEntMax=313.15)
    "Subsystem with heat recovery chiller"
  Fluid.Sources.Boundary_pT conWat(
    redeclare package Medium=Medium,
    use_T_in=true,
    nPorts=2)
    "Condenser water boundary conditions"
  Fluid.Sensors.TemperatureTwoPort senTInl(
    redeclare final package Medium=Medium,
    m_flow_nominal=borFie.pum.m_flow_nominal)
    "Water inlet temperature"
  Fluid.Sensors.TemperatureTwoPort senTOut(
    redeclare final package Medium=Medium,
    m_flow_nominal=borFie.pum.m_flow_nominal)
    "Water outlet temperature"
  parameter Fluid.Geothermal.Borefields.Data.Borefield.Example datBorFie(
    conDat=Fluid.Geothermal.Borefields.Data.Configuration.Example(
      cooBor=cooBor,
      dp_nominal=0))
    "Borefield design data"
  Modelica.Blocks.Sources.TimeTable TInlVal(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,2;
      2,2;
      3,15;
      7,15;
      9,35;
      10,45;
      11,30;
      20,30],
    timeScale=1000,
    offset=273.15)
    "Inlet temperature values"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer(
    k=0)
    "Zero"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp u(
    duration=1000,
    startTime=2500)
    "Control signal"
equation
  connect(senTInl.port_b,conWat.ports[1])
  connect(conWat.ports[2],senTOut.port_a)
  connect(senTInl.port_a,borFie.port_a)
  connect(borFie.port_b,senTOut.port_b)
  connect(TInlVal.y,conWat.T_in)
  connect(zer.y,borFie.yValIso_actual[2])
  connect(u.y,borFie.u)
  connect(u.y,borFie.yValIso_actual[1])
end Borefield;


within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model Chiller
  "Validation of the base subsystem model with heat recovery chiller"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  parameter Fluid.Chillers.Data.ElectricEIR.Generic datChi(
    QEva_flow_nominal=-1E6,
    COP_nominal=3,
    PLRMax=1,
    PLRMinUnl=0.3,
    PLRMin=0.3,
    etaMotor=1,
    mEva_flow_nominal=30,
    mCon_flow_nominal=30,
    TEvaLvg_nominal=280.15,
    capFunT={1,0,0,0,0,0},
    EIRFunT={1,0,0,0,0,0},
    EIRFunPLR={1,0,0},
    TEvaLvgMin=276.15,
    TEvaLvgMax=288.15,
    TConEnt_nominal=313.15,
    TConEntMin=303.15,
    TConEntMax=333.15)
    "Chiller performance data"
  Buildings.DHC.ETS.Combined.Subsystems.Chiller chi(
    redeclare final package Medium=Medium,
    final dat=datChi,
    dpCon_nominal=15E3,
    dpEva_nominal=15E3)
    "Subsystem with heat recovery chiller"
  Fluid.Sources.Boundary_pT evaWat(
    redeclare package Medium=Medium,
    use_T_in=true,
    nPorts=2)
    "Evaporator water boundary conditions"
  Fluid.Sources.Boundary_pT conWat(
    redeclare package Medium=Medium,
    use_T_in=true,
    nPorts=2)
    "Condenser water boundary conditions"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSupSet(
    k=7+273.15,
    y(final unit="K",
      displayUnit="degC"))
    "Chilled water supply temperature set point"
  Fluid.Sensors.TemperatureTwoPort senTHeaWatSup(
    redeclare final package Medium=Medium,
    m_flow_nominal=datChi.mCon_flow_nominal)
    "Heating water supply temperature"
  Fluid.Sensors.TemperatureTwoPort senTChiWatSup(
    redeclare final package Medium=Medium,
    m_flow_nominal=datChi.mEva_flow_nominal)
    "Chilled water supply temperature"
  Fluid.Sensors.TemperatureTwoPort senTHeaWatRet(
    redeclare final package Medium=Medium,
    m_flow_nominal=datChi.mCon_flow_nominal)
    "Heating water return temperature"
  Fluid.Sensors.TemperatureTwoPort senTChiWatRet(
    redeclare final package Medium=Medium,
    m_flow_nominal=datChi.mEva_flow_nominal)
    "Chilled water return temperature"
  Modelica.Blocks.Sources.BooleanExpression uHea(
    y=time < 4000)
    "Heating enable signal"
  Modelica.Blocks.Sources.BooleanExpression uCoo(
    y=time >= 1000)
    "Cooling enable signal"
  Modelica.Blocks.Sources.TimeTable THeaWatRet(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,44;
      2,44;
      3,34;
      4.5,34;
      5,14;
      10,14],
    timeScale=1000,
    offset=273.15)
    "Heating water return temperature values"
  Modelica.Blocks.Sources.TimeTable TChiWatRet(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,9;
      1,9;
      2,14;
      3,14;
      4,11;
      5,11],
    timeScale=1000,
    offset=273.15)
    "Chilled water return temperature values"
equation
  connect(chi.port_bHeaWat,senTHeaWatSup.port_a)
  connect(senTHeaWatSup.port_b,conWat.ports[1])
  connect(evaWat.ports[1],senTChiWatSup.port_b)
  connect(senTChiWatSup.port_a,chi.port_bChiWat)
  connect(conWat.ports[2],senTHeaWatRet.port_a)
  connect(senTHeaWatRet.port_b,chi.port_aHeaWat)
  connect(chi.port_aChiWat,senTChiWatRet.port_b)
  connect(senTChiWatRet.port_a,evaWat.ports[2])
  connect(uCoo.y,chi.uCoo)
  connect(uHea.y,chi.uHea)
  connect(TChiWatSupSet.y,chi.TChiWatSupSet)
  connect(THeaWatRet.y,conWat.T_in)
  connect(TChiWatRet.y,evaWat.T_in)
end Chiller;


within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model HeatExchanger
  "Validation of the base subsystem model with district heat exchanger"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  Buildings.Fluid.Sources.Boundary_pT bou1Pum(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=2) "Primary boundary conditions"
  Buildings.Fluid.Sources.Boundary_pT bou2(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=4) "Secondary boundary conditions"
  Modelica.Blocks.Sources.BooleanExpression uHeaRej(
    y=time >= 3000) "Heat rejection enable signal"
  Modelica.Blocks.Sources.BooleanExpression uEnaColRej(
    y=time >= 1000 and time < 3000)
    "Cold rejection enable signal"
  Buildings.DHC.ETS.Combined.Subsystems.HeatExchanger hexPum(
    redeclare final package Medium1 = Medium,
    redeclare final package Medium2 = Medium,
    show_T=true,
    conCon=Buildings.DHC.ETS.Types.ConnectionConfiguration.Pump,
    dp1Hex_nominal=20E3,
    dp2Hex_nominal=20E3,
    Q_flow_nominal=1E6,
    T_a1_nominal=281.15,
    T_b1_nominal=277.15,
    T_a2_nominal=275.15,
    T_b2_nominal=279.15)
    "Heat exchanger with primary pump"
  Buildings.Controls.OBC.CDL.Reals.Switch swi
    "Switch secondary temperature value depending on heat/cold rejection mode"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1OutPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m1_flow_nominal)
    "Primary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1InlPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m1_flow_nominal)
    "Primary inlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2OutPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m2_flow_nominal)
    "Secondary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2InlPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m2_flow_nominal)
    "Secondary inlet temperature"
  Buildings.DHC.ETS.Combined.Subsystems.HeatExchanger hexVal(
    redeclare final package Medium1 = Medium,
    redeclare final package Medium2 = Medium,
    show_T=true,
    conCon=Buildings.DHC.ETS.Types.ConnectionConfiguration.TwoWayValve,
    dp1Hex_nominal=20E3,
    dp2Hex_nominal=20E3,
    Q_flow_nominal=1E6,
    T_a1_nominal=281.15,
    T_b1_nominal=277.15,
    T_a2_nominal=275.15,
    T_b2_nominal=279.15)
    "Heat exchanger with primary control valve"

  Buildings.Fluid.Sources.Boundary_pT bou1InlVal(
    redeclare package Medium = Medium,
    p=Medium.p_default + 30E3,
    use_T_in=true,
    nPorts=1) "Primary boundary conditions"
  Buildings.Fluid.Sources.Boundary_pT bou1OutVal(redeclare package Medium =
        Medium, nPorts=1) "Primary boundary conditions"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1InlVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m1_flow_nominal)
    "Primary inlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1OutVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m1_flow_nominal)
    "Primary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2OutVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m2_flow_nominal)
    "Secondary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2InlVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m2_flow_nominal)
    "Secondary inlet temperature"
  Buildings.Controls.OBC.CDL.Logical.Or or2
    "Compute enable signal for heat/cold rejection"
  Modelica.Blocks.Sources.RealExpression yValIsoCon(
    y=if time >= 2500 then
        1
      else
        0)
    "Condenser loop isolation valve opening"
  Modelica.Blocks.Sources.RealExpression yValIsoEva(
    y=if time >= 500 then
        1
      else
        0)
    "Evaporator loop isolation valve opening"
  Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin1(
    amplitude=0.5,
    freqHz=1e-3,
    offset=0.5)
    "Control signal"
  Buildings.Controls.OBC.CDL.Reals.Switch swi1 "Activate heat/cold rejection"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer(
    k=0) "Zero"
  Modelica.Blocks.Sources.TimeTable TColVal(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,6;
      2,6;
      3,16;
      4.5,16;
      5,6;
      10,6],
    timeScale=1000,
    offset=273.15) "Cold side temperature values"
  Modelica.Blocks.Sources.TimeTable THotVal(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,45;
      2,45;
      3,55;
      4.5,55;
      5,25;
      10,25],
    timeScale=1000,
    offset=273.15)
    "Hot side temperature values"
  Modelica.Blocks.Sources.TimeTable TSerWat(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,8;
      1,8;
      2,13;
      3,18;
      4,6;
      5,18],
    timeScale=1000,
    offset=273.15) "Service water temperature values"
equation
  connect(swi.y, bou2.T_in)
  connect(uEnaColRej.y,swi.u2)
  connect(hexPum.port_b1,senT1OutPum.port_a)
  connect(senT1OutPum.port_b, bou1Pum.ports[1])
  connect(hexPum.port_a1,senT1InlPum.port_b)
  connect(senT1InlPum.port_a, bou1Pum.ports[2])
  connect(hexPum.port_b2,senT2OutPum.port_a)
  connect(senT2OutPum.port_b, bou2.ports[1])
  connect(bou2.ports[2], senT2InlPum.port_a)
  connect(senT2InlPum.port_b,hexPum.port_a2)
  connect(hexVal.port_a1,senT1InlVal.port_b)
  connect(senT1InlVal.port_a, bou1InlVal.ports[1])
  connect(bou1OutVal.ports[1], senT1OutVal.port_b)
  connect(senT1OutVal.port_a,hexVal.port_b1)
  connect(hexVal.port_a2,senT2InlVal.port_b)
  connect(senT2OutVal.port_a,hexVal.port_b2)
  connect(uEnaColRej.y,or2.u2)
  connect(uHeaRej.y,or2.u1)
  connect(yValIsoCon.y,hexVal.yValIso_actual[1])
  connect(yValIsoCon.y,hexPum.yValIso_actual[1])
  connect(yValIsoEva.y,hexVal.yValIso_actual[2])
  connect(yValIsoEva.y,hexPum.yValIso_actual[2])
  connect(or2.y,swi1.u2)
  connect(sin1.y,swi1.u1)
  connect(zer.y,swi1.u3)
  connect(swi1.y,hexVal.u)
  connect(swi1.y,hexPum.u)
  connect(TColVal.y,swi.u1)
  connect(THotVal.y,swi.u3)
  connect(TSerWat.y, bou1Pum.T_in)
  connect(TSerWat.y, bou1InlVal.T_in)
  connect(senT2OutVal.port_b, bou2.ports[3])
  connect(bou2.ports[4], senT2InlVal.port_a)
end HeatExchanger;


within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model HeatPump
  "Validation of the base subsystem model with heat pump"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  parameter Modelica.Units.SI.Temperature TCon_nominal = 273.15+30 "Nominal condenser outlet temperature";
  parameter Modelica.Units.SI.Temperature TAmb_nominal = 273.15+15 "Nominal ambient loop temperature to evaporator";
  parameter Modelica.Units.SI.Power QLoa_nominal = 1000 "Nominal load";
  Buildings.DHC.ETS.Combined.Subsystems.HeatPump
    heaPum(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    COP_nominal=2.3,
    TCon_nominal=TCon_nominal,
    TEva_nominal(displayUnit="K") = TAmb_nominal - heaPum.dT_nominal,
    dp1_nominal=6000,
    dp2_nominal=6000,
    Q1_flow_nominal=QLoa_nominal)
  Fluid.Sources.Boundary_pT supAmb(
    redeclare package Medium = Medium,
    p(displayUnit="bar"),
    T=TAmb_nominal,
    nPorts=1) "Ambient water supply"
  Fluid.Sources.Boundary_pT sinAmb(
    redeclare package Medium = Medium,
    p(displayUnit="bar"),
    nPorts=1) "Sink for ambient water"
  Fluid.Sources.Boundary_pT souLoa(
    redeclare final package Medium = Medium,
    T=TCon_nominal - heaPum.dT_nominal,
    nPorts=1) "Source for load (return from load)"

  Modelica.Blocks.Sources.Sine sin(f=1/(86400/2)) "Load signal"
  Modelica.Blocks.Nonlinear.Limiter limiter(uMax=1, uMin=0)
  Modelica.Blocks.Math.Gain gain(k=QLoa_nominal/(4200*5))
  Modelica.Blocks.Sources.Step TSetCon(
    height=-2,
    offset=TCon_nominal,
    startTime=86400/2) "Set point of condenser outlet"
  Fluid.Sources.Boundary_pT sinLoa(redeclare final package Medium = Medium,
      nPorts=1) "Sink for load"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold enaHea(t=1e-4)
    "Threshold comparison to enable heating"
  Fluid.Sensors.TemperatureTwoPort senTLoaSup(
    redeclare final package Medium = Medium,
    final m_flow_nominal=QLoa_nominal/(4200*5),
    tau=0) "Load supply temperature sensor"
  Fluid.Sensors.MassFlowRate senMasFloAmb(redeclare package Medium = Medium)
    "Mass flow rate sensor for ambient loop"
equation
  connect(sinAmb.ports[1], heaPum.port_b2)
  connect(sin.y, limiter.u)
  connect(limiter.y, gain.u)
  connect(heaPum.m1_flow, gain.y)
  connect(TSetCon.y, heaPum.TSupSet)
  connect(souLoa.ports[1], heaPum.port_a1)
  connect(enaHea.y, heaPum.uEna)
  connect(limiter.y, enaHea.u)
  connect(sinLoa.ports[1], senTLoaSup.port_b)
  connect(senTLoaSup.port_a, heaPum.port_b1)
  connect(heaPum.port_a2, senMasFloAmb.port_b)
  connect(senMasFloAmb.port_a, supAmb.ports[1])
end HeatPump;


within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model HeatPumpDHWTank
  "Validation of the base subsystem model with domestic hot water tank and heat pump"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  parameter Modelica.Units.SI.TemperatureDifference dT_nominal = 5
    "Nominal temperature difference across heat pump condensor and district supply/return water";
  parameter Modelica.Units.SI.Temperature TDisSup_nominal = 273.15 + 15
    "Nominal district supply water temperature";
  Buildings.DHC.ETS.Combined.Subsystems.HeatPumpDHWTank
    heaPum(
    redeclare package Medium1 = Medium,
    redeclare package Medium2 = Medium,
    datWatHea=datWatHea,
    COP_nominal=2.3,
    TCon_nominal=datWatHea.TDom_nominal + datWatHea.dTHexApp_nominal +
        dT_nominal,
    TEva_nominal(displayUnit="K") = TDisSup_nominal - dT_nominal,
    QHotWat_flow_nominal=datWatHea.QHex_flow_nominal,
    dT_nominal=dT_nominal,
    dp1_nominal=6000,
    dp2_nominal=6000)
  Fluid.Sources.Boundary_pT           supAmbWat(
    redeclare package Medium = Medium,
    p(displayUnit="bar"),
    use_T_in=true,
    T=280.15,
    nPorts=1) "Ambient water supply"
  Fluid.Sources.Boundary_pT           sinAmbWat(
    redeclare package Medium = Medium,
    p(displayUnit="bar"),
    nPorts=1) "Sink for ambient water"
  Fluid.Sensors.MassFlowRate           senMasFlo(redeclare package Medium =
        Medium)
    "Mass flow rate sensor"
  Modelica.Blocks.Sources.Constant TDisSup(k = TDisSup_nominal)
    "District supply temperature"
  Fluid.Sources.Boundary_pT souDCW(
    redeclare final package Medium = Medium,
    T=283.15,
    nPorts=1) "Source for domestic cold water"
  Buildings.DHC.ETS.BaseClasses.Junction dcwSpl(
      redeclare final package Medium = Medium, final m_flow_nominal=6000*{1,-1,
        -1})                                 "Splitter for domestic cold water"
  Modelica.Blocks.Sources.CombiTimeTable sch(
    tableOnFile=true,
    tableName="tab1",
    fileName=Modelica.Utilities.Files.loadResource("modelica://Buildings/Resources/Data/DHC/Loads/HotWater/DHW_ApartmentMidRise.mos"),
    smoothness=Modelica.Blocks.Types.Smoothness.ContinuousDerivative,
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic)
    "Domestic hot water fixture draw fraction schedule"

  Modelica.Blocks.Sources.Constant conTSetMix(k(
      final unit="K",
      displayUnit="degC") = 308.15)
    "Temperature setpoint for mixed water supply to fixture"
  Loads.HotWater.ThermostaticMixingValve
                          theMixVal(redeclare package Medium = Medium,
      mMix_flow_nominal=1.2*datWatHea.mDom_flow_nominal)
  parameter Loads.HotWater.Data.GenericDomesticHotWaterWithHeatExchanger
    datWatHea(VTan=0.1892706, mDom_flow_nominal=6.52944E-06*1000)
    "Data for heat pump water heater with tank"
  Modelica.Blocks.Sources.BooleanConstant on "Enable"
equation
  connect(TDisSup.y,supAmbWat. T_in)
  connect(supAmbWat.ports[1], senMasFlo.port_a)
  connect(senMasFlo.port_b, heaPum.port_a2)
  connect(sinAmbWat.ports[1], heaPum.port_b2)
  connect(dcwSpl.port_1, souDCW.ports[1])
  connect(dcwSpl.port_3, heaPum.port_a1)
  connect(sch.y[1], theMixVal.yMixSet)
  connect(conTSetMix.y, theMixVal.TMixSet)
  connect(dcwSpl.port_2, theMixVal.port_col)
  connect(theMixVal.port_hot, heaPum.port_b1)
  connect(on.y, heaPum.uEna)
end HeatPumpDHWTank;


Collection of validation models

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


Validation of flow switch box

within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model SwitchBox "Validation of flow switch box"
  extends Modelica.Icons.Example;

  package Medium=Buildings.Media.Water
    "Medium model";
  parameter Modelica.Units.SI.MassFlowRate m_flow_nominal=1
    "Nominal water mass flow rate";
  Fluid.Delays.DelayFirstOrder volSup(
    redeclare final package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial,
    final m_flow_nominal=m_flow_nominal,
    tau=60,
    nPorts=3) "Mixing volume supply"
  Fluid.Delays.DelayFirstOrder volRet(
    redeclare final package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.SteadyStateInitial,
    final m_flow_nominal=m_flow_nominal,
    tau=60,
    nPorts=3) "Mixing volume return"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow pum1(
    redeclare package Medium = Medium,
    final m_flow_nominal=m_flow_nominal)
    "Chilled water HX secondary pump"
  Buildings.DHC.ETS.BaseClasses.Pump_m_flow pum2(
    redeclare package Medium = Medium,
    final m_flow_nominal=m_flow_nominal)
    "Chilled water HX secondary pump"
  Buildings.DHC.ETS.Combined.Subsystems.SwitchBox
    floSwiBox(final m_flow_nominal=m_flow_nominal, redeclare final package
      Medium = Medium,
    trueHoldDuration=300)
                       "Flow switch box"
  Fluid.Sensors.MassFlowRate senMasFlo(
    redeclare final package Medium = Medium) "District water mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant setMasFlo1(k=0.5)
    "Set point for mass flow rate (normalized)"
  Fluid.Sources.Boundary_pT disWatBou(redeclare package Medium = Medium,
      nPorts=2) "District water boundary conditions"
  Modelica.Blocks.Sources.CombiTimeTable setMasFlo2(
    tableName="tab1",
    table=[0,0; 0.6,1; 0.7,0; 1,1],
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    columns={2},
    timeScale=1000) "Set point for mass flow rate (normalized)"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai2(final k=
        m_flow_nominal) "Scale with nominal mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai1(final k=
        m_flow_nominal) "Scale with nominal mass flow rate"
equation
  connect(pum1.port_b, volSup.ports[1])
  connect(volSup.ports[2], pum2.port_a)
  connect(pum2.port_b, volRet.ports[1])
  connect(volRet.ports[2], pum1.port_a)
  connect(floSwiBox.port_bSup, volSup.ports[3])
  connect(floSwiBox.port_aRet, volRet.ports[3])
  connect(floSwiBox.port_bRet, senMasFlo.port_a)
  connect(senMasFlo.port_b, disWatBou.ports[1])
  connect(disWatBou.ports[2], floSwiBox.port_aSup)
  connect(pum1.m_flow_actual, floSwiBox.mRev_flow)
  connect(setMasFlo2.y[1], gai2.u)
  connect(gai2.y, pum2.m_flow_in)
  connect(setMasFlo1.y, gai1.u)
  connect(gai1.y, pum1.m_flow_in)
  connect(pum2.m_flow_actual, floSwiBox.mPos_flow)
end SwitchBox;


within Buildings.DHC.ETS.Combined.Subsystems.Validation;
model WatersideEconomizer
  "Validation of the base subsystem model with waterside economizer"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  Buildings.Fluid.Sources.Boundary_pT bou1Pum(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=2) "Primary boundary conditions"
  Buildings.Fluid.Movers.FlowControlled_dp pum2Pum(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=hexPum.m2_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true,
    dp_nominal=25E4) "CHW pump"
  Modelica.Blocks.Sources.BooleanExpression uCoo(y=time >= 1000)
    "Cooling enable signal"
  Buildings.DHC.ETS.Combined.Subsystems.WatersideEconomizer hexPum(
    redeclare final package Medium1=Medium,
    redeclare final package Medium2=Medium,
    show_T=true,
    conCon=Buildings.DHC.ETS.Types.ConnectionConfiguration.Pump,
    dp1Hex_nominal=3E4,
    dp2Hex_nominal=3E4,
    Q_flow_nominal=-1E6,
    T_a1_nominal=281.15,
    T_b1_nominal=291.15,
    T_a2_nominal=293.15,
    T_b2_nominal=283.15)
    "Heat exchanger with primary pump"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1OutPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m1_flow_nominal)
    "Primary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1InlPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m1_flow_nominal)
    "Primary inlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2OutPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m2_flow_nominal)
    "Secondary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2InlPum(redeclare final
      package Medium = Medium, m_flow_nominal=hexPum.m2_flow_nominal)
    "Secondary inlet temperature"
  Buildings.DHC.ETS.Combined.Subsystems.WatersideEconomizer hexVal(
    redeclare final package Medium1=Medium,
    redeclare final package Medium2=Medium,
    show_T=true,
    conCon=Buildings.DHC.ETS.Types.ConnectionConfiguration.TwoWayValve,
    dp1Hex_nominal=3E4,
    dp2Hex_nominal=3E4,
    Q_flow_nominal=-1E6,
    T_a1_nominal=281.15,
    T_b1_nominal=291.15,
    T_a2_nominal=293.15,
    T_b2_nominal=283.15)
    "Heat exchanger with primary control valve"
  Buildings.Fluid.Sources.Boundary_pT bou1InlVal(
    redeclare package Medium = Medium,
    p=Medium.p_default + 45E3,
    use_T_in=true,
    nPorts=1) "Primary boundary conditions"
  Buildings.Fluid.Sources.Boundary_pT bou1OutVal(redeclare package Medium =
        Medium, nPorts=1) "Primary boundary conditions"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1InlVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m1_flow_nominal)
    "Primary inlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT1OutVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m1_flow_nominal)
    "Primary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2OutVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m2_flow_nominal)
    "Secondary outlet temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senT2InlVal(redeclare final
      package Medium = Medium, m_flow_nominal=hexVal.m2_flow_nominal)
    "Secondary inlet temperature"
  Buildings.Fluid.Sensors.RelativePressure senRelPre(redeclare final package
      Medium = Medium)
  Modelica.Blocks.Sources.TimeTable TChiWatRet(
    y(final unit="K", displayUnit="degC"),
    table=[0,10; 2,15; 3,16; 4.5,16; 5,13; 10,9],
    timeScale=1000,
    offset=273.15) "Chilled water return temperature values"
  Modelica.Blocks.Sources.TimeTable TSerWat(
    y(final unit="K",
      displayUnit="degC"),
    table=[
      0,8;
      1,8;
      2,13;
      3,18;
      4,6;
      5,18],
    timeScale=1000,
    offset=273.15) "Service water temperature values"
  Buildings.Fluid.Sources.Boundary_pT bou2(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=4) "Secondary boundary conditions"
  Buildings.Fluid.FixedResistances.PressureDrop resPum(
    redeclare package Medium = Medium,
    m_flow_nominal=hexPum.m2_flow_nominal,
    dp_nominal=20E4) "Pipe flow resistance"
  Buildings.Controls.OBC.CDL.Reals.Sources.Ramp     dpSet(
    height=15E4,
    duration=1000,
    offset=10E4,
    startTime=1500)                                                    "Differential pressure set point"
  Buildings.Fluid.Movers.FlowControlled_dp pum2Val(
    redeclare package Medium = Medium,
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    m_flow_nominal=hexPum.m2_flow_nominal,
    addPowerToMedium=false,
    nominalValuesDefineDefaultPressureCurve=true,
    dp_nominal=25E4) "CHW pump"
  Buildings.Fluid.FixedResistances.PressureDrop resVal(
    redeclare package Medium = Medium,
    m_flow_nominal=hexPum.m2_flow_nominal,
    dp_nominal=20E4) "Pipe flow resistance"
  Modelica.Blocks.Sources.RealExpression yEva(y=0) "Isolation valve signal"
equation
  connect(hexPum.port_b1,senT1OutPum.port_a)
  connect(senT1OutPum.port_b, bou1Pum.ports[1])
  connect(hexPum.port_a1,senT1InlPum.port_b)
  connect(senT1InlPum.port_a, bou1Pum.ports[2])
  connect(hexPum.port_b2,senT2OutPum.port_a)
  connect(senT2InlPum.port_b,hexPum.port_a2)
  connect(hexVal.port_a1,senT1InlVal.port_b)
  connect(senT1InlVal.port_a, bou1InlVal.ports[1])
  connect(bou1OutVal.ports[1], senT1OutVal.port_b)
  connect(senT1OutVal.port_a,hexVal.port_b1)
  connect(hexVal.port_a2,senT2InlVal.port_b)
  connect(senT2OutVal.port_a,hexVal.port_b2)
  connect(hexVal.port_a1,senRelPre.port_a)
  connect(senRelPre.port_b,senT1OutVal.port_a)
  connect(TSerWat.y, bou1Pum.T_in)
  connect(TSerWat.y, bou1InlVal.T_in)
  connect(uCoo.y, hexVal.uCoo)
  connect(uCoo.y, hexPum.uCoo)
  connect(bou2.ports[1], senT2InlVal.port_a)
  connect(TChiWatRet.y, bou2.T_in)
  connect(pum2Pum.port_a, senT2OutPum.port_b)
  connect(resPum.port_a, pum2Pum.port_b)
  connect(dpSet.y, pum2Pum.dp_in)
  connect(senT2OutVal.port_b, pum2Val.port_a)
  connect(pum2Val.port_b, resVal.port_a)
  connect(dpSet.y, pum2Val.dp_in)
  connect(resVal.port_b, bou2.ports[2])
  connect(yEva.y, hexVal.yValIsoEva_actual)
  connect(yEva.y, hexPum.yValIsoEva_actual)
  connect(bou2.ports[3], resPum.port_b)
  connect(senT2InlPum.port_a, bou2.ports[4])
end WatersideEconomizer;


Validation of the ETS model with heat recovery chiller and borefield. This model validates

Buildings.DHC.ETS.Combined.ChillerBorefield
in a system configuration including a geothermal borefield.
See

Buildings.DHC.ETS.Combined.Validation.ChillerOnly
for the description of the main modeling assumptions.

within Buildings.DHC.ETS.Combined.Validation;
model ChillerBorefield
  "Validation of the ETS model with heat recovery chiller and borefield"
  extends ChillerOnly(
    ets(
      have_borFie=true,
      datBorFie=datBorFie));
  parameter Integer nBorHol=64
    "Number of boreholes (must be a square number)";
  parameter Modelica.Units.SI.Distance dxy=6
    "Distance in x-axis (and y-axis) between borehole axes";
  final parameter Modelica.Units.SI.Distance cooBor[nBorHol,2]=
      Buildings.DHC.ETS.BaseClasses.computeCoordinates(nBorHol, dxy)
    "Coordinates of boreholes";
  parameter Fluid.Geothermal.Borefields.Data.Borefield.Example datBorFie(
    conDat=Fluid.Geothermal.Borefields.Data.Configuration.Example(
      dp_nominal=0,
      cooBor=cooBor))
    "Borefield design data"
end ChillerBorefield;


Validation of the ETS model with heat recovery chiller. This model validates

Buildings.DHC.ETS.Combined.ChillerBorefield
in a system configuration with no geothermal borefield.

within Buildings.DHC.ETS.Combined.Validation;
model ChillerOnly
  "Validation of the ETS model with heat recovery chiller"
  extends Buildings.DHC.ETS.Combined.Validation.BaseClasses.PartialChillerBorefield;
  Modelica.Blocks.Sources.CombiTimeTable TDisWatSup(
    tableName="tab1",
    table=[
      0,11;
      49,11;
      50,20;
      100,20],
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    timeScale=3600,
    offset={273.15},
    columns={2},
    smoothness=Modelica.Blocks.Types.Smoothness.MonotoneContinuousDerivative1)
    "District water supply temperature"
equation
  connect(TDisWatSup.y[1],disWat.T_in)
  connect(loa.y[2],heaLoaNor.u)
  connect(loa.y[1],loaCooNor.u)
end ChillerOnly;


Validation of the ETS model with heat recovery chiller and waterside economizer. This model validates

Buildings.DHC.ETS.Combined.ChillerBorefield
in a system configuration with no geothermal borefield.

within Buildings.DHC.ETS.Combined.Validation;
model ChillerWSE
  "Validation of the ETS model with heat recovery chiller and waterside economizer"
  extends ChillerOnly(
    ets(
      have_WSE=true), TChiWatSupSet(k=12 + 273.15));
  Modelica.Blocks.Sources.CombiTimeTable TDisWatSup(
    tableName="tab1",
    table=[
      0,11;
      49,11;
      50,20;
      100,20],
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    timeScale=3600,
    offset={273.15},
    columns={2},
    smoothness=Modelica.Blocks.Types.Smoothness.MonotoneContinuousDerivative1)
    "District water supply temperature"
equation
  connect(TDisWatSup.y[1],disWat.T_in)
  connect(loa.y[2],heaLoaNor.u)
  connect(loa.y[1],loaCooNor.u)
end ChillerWSE;


Collection of validation models

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


Package with base classes

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


within Buildings.DHC.ETS.Combined.Validation.BaseClasses;
partial model PartialChillerBorefield
  "Partial validation of the ETS model with heat recovery chiller and optional borefield"
  extends Modelica.Icons.Example;
  package Medium=Buildings.Media.Water
    "Medium model";
  parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal=0.9*datChi.mCon_flow_nominal
    "Nominal heating water mass flow rate";
  parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal=0.9*datChi.mEva_flow_nominal
    "Nominal chilled water mass flow rate";
  parameter Modelica.Units.SI.HeatFlowRate QCoo_flow_nominal(max=-Modelica.Constants.eps)=
       -1e6 "Design cooling heat flow rate (<=0)"
  parameter Modelica.Units.SI.HeatFlowRate QHea_flow_nominal(min=Modelica.Constants.eps)=
       abs(QCoo_flow_nominal)*(1 + 1/datChi.COP_nominal)
    "Design heating heat flow rate (>=0)"
  parameter Buildings.Fluid.Chillers.Data.ElectricEIR.Generic datChi(
    QEva_flow_nominal=QCoo_flow_nominal,
    COP_nominal=3,
    PLRMax=1,
    PLRMinUnl=0.3,
    PLRMin=0.3,
    etaMotor=1,
    mEva_flow_nominal=abs(QCoo_flow_nominal)/5/4186,
    mCon_flow_nominal=QHea_flow_nominal/5/4186,
    TEvaLvg_nominal=277.15,
    capFunT={1.72,0.02,0,-0.02,0,0},
    EIRFunT={0.28,-0.02,0,0.02,0,0},
    EIRFunPLR={0.1,0.9,0},
    TEvaLvgMin=277.15,
    TEvaLvgMax=288.15,
    TConEnt_nominal=313.15,
    TConEntMin=298.15,
    TConEntMax=328.15) "Chiller performance data"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet(
    k=45+273.15,
    y(final unit="K",
      displayUnit="degC"))
    "Heating water supply temperature set point"
  Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSupSet(
    k=7+273.15,
    y(final unit="K",
      displayUnit="degC"))
    "Chilled water supply temperature set point"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTHeaWatSup(redeclare package
      Medium = Medium, m_flow_nominal=datChi.mCon_flow_nominal)
    "Heating water supply temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTChiWatSup(redeclare package
      Medium = Medium, m_flow_nominal=datChi.mEva_flow_nominal)
    "Chilled water supply temperature"
  Buildings.DHC.ETS.Combined.ChillerBorefield ets(
    redeclare package MediumSer = Medium,
    redeclare package MediumBui = Medium,
    QChiWat_flow_nominal=QCoo_flow_nominal,
    QHeaWat_flow_nominal=QHea_flow_nominal,
    dp1Hex_nominal=40E3,
    dp2Hex_nominal=40E3,
    QHex_flow_nominal=-QCoo_flow_nominal,
    T_a1Hex_nominal=284.15,
    T_b1Hex_nominal=279.15,
    T_a2Hex_nominal=277.15,
    T_b2Hex_nominal=282.15,
    QWSE_flow_nominal=QCoo_flow_nominal,
    dpCon_nominal=40E3,
    dpEva_nominal=40E3,
    datChi=datChi,
    nPorts_bChiWat=1,
    nPorts_bHeaWat=1,
    nPorts_aHeaWat=1,
    nPorts_aChiWat=1)
    "ETS"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTHeaWatRet(redeclare final
      package Medium = Medium, m_flow_nominal=datChi.mCon_flow_nominal)
    "Heating water return temperature"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTChiWatRet(redeclare final
      package Medium = Medium, m_flow_nominal=datChi.mEva_flow_nominal)
    "Chilled water return temperature"
  Buildings.Fluid.Sources.Boundary_pT disWat(
    redeclare package Medium = Medium,
    use_T_in=true,
    nPorts=2) "District water boundary conditions"
  DHC.ETS.BaseClasses.Pump_m_flow pumChiWat(
    redeclare package Medium = Medium,
    final m_flow_nominal=mChiWat_flow_nominal,
    dp_nominal=100E3) "Chilled water distribution pump"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai2(final k=
        mChiWat_flow_nominal) "Scale to nominal mass flow rate"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai1(final k=
        mHeaWat_flow_nominal) "Scale to nominal mass flow rate"
  DHC.ETS.BaseClasses.Pump_m_flow pumHeaWat(
    redeclare package Medium = Medium,
    final m_flow_nominal=mHeaWat_flow_nominal,
    dp_nominal=100E3) "Heating water distribution pump"
  Buildings.Fluid.MixingVolumes.MixingVolume volHeaWat(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=45 + 273.15,
    final prescribedHeatFlowRate=true,
    redeclare package Medium = Medium,
    V=10,
    final mSenFac=1,
    final m_flow_nominal=mHeaWat_flow_nominal,
    nPorts=2) "Volume for heating water distribution circuit"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai3(final k=-ets.QHeaWat_flow_nominal)
    "Scale to nominal heat flow rate"
  Buildings.HeatTransfer.Sources.PrescribedHeatFlow loaHea
    "Heating load as prescribed heat flow rate"
  Buildings.Fluid.MixingVolumes.MixingVolume volChiWat(
    energyDynamics=Modelica.Fluid.Types.Dynamics.FixedInitial,
    T_start=7 + 273.15,
    final prescribedHeatFlowRate=true,
    redeclare package Medium = Medium,
    V=10,
    final mSenFac=1,
    final m_flow_nominal=mChiWat_flow_nominal,
    nPorts=2) "Volume for chilled water distribution circuit"
  Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai4(final k=-ets.QChiWat_flow_nominal)
    "Scale to nominal heat flow rate"
  Buildings.HeatTransfer.Sources.PrescribedHeatFlow loaCoo
    "Cooling load as prescribed heat flow rate"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold uHea(
    final t=0.01,
    final h=0.005)
    "Enable heating"
  Buildings.Controls.OBC.CDL.Reals.GreaterThreshold uCoo(
    final t=0.01,
    final h=0.005)
    "Enable cooling"
  Modelica.Blocks.Routing.RealPassThrough heaLoaNor
    "Connect with normalized heating load"
  Modelica.Blocks.Routing.RealPassThrough loaCooNor
    "Connect with normalized cooling load"
  Modelica.Blocks.Sources.CombiTimeTable TDisWatSup(
    tableName="tab1",
    table=[
      0,11;
      49,11;
      50,20;
      100,20],
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    timeScale=3600,
    offset={273.15},
    columns={2},
    smoothness=Modelica.Blocks.Types.Smoothness.MonotoneContinuousDerivative1)
    "District water supply temperature"
  Modelica.Blocks.Sources.CombiTimeTable loa(
    tableName="tab1",
    table=[
      0,0,0;
      1,0,0;
      2,0,1;
      3,0,1;
      4,0,0.5;
      5,0,0.5;
      6,0,0.1;
      7,0,0.1;
      8,0,0;
      9,0,0;
      10,0,0;
      11,0,0;
      12,1,0;
      13,1,0;
      14,0.5,0;
      15,0.5,0;
      16,0.1,0;
      17,0.1,0;
      18,0,0;
      19,0,0;
      20,0,0;
      21,0,0;
      22,1,1;
      23,1,1;
      24,0.5,0.5;
      25,0.5,0.5;
      26,0.1,0.1;
      27,0.1,0.1;
      28,0,0;
      29,0,0;
      30,0,0;
      31,0,0;
      32,0.1,1;
      33,0.1,1;
      34,0.5,0.5;
      35,0.5,0.5;
      36,1,0.1;
      37,1,0.1;
      38,0,0;
      39,0,0;
      40,0,0;
      41,0,0;
      42,0.1,0.3;
      43,0.1,0.3;
      44,0.3,0.1;
      45,0.3,0.1;
      46,0.1,0.1;
      47,0.1,0.1;
      48,0,0;
      49,0,0],
    extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic,
    timeScale=3600,
    offset={0,0},
    columns={2,3},
    smoothness=Modelica.Blocks.Types.Smoothness.MonotoneContinuousDerivative1)
    "Thermal loads (y[1] is cooling load, y[2] is heating load)"
  Buildings.Fluid.Sensors.TemperatureTwoPort senTDisWatSup(redeclare final
      package Medium = Medium, final m_flow_nominal=ets.hex.m1_flow_nominal)
    "District water supply temperature"
  Modelica.Blocks.Continuous.Integrator EChi(
    y(unit="J"))
    "Chiller electricity use"
  Fluid.Sensors.TemperatureTwoPort senTDisWatRet(redeclare final package Medium =
        Medium, final m_flow_nominal=ets.hex.m1_flow_nominal)
    "District water return temperature"
equation
  connect(TChiWatSupSet.y,ets.TChiWatSupSet)
  connect(THeaWatSupSet.y,ets.THeaWatSupSet)
  connect(pumChiWat.port_a,senTChiWatSup.port_b)
  connect(gai2.y,pumChiWat.m_flow_in)
  connect(pumHeaWat.port_b,senTHeaWatSup.port_a)
  connect(gai1.y,pumHeaWat.m_flow_in)
  connect(gai3.y,loaHea.Q_flow)
  connect(loaHea.port,volHeaWat.heatPort)
  connect(pumChiWat.port_b,volChiWat.ports[1])
  connect(volChiWat.ports[2],senTChiWatRet.port_a)
  connect(senTHeaWatSup.port_b,volHeaWat.ports[1])
  connect(gai4.y,loaCoo.Q_flow)
  connect(loaCoo.port,volChiWat.heatPort)
  connect(volHeaWat.ports[2],senTHeaWatRet.port_a)
  connect(heaLoaNor.y,gai3.u)
  connect(heaLoaNor.y,uHea.u)
  connect(heaLoaNor.y,gai1.u)
  connect(loaCooNor.y,gai4.u)
  connect(loaCooNor.y,gai2.u)
  connect(loaCooNor.y,uCoo.u)
  connect(TDisWatSup.y[1],disWat.T_in)
  connect(uCoo.y,ets.uCoo)
  connect(uHea.y,ets.uHea)
  connect(disWat.ports[1],senTDisWatSup.port_a)
  connect(senTDisWatSup.port_b, ets.port_aSerAmb)
  connect(ets.ports_bChiWat[1],senTChiWatSup.port_a)
  connect(ets.ports_bHeaWat[1],pumHeaWat.port_a)
  connect(senTHeaWatRet.port_b,ets.ports_aHeaWat[1])
  connect(senTChiWatRet.port_b,ets.ports_aChiWat[1])
  connect(ets.PCoo, EChi.u)
  connect(ets.port_bSerAmb, senTDisWatRet.port_a)
  connect(senTDisWatRet.port_b, disWat.ports[2])
end PartialChillerBorefield;


Direct cooling ETS model for district energy systems with in-building
  pumping and deltaT control. Direct cooling energy transfer station (ETS) model with in-building pumping and
deltaT control. The design is based on a typical district cooling ETS described
in ASHRAE's District Cooling Guide.
As shown in the figure below, the district and building piping are hydronically
coupled. The control valve ensures that the return temperature to the district
cooling network is at or above the minimum specified value. This configuration
naturally results in a fluctuating building supply tempearture.

within Buildings.DHC.ETS.Cooling;
model Direct "Direct cooling ETS model for district energy systems with in-building
  pumping and deltaT control"
  extends
    Buildings.DHC.ETS.BaseClasses.PartialDirect(
      final typ=Buildings.DHC.Types.DistrictSystemType.Cooling,
      final have_chiWat=true,
      final have_heaWat=false,
      con(reverseActing=false),
      nPorts_aChiWat=1,
      nPorts_bChiWat=1);
equation
  connect(port_aSerCoo, senTDisSup.port_a)
  connect(ports_aChiWat[1], senTBuiRet.port_a)
  connect(senTDisRet.port_b, port_bSerCoo)
  connect(senTBuiSup.port_b, ports_bChiWat[1])
end Direct;


Indirect cooling energy transfer station for district energy systems. Indirect cooling energy transfer station (ETS) model that controls the
building chilled water supply temperature by modulating a primary control valve
on the district supply side. The design is based on a typical district cooling
ETS described in ASHRAE's District Cooling Guide.
As shown in the figure below, the building pumping design (constant/variable)
is specified on the building side and not within the ETS.

within Buildings.DHC.ETS.Cooling;
model Indirect
  "Indirect cooling energy transfer station for district energy systems"
  extends
    Buildings.DHC.ETS.BaseClasses.PartialIndirect(
      QChiWat_flow_nominal=-Q_flow_nominal,
      final typ=Buildings.DHC.Types.DistrictSystemType.Cooling,
      final have_chiWat=true,
      final have_heaWat=false,
      Q_flow_nominal(max=0),
      nPorts_aChiWat=1,
      nPorts_bChiWat=1,
      con(reverseActing=false));
equation
  connect(senTBuiRet.port_a, ports_aChiWat[1])
  connect(senTBuiSup.port_b, ports_bChiWat[1])
  connect(senTDisRet.port_b, port_bSerCoo)
  connect(port_aSerCoo, senTDisSup.port_a)
end Indirect;


within Buildings.DHC.ETS;
package Cooling "This package contains models for energy transfer stations used in district cooling systems"
  extends Modelica.Icons.VariantsPackage;
end Cooling;