diff --git a/.travis.yml b/.travis.yml index 4238290ed80..094c1c9f049 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,83 +40,75 @@ env: - MODELICA_JSON_HOME=${TRAVIS_BUILD_DIR}/modelica-json jobs: - - TEST_ARG="make test-cdl-conformance" - - TEST_ARG="make test-energyplus-validations test-dymola-spawn-spaces test-openmodelica-spawn-spaces test-openmodelica-cdl" #target test-optimica-spawn-fmu removed as it requires a local installation of OCT - - TEST_ARG="make test-bestest" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Air,Examples}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Air,Examples}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Air,Examples}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.EnergyPlus_9_6_0\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.EnergyPlus_9_6_0\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.EnergyPlus_9_6_0\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.{BaseClasses,Constructions,Examples}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.{BaseClasses,Constructions,Examples}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.{BaseClasses,Constructions,Examples}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.BESTEST\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.BESTEST\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.BESTEST\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.{Initialization,LBNL_71T,TestConditionalConstructions}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.{Initialization,LBNL_71T,TestConditionalConstructions}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.{Initialization,LBNL_71T,TestConditionalConstructions}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.FLEXLAB\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.FLEXLAB\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.FLEXLAB\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.{ISO13790,ReducedOrder}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.{ISO13790,ReducedOrder}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.{ISO13790,ReducedOrder}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Applications\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Applications\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Applications\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Experimental.DHC.{EnergyTransferStations,Loads,Networks,Plants}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Experimental.DHC.{EnergyTransferStations,Loads,Networks,Plants}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Experimental.DHC.{EnergyTransferStations,Loads,Networks,Plants}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Experimental.DHC.Examples.Combined\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Experimental.DHC.Examples.Combined\" SINGLEPROC=\"true\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Experimental.DHC.Examples.Combined\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Experimental.DHC.Examples.{Cooling,Steam}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Experimental.DHC.Examples.{Cooling,Steam}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Experimental.DHC.Examples.{Cooling,Steam}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{Actuators,BaseClasses,Boilers,Chillers,CHPs,Delays}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{Actuators,BaseClasses,Boilers,Chillers,CHPs,Delays}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{Actuators,BaseClasses,Boilers,Chillers,CHPs,Delays}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{Examples,FMI}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{Examples,FMI}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{Examples,FMI}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.FixedResistances\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.FixedResistances\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.FixedResistances\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{Geothermal,HeatExchangers,HeatPumps,Humidifiers,HydronicConfigurations,Interfaces}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{Geothermal,HeatExchangers,HeatPumps,Humidifiers,HydronicConfigurations,Interfaces}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{Geothermal,HeatExchangers,HeatPumps,Humidifiers,HydronicConfigurations,Interfaces}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{MassExchangers,MixingVolumes,Movers,Sensors,SolarCollectors,Sources,Storage,Utilities}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{MassExchangers,MixingVolumes,Movers,Sensors,SolarCollectors,Sources,Storage,Utilities}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{MassExchangers,MixingVolumes,Movers,Sensors,SolarCollectors,Sources,Storage,Utilities}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Electrical\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Electrical\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Electrical\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Airflow,BoundaryConditions,Controls}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Airflow,BoundaryConditions,Controls}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Airflow,BoundaryConditions,Controls}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.HeatTransfer\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.HeatTransfer\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.HeatTransfer\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Obsolete,Occupants,Media}\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Obsolete,Occupants,Media}\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Obsolete,Occupants,Media}\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Utilities\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Utilities\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Utilities\"" - - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Templates\"" - - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Templates\"" - - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Templates\"" + # - TEST_ARG="make test-cdl-conformance" + # - TEST_ARG="make test-energyplus-validations test-dymola-spawn-spaces test-openmodelica-spawn-spaces test-openmodelica-cdl" #target test-optimica-spawn-fmu removed as it requires a local installation of OCT + # - TEST_ARG="make test-bestest" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Air,Examples}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Air,Examples}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Air,Examples}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.EnergyPlus_9_6_0\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.EnergyPlus_9_6_0\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.EnergyPlus_9_6_0\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.{BaseClasses,Constructions,Examples}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.{BaseClasses,Constructions,Examples}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.{BaseClasses,Constructions,Examples}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.BESTEST\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.BESTEST\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.BESTEST\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.{Initialization,LBNL_71T,TestConditionalConstructions}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.{Initialization,LBNL_71T,TestConditionalConstructions}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.Validation.{Initialization,LBNL_71T,TestConditionalConstructions}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.Detailed.FLEXLAB\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.Detailed.FLEXLAB\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.Detailed.FLEXLAB\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.ThermalZones.{ISO13790,ReducedOrder}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.ThermalZones.{ISO13790,ReducedOrder}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.ThermalZones.{ISO13790,ReducedOrder}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Applications,Experimental}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Applications,Experimental}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Applications,Experimental}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{Actuators,BaseClasses,Boilers,Chillers,CHPs,Delays}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{Actuators,BaseClasses,Boilers,Chillers,CHPs,Delays}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{Actuators,BaseClasses,Boilers,Chillers,CHPs,Delays}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{Examples,FMI}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{Examples,FMI}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{Examples,FMI}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.FixedResistances\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.FixedResistances\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.FixedResistances\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{Geothermal,HeatExchangers,HeatPumps,Humidifiers,HydronicConfigurations,Interfaces}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{Geothermal,HeatExchangers,HeatPumps,Humidifiers,HydronicConfigurations,Interfaces}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{Geothermal,HeatExchangers,HeatPumps,Humidifiers,HydronicConfigurations,Interfaces}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Fluid.{MassExchangers,MixingVolumes,Movers,Sensors,SolarCollectors,Sources,Storage,Utilities}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Fluid.{MassExchangers,MixingVolumes,Movers,Sensors,SolarCollectors,Sources,Storage,Utilities}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Fluid.{MassExchangers,MixingVolumes,Movers,Sensors,SolarCollectors,Sources,Storage,Utilities}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Electrical\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Electrical\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Electrical\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Airflow,BoundaryConditions,Controls}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Airflow,BoundaryConditions,Controls}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Airflow,BoundaryConditions,Controls}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.HeatTransfer\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.HeatTransfer\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.HeatTransfer\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.{Obsolete,Occupants,Media}\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.{Obsolete,Occupants,Media}\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.{Obsolete,Occupants,Media}\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Utilities\"" + # - TEST_ARG="make test-openmodelica PACKAGE=\"Buildings.Utilities\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Utilities\"" + # - TEST_ARG="make test-dymola PACKAGE=\"Buildings.Templates.AirHandlers\"" + # - TEST_ARG="make test-optimica PACKAGE=\"Buildings.Templates.AirHandlers\"" + - TEST_ARG="make test-templates-dymola" + - TEST_ARG="make test-templates-optimica" before_install: - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin - - if [[ "$TEST_ARG" == *test-dymola* || "$TEST_ARG" == *test-bestest* || "$TEST_ARG" == *spawn-portability* ]]; then + - if [[ "$TEST_ARG" == *test-*dymola* || "$TEST_ARG" == *test-bestest* || "$TEST_ARG" == *spawn-portability* ]]; then docker pull "$DOCKER_USERNAME"/${DYMOLA_VERSION}; cp Buildings/Resources/Scripts/travis/dymola/dymola $HOME/bin/; fi; - - if [[ "$TEST_ARG" == *test-optimica* ]]; then + - if [[ "$TEST_ARG" == *test-*optimica* ]]; then docker pull "$DOCKER_USERNAME"/${OPTIMICA_VERSION}; cp Buildings/Resources/Scripts/travis/optimica/jm_ipython.sh $HOME/bin/jm_ipython.sh; fi; @@ -143,7 +135,7 @@ before_install: cd -; echo "Installed modelica-json in ${MODELICA_JSON_HOME}"; fi; - - if [[ "$TEST_ARG" == *test-openmodelica* ]]; then + - if [[ "$TEST_ARG" == *test-*openmodelica* ]]; then docker pull "$DOCKER_USERNAME"/${OMC_VERSION}; cp Buildings/Resources/Scripts/travis/omc/omc $HOME/bin/omc; fi; @@ -157,7 +149,7 @@ install: - pip3 install --upgrade pip wheel - pip3 install --only-binary=numpy,scipy,matplotlib numpy==1.21.4 scipy==1.7.3 matplotlib==3.5.1 - pip3 install git+https://github.com/lbl-srg/${BUILDINGSPY_VERSION} - - if [[ "$TEST_ARG" == *test-energyplus* ]]; then + - if [[ "$TEST_ARG" == *test-energyplus* ]] || [[ "$TEST_ARG" == *test-templates* ]]; then export ENERGYPLUS_9_6_0=${ENERGYPLUS_9_6_0}; export ENERGYPLUS_23_1_0=${ENERGYPLUS_23_1_0}; pip3 install pandas==1.3.5; diff --git a/Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg b/Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg new file mode 100644 index 00000000000..5fe70694b31 --- /dev/null +++ b/Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg b/Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg new file mode 100644 index 00000000000..ffb0936ef06 --- /dev/null +++ b/Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Buildings/Resources/Images/Templates/Components/Pumps/Single.svg b/Buildings/Resources/Images/Templates/Components/Pumps/Single.svg new file mode 100644 index 00000000000..0a1e92034bc --- /dev/null +++ b/Buildings/Resources/Images/Templates/Components/Pumps/Single.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + diff --git a/Buildings/Resources/Images/Templates/Components/Valves/Check.svg b/Buildings/Resources/Images/Templates/Components/Valves/Check.svg new file mode 100644 index 00000000000..07d84ffe1f2 --- /dev/null +++ b/Buildings/Resources/Images/Templates/Components/Valves/Check.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWater.mos b/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWater.mos new file mode 100644 index 00000000000..a1410ac1175 --- /dev/null +++ b/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWater.mos @@ -0,0 +1,21 @@ +simulateModel("Buildings.Templates.Components.Validation.BoilerHotWater", + method="cvode", + tolerance=1e-6, + stopTime=2000.0, + resultFile="BoilerHotWater"); +createPlot(id=1, + position={19, 10, 474, 390}, + y={"THeaWatRet.y", "THeaWatSupSet.y", "boiTab.bus.THeaWatSup", "boiPol.bus.THeaWatSup"}, + subPlot=1, + autoscale=true, + grid=true); +createPlot(id=1, + y={"boiTab.boi.Q_flow_nominal", "boiPol.boi.Q_flow_nominal", "boiTab.boi.QWat_flow", "boiPol.boi.QWat_flow"}, + subPlot=2, + autoscale=true, + grid=true); +createPlot(id=1, + y={"boiTab.boi.m_flow_nominal", "boiPol.boi.m_flow_nominal", "boiTab.boi.m_flow", "boiPol.boi.m_flow"}, + subPlot=3, + autoscale=true, + grid=true); \ No newline at end of file diff --git a/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWaterRecord.mos b/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWaterRecord.mos new file mode 100644 index 00000000000..a573c2f23b1 --- /dev/null +++ b/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWaterRecord.mos @@ -0,0 +1,16 @@ +simulateModel("Buildings.Templates.Components.Validation.BoilerHotWaterRecord", + method="cvode", + tolerance=1e-6, + stopTime=1.0, + resultFile="BoilerHotWaterRecord"); +createPlot(id=1, + position={19, 10, 474, 390}, + y={"per.Q_flow_nominal", "datBoiTab.per.Q_flow_nominal", "datBoiTabRed.per.Q_flow_nominal", "datBoiTabLoc.per.Q_flow_nominal"}, + subPlot=1, + autoscale=true, + grid=true); +createPlot(id=1, + y={"per.effCur[4, 11]", "datBoiTab.per.effCur[4, 11]", "datBoiTabRed.per.effCur[4, 11]", "datBoiTabLoc.per.effCur[4, 11]"}, + subPlot=2, + autoscale=true, + grid=true); diff --git a/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/PumpMultipleRecord.mos b/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/PumpMultipleRecord.mos new file mode 100644 index 00000000000..26e42444490 --- /dev/null +++ b/Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/PumpMultipleRecord.mos @@ -0,0 +1,31 @@ +simulateModel("Buildings.Templates.Components.Validation.PumpMultipleRecord", + method="cvode", + tolerance=1e-6, + stopTime=1.0, + resultFile="PumpMultipleRecord"); +createPlot(id=1, + position={19, 10, 476, 550}, + y={"V_flow_nominal[1]", "V_flow_nominal[2]"}, + subPlot=1, + autoscale=true, + grid=true); +createPlot(id=1, + y={"datDef.per[1].pressure.V_flow[2]", "datDef.per[2].pressure.V_flow[2]"}, + subPlot=2, + autoscale=true, + grid=true); +createPlot(id=1, + y={"datRed.per[1].pressure.V_flow[2]", "datRed.per[2].pressure.V_flow[2]"}, + subPlot=3, + autoscale=true, + grid=true); +createPlot(id=1, + y={"datAss.per[1].pressure.V_flow[2]", "datAss.per[2].pressure.V_flow[2]"}, + subPlot=4, + autoscale=true, + grid=true); +createPlot(id=1, + y={"datPre.per[1].pressure.V_flow[2]", "datPre.per[2].pressure.V_flow[2]"}, + subPlot=5, + autoscale=true, + grid=true); \ No newline at end of file diff --git a/Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mos b/Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mos new file mode 100644 index 00000000000..b8003cd7303 --- /dev/null +++ b/Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mos @@ -0,0 +1,21 @@ +simulateModel("Buildings.Templates.HeatingPlants.HotWater.Components.Validation.BoilerGroupPolynomial", + method="cvode", + tolerance=1e-6, + stopTime=2000.0, + resultFile="BoilerGroupPolynomial"); +createPlot(id=1, + position={19, 10, 508, 564}, + y={"THeaWatRet.T", "THeaWatSup.T", "ctl.THeaWatConSupSet.y"}, + subPlot=101, + autoscale=true, + grid=true); +createPlot(id=1, + y={"busPla.boiCon[1].y1", "busPla.boiCon[1].y_actual"}, + subPlot=102, + autoscale=true, + grid=true); +createPlot(id=1, + y={"mHeaWat_flow_nominal", "mHeaWat_flow.m_flow"}, + subPlot=103, + autoscale=true, + grid=true); \ No newline at end of file diff --git a/Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mos b/Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mos new file mode 100644 index 00000000000..3c3fc4f8855 --- /dev/null +++ b/Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mos @@ -0,0 +1,21 @@ +simulateModel("Buildings.Templates.HeatingPlants.HotWater.Components.Validation.BoilerGroupTable", + method="cvode", + tolerance=1e-6, + stopTime=2000.0, + resultFile="BoilerGroupTable"); +createPlot(id=1, + position={19, 10, 508, 564}, + y={"THeaWatRet.T", "THeaWatSup.T", "ctl.THeaWatConSupSet.y"}, + subPlot=101, + autoscale=true, + grid=true); +createPlot(id=1, + y={"busPla.boiCon[1].y1", "busPla.boiCon[1].y_actual"}, + subPlot=102, + autoscale=true, + grid=true); +createPlot(id=1, + y={"mHeaWat_flow_nominal", "mHeaWat_flow.m_flow"}, + subPlot=103, + autoscale=true, + grid=true); \ No newline at end of file diff --git a/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.AirHandlersFans.Validation.VAVMZCoilWaterHeatingCooling.mos b/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.AirHandlersFans.Validation.VAVMZCoilWaterHeatingCooling.mos new file mode 100644 index 00000000000..13bc3dcfedd --- /dev/null +++ b/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.AirHandlersFans.Validation.VAVMZCoilWaterHeatingCooling.mos @@ -0,0 +1,4 @@ +compareVars := + { + "VAV_1.port_Sup.m_flow" + }; diff --git a/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.AirHandlersFans.Validation.VAVMZDedicatedDampersAirflow.mos b/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.AirHandlersFans.Validation.VAVMZDedicatedDampersAirflow.mos new file mode 100644 index 00000000000..13bc3dcfedd --- /dev/null +++ b/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.AirHandlersFans.Validation.VAVMZDedicatedDampersAirflow.mos @@ -0,0 +1,4 @@ +compareVars := + { + "VAV_1.port_Sup.m_flow" + }; diff --git a/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.ZoneEquipment.Validation.VAVBoxReheat.mos b/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.ZoneEquipment.Validation.VAVBoxReheat.mos new file mode 100644 index 00000000000..588a9223611 --- /dev/null +++ b/Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.ZoneEquipment.Validation.VAVBoxReheat.mos @@ -0,0 +1,4 @@ +compareVars := + { + "VAVBox_1.port_Sup.m_flow" + }; diff --git a/Buildings/Resources/Scripts/travis/Makefile b/Buildings/Resources/Scripts/travis/Makefile index 0456be0ac5a..92cb5592800 100644 --- a/Buildings/Resources/Scripts/travis/Makefile +++ b/Buildings/Resources/Scripts/travis/Makefile @@ -172,3 +172,9 @@ test-optimica: (cd $(ROOT)/Buildings && \ export PYTHONPATH=$(TRAVIS_BUILD_DIR)/Buildings/Resources/Python-Sources && \ python3 ../bin/runUnitTests.py --batch --single-package $(PACKAGE) --tool optimica --skip-verification -n $(NPROC)) + +test-templates-dymola: + (cd $(ROOT)/Buildings && ../Buildings/Resources/Scripts/travis/templates/checkandrun.sh Dymola) + +test-templates-optimica: + (cd $(ROOT)/Buildings && ../Buildings/Resources/Scripts/travis/templates/checkandrun.sh Optimica) diff --git a/Buildings/Resources/Scripts/travis/templates/BoilerPlant.py b/Buildings/Resources/Scripts/travis/templates/BoilerPlant.py new file mode 100755 index 00000000000..4aa721755d9 --- /dev/null +++ b/Buildings/Resources/Scripts/travis/templates/BoilerPlant.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This script shall be run from the directory `modelica-buildings/Buildings`, +# i.e., where the top-level `package.mo` file can be found. +# The script takes as an optional positional argument the Modelica tool to use +# (Dymola or Optimica, defaulting to Dymola). +# The script performs the following tasks. +# - Generate all possible combinations of class modifications based on a set of +# parameter bindings and redeclare statements provided in `MODIF_GRID`. +# - Exclude the combinations based on a match with the patterns provided in `EXCLUDE`. +# - This allows excluding unsupported configurations. +# - Exclude the class modifications based on a match with the patterns provided in `REMOVE_MODIF`, +# and prune the resulting duplicated combinations. +# - This allows reducing the number of simulations by excluding class modifications that +# yield the same model, i.e., modifications to parameters that are not used (disabled) in +# the given configuration. +# - For the remaining combinations: run the corresponding simulations for the models in `MODELS`. +# The script returns +# - 0 if all simulations succeed, +# - 1 otherwise. + +from core import * + +MODELS = [ + 'Buildings.Templates.HeatingPlants.HotWater.Validation.BoilerPlant', +] + +MODIF_GRID = { + 'Buildings.Templates.HeatingPlants.HotWater.Validation.BoilerPlant': dict( + BOI__typ=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing', + 'Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing', + 'Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid', + ], + BOI__nBoiCon_select=[ + '2', + ], + BOI__nBoiNon_select=[ + '2', + ], + BOI__typPumHeaWatPriCon=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Constant', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryConstant', + ], + BOI__typPumHeaWatPriNon=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Constant', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryConstant', + ], + BOI__typArrPumHeaWatPriCon_select=[ + 'Buildings.Templates.Components.Types.PumpArrangement.Dedicated', + 'Buildings.Templates.Components.Types.PumpArrangement.Headered', + ], + BOI__typArrPumHeaWatPriNon_select=[ + 'Buildings.Templates.Components.Types.PumpArrangement.Dedicated', + 'Buildings.Templates.Components.Types.PumpArrangement.Headered', + ], + BOI__typPumHeaWatSec1_select=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None', + ], + BOI__typPumHeaWatSec2_select=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized', + ], + BOI__ctl__typMeaCtlHeaWatPri=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDecoupler', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDifference', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.TemperatureSupplySensor', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.TemperatureBoilerSensor', + ], + BOI__ctl__have_senDpHeaWatLoc=[ + 'true', + 'false', + ], + BOI__ctl__locSenVHeaWatPri=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Supply', + 'Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return', + ], + BOI__ctl__locSenVHeaWatSec=[ + 'Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Supply', + 'Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return', + ], + ), +} + +# See docstring of `prune_modifications` function for the structure of EXCLUDE. +EXCLUDE = { + 'Buildings.Templates.HeatingPlants.HotWater.Validation.BoilerPlant': [ + [ + 'Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid', + 'Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None', + ], + ], +} + +# See docstring of `prune_modifications` function for the structure of REMOVE_MODIF. +REMOVE_MODIF = { + 'Buildings.Templates.HeatingPlants.HotWater.Validation.BoilerPlant': [ + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid', + ], + [ + 'typPumHeaWatSec1_select', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.(?!Hybrid)', + ], + [ + 'typPumHeaWatSec2_select', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.(?!Hybrid)', + 'typPumHeaWatSec1_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None', + ], + [ + 'typMeaCtlHeaWatPri', + 'locSenVHeaWatSec', + ], + ), + ( + [ + 'typPumHeaWatSec(1|2)_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.(?!None)', + 'typMeaCtlHeaWatPri=Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.(?!FlowDifference)', + ], + [ + 'locSenVHeaWatSec', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing', + 'typPumHeaWatSec1_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.(?!None)', + 'typPumHeaWatPriCon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.(Factory)?Constant', + ], + [ + 'typMeaCtlHeaWatPri', + 'locSenVHeaWatPri', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing', + 'typPumHeaWatSec1_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.(?!None)', + 'typPumHeaWatPriNon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.(Factory)?Constant', + ], + [ + 'typMeaCtlHeaWatPri', + 'locSenVHeaWatPri', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing', + 'typPumHeaWatSec1_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.(?!None)', + 'typPumHeaWatPriCon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.(Factory)?Variable', + 'typMeaCtlHeaWatPri=Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.(?!FlowDifference)', + ], + [ + 'locSenVHeaWatPri', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing', + 'typPumHeaWatSec1_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.(?!None)', + 'typPumHeaWatPriNon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.(Factory)?Variable', + 'typMeaCtlHeaWatPri=Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.(?!FlowDifference)', + ], + [ + 'locSenVHeaWatPri', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid', + 'typPumHeaWatSec2_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.(?!None)', + 'typPumHeaWatPri(Con|Non)=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.(Factory)?Variable', + 'typMeaCtlHeaWatPri=Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.(?!FlowDifference)', + ], + [ + 'locSenVHeaWatPri', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing', + ], + [ + 'typArrPumHeaWatPriNon_select', + 'nBoiNon_select', + 'typPumHeaWatPriNon', + ], + ), + ( + [ + 'typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing', + ], + [ + 'typArrPumHeaWatPriCon_select', + 'nBoiCon_select', + 'typPumHeaWatPriCon', + ], + ), + ( + [ + 'typPumHeaWatPriCon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Factory' + ], + [ + 'typArrPumHeaWatPriCon_select', + ], + ), + ( + [ + 'typPumHeaWatPriNon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Factory' + ], + [ + 'typArrPumHeaWatPriNon_select', + ], + ), + ], +} + + +if __name__ == '__main__': + # Generate combinations. + combinations = generate_combinations( + models=MODELS, modif_grid=MODIF_GRID + ) + + # Prune class modifications. + prune_modifications( + combinations=combinations, + exclude=EXCLUDE, + remove_modif=REMOVE_MODIF, + fraction_test_coverage=FRACTION_TEST_COVERAGE, + ) + + print(f'Number of cases to be simulated: {len(combinations)}.\n') + + # FIXME(AntoineGautier PR#3364): Temporarily limit the number of simulations to be run (for testing purposes only). + combinations = combinations[:2] + + # Simulate cases. + results = simulate_cases(combinations, simulator=SIMULATOR, asy=False) + + # Report and clean. + df = report_clean(combinations, results) + + # Log and exit. + if df.errorcode.abs().sum() != 0: + print( + CRED + 'Some simulations failed: ' + CEND + 'see the file `unitTestsTemplates.log`.\n' + ) + sys.exit(1) + else: + print(CGREEN + 'All simulations succeeded.\n' + CEND) + sys.exit(0) diff --git a/Buildings/Resources/Scripts/travis/templates/HeatingPlants.HotWater.checksum b/Buildings/Resources/Scripts/travis/templates/HeatingPlants.HotWater.checksum new file mode 100644 index 00000000000..0d0f3a62684 --- /dev/null +++ b/Buildings/Resources/Scripts/travis/templates/HeatingPlants.HotWater.checksum @@ -0,0 +1 @@ +678b2b19507a5ffddd9efd9878ceb268 diff --git a/Buildings/Resources/Scripts/travis/templates/VAVMultiZone.py b/Buildings/Resources/Scripts/travis/templates/VAVMultiZone.py new file mode 100755 index 00000000000..dae6f072286 --- /dev/null +++ b/Buildings/Resources/Scripts/travis/templates/VAVMultiZone.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This script shall be run from the directory `modelica-buildings/Buildings`, +# i.e., where the top-level `package.mo` file can be found. +# The script takes as an optional positional argument the Modelica tool to use +# (Dymola or Optimica, defaulting to Dymola). +# The script performs the following tasks. +# - Generate all possible combinations of class modifications based on a set of +# parameter bindings and redeclare statements provided in `MODIF_GRID`. +# - Exclude the combinations based on a match with the patterns provided in `EXCLUDE`. +# - This allows excluding unsupported configurations. +# - Exclude the class modifications based on a match with the patterns provided in `REMOVE_MODIF`, +# and prune the resulting duplicated combinations. +# - This allows reducing the number of simulations by excluding class modifications that +# yield the same model, i.e., modifications to parameters that are not used (disabled) in +# the given configuration. +# - For the remaining combinations: run the corresponding simulations for the models in `MODELS`. +# The script returns +# - 0 if all simulations succeed, +# - 1 otherwise. + +from core import * + +MODELS = [ + 'Buildings.Templates.AirHandlersFans.Validation.VAVMultiZone', +] + +# Tested modifications should at least cover the options specified at: +# https://github.com/lbl-srg/ctrl-flow-dev/blob/main/server/scripts/sequence-doc/src/version/Current%20G36%20Decisions/Guideline%2036-2021%20(mappings).csv +MODIF_GRID = { + 'Buildings.Templates.AirHandlersFans.Validation.VAVMultiZone': { + # FIXME(AntoineGautier #3526): Some options are currently not supported by G36 controller. + 'VAV_1__redeclare__coiHeaPre': [ + 'Buildings.Templates.Components.Coils.None', + 'Buildings.Templates.Components.Coils.WaterBasedHeating', + # 'Buildings.Templates.Components.Coils.ElectricHeating', + ], + # FIXME(AntoineGautier #3526): Some options are currently not supported by G36 controller. + 'VAV_1__redeclare__coiCoo': [ + # 'Buildings.Templates.Components.Coils.None', + 'Buildings.Templates.Components.Coils.WaterBasedCooling', + # 'Buildings.Templates.Components.Coils.EvaporatorVariableSpeed', + ], + 'VAV_1__secOutRel__redeclare__secOut': [ + 'Buildings.Templates.AirHandlersFans.Components.OutdoorSection.DedicatedDampersAirflow', + 'Buildings.Templates.AirHandlersFans.Components.OutdoorSection.DedicatedDampersPressure', + 'Buildings.Templates.AirHandlersFans.Components.OutdoorSection.SingleDamper', + ], + # FIXME(AntoineGautier #3526): Some options are currently not supported by G36 controller. + 'VAV_1__secOutRel__redeclare__secRel': [ + 'Buildings.Templates.AirHandlersFans.Components.ReliefReturnSection.ReliefDamper', + # 'Buildings.Templates.AirHandlersFans.Components.ReliefReturnSection.ReliefFan', + 'Buildings.Templates.AirHandlersFans.Components.ReliefReturnSection.ReturnFan', + ], + 'VAV_1__redeclare__fanSupBlo': [ + 'Buildings.Templates.Components.Fans.None', + 'Buildings.Templates.Components.Fans.SingleVariable', + 'Buildings.Templates.Components.Fans.ArrayVariable(nFan=2)', + ], + 'VAV_1__redeclare__fanSupDra': [ + 'Buildings.Templates.Components.Fans.None', + 'Buildings.Templates.Components.Fans.SingleVariable', + 'Buildings.Templates.Components.Fans.ArrayVariable(nFan=2)', + ], + 'VAV_1__ctl__typCtlEco': [ + 'Buildings.Controls.OBC.ASHRAE.G36.Types.ControlEconomizer.FixedDryBulb', + 'Buildings.Controls.OBC.ASHRAE.G36.Types.ControlEconomizer.DifferentialDryBulb', + # 'Buildings.Controls.OBC.ASHRAE.G36.Types.ControlEconomizer.FixedDryBulbWithDifferentialDryBulb', + 'Buildings.Controls.OBC.ASHRAE.G36.Types.ControlEconomizer.FixedEnthalpyWithFixedDryBulb', + 'Buildings.Controls.OBC.ASHRAE.G36.Types.ControlEconomizer.DifferentialEnthalpyWithFixedDryBulb', + ], + 'VAV_1__ctl__typCtlFanRet': [ + 'Buildings.Templates.AirHandlersFans.Types.ControlFanReturn.AirflowMeasured', + 'Buildings.Templates.AirHandlersFans.Types.ControlFanReturn.BuildingPressure', + ], + 'VAV_1__ctl__have_perZonRehBox': [ + 'true', + 'false', + ], + # FIXME(AntoineGautier #3526): Some options are currently not supported by G36 controller. + 'VAV_1__ctl__have_frePro': [ + 'true', + # 'false', + ], + # FIXME(AntoineGautier #3526): Some options are currently not supported by G36 controller. + 'VAV_1__ctl__typFreSta': [ + 'Buildings.Controls.OBC.ASHRAE.G36.Types.FreezeStat.No_freeze_stat', + # 'Buildings.Controls.OBC.ASHRAE.G36.Types.FreezeStat.Hardwired_to_equipment', + # 'Buildings.Controls.OBC.ASHRAE.G36.Types.FreezeStat.Hardwired_to_BAS', + ], + 'VAV_1__ctl__have_CO2Sen': [ + 'true', + 'false', + ], + }, +} + +# See docstring of `prune_modifications` function for the structure of EXCLUDE. +EXCLUDE = { + 'Buildings.Templates.AirHandlersFans.Validation.VAVMultiZone': [ + [ + 'Buildings.Templates.Components.Fans.None fanSupBlo', + 'Buildings.Templates.Components.Fans.None fanSupDra', + ], + [ + 'Buildings.Templates.Components.Fans.(SingleVariable|ArrayVariable) fanSupBlo', + 'Buildings.Templates.Components.Fans.(SingleVariable|ArrayVariable) fanSupDra', + ], + # FIXME(AntoineGautier #3527): Simulation fails with Cvode. + [ + 'Buildings.Templates.Components.Coils.None coiHeaPre', + 'Buildings.Templates.Components.Fans.ArrayVariable fanSup(Blo|Dra)', + ], + ], +} + +# See docstring of `prune_modifications` function for the structure of REMOVE_MODIF. +REMOVE_MODIF = { + 'Buildings.Templates.AirHandlersFans.Validation.VAVMultiZone': [ + ( + [ + 'Buildings.Templates.AirHandlersFans.Components.ReliefReturnSection.(?!ReturnFan)', + ], + [ + 'typCtlFanRet', + ], + ), + ( + [ + 'have_frePro=false', + ], + [ + 'typFreSta', + ], + ), + ( + [ + 'Buildings.Controls.OBC.ASHRAE.G36.Types.OutdoorAirSection.(?!DedicatedDampersPressure)', + ], + [ + 'have_CO2Sen', + ], + ), + # We don't test all combinations of control options to limit the number of simulations. + ( + [ + 'typCtlEco=Buildings.Controls.OBC.ASHRAE.G36.Types.ControlEconomizer.(?!FixedDryBulb)', + ], + [ + 'typCtlFanRet', + 'have_perZonRehBox', + 'have_frePro', + 'typFreSta', + 'have_CO2Sen', + ], + ), + ( + [ + 'typCtlFanRet=Buildings.Templates.AirHandlersFans.Types.ControlFanReturn.BuildingPressure', + ], + [ + 'typCtlEco', + 'have_perZonRehBox', + 'have_frePro', + 'typFreSta', + 'have_CO2Sen', + ], + ), + ( + [ + 'have_perZonRehBox=false', + ], + [ + 'typCtlEco', + 'typCtlFanRet', + 'have_frePro', + 'typFreSta', + 'have_CO2Sen', + ], + ), + ( + [ + 'have_frePro=false', + ], + [ + 'typCtlEco', + 'typCtlFanRet', + 'have_perZonRehBox', + 'typFreSta', + 'have_CO2Sen', + ], + ), + ( + [ + 'typFreSta=Buildings.Controls.OBC.ASHRAE.G36.Types.FreezeStat.(?!No_freeze_stat)', + ], + [ + 'typCtlEco', + 'typCtlFanRet', + 'have_perZonRehBox', + 'have_CO2Sen', + ], + ), + ( + [ + 'have_CO2Sen=false', + ], + [ + 'typCtlEco', + 'typCtlFanRet', + 'have_perZonRehBox', + 'have_frePro', + 'typFreSta', + ], + ), + ] +} + + +if __name__ == '__main__': + # Generate combinations. + combinations = generate_combinations( + models=MODELS, modif_grid=MODIF_GRID + ) + + # Prune class modifications. + prune_modifications( + combinations=combinations, + exclude=EXCLUDE, + remove_modif=REMOVE_MODIF, + fraction_test_coverage=FRACTION_TEST_COVERAGE, + ) + + print(f'Number of cases to be simulated: {len(combinations)}.\n') + + # Lof combinations for debugging. + with open('unitTestsCombinations.log', 'w') as FH: + for c in combinations: + FH.write("*********" + c[0] + "\n\n" + "\n".join(c[1]) + "\n\n") + + # Simulate cases. + results = simulate_cases(combinations, simulator=SIMULATOR, asy=False) + + # Report and clean. + df = report_clean(combinations, results) + + # Log and exit. + if df.errorcode.abs().sum() != 0: + print( + CRED + 'Some simulations failed: ' + CEND + 'see the file `unitTestsTemplates.log`.\n' + ) + sys.exit(1) + else: + print(CGREEN + 'All simulations succeeded.\n' + CEND) + sys.exit(0) diff --git a/Buildings/Resources/Scripts/travis/templates/checkandrun.sh b/Buildings/Resources/Scripts/travis/templates/checkandrun.sh new file mode 100755 index 00000000000..c119d8faee4 --- /dev/null +++ b/Buildings/Resources/Scripts/travis/templates/checkandrun.sh @@ -0,0 +1,107 @@ +#!/bin/bash +# coding: utf-8 + +# This script shall be run from `modelica-buildings/Buildings`, +# i.e., where the top-level `package.mo` file can be found. +# +# Command line flag -l is for a local run of this script to run simulations and update the checksum. +# Without -l TRAVISRUN is set to false which triggers the comparison of the checksum against HEAD. +# The first argument after the optional flag is for the Modelica tool, defaulting to Dymola. +# The second argument after the optional flag is the fraction of test coverage, for testing purposes only +# (the default value of 1 should be for used for PR against master). +# +# The script performs the following tasks. +# - Generate checksums for all *.mo files within the Templates package, order them +# based on the file names, and generates the checksum of those checksums. +# - Compare the resulting checksum with the stored value from previous evaluation. +# - If the values differ: run simulation script (*.py), +# otherwise do nothing. +# - If all simulations succeed: overwrite stored checksum with new value, +# otherwise do nothing. + +TRAVISRUN=true +OPTIND=1 + +while getopts 'l' flag; do + case "${flag}" in + l) TRAVISRUN=false;; + *) echo 'Error in command line parsing' >&2 + exit 1 + esac +done + +shift "$(( OPTIND - 1 ))" +SIMULATOR=${1:-Dymola} +FRACTION_TEST_COVERAGE=${2:-1} + +# Declare directories that must be checked (with checksum) for each template package. +# Each key is a Modelica package name under Buildings.Templates (with . as separator). +# Each value is a string containing directory paths (relative to `modelica-buildings/Buildings`). +declare -A checksum_dirs=( + # ["AirHandlersFans"]="Templates/AirHandlersFans + # Controls/OBC/ASHRAE/G36/AHUs/MultiZone/VAV" + # ["ZoneEquipment"]="Templates/ZoneEquipment + # Controls/OBC/ASHRAE/G36/TerminalUnits/CoolingOnly + # Controls/OBC/ASHRAE/G36/TerminalUnits/Reheat" + ["HeatingPlants.HotWater"]="Templates/HeatingPlants/HotWater" +) +# Declare the python script that must be run for each template package. +# Each key is a Modelica package name under Buildings.Templates (with . as separator). +# Each value is a string containing the script path (relative to `modelica-buildings/Buildings`). +declare -A test_script=( + # ["AirHandlersFans"]="./Resources/Scripts/travis/templates/VAVMultiZone.py" + # ["ZoneEquipment"]="./Resources/Scripts/travis/templates/VAVBox.py" + ["HeatingPlants.HotWater"]="./Resources/Scripts/travis/templates/BoilerPlant.py" +) + +for type in "${!checksum_dirs[@]}"; do + # For each system type: compute checksum of checksum of all mo files under corresponding checksum_dirs, and store value. + checksum="$( + find ${checksum_dirs[$type]} -type f -name '*.mo' -exec md5sum {} \; \ + | LC_ALL=C sort -f -k 2 \ + | awk '{ print $1; }' \ + | md5sum \ + | awk '{ print $1; }' + )" + echo $checksum > "./Resources/Scripts/travis/templates/$type.checksum" + + # Add checksum file to the index so that differences shows up in git diff. + git add --intent-to-add "./Resources/Scripts/travis/templates/$type.checksum" + + # Diff/HEAD: only for remote testing. + # Locally, it is expected that there is some diff/HEAD (and we proceed directly to the next step: diff/master). + if $TRAVISRUN; then + diff_checksum="$(git diff --name-only HEAD | grep Resources/Scripts/travis/templates/$type.checksum)" + if (( $? == 0 )); then + echo "Computed checksum does not match checksum on HEAD: please commit updated checksum for Templates.$type." + echo "Computed checksum: $checksum" + checksum_head=$(git show HEAD:Buildings/Resources/Scripts/travis/templates/$type.checksum 2>/dev/null) + if [[ -z "$checksum_head" ]]; then + echo "There is no checksum on HEAD for $type." + else + echo "Checksum on HEAD: $checksum_head" + fi + exit 1 + fi + fi + + # Diff/master + diff_checksum="$(git diff --name-only origin/master | grep Resources/Scripts/travis/templates/$type.checksum)" + if (( $? == 0 )); then + echo "Computed checksum does not match checksum on master." + echo "Running simulations for models in Templates.$type with $SIMULATOR." + # Launch simulations (typically several thousands). + python "${test_script[$type]}" $SIMULATOR $FRACTION_TEST_COVERAGE + if (( $? != 0 )); then + if [[ -s unitTestsTemplates.log ]]; then + printf "Below is the error log.\n\n" + cat unitTestsTemplates.log + fi + exit 1 + fi + else + echo "Computed checksum matches checksum on master: no further check performed." + fi +done + +exit 0 diff --git a/Buildings/Resources/Scripts/travis/templates/checksum b/Buildings/Resources/Scripts/travis/templates/checksum new file mode 100644 index 00000000000..9dfd20c0f35 --- /dev/null +++ b/Buildings/Resources/Scripts/travis/templates/checksum @@ -0,0 +1 @@ +d791977c7068d26965b9dec334a2a3be diff --git a/Buildings/Resources/Scripts/travis/templates/core.py b/Buildings/Resources/Scripts/travis/templates/core.py new file mode 100644 index 00000000000..9035a2af3a4 --- /dev/null +++ b/Buildings/Resources/Scripts/travis/templates/core.py @@ -0,0 +1,380 @@ +#!/usr/bin/env python +# coding: utf-8 + +# This file contains imports and functions used by other Python scripts in the same directory. + +import inspect +import itertools +import os +import random +import re +import sys + +# For CPU- and I/O-heavy jobs, we prefer multiprocessing.Pool because it provides better process isolation. +from multiprocessing import Pool + +import pandas as pd + +assert sys.version_info >= (3, 8), "This script requires a Python version >= 3.8." + +# Simulator is used later with case-insensitive match, e.g., both Dymola and dymola can be used. +try: + SIMULATOR = sys.argv[1] +except IndexError: + SIMULATOR = 'dymola' +# Fraction of test coverage between 0 and 1 (1 should be for used for PR against master). +try: + FRACTION_TEST_COVERAGE = float(sys.argv[2]) +except IndexError: + FRACTION_TEST_COVERAGE = 1 +assert ( + FRACTION_TEST_COVERAGE > 0 and FRACTION_TEST_COVERAGE <= 1 +), "FRACTION_TEST_COVERAGE must be between (>) 0 and (<=) 1." + +CRED = '\033[91m' +CGREEN = '\033[92m' +CEND = '\033[0m' + + +def simulate_case(arg, simulator): + """Set common parameters and run simulation with buildingspy. + + Args: + arg: tuple[str, list[str], str]: Model name, list of class modifications, suffix for mat file name. + simulator: str: Modelica tool for simulating the model. + + Returns: + tuple[int, str]: Error code, log. + """ + # Local imports required for multiprocessing in Jupyter notebook. + import glob + import json + import os + import re + import shutil + import tempfile + + simulator = simulator.lower() + + if simulator == 'dymola': + from buildingspy.simulate.Dymola import Simulator + elif simulator == 'optimica': + from buildingspy.simulate.Optimica import Simulator + else: + return 4, f'Unsupported simulation tool: {simulator}.' + + mat_root = re.split(r"\.", arg[0])[-1] + mat_suffix = re.sub(r"\.", "_", str(arg[2])) + output_dir_prefix = f"{mat_root}_{mat_suffix}" + cwd = os.getcwd() + # We need to create temporary directories at the same level as Buildings because of + # the way volumes are mounted in docker run, see Buildings/Resources/Scripts/travis/dymola/dymola. + output_dir_path = tempfile.mkdtemp(prefix=output_dir_prefix, dir=os.path.abspath(os.pardir)) + + # The following make Dymola worker cd into outputDirectory. + s = Simulator(arg[0], outputDirectory=output_dir_path) + + if simulator == 'dymola': + s.addPreProcessingStatement(r'Advanced.TranslationInCommandLog:=true;') + s.addPreProcessingStatement(r'openModel("../Buildings/package.mo", changeDirectory=false);') + if simulator == 'optimica': + # Set MODELICAPATH (only in child process, so this won't affect main process). + os.environ['MODELICAPATH'] = os.path.abspath(os.pardir) + + for modif in arg[1]: + s.addModelModifier(modif) + + s.setSolver("CVode") + s.setTolerance(1e-6) + s.printModelAndTime() + + try: + s.simulate() + except Exception as e: + toreturn = 2 + print(e) + finally: + os.chdir(cwd) + + # Test if simulation succeeded. + try: + if simulator == 'dymola': + with open(os.path.join(output_dir_path, 'simulator.log')) as fh: + log = fh.read() + if re.search('\n = false', log): + toreturn = 1 + else: + toreturn = 0 + elif simulator == 'optimica': + with open( + glob.glob(os.path.join(fr'{output_dir_path}', '*buildingspy.json'))[0], 'r' + ) as f: + log = json.load(f) + if log['simulation']['success']: + toreturn = 0 + else: + toreturn = 1 + except (FileNotFoundError, IndexError) as e: + toreturn = 3 + log = e + finally: + if toreturn == 0: + shutil.rmtree(output_dir_path, ignore_errors=True) + else: + print( + f'Simulation failed in {output_dir_path} with the following class modifications:\n' + + ',\n'.join(arg[1]) + + '\n' + ) + + return toreturn, log + + +def simulate_cases(args, simulator, asy=True): + """Configure and run all simulations. + + Args: + args: list[tuple[str, list[str]]]: List of (model name, list of class modifications, suffix for mat file name). + simulator: str: Modelica tool for simulating the model. + asy: bool: If True run simulations asynchronously. + + Returns: + list[tuple[int, str]]: List of (error code, log). + """ + # Workaround for multiprocessing that isn't strictly supported on Windows Jupyter Notebook. + with open('tmp_func.py', 'w') as file: + file.write(inspect.getsource(simulate_case).replace(simulate_case.__name__, "task")) + sys.path.append('.') + from tmp_func import task + + args_with_fixed = [(el, simulator) for el in args] + results = [] + func = task + pool = Pool(os.cpu_count()) + if asy: + results = pool.starmap_async(func, args_with_fixed) + else: + results = pool.starmap(func, args_with_fixed) + pool.close() + pool.join() + + return results + + +def generate_modif_list(dic): + """Generate list of class modifications. + + Args: + dic: dict[str, list[str]]: Dictionary where each key is the component or variable to be modified, + and each value is a list of modifications to be applied. + Bindings for parameters of redeclared components can be appended as class modifications, e.g. + 'VAV_1__redeclare__fanSupBlo': [ + 'Buildings.Templates.Components.Fans.ArrayVariable(nFan=2)', + ], + + Returns: + list[str]: List of class modifications. + """ + to_return = [] + for param, val in dic.items(): + if 'redeclare' in param: + modif_val = re.search('(.*)\((.*)\)', val) + if modif_val is not None: + comp_type = modif_val.group(1) + comp_modif = '(' + modif_val.group(2) + else: + comp_type = val + comp_modif = '' + modif = re.sub( + '(.*)redeclare__(.*)', + fr'\g<1>redeclare {comp_type} \g<2>', + param + comp_modif, + ) + else: + modif = param + '=' + val + modif = re.sub('__', '(', modif) + modif = modif + ')' * modif.count('(') + to_return.append(modif) + return to_return + + +def remove_items_by_indices(lst, indices): + """Removes (inplace) items from list based on their indices. + + Args: + lst: list + indices: list[int] + + Returns: + None + """ + for idx in sorted(list(dict.fromkeys(indices)), reverse=True): + if idx < len(lst): + lst.pop(idx) + + +def generate_combinations(models, modif_grid): + """Generate all possible combinations. + + Args: + models: list[str]: List of model names. + modif_grid: dict[str, dict[str, list[str]]]: Dictionary where each key is a model name, + and each value is a dictionary where each key resolves into a component to modify + and each value is a list of modifications to be applied to the component. + + Returns: + list[tuple[str, list[str], str]]: List of 3-tuples where + the first item of the tuple is a model to be simulated, + the second item of the tuple is the list of class modifications, + the third item of the tuple is a tag. + """ + # Generate combinations. + # combinations_dicts is a dictionary where + # each key is a model to be simulated, + # each value is a list of dictionaries where each key is the component or variable + # to be modified, and the corresponding value is the modification to be applied. + combinations_dicts = dict() + for model in models: + keys, values = zip(*modif_grid[model].items()) + combinations_dicts[model] = [dict(zip(keys, v)) for v in itertools.product(*values)] + + combinations = [] + tag = 0 # Simply tag each element with str(index). + for model, modif_dict_list in combinations_dicts.items(): + for el in modif_dict_list: + combinations.append((model, generate_modif_list(el), str(tag))) + tag = tag + 1 + + return combinations + + +def prune_modifications(combinations, exclude, remove_modif, fraction_test_coverage): + """Remove class modifications, and update combination tag. + + Args: + combinations: list[tuple[str, list[str], str]]: List of combinations as generated + by `generate_combinations`. + remove_modif: dict[str, list[tuple[list[str], list[str]]]]: Dictionary providing modifications + to be removed, see below. + exclude: dict[str, list[list[str]]]: Dictionary providing modifications to be excluded, see below. + fraction_test_coverage: float = Fraction (>0 and <=1) of test coverage to further reduce the number + of combinations (randomly). 1 should be for used for PR against master. + + Returns: + None (modifies inplace) + + Details: + A combination is a model and a list of class modifications (and a tag). + + For a given combination: + - The `remove_modif` argument is used to remove a *single* class modification. + Removing class modifications this way yields many duplicate combinations. + These duplicates are pruned afterwards. + - The `exclude` argument is used to exclude a combination entirely, i.e., *all* class modifications. + + Exclude (first): A combination is excluded if the following exclusion test returns true. + - Look for the model (key) in exclude (dict). + - Iterate over the list of list of class modifications for this model (value of exclude[model]). + - For a given list of class modifications, return true if all strings are found in the original + class modifications of the combination (concatenated). + - Note: re patterns are supported, e.g., negative lookahead using (?!pattern) + + Remove (after exclude): A class modification is removed from a combination according to the following rules. + For each item (2-tuple) of the list provided (as value) for each model (key) in remove_modif (dict): + - if all patterns of item[0] are found in the original class modifications of the combination (concatenated), and + - if a class modification contains any item within item[1], then + - this class modification is removed. + - Note: re patterns are supported, e.g., negative lookahead using (?!pattern) + + Example: + - Exclude: For a CHW plant, a combination with chillers in series arrangement and dedicated primary CHW pumps + can be excluded. + - Remove single modification: For a VAV air handler, a combination with a electric heating coil and a three-way valve + for the heating coil should use `remove_modif` to remove the valve component modification. We cannot use + `exclude` here because there is a modification of the valve component in each combination, so we would end up + excluding all combinations with a electric heating coil. + """ + # Exclude cases. + ## We iterate over a copy of the `combinations` list to allow removing items of `combinations` during iteration. + if exclude is not None: + for arg in combinations.copy(): + if arg[0] in exclude: + modif_concat = ''.join(arg[1]) + if any( + all(re.search(modif_ex, modif_concat) for modif_ex in list_modif_ex) + for list_modif_ex in exclude[arg[0]] + ): + combinations.remove(arg) + + if remove_modif is not None: + for i, arg in enumerate(combinations): + indices_to_pop = [] + if arg[0] in remove_modif: + modif_concat = ''.join(arg[1]) + for item in remove_modif[arg[0]]: + if all(re.search(el, modif_concat) for el in item[0]): + for pattern_to_remove in item[1]: + for j, modif in enumerate(arg[1]): + if re.search(pattern_to_remove, modif): + indices_to_pop.append(j) + remove_items_by_indices(combinations[i][1], indices_to_pop) + + # Remove duplicates. + indices_to_pop = [] + for i, arg in enumerate(combinations): + for j in range(i + 1, len(combinations)): + if arg[:2] == combinations[j][:2]: # Compare w/o tag at index 3. + indices_to_pop.append(j) + remove_items_by_indices(combinations, indices_to_pop) + + # Apply fraction of test coverage. + if fraction_test_coverage is not None: + remove_items_by_indices( + combinations, + random.sample( + range(len(combinations)), int(len(combinations) * (1 - fraction_test_coverage)) + ), + ) + + # Update tags. (Because pruning resulted in a sparse list of indices.) + for i, arg in enumerate(combinations): + combinations[i] = (*combinations[i][:2], str(i)) + + +def report_clean(combinations, results): + """Report and clean after simulations. + + Args: + combinations: list[tuple[str, list[str], str]]: List of combinations. + results: list[tuple[int, str]]: List of (error code, log). + + Returns: + pd.DataFrame + """ + + try: + os.unlink('tmp_func.py') + os.unlink('unitTestsTemplates.log') + except FileNotFoundError: + pass + + df = pd.DataFrame( + dict( + model=[el[0] for el in combinations], + tag=[el[2] for el in combinations], + modif=[el[1] for el in combinations], + errorcode=[r[0] for r in results], + errorlog=[r[1] for r in results], + ) + ) + + with open('unitTestsTemplates.log', 'w') as FH: + for idx in df[df.errorcode != 0].index: + FH.write( + f'*** Simulation failed for {df.iloc[idx].model} with the error code {df.iloc[idx].errorcode} ' + + 'and the following class modifications and error log.\n\n' + + ',\n'.join(df.iloc[idx].modif) + + f'\n\n{df.iloc[idx].errorlog}\n\n' + ) + + return df diff --git a/Buildings/Templates/Components/Boilers/HotWaterPolynomial.mo b/Buildings/Templates/Components/Boilers/HotWaterPolynomial.mo new file mode 100644 index 00000000000..acf553fcfd4 --- /dev/null +++ b/Buildings/Templates/Components/Boilers/HotWaterPolynomial.mo @@ -0,0 +1,42 @@ +within Buildings.Templates.Components.Boilers; +model HotWaterPolynomial "Hot water boiler with efficiency described by a polynomial" + extends Buildings.Templates.Components.Interfaces.PartialBoilerHotWater( + final typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial, + redeclare Buildings.Fluid.Boilers.BoilerPolynomial boi( + final Q_flow_nominal = dat.cap_nominal, + final m_flow_nominal=dat.mHeaWat_flow_nominal, + final dp_nominal=dat.dpHeaWat_nominal, + final fue=dat.fue)); + + annotation ( + defaultComponentName="boi", + Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +

+This is a model for a hot water boiler where the efficiency is computed +based on a polynomial of the firing rate and optionally of the hot water +temperature. +This model is based on + +Buildings.Fluid.Boilers.BoilerPolynomial. +The user may refer to the documentation of + +Buildings.Fluid.Boilers.UsersGuide +for the modeling assumptions. +

+

Control points

+

+See the documentation of + +Buildings.Templates.Components.Interfaces.BoilerHotWater. +

+", revisions=" + +")); +end HotWaterPolynomial; diff --git a/Buildings/Templates/Components/Boilers/HotWaterTable.mo b/Buildings/Templates/Components/Boilers/HotWaterTable.mo new file mode 100644 index 00000000000..a7f5065b7ed --- /dev/null +++ b/Buildings/Templates/Components/Boilers/HotWaterTable.mo @@ -0,0 +1,45 @@ +within Buildings.Templates.Components.Boilers; +model HotWaterTable "Hot water boiler with efficiency described by a table" + extends Buildings.Templates.Components.Interfaces.PartialBoilerHotWater( + final typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Table, + redeclare Buildings.Fluid.Boilers.BoilerTable boi(final per=dat.per)); + + annotation ( + defaultComponentName="boi", + Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +

+This is a model for a hot water boiler where the efficiency is computed +based on a lookup table indexed by the firing rate and the inlet temperature. +This model is based on + +Buildings.Fluid.Boilers.BoilerTable. +The user may refer to the documentation of + +Buildings.Fluid.Boilers.UsersGuide +for the modeling assumptions. +

+

Control points

+

+See the documentation of + +Buildings.Templates.Components.Interfaces.BoilerHotWater. +

+

Model parameters

+

+The design parameters and the efficiency table are specified with an instance of + +Buildings.Templates.Components.Data.BoilerHotWater. +The documentation of this record class provides further details on how to +properly parameterize the model. +

+", revisions=" + +")); +end HotWaterTable; diff --git a/Buildings/Templates/Components/Boilers/package.mo b/Buildings/Templates/Components/Boilers/package.mo new file mode 100644 index 00000000000..a945707be75 --- /dev/null +++ b/Buildings/Templates/Components/Boilers/package.mo @@ -0,0 +1,11 @@ +within Buildings.Templates.Components; +package Boilers "Boiler models" + extends Modelica.Icons.VariantsPackage; + + + annotation (Documentation(info=" +

+This package contains models for boilers. +

+")); +end Boilers; diff --git a/Buildings/Templates/Components/Boilers/package.order b/Buildings/Templates/Components/Boilers/package.order new file mode 100644 index 00000000000..287d73af491 --- /dev/null +++ b/Buildings/Templates/Components/Boilers/package.order @@ -0,0 +1,2 @@ +HotWaterPolynomial +HotWaterTable diff --git a/Buildings/Templates/Components/Data/BoilerHotWater.mo b/Buildings/Templates/Components/Data/BoilerHotWater.mo new file mode 100644 index 00000000000..228aed3520d --- /dev/null +++ b/Buildings/Templates/Components/Data/BoilerHotWater.mo @@ -0,0 +1,98 @@ +within Buildings.Templates.Components.Data; +record BoilerHotWater "Data for hot water boilers" + extends Modelica.Icons.Record; + + parameter Buildings.Templates.Components.Types.BoilerHotWaterModel typMod + "Type of boiler model" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Buildings.Fluid.Data.Fuels.Generic fue + "Fuel type" + annotation (choicesAllMatching = true); + + parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal( + final min=0) + "HW mass flow rate" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.HeatFlowRate cap_nominal + "Heating capacity" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpHeaWat_nominal( + final min=0, + start=Buildings.Templates.Data.Defaults.dpHeaWatBoi) + "HW pressure drop" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.Temperature THeaWatSup_nominal( + final min=260) + "HW supply temperature" + annotation(Dialog(group="Nominal condition")); + + replaceable parameter Buildings.Fluid.Boilers.Data.Generic per(fue=fue) + constrainedby Buildings.Fluid.Boilers.Data.Generic( + Q_flow_nominal=abs(cap_nominal), + TIn_nominal=THeaWatSup_nominal - + abs(cap_nominal)/ + Buildings.Utilities.Psychrometrics.Constants.cpWatLiq/ + mHeaWat_flow_nominal, + m_flow_nominal=mHeaWat_flow_nominal, + dp_nominal=dpHeaWat_nominal) + "Boiler performance data" + annotation ( + Dialog(enable=typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Table), + choicesAllMatching=true); + + parameter Buildings.Fluid.Types.EfficiencyCurves effCur= + Buildings.Fluid.Types.EfficiencyCurves.Constant + "Curve used to compute the efficiency" + annotation (Dialog(enable= + typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial)); + parameter Real a[:] = {0.9} + "Coefficients for efficiency curve" + annotation (Dialog(enable= + typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial)); + parameter Modelica.Units.SI.Temperature T_nominal=THeaWatSup_nominal + "Temperature used to compute nominal efficiency (only used if efficiency curve depends on temperature)" + annotation (Dialog(enable= + typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial and + (effCur==Buildings.Fluid.Types.EfficiencyCurves.QuadraticLinear))); + +annotation ( + defaultComponentName="datBoi", Documentation(info=" +

+This record provides the set of sizing and operating parameters for +the classes within + +Buildings.Templates.Components.Boilers. +

+

+When using the boiler model where the efficiency is based on a lookup table +(typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Table), +the design values declared at the top-level are propagated by default to the +performance data record per under the assumption that the nominal +conditions from the performance data match the design conditions. +Redeclaring the parameter per allows assigning a value to the efficiency curve +without overwriting the default bindings to the design values for the other parameters. +This is the recommended approach. +Alternatively, assigning the parameter per to a local instance of a +compatible record allows completely overwriting all the parameters inside per. +In this case, the consistency between the design parameters and the values from the +subrecord per is checked and a warning is issued if the design capacity or +HW flow rate (resp. pressure drop) is higher (resp. lower) than the value from the +performance data record. +This check is performed within + +Buildings.Templates.Components.Interfaces.PartialBoilerHotWater. +The validation model + +Buildings.Templates.Components.Validation.BoilerHotWater +illustrates the different use cases of this record. +

+", revisions=" + +")); +end BoilerHotWater; diff --git a/Buildings/Templates/Components/Data/PumpMultiple.mo b/Buildings/Templates/Components/Data/PumpMultiple.mo new file mode 100644 index 00000000000..6825b51a086 --- /dev/null +++ b/Buildings/Templates/Components/Data/PumpMultiple.mo @@ -0,0 +1,90 @@ +within Buildings.Templates.Components.Data; +record PumpMultiple "Record for multiple-pump models" + extends Modelica.Icons.Record; + + parameter Buildings.Templates.Components.Types.Pump typ + "Equipment type" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nPum( + final min=0, + start=1) + "Number of pumps" + annotation (Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_nominal[nPum]( + each start=1, + each final min=0) + "Mass flow rate - Each pump" + annotation ( + Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + parameter Modelica.Units.SI.PressureDifference dp_nominal[nPum]( + each start=0, + each final min=0) + "Total pressure rise - Each pump" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + // To avoid missing support for zero-sized record in case of nPum=0 we use max(nPum, 1). + replaceable parameter Fluid.Movers.Data.Generic per[max(nPum, 1)]( + pressure( + V_flow=if typ<>Buildings.Templates.Components.Types.Pump.None then + {{0, 1, 2} * m_flow_nominal[i] / rho_default for i in 1:nPum} else [0], + dp=if typ<>Buildings.Templates.Components.Types.Pump.None then + {{1.14, 1, 0.42} * dp_nominal[i] for i in 1:nPum} else [0])) + constrainedby Buildings.Fluid.Movers.Data.Generic + "Performance data - Each pump" + annotation(Dialog(enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + + parameter Modelica.Units.SI.Density rho_default= + Modelica.Media.Water.ConstantPropertyLiquidWater.d_const + "Default medium density" + annotation(Dialog(enable=false)); + + annotation ( + defaultComponentName="datPum", Documentation(info=" +

+This record provides the set of sizing and operating parameters for +the multiple-pump model + +Buildings.Templates.Components.Pumps.Multiple. +

+

+A default flow characteristic is provided, which goes through +the design operating point and spans over +0 and twice the design flow rate at maximum speed. +This default characteristic is based on a least squares +polynomial fit of the characteristics from + +Buildings.Fluid.Movers.Data.Pumps.Wilo. +The user may refer to the documentation of + +Buildings.Fluid.HydronicConfigurations.UsersGuide.ModelParameters +for further details. +Note that a default medium density is used to parameterize +the pump characteristic. So models that use this record should +overwrite this default value with the density of the medium +in use, especially in the case of a water/glycol mix. +

+

+In order to modify the default characteristic, one may use either +of the following methods. +

+ +

+Those various use cases are illustrated in + +Buildings.Templates.Components.Validation.PumpMultipleRecord. +

+")); +end PumpMultiple; diff --git a/Buildings/Templates/Components/Data/PumpSingle.mo b/Buildings/Templates/Components/Data/PumpSingle.mo new file mode 100644 index 00000000000..227ead5b1cf --- /dev/null +++ b/Buildings/Templates/Components/Data/PumpSingle.mo @@ -0,0 +1,50 @@ +within Buildings.Templates.Components.Data; +record PumpSingle "Record for single pump model" + extends Modelica.Icons.Record; + + parameter Buildings.Templates.Components.Types.Pump typ + "Equipment type" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_nominal( + start=1, + final min=0) + "Mass flow rate" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + parameter Modelica.Units.SI.PressureDifference dp_nominal( + start=0, + final min=0) + "Total pressure rise" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + replaceable parameter Fluid.Movers.Data.Generic per( + pressure( + V_flow={0, 1, 2} * m_flow_nominal / rho_default, + dp={1.14, 1, 0.42} * dp_nominal)) + constrainedby Buildings.Fluid.Movers.Data.Generic + "Performance data" + annotation(Dialog(enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + + parameter Modelica.Units.SI.Density rho_default= + Modelica.Media.Water.ConstantPropertyLiquidWater.d_const + "Default medium density" + annotation(Dialog(enable=false)); + + annotation ( + defaultComponentName="datPum", Documentation(info=" +

+This record provides the set of sizing and operating parameters for +the single pump model + +Buildings.Templates.Components.Pumps.Single. +

+

+A default flow characteristic is provided and can be overwritten as +described in the documentation of + +Buildings.Templates.Components.Data.PumpMultiple +in the more generic case of multiple units. +

+")); +end PumpSingle; diff --git a/Buildings/Templates/Components/Data/package.order b/Buildings/Templates/Components/Data/package.order index 96dad205471..67721409f2c 100644 --- a/Buildings/Templates/Components/Data/package.order +++ b/Buildings/Templates/Components/Data/package.order @@ -1,4 +1,7 @@ +BoilerHotWater Coil Damper Fan +PumpMultiple +PumpSingle Valve diff --git a/Buildings/Templates/Components/Interfaces/PartialBoilerHotWater.mo b/Buildings/Templates/Components/Interfaces/PartialBoilerHotWater.mo new file mode 100644 index 00000000000..fd11a8baa83 --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialBoilerHotWater.mo @@ -0,0 +1,177 @@ +within Buildings.Templates.Components.Interfaces; +partial model PartialBoilerHotWater "Interface class for hot water boiler models" + extends Buildings.Fluid.Interfaces.PartialTwoPortInterface( + final m_flow_nominal=mHeaWat_flow_nominal); + + parameter Buildings.Templates.Components.Types.BoilerHotWaterModel typMod + "Type of boiler model" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Buildings.Templates.Components.Data.BoilerHotWater dat( + final typMod=typMod) + "Design and operating parameters"; + + parameter Boolean is_con + "Set to true for condensing boiler, false for non-condensing boiler" + annotation (Evaluate=true, Dialog(group="Configuration")); + + final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal= + dat.mHeaWat_flow_nominal + "HW mass flow rate"; + final parameter Modelica.Units.SI.HeatFlowRate cap_nominal= + dat.cap_nominal + "Heating capacity"; + final parameter Modelica.Units.SI.PressureDifference dpHeaWat_nominal= + dat.dpHeaWat_nominal + "HW pressure drop"; + final parameter Modelica.Units.SI.Temperature THeaWatSup_nominal= + dat.THeaWatSup_nominal + "HW supply temperature"; + + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.DynamicFreeInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab="Dynamics", group="Conservation equations")); + + Buildings.Templates.Components.Interfaces.Bus bus + "Control bus" + annotation (Placement(transformation(extent={{-20,80},{20,120}}), + iconTransformation(extent={{-20,80},{20, 120}}))); + + replaceable Buildings.Fluid.Boilers.BaseClasses.PartialBoiler boi( + redeclare final package Medium=Medium, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final show_T=show_T, + final m_flow_small=m_flow_small) + "Boiler" + annotation (Placement(transformation(extent={{-10,-70},{10,-50}}))); + + Buildings.Controls.OBC.CDL.Reals.PIDWithReset ctl( + Ti=60, + final yMax=1, + final yMin=0, + final reverseActing=true) + "HW supply temperature controller" + annotation (Placement(transformation(extent={{-50,30},{-30,50}}))); + Buildings.Controls.OBC.CDL.Reals.Switch swiSet + "Switch setpoint to measured value when disabled" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Buildings.Controls.OBC.CDL.Reals.Switch swiSig + "Switch control signal to zero when disabled" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant valDis(final k=0) + "Value when disabled" + annotation (Placement(transformation(extent={{-50,-10},{-30,10}}))); + +initial equation + if typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Table then + assert(mHeaWat_flow_nominal <= dat.per.m_flow_nominal, + "In "+ getInstanceName() + ": " + + "The design HW flow rate of the boiler model (" + + String(mHeaWat_flow_nominal) + " kg/s) should be lower than the value from " + + "the performance data record (" + String(dat.per.m_flow_nominal) + " kg/s)", + level=AssertionLevel.warning); + assert(dpHeaWat_nominal >= dat.per.dp_nominal, + "In "+ getInstanceName() + ": " + + "The design HW pressure drop of the boiler model (" + + String(dpHeaWat_nominal) + " Pa) should be higher than the value from " + + "the performance data record (" + String(dat.per.dp_nominal) + " Pa)", + level=AssertionLevel.warning); + assert(cap_nominal <= dat.per.Q_flow_nominal, + "In "+ getInstanceName() + ": " + + "The design capacity of the boiler model (" + + String(cap_nominal) + " W) should be lower than the value from " + + "the performance data record (" + String(dat.per.Q_flow_nominal) + " W)", + level=AssertionLevel.warning); + end if; + +equation + connect(port_a, boi.port_a) + annotation (Line(points={{-100,0},{-80,0},{-80,-60},{-10,-60}}, + color={0,127,255})); + connect(boi.port_b, port_b) + annotation (Line(points={{10,-60},{80,-60},{80,0},{100,0}}, + color={0,127,255})); + connect(boi.T, ctl.u_m) annotation (Line(points={{11,-52},{20,-52},{20,20},{ + -40,20},{-40,28}}, + color={0,0,127})); + connect(swiSet.y, ctl.u_s) + annotation (Line(points={{-58,40},{-52,40}}, color={0,0,127})); + connect(boi.T, swiSet.u3) annotation (Line(points={{11,-52},{20,-52},{20,20}, + {-90,20},{-90,32},{-82,32}}, color={0,0,127})); + connect(bus.THeaWatSupSet, swiSet.u1) annotation (Line( + points={{0,100},{0,80},{-90,80},{-90,48},{-82,48}}, + color={255,204,51}, + thickness=0.5)); + connect(bus.y1, swiSet.u2) annotation (Line( + points={{0,100},{0,80},{-90,80},{-90,40},{-82,40}}, + color={255,204,51}, + thickness=0.5)); + connect(swiSet.u2, ctl.trigger) annotation (Line(points={{-82,40},{-86,40},{ + -86,24},{-46,24},{-46,28}}, color={255,0,255})); + connect(ctl.y, swiSig.u1) annotation (Line(points={{-28,40},{-20,40},{-20,48}, + {-2,48}}, color={0,0,127})); + connect(valDis.y, swiSig.u3) annotation (Line(points={{-28,0},{-4,0},{-4,32}, + {-2,32}}, color={0,0,127})); + connect(swiSet.u2, swiSig.u2) annotation (Line(points={{-82,40},{-86.1538,40}, + {-86.1538,24},{-10,24},{-10,40},{-2,40}}, color={255,0,255})); + connect(swiSig.y, bus.y_actual) annotation (Line(points={{22,40},{40,40},{40, + 96},{0,96},{0,100}}, + color={0,0,127})); + connect(swiSig.y, boi.y) annotation (Line(points={{22,40},{40,40},{40,-40},{ + -20,-40},{-20,-52},{-12,-52}}, color={0,0,127})); + connect(boi.T, bus.THeaWatSup) annotation (Line(points={{11,-52},{60,-52},{60, + 98},{0,98},{0,100}}, color={0,0,127})); + + + annotation (Documentation(info=" +

+This partial class provides a standard interface for hot water boiler models. +It includes a replaceable instance of + +Buildings.Fluid.Boilers.BaseClasses.PartialBoiler. +This model is used to construct the hot water boiler models within + +Buildings.Templates.Components.Boilers. +

+

Control points

+

+The following input and output points are available. +

+ +", revisions=" + +"), Icon(graphics={ + Rectangle( + extent={{100,60},{-100,-60}}, + lineColor={0,0,0}, + lineThickness=1), + Text( extent={{-60,20},{60,-20}}, + textColor={0,0,0}, + textString="BOI"), + Bitmap(extent={{-20,60},{20,100}}, fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg")})); +end PartialBoilerHotWater; diff --git a/Buildings/Templates/Components/Interfaces/PartialCoil.mo b/Buildings/Templates/Components/Interfaces/PartialCoil.mo index 04bc99e62ef..e959aeb4ea1 100644 --- a/Buildings/Templates/Components/Interfaces/PartialCoil.mo +++ b/Buildings/Templates/Components/Interfaces/PartialCoil.mo @@ -117,7 +117,6 @@ partial model PartialCoil "Interface class for coil" extent={{-10,-10},{10,10}}, rotation=0, origin={0,100}))); - protected parameter Buildings.Templates.Components.Data.Valve datVal( final typ=typVal, diff --git a/Buildings/Templates/Components/Interfaces/PartialPump.mo b/Buildings/Templates/Components/Interfaces/PartialPump.mo new file mode 100644 index 00000000000..1d1ab7160c3 --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialPump.mo @@ -0,0 +1,97 @@ +within Buildings.Templates.Components.Interfaces; +model PartialPump "Base class for all pump models" + parameter Buildings.Templates.Components.Types.Pump typ + "Equipment type" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Boolean have_var=true + "Set to true for variable speed pump, false for constant speed pump" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + parameter Boolean have_varCom=true + "Set to true for single common speed signal, false for dedicated signals" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ==Buildings.Templates.Components.Types.Pump.Multiple and have_var)); + + parameter Boolean have_valChe=true + "Set to true to include a check valve in pump line" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Components.Types.Pump.None), + __Linkage(enable=false)); + + parameter Boolean addPowerToMedium=false + "Set to false to avoid any power (=heat and flow work) being added to medium (may give simpler equations)" + annotation(__Linkage(enable=false)); + + parameter Modelica.Units.SI.Time tau=1 + "Time constant of fluid volume for nominal flow, used if energy or mass balance is dynamic" + annotation (Dialog( + tab="Dynamics", + group="Nominal condition", + enable=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState), + __Linkage(enable=false)); + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.DynamicFreeInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab = "Dynamics", group="Conservation equations"), + __Linkage(enable=false)); + parameter Boolean allowFlowReversal = true + "= false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation(Dialog(tab="Assumptions"), Evaluate=true, __Linkage(enable=false)); + + parameter Integer text_rotation = 0 + "Text rotation angle in icon layer" + annotation(Dialog(tab="Graphics", enable=false)); + parameter Boolean text_flip = false + "True to flip text horizontally in icon layer" + annotation(Dialog(tab="Graphics", enable=false)); + + Buildings.Templates.Components.Interfaces.Bus bus + "Control bus" + annotation ( + Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,100}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={0,100}))); + + annotation ( Documentation(info=" +

+This partial class provides a standard interface for pump models. +

+", revisions=" + +"), Icon(graphics={ + Line( points={{-100,0},{100,0}}, + color={0,0,0}, + thickness=5), + Bitmap( + visible=typ <> Buildings.Templates.Components.Types.Pump.None and + have_valChe, + extent={{20,-40},{100,40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ <> Buildings.Templates.Components.Types.Pump.None, + extent={{-100,-70},{0,30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var, + extent={{-100,60},{0,160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var, + extent={{-100,60},{0,160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( visible=typ <> Buildings.Templates.Components.Types.Pump.None, + points={{-50,60},{-50,22}}, + color={0,0,0})})); +end PartialPump; diff --git a/Buildings/Templates/Components/Interfaces/PartialPumpMultiple.mo b/Buildings/Templates/Components/Interfaces/PartialPumpMultiple.mo new file mode 100644 index 00000000000..b372c10e1bb --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialPumpMultiple.mo @@ -0,0 +1,211 @@ +within Buildings.Templates.Components.Interfaces; +partial model PartialPumpMultiple + "Interface class for multiple pumps in parallel arrangement" + extends Buildings.Templates.Components.Interfaces.PartialPump; + + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium in the component" + annotation(__Linkage(enable=false)); + + parameter Integer nPum( + final min=0, + start=1) + "Number of pumps" + annotation (Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + + parameter Buildings.Templates.Components.Data.PumpMultiple dat( + final nPum=nPum, + final typ=typ) + "Design and operating parameters" + annotation(__Linkage(enable=false)); + + final parameter Modelica.Units.SI.MassFlowRate m_flow_nominal[nPum]( + each final min=0)=dat.m_flow_nominal + "Nominal mass flow rate" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + final parameter Modelica.Units.SI.PressureDifference dp_nominal[nPum]( + each final min=0, + each displayUnit="Pa")=dat.dp_nominal + "Pump head at design conditions" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + + Modelica.Fluid.Interfaces.FluidPorts_a ports_a[nPum]( + redeclare each final package Medium = Medium, + each m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0), + each h_outflow(start = Medium.h_default, nominal = Medium.h_default), + each p(start=Medium.p_default)) + "Vectorized fluid connector a (positive design flow direction is from port(s)_a to port(s)_b)" + annotation (Placement( + transformation(extent={{-110,-40},{-90,40}}), iconTransformation(extent={{-110, + -40},{-90,40}}))); + Modelica.Fluid.Interfaces.FluidPorts_b ports_b[nPum]( + redeclare each final package Medium = Medium, + each m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0), + each h_outflow(start = Medium.h_default, nominal = Medium.h_default), + each p(start=Medium.p_default)) + "Vectorized fluid connector b (positive design flow direction is from port(s)_a to port(s)_b)" + annotation (Placement( + transformation(extent={{90,-40},{110,40}}), iconTransformation(extent={{90,-40}, + {110,40}}))); + + parameter Integer icon_dy = 300 + "Distance in y-direction between each unit in icon layer" + annotation(Dialog(tab="Graphics", enable=false)); + + annotation (Documentation(info=" +

+This partial class provides a standard interface for models +of multiple pumps in parallel arrangement. +Note that the inlet and outlet manifolds are not included +in this model. This way, the same interface can be used to model +both headered pumps and dedicated pumps. +

+", revisions=" + +"), Icon(graphics={ + Text( + extent={{-149,-114},{151,-154}}, + textColor={0,0,255}, + textString="%name"), + Line( visible=typ <> Buildings.Templates.Components.Types.Pump.None and + nPum >= 2, + points={{-100,icon_dy},{100,icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=2, + points={{-50,icon_dy+60},{-50,icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=2, + extent={{-100,icon_dy-70},{0,icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=2, + extent={{20,icon_dy-40},{100,icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=2, + extent={{-100,icon_dy+60},{0,icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=2, + extent={{-100,icon_dy+60},{0,icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=3, + points={{-100,2*icon_dy},{100,2*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=3, + points={{-50,2*icon_dy+60},{-50,2*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=3, + extent={{-100,2*icon_dy-70},{0,2*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=3, + extent={{20, 2*icon_dy-40},{100, 2*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=3, + extent={{-100, 2*icon_dy+60},{0, 2*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=3, + extent={{-100, 2*icon_dy+60},{0, 2*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=4, + points={{-100, 3*icon_dy},{100, 3*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=4, + points={{-50, 3*icon_dy+60},{-50, 3*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=4, + extent={{-100, 3*icon_dy-70},{0, 3*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=4, + extent={{20, 3*icon_dy-40},{100, 3*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=4, + extent={{-100, 3*icon_dy+60},{0, 3*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=4, + extent={{-100, 3*icon_dy+60},{0, 3*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=5, + points={{-100, 4*icon_dy},{100, 4*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=5, + points={{-50, 4*icon_dy+60},{-50, 4*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=5, + extent={{-100, 4*icon_dy-70},{0, 4*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=5, + extent={{20, 4*icon_dy-40},{100, 4*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=5, + extent={{-100, 4*icon_dy+60},{0, 4*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=5, + extent={{-100, 4*icon_dy+60},{0, 4*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=6, + points={{-100, 5*icon_dy},{100, 5*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=6, + points={{-50, 5*icon_dy+60},{-50, 5*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=6, + extent={{-100, 5*icon_dy-70},{0, 5*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=6, + extent={{20, 5*icon_dy-40},{100, 5*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=6, + extent={{-100, 5*icon_dy+60},{0, 5*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=6, + extent={{-100, 5*icon_dy+60},{0, 5*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg") +})); + +end PartialPumpMultiple; diff --git a/Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo b/Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo new file mode 100644 index 00000000000..933d5730910 --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo @@ -0,0 +1,36 @@ +within Buildings.Templates.Components.Interfaces; +partial model PartialPumpSingle "Interface class for single pump" + extends Buildings.Templates.Components.Interfaces.PartialPump; + extends Buildings.Fluid.Interfaces.PartialTwoPortInterface( + redeclare replaceable package Medium=Buildings.Media.Water, + final m_flow_nominal(min=0)=dat.m_flow_nominal) + annotation(__Linkage(enable=false)); + + parameter Buildings.Templates.Components.Data.PumpSingle dat( + final typ=typ) + "Design and operating parameters" + annotation(__Linkage(enable=false)); + + final parameter Modelica.Units.SI.PressureDifference dp_nominal( + final min=0, + displayUnit="Pa")=dat.dp_nominal + "Pump head at design conditions" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +

+This partial class provides a standard interface for +single pump models. +

+", revisions=" + +")); +end PartialPumpSingle; diff --git a/Buildings/Templates/Components/Interfaces/PartialSensor.mo b/Buildings/Templates/Components/Interfaces/PartialSensor.mo index 24dd22ed63b..3bb77744a2f 100644 --- a/Buildings/Templates/Components/Interfaces/PartialSensor.mo +++ b/Buildings/Templates/Components/Interfaces/PartialSensor.mo @@ -16,6 +16,10 @@ partial model PartialSensor "Interface class for sensor" parameter Boolean text_flip = false "True to flip text horizontally in icon layer" annotation(Dialog(tab="Graphics", enable=false)); + parameter Buildings.Templates.Components.Types.IconPipe icon_pipe = + Buildings.Templates.Components.Types.IconPipe.None + "Pipe symbol" + annotation(Dialog(tab="Graphics", enable=false)); Buildings.Controls.OBC.CDL.Interfaces.RealOutput y if have_sen "Connector for measured value" @@ -42,12 +46,16 @@ equation annotation ( Icon(coordinateSystem(preserveAspectRatio=false), - graphics={ - Line( - visible=(not have_sen) and (not isDifPreSen), - points={{-100,0},{100,0}}, - color={28,108,200}, - thickness=1)}), + graphics={Line( + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None + or (not have_sen) and (not isDifPreSen), + points={{-100,0},{100,0}}, + color=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.None + then {28,108,200} else {0,0,0}, + thickness=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.None + then 1 else 5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Return + then LinePattern.Dash else LinePattern.Solid)}), Diagram(coordinateSystem(preserveAspectRatio=false)), Documentation(info="

diff --git a/Buildings/Templates/Components/Interfaces/package.order b/Buildings/Templates/Components/Interfaces/package.order index 9c481d0f47a..ef3e94d40fd 100644 --- a/Buildings/Templates/Components/Interfaces/package.order +++ b/Buildings/Templates/Components/Interfaces/package.order @@ -1,6 +1,10 @@ Bus +PartialBoilerHotWater PartialCoil PartialDamper PartialFan +PartialPump +PartialPumpMultiple +PartialPumpSingle PartialSensor PartialValve diff --git a/Buildings/Templates/Components/Pumps/Multiple.mo b/Buildings/Templates/Components/Pumps/Multiple.mo new file mode 100644 index 00000000000..cdd432b3834 --- /dev/null +++ b/Buildings/Templates/Components/Pumps/Multiple.mo @@ -0,0 +1,188 @@ +within Buildings.Templates.Components.Pumps; +model Multiple "Multiple pumps in parallel" + extends Buildings.Templates.Components.Interfaces.PartialPumpMultiple( + final typ=Buildings.Templates.Components.Types.Pump.Multiple); + + replaceable Buildings.Fluid.Movers.SpeedControlled_y pum[nPum]( + redeclare each final package Medium=Medium, + final per=dat.per, + each final inputType=Buildings.Fluid.Types.InputType.Continuous, + each final addPowerToMedium=addPowerToMedium, + each final energyDynamics=energyDynamics, + each final tau=tau, + each final allowFlowReversal=allowFlowReversal) + "Pumps" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Fluid.FixedResistances.CheckValve valChe[nPum]( + redeclare each final package Medium = Medium, + final m_flow_nominal=m_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValChe) + if have_valChe "Check valve" + annotation (Placement(transformation(extent={{40,10},{60,30}}))); + Routing.PassThroughFluid pas[nPum]( + redeclare each final package Medium = Medium) if not have_valChe + "Fluid pass through if no check valve" + annotation (Placement(transformation(extent={{40,-30},{60,-10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal sigSta[nPum] + "Start/stop signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-60,70}))); + Buildings.Controls.OBC.CDL.Reals.Multiply sigCon[nPum] + "Resulting control signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={0,30}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold evaSta[nPum]( + each t=1E-2, + each h=0.5E-2) + "Evaluate pump status" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={20,-50}))); + Controls.OBC.CDL.Routing.RealScalarReplicator reaSpe( + final nout=nPum) if have_var and have_varCom + "Replicate signal in case of common unique commanded speed" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-20,70}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant speCst[nPum]( + final k=fill(1, nPum)) if not have_var + "Constant signal in case of constant speed pump" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={60,70}))); + Controls.OBC.CDL.Routing.RealExtractSignal pasSpe( + final nin=nPum, + final nout=nPum) if have_var and not have_varCom + "Direct pass through for dedicated speed signals" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={20,70}))); +equation + connect(pum.port_b,valChe. port_a) + annotation (Line(points={{10,0},{30,0},{30,20},{40,20}}, color={0,127,255})); + connect(sigSta.y, sigCon.u2) + annotation (Line(points={{-60,58},{-60,46},{-6,46},{-6,42}}, + color={0,0,127})); + connect(sigCon.y, pum.y) + annotation (Line(points={{0,18},{0,15},{0,12}}, color={0,0,127})); + connect(pum.y_actual, evaSta.u) + annotation (Line(points={{11,7},{20,7},{20,-38}}, color={0,0,127})); + connect(evaSta.y, bus.y1_actual) + annotation (Line(points={{20,-62},{20,-72},{80,-72},{80,96},{0,96},{0,100}}, + color={255,0,255}), Text( + string="%second", + index=1, + extent={{-3,-6},{-3,-6}}, + horizontalAlignment=TextAlignment.Right)); + connect(valChe.port_b, ports_b) + annotation (Line(points={{60,20},{70,20},{70,0},{100,0}}, color={0,127,255})); + connect(ports_a, pum.port_a) + annotation (Line(points={{-100,0},{-10,0}}, color={0,127,255})); + connect(bus.y1, sigSta.u) annotation (Line( + points={{0,100},{0,88},{-60,88},{-60,82}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{-3,6},{-3,6}}, + horizontalAlignment=TextAlignment.Right)); + connect(reaSpe.y, sigCon.u1) annotation (Line(points={{-20,58},{-20,50},{6,50}, + {6,42}}, color={0,0,127})); + connect(bus.y, reaSpe.u) annotation (Line( + points={{0,100},{0,88},{-20,88},{-20,82}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{-3,6},{-3,6}}, + horizontalAlignment=TextAlignment.Right)); + connect(speCst.y, sigCon.u1) + annotation (Line(points={{60,58},{60,50},{6,50},{6,42}}, color={0,0,127})); + connect(bus.y, pasSpe.u) annotation (Line( + points={{0,100},{0,88},{20,88},{20,82}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{-6,3},{-6,3}}, + horizontalAlignment=TextAlignment.Right)); + connect(pasSpe.y, sigCon.u1) + annotation (Line(points={{20,58},{20,50},{6,50},{6,42}}, color={0,0,127})); + connect(pum.port_b, pas.port_a) annotation (Line(points={{10,0},{30,0},{30,-20}, + {40,-20}}, color={0,127,255})); + connect(pas.port_b, ports_b) annotation (Line(points={{60,-20},{70,-20},{70,0}, + {100,0}}, color={0,127,255})); + annotation ( + defaultComponentName="pum", + Documentation(info=" +

+This is a model for a parallel arrangement of nPum pumps +with optional check valves (depending on the value of the parameter +have_valChe). +

+

+Note that the inlet and outlet manifolds are not included in this model. +The manifolds may be modeled with + +Buildings.Templates.Components.Routing.MultipleToMultiple. +This allows representing both headered and dedicated arrangements. +

+

+By default, variable speed pumps are modeled. +Constant speed pumps can be modeled by setting the parameter +have_var to false. +

+

Control points

+

+The following input and output points are available. +

+ +

Model parameters

+

+The design parameters and the pump characteristics are specified with an instance of + +Buildings.Templates.Components.Data.PumpMultiple. +The documentation of this record class provides further details on how to +properly parameterize the model. +

+", revisions=" + +")); +end Multiple; diff --git a/Buildings/Templates/Components/Pumps/Single.mo b/Buildings/Templates/Components/Pumps/Single.mo new file mode 100644 index 00000000000..1e061e11000 --- /dev/null +++ b/Buildings/Templates/Components/Pumps/Single.mo @@ -0,0 +1,156 @@ +within Buildings.Templates.Components.Pumps; +model Single "Single pump" + extends Buildings.Templates.Components.Interfaces.PartialPumpSingle( + final typ=Buildings.Templates.Components.Types.Pump.Single); + + replaceable Buildings.Fluid.Movers.SpeedControlled_y pum( + redeclare final package Medium=Medium, + final per=dat.per, + final inputType=Buildings.Fluid.Types.InputType.Continuous, + final addPowerToMedium=addPowerToMedium, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal) + "Pump" + annotation ( + Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal sigSta + "Start/stop signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-60,70}))); + Buildings.Controls.OBC.CDL.Reals.Multiply sigCon + "Resulting control signal" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={0,30}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold evaSta( + t=1E-2, + h=0.5E-2) + "Evaluate pump status" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={20,-50}))); + Fluid.FixedResistances.CheckValve valChe( + redeclare final package Medium = Medium, + final m_flow_nominal=dat.m_flow_nominal, + dpValve_nominal=Buildings.Templates.Data.Defaults.dpValChe) if have_valChe + "Check valve" + annotation (Placement(transformation(extent={{40,10},{60,30}}))); + Routing.PassThroughFluid pas( + redeclare final package Medium=Medium) if not have_valChe + "Fluid pass through if no check valve" + annotation (Placement(transformation(extent={{40,-30},{60,-10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant speCst( + final k=1) if not have_var + "Constant signal in case of constant speed pump" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={60,70}))); + Modelica.Blocks.Routing.RealPassThrough pasSpe if have_var + "Direct pass through for variable speed signal" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={0,70}))); +equation + connect(sigSta.y, sigCon.u2) + annotation (Line(points={{-60,58},{-60,50},{-6,50},{-6,42}}, + color={0,0,127})); + connect(sigCon.y, pum.y) + annotation (Line(points={{0,18},{0,15},{0,12}}, color={0,0,127})); + connect(pum.y_actual, evaSta.u) + annotation (Line(points={{11,7},{20,7},{20,-38}}, color={0,0,127})); + connect(evaSta.y, bus.y1_actual) + annotation (Line(points={{20,-62},{20,-80},{80,-80},{80,88},{0,88},{0,100}}, + color={255,0,255}), Text( + string="%second", + index=1, + extent={{-3,-6},{-3,-6}}, + horizontalAlignment=TextAlignment.Right)); + connect(port_a, pum.port_a) + annotation (Line(points={{-100,0},{-10,0}}, color={0,127,255})); + connect(bus.y, pasSpe.u) annotation (Line( + points={{0,100},{2.22045e-15,100},{2.22045e-15,82}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{-3,6},{-3,6}}, + horizontalAlignment=TextAlignment.Right)); + connect(pasSpe.y, sigCon.u1) + annotation (Line(points={{0,59},{0,50},{6,50},{6,42}}, color={0,0,127})); + connect(speCst.y, sigCon.u1) + annotation (Line(points={{60,58},{60,50},{6,50},{6,42}}, color={0,0,127})); + connect(bus.y1, sigSta.u) annotation (Line( + points={{0,100},{0,88},{-60,88},{-60,82}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{6,3},{6,3}}, + horizontalAlignment=TextAlignment.Left)); + connect(pum.port_b, valChe.port_a) annotation (Line(points={{10,0},{28,0},{28, + 20},{40,20}}, color={0,127,255})); + connect(valChe.port_b, port_b) annotation (Line(points={{60,20},{70,20},{70,0}, + {100,0}}, color={0,127,255})); + connect(pum.port_b, pas.port_a) annotation (Line(points={{10,0},{28,0},{28,-20}, + {40,-20}}, color={0,127,255})); + connect(pas.port_b, port_b) annotation (Line(points={{60,-20},{70,-20},{70,0}, + {100,0}}, color={0,127,255})); + annotation ( + defaultComponentName="pum", + Documentation(info=" +

+This is a model for a single pump +with an optional check valve (depending on the value of the parameter +have_valChe). +

+

+By default, a variable speed pump is modeled. +A constant speed pump can be modeled by setting the parameter +have_var to false. +

+

Control points

+

+The following input and output points are available. +

+ +

Model parameters

+

+The design parameters and the pump characteristics are specified with an instance of + +Buildings.Templates.Components.Data.PumpSingle. +The documentation of this record class provides further details on how to +properly parameterize the model. +

+", revisions=" + +")); +end Single; diff --git a/Buildings/Templates/Components/Pumps/package.mo b/Buildings/Templates/Components/Pumps/package.mo new file mode 100644 index 00000000000..d1f4ec5215f --- /dev/null +++ b/Buildings/Templates/Components/Pumps/package.mo @@ -0,0 +1,15 @@ +within Buildings.Templates.Components; +package Pumps "Pump models" + extends Modelica.Icons.VariantsPackage; + + + + + + +annotation (Documentation(info=" +

+This package contains models for pumps. +

+")); +end Pumps; diff --git a/Buildings/Templates/Components/Pumps/package.order b/Buildings/Templates/Components/Pumps/package.order new file mode 100644 index 00000000000..b8bb7e28f05 --- /dev/null +++ b/Buildings/Templates/Components/Pumps/package.order @@ -0,0 +1,2 @@ +Multiple +Single diff --git a/Buildings/Templates/Components/Routing/Junction.mo b/Buildings/Templates/Components/Routing/Junction.mo new file mode 100644 index 00000000000..a428046cda6 --- /dev/null +++ b/Buildings/Templates/Components/Routing/Junction.mo @@ -0,0 +1,39 @@ +within Buildings.Templates.Components.Routing; +model Junction "Flow splitter with fixed resistance at each port" + extends Buildings.Fluid.FixedResistances.Junction + annotation ( + IconMap(primitivesVisible = false)); + + parameter Buildings.Templates.Components.Types.IconPipe icon_pipe1 = + Buildings.Templates.Components.Types.IconPipe.Supply + "Pipe symbol - Branch 1" + annotation(Dialog(tab="Graphics", enable=false)); + parameter Buildings.Templates.Components.Types.IconPipe icon_pipe2 = icon_pipe1 + "Pipe symbol - Branch 2" + annotation(Dialog(tab="Graphics", enable=false)); + parameter Buildings.Templates.Components.Types.IconPipe icon_pipe3 = icon_pipe1 + "Pipe symbol - Branch 3" + annotation(Dialog(tab="Graphics", enable=false)); + annotation (Icon(graphics={ + Line( + points={{-100,0},{0,0}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe1==Buildings.Templates.Components.Types.IconPipe.Supply then + LinePattern.Solid elseif icon_pipe1==Buildings.Templates.Components.Types.IconPipe.Return + then LinePattern.Dash else LinePattern.None), + Line( + points={{0,0},{100,0}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe2==Buildings.Templates.Components.Types.IconPipe.Supply then + LinePattern.Solid elseif icon_pipe2==Buildings.Templates.Components.Types.IconPipe.Return + then LinePattern.Dash else LinePattern.None), + Line( + points={{0,0},{0,-100}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe3==Buildings.Templates.Components.Types.IconPipe.Supply then + LinePattern.Solid elseif icon_pipe3==Buildings.Templates.Components.Types.IconPipe.Return + then LinePattern.Dash else LinePattern.None)})); +end Junction; diff --git a/Buildings/Templates/Components/Routing/MultipleToMultiple.mo b/Buildings/Templates/Components/Routing/MultipleToMultiple.mo index e23e8ac3d7c..c94efade48e 100644 --- a/Buildings/Templates/Components/Routing/MultipleToMultiple.mo +++ b/Buildings/Templates/Components/Routing/MultipleToMultiple.mo @@ -42,16 +42,17 @@ model MultipleToMultiple annotation ( Dialog(tab="Advanced", group="Diagnostics"), HideResult=true); - parameter Integer icon_extend = 0 - "Extend lines by this amount in x-direction in icon layer: >0 at outlet, <0 at inlet" - annotation(Dialog(tab="Graphics", enable=false)); - parameter Integer icon_dy = 100 - "Distance in y-direction between each branch in icon layer" - annotation(Dialog(tab="Graphics", enable=false)); - parameter Buildings.Templates.Components.Types.IconPipe icon_pipe = + constant Integer icon_xinl = -100 + "Minimum x-coordinate of inlet connection lines"; + constant Integer icon_xout = 100 + "Maximum x-coordinate of outlet connection lines"; + constant Integer icon_offset = 0 + "Offset in y-direction between inlet and outlet in icon layer"; + constant Integer icon_dy = 100 + "Distance in y-direction between each branch in icon layer"; + constant Buildings.Templates.Components.Types.IconPipe icon_pipe = Buildings.Templates.Components.Types.IconPipe.Supply - "Pipe symbol" - annotation(Dialog(tab="Graphics", enable=false)); + "Pipe symbol"; Modelica.Fluid.Interfaces.FluidPorts_a ports_a[nPorts_a]( redeclare each final package Medium = Medium, @@ -160,49 +161,84 @@ equation Text( extent={{-149,-114},{151,-154}}, textColor={0,0,255}, textString="%name"), - Line( points={{-100 + min(0,icon_extend), 0}, {100 + max(0, icon_extend),0}}, + Line( points={{-100, 0}, {100, 0}}, + color={0,127,255}, + visible=icon_pipe==Buildings.Templates.Components.Types.IconPipe.None), + Line( points={{icon_xinl, 0}, {0,0}}, color={0,0,0}, thickness=5, + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts_a>=2, - points=if have_comLeg then - {{-100 + min(0,icon_extend), icon_dy}, {-40,icon_dy}, {-40, 0}} - else {{-100 + min(0,icon_extend),icon_dy}, {100 + max(0, icon_extend),icon_dy}}, + Line( visible=nPorts_a>=2 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{icon_xinl, icon_dy}, {0,icon_dy}}, color={0,0,0}, thickness=5, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts_a>=3, - points=if have_comLeg then - {{-100 + min(0,icon_extend), 2*icon_dy}, {-40, 2*icon_dy}, {-40, icon_dy}} - else {{-100 + min(0,icon_extend),2*icon_dy}, {100 + max(0, icon_extend),2*icon_dy}}, + Line( visible=nPorts_a>=3 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{icon_xinl, 2*icon_dy}, {0, 2*icon_dy}}, color={0,0,0}, thickness=5, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts_a>=4, - points=if have_comLeg then - {{-100 + min(0,icon_extend), 3*icon_dy}, {-40, 3*icon_dy}, {-40, 2*icon_dy}} - else {{-100 + min(0,icon_extend),3*icon_dy}, {100 + max(0, icon_extend),3*icon_dy}}, + Line( visible=nPorts_a>=4 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{icon_xinl, 3*icon_dy}, {0, 3*icon_dy}}, color={0,0,0}, thickness=5, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts_b>=2 and have_comLeg, - points={{40, 0}, {40, icon_dy}, {100 + max(0, icon_extend), icon_dy}}, + Line( visible=nPorts_a>=5 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{icon_xinl, 4*icon_dy}, {0, 4*icon_dy}}, color={0,0,0}, thickness=5, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts_b>=3 and have_comLeg, - points={{40, icon_dy}, {40, 2*icon_dy}, {100 + max(0, icon_extend), 2*icon_dy}}, + Line( visible=nPorts_a>=6 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{icon_xinl, 5*icon_dy}, {0, 5*icon_dy}}, color={0,0,0}, thickness=5, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts_b>=4 and have_comLeg, - points={{40, 2*icon_dy}, {40, 3*icon_dy}, {100 + max(0, icon_extend), 3*icon_dy}}, + Line( points={{0, icon_offset}, {icon_xout,icon_offset}}, + color={0,0,0}, + thickness=5, + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash), + Line( visible=nPorts_b>=2 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{0, icon_offset + 1*icon_dy}, {icon_xout,icon_offset + 1*icon_dy}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash), + Line( visible=nPorts_b>=3 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{0, icon_offset + 2*icon_dy}, {icon_xout,icon_offset + 2*icon_dy}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash), + Line( visible=nPorts_b>=4 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{0, icon_offset + 3*icon_dy}, {icon_xout,icon_offset + 3*icon_dy}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash), + Line( visible=nPorts_b>=5 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{0, icon_offset + 4*icon_dy}, {icon_xout,icon_offset + 4*icon_dy}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash), + Line( visible=nPorts_b>=6 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points={{0, icon_offset + 5*icon_dy}, {icon_xout,icon_offset + 5*icon_dy}}, + color={0,0,0}, + thickness=5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash), + Line( visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None and + max(nPorts_a, nPorts_b)>=2 and have_comLeg, + points={{0, 0}, {0, icon_offset + (max(nPorts_a, nPorts_b)-1)*icon_dy}}, color={0,0,0}, thickness=5, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply @@ -221,7 +257,7 @@ First implementation. This is a model of a many-to-many fluid connector with an optional control volume, and an optional mixing port (common leg). It is typically used to connect parallel pumps with parallel -chillers or boilers. +chillers or boilers. Selecting a mixing port allows modeling a headered pumping arrangement. Without any mixing port, a dedicated pumping arrangement is modeled.

diff --git a/Buildings/Templates/Components/Routing/MultipleToSingle.mo b/Buildings/Templates/Components/Routing/MultipleToSingle.mo index df088e2bfe3..a42b8bcda4e 100644 --- a/Buildings/Templates/Components/Routing/MultipleToSingle.mo +++ b/Buildings/Templates/Components/Routing/MultipleToSingle.mo @@ -35,16 +35,13 @@ model MultipleToSingle "Multiple inlet port, single outlet ports" Dialog(tab="Advanced", group="Diagnostics"), HideResult=true); - parameter Integer icon_offset = 0 - "Offset in y-direction between inlet and outlet in icon layer" - annotation(Dialog(tab="Graphics", enable=false)); - parameter Integer icon_dy = 100 - "Distance in y-direction between each branch in icon layer" - annotation(Dialog(tab="Graphics", enable=false)); - parameter Buildings.Templates.Components.Types.IconPipe icon_pipe = - Buildings.Templates.Components.Types.IconPipe.Supply - "Pipe symbol" - annotation(Dialog(tab="Graphics", enable=false)); + constant Integer icon_offset = 0 + "Offset in y-direction between inlet and outlet in icon layer"; + constant Integer icon_dy = 100 + "Distance in y-direction between each branch in icon layer"; + constant Buildings.Templates.Components.Types.IconPipe icon_pipe = + Buildings.Templates.Components.Types.IconPipe.None + "Pipe symbol"; Modelica.Fluid.Interfaces.FluidPorts_a ports_a[nPorts]( redeclare each final package Medium = Medium, @@ -100,8 +97,7 @@ equation -20,20},{-10,20}}, color={0,127,255})); end for; connect(ports_a, del.ports[1:nPorts]) annotation (Line(points={{-100,0},{-20,0}, - {-20,-20},{0,-20}}, - color={0,127,255})); + {-20,-20},{0,-20}}, color={0,127,255})); connect(del.ports[nPorts+1], port_b) annotation (Line(points={{0,-20},{20,-20}, {20,0},{100,0}}, color={0,127,255})); connect(pasSte.port_b, port_b) annotation (Line(points={{10,20},{20,20},{20,0}, @@ -112,12 +108,16 @@ equation Text( extent={{-149,-114},{151,-154}}, textColor={0,0,255}, textString="%name"), + Line( points={{-100, 0}, {100, 0}}, + color={0,127,255}, + visible=icon_pipe==Buildings.Templates.Components.Types.IconPipe.None), Line( points={{-100, icon_offset}, {0, icon_offset}, {0,0}, {100,0}}, color={0,0,0}, thickness=5, + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts>=2, + Line( visible=nPorts>=2 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, points=if icon_offset*icon_dy>=0 then {{0,icon_offset},{0,icon_offset+icon_dy},{-100,icon_offset+icon_dy}} elseif icon_offset>0 and icon_offset+icon_dy<0 or icon_offset<0 and icon_offset+icon_dy>0 then @@ -127,7 +127,7 @@ equation pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash, thickness=5), - Line( visible=nPorts>=3, + Line( visible=nPorts>=3 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, points=if icon_offset*icon_dy>=0 then {{0, icon_offset+icon_dy},{0, icon_offset+2*icon_dy},{-100, icon_offset+2*icon_dy}} elseif icon_offset>0 and icon_offset+2*icon_dy<0 or icon_offset<0 and icon_offset+2*icon_dy>0 then @@ -137,7 +137,7 @@ equation pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash, thickness=5), - Line( visible=nPorts>=4, + Line( visible=nPorts>=4 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, points=if icon_offset*icon_dy>=0 then {{0, icon_offset+2*icon_dy},{0, icon_offset+3*icon_dy},{-100, icon_offset+3*icon_dy}} elseif icon_offset>0 and icon_offset+3*icon_dy<0 or icon_offset<0 and icon_offset+3*icon_dy>0 then @@ -146,6 +146,26 @@ equation color={0,0,0}, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash, + thickness=5), + Line( visible=nPorts>=5 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points=if icon_offset*icon_dy>=0 then + {{0, icon_offset+3*icon_dy},{0, icon_offset+4*icon_dy},{-100, icon_offset+4*icon_dy}} + elseif icon_offset>0 and icon_offset+4*icon_dy<0 or icon_offset<0 and icon_offset+4*icon_dy>0 then + {{0, 0},{0, icon_offset+4*icon_dy},{-100, icon_offset+4*icon_dy}} + else {{0, icon_offset+4*icon_dy},{-100, icon_offset+4*icon_dy}}, + color={0,0,0}, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash, + thickness=5), + Line( visible=nPorts>=6 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points=if icon_offset*icon_dy>=0 then + {{0, icon_offset+4*icon_dy},{0, icon_offset+5*icon_dy},{-100, icon_offset+5*icon_dy}} + elseif icon_offset>0 and icon_offset+5*icon_dy<0 or icon_offset<0 and icon_offset+5*icon_dy>0 then + {{0, 0},{0, icon_offset+5*icon_dy},{-100, icon_offset+5*icon_dy}} + else {{0, icon_offset+5*icon_dy},{-100, icon_offset+5*icon_dy}}, + color={0,0,0}, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash, thickness=5)}), Diagram( coordinateSystem(preserveAspectRatio=false)), diff --git a/Buildings/Templates/Components/Routing/PassThroughFluid.mo b/Buildings/Templates/Components/Routing/PassThroughFluid.mo index 410acee7d08..cd00c5dcfd0 100644 --- a/Buildings/Templates/Components/Routing/PassThroughFluid.mo +++ b/Buildings/Templates/Components/Routing/PassThroughFluid.mo @@ -1,6 +1,13 @@ within Buildings.Templates.Components.Routing; model PassThroughFluid "Direct fluid pass-through" - extends Buildings.Fluid.Interfaces.PartialTwoPort; + extends Buildings.Fluid.Interfaces.PartialTwoPort + annotation ( + IconMap(primitivesVisible = false)); + + parameter Buildings.Templates.Components.Types.IconPipe icon_pipe = + Buildings.Templates.Components.Types.IconPipe.Supply + "Pipe symbol" + annotation(Dialog(tab="Graphics", enable=false)); equation connect(port_a, port_b) annotation (Line(points={{-100,0},{0,0},{0,0},{100,0}}, @@ -8,10 +15,14 @@ equation annotation ( defaultComponentName="pas", Icon(coordinateSystem(preserveAspectRatio=false), - graphics={Line( - points={{-100,0},{100,0}}, - color={28,108,200}, - thickness=1)}), Diagram(coordinateSystem(preserveAspectRatio=false)), + graphics={ + Line( + points={{-100,0},{100,0}}, + color={0,0,0}, + thickness=5, + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then + LinePattern.Solid else LinePattern.Dash)}), Documentation(info="

This is a model of a direct fluid pass-through used for diff --git a/Buildings/Templates/Components/Routing/SingleToMultiple.mo b/Buildings/Templates/Components/Routing/SingleToMultiple.mo index 0c8996d1449..6bfd895ae96 100644 --- a/Buildings/Templates/Components/Routing/SingleToMultiple.mo +++ b/Buildings/Templates/Components/Routing/SingleToMultiple.mo @@ -35,16 +35,13 @@ model SingleToMultiple "Single inlet port, multiple outlet ports" Dialog(tab="Advanced", group="Diagnostics"), HideResult=true); - parameter Integer icon_offset = 0 - "Offset in y-direction between inlet and outlet in icon layer" - annotation(Dialog(tab="Graphics", enable=false)); - parameter Integer icon_dy = 100 - "Distance in y-direction between each branch in icon layer" - annotation(Dialog(tab="Graphics", enable=false)); - parameter Buildings.Templates.Components.Types.IconPipe icon_pipe = - Buildings.Templates.Components.Types.IconPipe.Supply - "Pipe symbol" - annotation(Dialog(tab="Graphics", enable=false)); + constant Integer icon_offset = 0 + "Offset in y-direction between inlet and outlet in icon layer"; + constant Integer icon_dy = 100 + "Distance in y-direction between each branch in icon layer"; + constant Buildings.Templates.Components.Types.IconPipe icon_pipe = + Buildings.Templates.Components.Types.IconPipe.None + "Pipe symbol"; Modelica.Fluid.Interfaces.FluidPort_a port_a( redeclare final package Medium = Medium, @@ -114,12 +111,16 @@ equation Text( extent={{-149,-114},{151,-154}}, textColor={0,0,255}, textString="%name"), + Line( points={{-100, 0}, {100, 0}}, + color={0,127,255}, + visible=icon_pipe==Buildings.Templates.Components.Types.IconPipe.None), Line( points={{-100,0},{0,0},{0,icon_offset},{100,icon_offset}}, color={0,0,0}, thickness=5, + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash), - Line( visible=nPorts>=2, + Line( visible=nPorts>=2 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, points=if icon_offset*icon_dy>=0 then {{0, icon_offset}, {0,icon_offset+icon_dy}, {100,icon_offset+icon_dy}} elseif icon_offset>0 and icon_offset+icon_dy<0 or icon_offset<0 and icon_offset+icon_dy>0 then @@ -129,7 +130,7 @@ equation pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash, thickness=5), - Line( visible=nPorts>=3, + Line( visible=nPorts>=3 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, points=if icon_offset*icon_dy>=0 then {{0, icon_offset+icon_dy},{0, icon_offset+2*icon_dy},{100, icon_offset+2*icon_dy}} elseif icon_offset>0 and icon_offset+2*icon_dy<0 or icon_offset<0 and icon_offset+2*icon_dy>0 then @@ -139,7 +140,7 @@ equation pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash, thickness=5), - Line( visible=nPorts>=4, + Line( visible=nPorts>=4 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, points=if icon_offset*icon_dy>=0 then {{0, icon_offset+2*icon_dy},{0, icon_offset+3*icon_dy},{100, icon_offset+3*icon_dy}} elseif icon_offset>0 and icon_offset+3*icon_dy<0 or icon_offset<0 and icon_offset+3*icon_dy>0 then @@ -148,6 +149,26 @@ equation color={0,0,0}, pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply then LinePattern.Solid else LinePattern.Dash, + thickness=5), + Line( visible=nPorts>=5 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points=if icon_offset*icon_dy>=0 then + {{0, icon_offset+3*icon_dy},{0, icon_offset+4*icon_dy},{100, icon_offset+4*icon_dy}} + elseif icon_offset>0 and icon_offset+4*icon_dy<0 or icon_offset<0 and icon_offset+4*icon_dy>0 then + {{0, 0},{0, icon_offset+4*icon_dy},{100, icon_offset+4*icon_dy}} + else {{0, icon_offset+4*icon_dy},{100, icon_offset+4*icon_dy}}, + color={0,0,0}, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash, + thickness=5), + Line( visible=nPorts>=6 and icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None, + points=if icon_offset*icon_dy>=0 then + {{0, icon_offset+4*icon_dy},{0, icon_offset+5*icon_dy},{100, icon_offset+5*icon_dy}} + elseif icon_offset>0 and icon_offset+5*icon_dy<0 or icon_offset<0 and icon_offset+5*icon_dy>0 then + {{0, 0},{0, icon_offset+5*icon_dy},{100, icon_offset+5*icon_dy}} + else {{0, icon_offset+5*icon_dy},{100, icon_offset+5*icon_dy}}, + color={0,0,0}, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Supply + then LinePattern.Solid else LinePattern.Dash, thickness=5)}), Diagram( coordinateSystem(preserveAspectRatio=false)), diff --git a/Buildings/Templates/Components/Routing/package.order b/Buildings/Templates/Components/Routing/package.order index cb417ce6c69..3aed6c23d3f 100644 --- a/Buildings/Templates/Components/Routing/package.order +++ b/Buildings/Templates/Components/Routing/package.order @@ -1,3 +1,4 @@ +Junction MultipleToMultiple MultipleToSingle PassThroughFluid diff --git a/Buildings/Templates/Components/Types.mo b/Buildings/Templates/Components/Types.mo index a864929df7a..2d2b623cb63 100644 --- a/Buildings/Templates/Components/Types.mo +++ b/Buildings/Templates/Components/Types.mo @@ -1,6 +1,12 @@ within Buildings.Templates.Components; package Types "Package with type definitions" extends Modelica.Icons.TypesPackage; + type BoilerHotWaterModel = enumeration( + Polynomial + "Efficiency described by a polynomial", + Table + "Efficiency described by a table") + "Enumeration to specify the type of hot water boiler model"; type Chiller = enumeration( AirCooled "Air-cooled compression chiller", @@ -79,6 +85,17 @@ package Types "Package with type definitions" Supply "Supply pipe - Solid line") "Enumeration to specify the pipe symbol"; + type Pump = enumeration( + None + "No pump", + Single + "Single pump", + Multiple + "Multiple pumps in parallel") + "Enumeration to configure the pump"; + type PumpArrangement = enumeration( + Dedicated "Dedicated pumps", + Headered "Headered pumps") "Enumeration to specify the pump arrangement"; type Sensor = enumeration( DifferentialPressure "Differential pressure", diff --git a/Buildings/Templates/Components/Validation/BoilerHotWater.mo b/Buildings/Templates/Components/Validation/BoilerHotWater.mo new file mode 100644 index 00000000000..286a5076694 --- /dev/null +++ b/Buildings/Templates/Components/Validation/BoilerHotWater.mo @@ -0,0 +1,166 @@ +within Buildings.Templates.Components.Validation; +model BoilerHotWater "Test model for the hot water boiler model" + extends Buildings.Templates.Components.Validation.BoilerHotWaterRecord; + + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium"; + + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.FixedInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab="Dynamics", group="Conservation equations")); + + parameter Buildings.Templates.Components.Data.BoilerHotWater datBoiPol( + final typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial, + fue=Buildings.Fluid.Data.Fuels.NaturalGasLowerHeatingValue(), + mHeaWat_flow_nominal=datBoiTab.cap_nominal/15/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cap_nominal=1000E3, + dpHeaWat_nominal(displayUnit="Pa") = 5000, + THeaWatSup_nominal=333.15) + "Design and operating parameters for the boiler model using a polynomial" + annotation (Placement(transformation(extent={{60,20},{80,40}}))); + + Buildings.Templates.Components.Boilers.HotWaterTable boiTab( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final dat=datBoiTabRed, + is_con=false) + "Boiler model with efficiency described by a table" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Fluid.Sources.Boundary_pT retHeaWat( + redeclare final package Medium = Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_min + boiTab.dpHeaWat_nominal, + use_T_in=true, + T=datBoiTab.THeaWatSup_nominal - 15, + nPorts=2) "Boundary conditions for HW distribution system" + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + + Fluid.Sources.Boundary_pT supHeaWat(redeclare final package Medium =Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_min, + nPorts=2) + "Boundary conditions for HW distribution system" + annotation (Placement(transformation(extent={{90,-30},{70,-10}}))); + Fluid.Sensors.TemperatureTwoPort THeaWatSup(redeclare final package Medium = + Medium, final m_flow_nominal=datBoiTab.mHeaWat_flow_nominal) + "HW supply temperature" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp THeaWatRet( + y(final unit="K", displayUnit="degC"), + height=35, + duration=500, + offset=datBoiTab.THeaWatSup_nominal - 25, + startTime=100) "HW return temperature value" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Boi( + table=[0,1; 1,1], + timeScale=3600, + period=3600) "Boiler Enable signal" + annotation (Placement(transformation(extent={{-80,70},{-60,90}}))); + Buildings.Templates.HeatingPlants.HotWater.Interfaces.Bus bus + "Boiler control bus" + annotation ( + Placement(transformation(extent={{-20,20},{20,60}}), iconTransformation( + extent={{-296,-74},{-256,-34}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet( + k=Buildings.Templates.Data.Defaults.THeaWatSup, + y(final unit="K", displayUnit="degC")) + "HW supply temperature setpoint" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Boilers.HotWaterPolynomial boiPol( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final dat=datBoiPol, + is_con=false) + "Boiler model with efficiency described by a polynomial" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); + Fluid.Sensors.TemperatureTwoPort THeaWatSup1( + redeclare final package Medium =Medium, + final m_flow_nominal=datBoiTab.mHeaWat_flow_nominal) + "HW supply temperature" + annotation (Placement(transformation(extent={{30,-90},{50,-70}}))); + HeatingPlants.HotWater.Interfaces.Bus bus1 + "Boiler control bus" + annotation ( + Placement(transformation(extent={{-20,-60},{20,-20}}), + iconTransformation(extent={{-296,-74},{-256,-34}}))); +equation + connect(retHeaWat.ports[1], boiTab.port_a) annotation (Line(points={{-20,-21}, + {-20,0},{-10,0}}, color={0,127,255})); + connect(boiTab.port_b, THeaWatSup.port_a) + annotation (Line(points={{10,0},{30,0}}, color={0,127,255})); + connect(THeaWatSup.port_b, supHeaWat.ports[1]) + annotation (Line(points={{50,0},{60,0},{60,-21},{70,-21}}, + color={0,127,255})); + connect(THeaWatRet.y, retHeaWat.T_in) annotation (Line(points={{-58,0},{-50,0}, + {-50,-16},{-42,-16}}, + color={0,0,127})); + connect(boiTab.bus, bus) annotation (Line( + points={{0,10},{0,10},{0,40}}, + color={255,204,51}, + thickness=0.5), Text( + string="%second", + index=1, + extent={{6,3},{6,3}}, + horizontalAlignment=TextAlignment.Left)); + connect(y1Boi.y[1], bus.y1) annotation (Line(points={{-58,80},{0,80},{0,40}}, + color={255,0,255}), Text( + string="%second", + index=1, + extent={{6,3},{6,3}}, + horizontalAlignment=TextAlignment.Left)); + connect(THeaWatSupSet.y, bus.THeaWatSupSet) + annotation (Line(points={{-58,40},{0,40}}, color={0,0,127})); + connect(retHeaWat.ports[2], boiPol.port_a) + annotation (Line(points={{-20,-19},{-20,-80},{-10,-80}}, + color={0,127,255})); + connect(THeaWatSup1.port_b, supHeaWat.ports[2]) annotation (Line(points={{50,-80}, + {60,-80},{60,-19},{70,-19}}, + color={0,127,255})); + connect(boiPol.port_b, THeaWatSup1.port_a) + annotation (Line(points={{10,-80},{30,-80}}, color={0,127,255})); + connect(bus1, boiPol.bus) annotation (Line( + points={{0,-40},{0,-70}}, + color={255,204,51}, + thickness=0.5)); + connect(THeaWatSupSet.y, bus1.THeaWatSupSet) annotation (Line(points={{-58,40}, + {-50,40},{-50,-38},{0,-38},{0,-40}}, + color={0,0,127})); + connect(y1Boi.y[1], bus1.y1) annotation (Line(points={{-58,80},{-52,80},{-52,-40}, + {0,-40}}, color={255,0,255})); + annotation ( + experiment( + StopTime=2000, + Tolerance=1e-06), + __Dymola_Commands(file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWater.mos" + "Simulate and plot"), + Documentation(info=" +

+This model validates the parameter propagation within the record class + +Buildings.Templates.ChilledWaterPlants.Components.Data.ChillerGroup. +It illustrates +

+ +")); +end BoilerHotWater; diff --git a/Buildings/Templates/Components/Validation/BoilerHotWaterRecord.mo b/Buildings/Templates/Components/Validation/BoilerHotWaterRecord.mo new file mode 100644 index 00000000000..7fb658b6c6f --- /dev/null +++ b/Buildings/Templates/Components/Validation/BoilerHotWaterRecord.mo @@ -0,0 +1,75 @@ +within Buildings.Templates.Components.Validation; +model BoilerHotWaterRecord + "Test model for parameter propagation with the hot water boiler record" + extends Modelica.Icons.Example; + + parameter Buildings.Fluid.Boilers.Data.Lochinvar.KnightXL.KBXdash0500 per; + + parameter Buildings.Templates.Components.Data.BoilerHotWater datBoiTab( + final typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Table, + fue=Buildings.Fluid.Data.Fuels.NaturalGasLowerHeatingValue(), + per=per, + mHeaWat_flow_nominal=datBoiTab.cap_nominal/15/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cap_nominal=1000E3, + dpHeaWat_nominal(displayUnit="Pa") = 5000, + THeaWatSup_nominal=333.15) + "Design and operating parameters for the boiler model using a lookup table" + annotation (Placement(transformation(extent={{60,80},{80,100}}))); + + parameter Buildings.Templates.Components.Data.BoilerHotWater datBoiTabRed( + final typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Table, + fue=Buildings.Fluid.Data.Fuels.NaturalGasLowerHeatingValue(), + redeclare Buildings.Fluid.Boilers.Data.Lochinvar.KnightXL.KBXdash0500 per, + mHeaWat_flow_nominal=datBoiTab.cap_nominal/15/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cap_nominal=1000E3, + dpHeaWat_nominal(displayUnit="Pa") = 5000, + THeaWatSup_nominal=333.15) + "Design and operating parameters for the boiler model using a lookup table with redeclaration" + annotation (Placement(transformation(extent={{60,50},{80,70}}))); + + parameter Buildings.Templates.Components.Data.BoilerHotWater datBoiTabLoc( + final typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Table, + fue=Buildings.Fluid.Data.Fuels.NaturalGasLowerHeatingValue(), + per(effCur=per.effCur), + mHeaWat_flow_nominal=datBoiTab.cap_nominal/15/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cap_nominal=1000E3, + dpHeaWat_nominal(displayUnit="Pa") = 5000, + THeaWatSup_nominal=333.15) + "Design and operating parameters for the boiler model using a local assignment of the efficiency curve " + annotation (Placement(transformation(extent={{60,50},{80,70}}))); + + annotation ( + experiment( + StopTime=1, + Tolerance=1e-06), + __Dymola_Commands(file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/BoilerHotWaterRecord.mos" + "Simulate and plot"), + Documentation(info=" +

+This model validates the parameter propagation within the record class + +Buildings.Templates.Components.Data.BoilerHotWater. +It illustrates +

+ +")); +end BoilerHotWaterRecord; diff --git a/Buildings/Templates/Components/Validation/PumpMultipleRecord.mo b/Buildings/Templates/Components/Validation/PumpMultipleRecord.mo new file mode 100644 index 00000000000..5dbde7e7315 --- /dev/null +++ b/Buildings/Templates/Components/Validation/PumpMultipleRecord.mo @@ -0,0 +1,96 @@ +within Buildings.Templates.Components.Validation; +model PumpMultipleRecord "Test model for parameter propagation with the multiple-pump record" + extends Modelica.Icons.Example; + + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Fluid medium"; + + parameter Integer nPum( + final min=0, + start=1)=2 + "Number of pumps" + annotation (Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_nominal[nPum]( + each start=1, + each final min=0)={1, 2} + "Mass flow rate - Each pump"; + final parameter Modelica.Units.SI.VolumeFlowRate V_flow_nominal[nPum]= + m_flow_nominal ./ datDef.rho_default + "Mass flow rate - Each pump"; + parameter Modelica.Units.SI.PressureDifference dp_nominal[nPum]( + each start=0, + each final min=0)={1, 2} .* 1E4 + "Total pressure rise - Each pump"; + + parameter Buildings.Templates.Components.Data.PumpMultiple datDef( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal) + "Parameter record - Default bindings for subrecord per" + annotation (Placement(transformation(extent={{100,60},{120,80}}))); + + parameter Buildings.Templates.Components.Data.PumpMultiple datRed( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal, + redeclare Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos80slash1to12 per) + "Parameter record - Redeclaration of subrecord per" + annotation (Placement(transformation(extent={{100,30},{120,50}}))); + + parameter Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos80slash1to12 per1; + parameter Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos50slash1to12 per2; + + parameter Buildings.Templates.Components.Data.PumpMultiple datAss( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal, + per={per1, per2}) + "Parameter record - Assignment of subrecord per" + annotation (Placement(transformation(extent={{100,0},{120,20}}))); + + parameter Buildings.Templates.Components.Data.PumpMultiple datPre( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal, + per(pressure( + V_flow={{0, 2, 4} * m_flow_nominal[i] / datPre.rho_default for i in 1:nPum}, + dp={{2, 1.5, 0.8} * dp_nominal[i] for i in 1:nPum}))) + "Parameter record - Assignment of pressure inside the subrecord per" + annotation (Placement(transformation(extent={{100,0},{120,20}}))); + + annotation ( + experiment( + StopTime=1, + Tolerance=1e-06), + __Dymola_Commands(file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/PumpMultipleRecord.mos" + "Simulate and plot"), + Documentation(info=" +

+This model validates the parameter propagation within the record class + +Buildings.Templates.Components.Data.PumpMultiple. +

+

+The instance datDef illustrates the default pressure curve +assignment based on the design parameters. +

+

+The instance datRed illustrates the modification of the +pressure curve by redeclaring the subrecord per. +In this case, all elements per[i] are equal. +

+

+The instances datAss and datPre illustrate +the modification of the pressure curve by assigning either the whole +subrecord per or its component per.pressure. +This allows assigning different pressure curves to the elements per[i]. +

+")); +end PumpMultipleRecord; diff --git a/Buildings/Templates/Components/Validation/package.order b/Buildings/Templates/Components/Validation/package.order index 07f6cebf6fd..3a20fc561eb 100644 --- a/Buildings/Templates/Components/Validation/package.order +++ b/Buildings/Templates/Components/Validation/package.order @@ -1,6 +1,9 @@ +BoilerHotWater +BoilerHotWaterRecord Coils Dampers Fans +PumpMultipleRecord Routing Sensors Valves diff --git a/Buildings/Templates/Components/package.order b/Buildings/Templates/Components/package.order index fc2da254c48..7c0a9662619 100644 --- a/Buildings/Templates/Components/package.order +++ b/Buildings/Templates/Components/package.order @@ -1,6 +1,8 @@ +Boilers Coils Dampers Fans +Pumps Routing Sensors Valves diff --git a/Buildings/Templates/Data/Defaults.mo b/Buildings/Templates/Data/Defaults.mo new file mode 100644 index 00000000000..7d2463f1687 --- /dev/null +++ b/Buildings/Templates/Data/Defaults.mo @@ -0,0 +1,121 @@ +within Buildings.Templates.Data; +package Defaults "Package with default sizing parameters" + extends Modelica.Icons.MaterialPropertiesPackage; + + constant Modelica.Units.SI.Temperature TChiWatSup=7+273.15 + "CHW supply temperature"; + constant Modelica.Units.SI.Temperature TChiWatSup_max=16+273.15 + "Maximum CHW supply temperature (typical)"; + constant Modelica.Units.SI.Temperature TChiWatRet=12+273.15 + "CHW return temperature"; + constant Modelica.Units.SI.Temperature TConWatSup=29.4+273.15 + "CW supply temperature"; + constant Modelica.Units.SI.Temperature TConWatRet=35+273.15 + "CW return temperature"; + constant Modelica.Units.SI.Temperature TConAirEnt=35+273.15 + "Condenser entering air temperature for air-cooled chillers"; + constant Modelica.Units.SI.Temperature TConEnt_min=13+273.15 + "Minimum condenser entering fluid temperature (air or water)"; + constant Modelica.Units.SI.Temperature TConEnt_max=45+273.15 + "Maximum condenser entering fluid temperature (air or water)"; + constant Modelica.Units.SI.Temperature TChiWatEcoEnt=18+273.15 + "WSE entering CHW temperature"; + constant Modelica.Units.SI.Temperature TChiWatEcoLvg=11+273.15 + "WSE leaving CHW temperature"; + constant Modelica.Units.SI.Temperature TConWatEcoEnt=9+273.15 + "WSE entering CW temperature"; + constant Modelica.Units.SI.Temperature TConWatEcoLvg=16+273.15 + "WSE leaving CW temperature"; + constant Modelica.Units.SI.Temperature TOutChiLoc=16+273.15 + "Outdoor air lockout temperature below which the CHW plant is prevented from operating"; + constant Modelica.Units.SI.TemperatureDifference dTLifChi_min=5 + "Minimum chiller lift at minimum load"; + constant Modelica.Units.SI.Temperature TAirDryCooEnt=TConAirEnt + "Dry cooler entering air drybulb temperature"; + constant Modelica.Units.SI.Temperature TWetBulTowEnt=23.9+273.15 + "CT entering air wetbulb temperature"; + constant Real PFanByFloConWatTow(unit="W/(kg/s)")=340 + "CT fan power divided by CW mass flow rate"; + constant Real ratFloWatByAirTow(unit="1")=1.45 + "CT CW mass flow rate divided by air mass flow rate"; + constant Modelica.Units.SI.PressureDifference dpConWatFriTow=1E4 + "CW flow-friction losses through open-circuit tower and piping only (without elevation head or valve)"; + constant Modelica.Units.SI.PressureDifference dpConWatStaTow=3E4 + "CW elevation head (for open cooling towers only)"; + constant Modelica.Units.SI.PressureDifference dpConWatTowClo=5E4 + "CW flow-friction losses through closed-circuit tower and piping only (without valve)"; + constant Real mConAirByCapChi(unit="(kg/s)/W")=1E-4 + "Air mass flow rate at condenser divided by chiller capacity"; + constant Real COPChiAirCoo(unit="1")=3.0 + "Air-cooled chiller COP"; + constant Real COPChiWatCoo(unit="1")=5.0 + "Water-cooled chiller COP"; + constant Modelica.Units.SI.PressureDifference dpValIso=1E3 + "Isolation or bypass valve pressure drop"; + constant Modelica.Units.SI.PressureDifference dpValBypMin=5E3 + "Minimum flow bypass valve "; + constant Modelica.Units.SI.PressureDifference dpValChe=1E4 + "Check valve pressure drop"; + constant Modelica.Units.SI.PressureDifference dpChiWatChi=5E4 + "Chiller CHW pressure drop"; + constant Modelica.Units.SI.PressureDifference dpChiWatSet_min=3.5E4 + "Minimum CHW differential pressure setpoint used in CHW plant reset logic"; + constant Modelica.Units.SI.PressureDifference dpChiWatSet_max=5E4 + "Maximum CHW differential pressure setpoint remote from the CHW plant"; + constant Modelica.Units.SI.PressureDifference dpChiWatLocSet_max=15E4 + "Maximum CHW differential pressure setpoint local to the CHW plant"; + constant Modelica.Units.SI.PressureDifference dpConWatChi=5E4 + "Chiller CW pressure drop (water-cooled)"; + constant Modelica.Units.SI.PressureDifference dpConAirChi=2000 + "Chiller air pressure drop through condenser (air-cooled)"; + constant Modelica.Units.SI.PressureDifference dpChiWatEco=3E4 + "WSE CHW pressure drop"; + constant Modelica.Units.SI.PressureDifference dpConWatEco=3E4 + "WSE CW pressure drop"; + constant Modelica.Units.SI.PressureDifference pChiWat_rel_min=1.0E5 + "CHW circuit minimum pressure"; + constant Modelica.Units.SI.PressureDifference pHeaWat_rel_min=1.5E5 + "HHW circuit minimum pressure"; + constant Modelica.Units.SI.PressureDifference dpHeaWatBoi=5E3 + "Boiler HW pressure drop"; + constant Modelica.Units.SI.Temperature THeaWatSup=80+273.15 + "HW supply temperature"; + constant Modelica.Units.SI.Temperature THeaWatConSup=65+273.15 + "HW supply temperature for condensing boilers"; + constant Modelica.Units.SI.Temperature THeaWatRet=55+273.15 + "HW return temperature"; + constant Modelica.Units.SI.Temperature TOutBoiLck=24+273.15 + "Outdoor air lockout temperature above which the HW plant is prevented from operating"; + constant Modelica.Units.SI.PressureDifference dpHeaWatSet_min=3.5E4 + "Minimum HW differential pressure setpoint used in HW plant reset logic"; + constant Modelica.Units.SI.PressureDifference dpHeaWatSet_max=5E4 + "Maximum HW differential pressure setpoint remote from the HW plant"; + constant Modelica.Units.SI.PressureDifference dpHeaWatLocSet_max=15E4 + "Maximum HW differential pressure setpoint local to the CHW plant"; + annotation (Documentation(info=" +

+This package defines some constants that are either +

+ +", revisions=" + +")); +end Defaults; diff --git a/Buildings/Templates/Data/package.order b/Buildings/Templates/Data/package.order index 3831742ec60..4cd15e62047 100644 --- a/Buildings/Templates/Data/package.order +++ b/Buildings/Templates/Data/package.order @@ -1 +1,2 @@ AllSystems +Defaults diff --git a/Buildings/Templates/HeatingPlants/HotWater/BoilerPlant.mo b/Buildings/Templates/HeatingPlants/HotWater/BoilerPlant.mo new file mode 100644 index 00000000000..c6238f5ebfb --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/BoilerPlant.mo @@ -0,0 +1,895 @@ +within Buildings.Templates.HeatingPlants.HotWater; +model BoilerPlant "Boiler plant" + extends + Buildings.Templates.HeatingPlants.HotWater.Interfaces.PartialBoilerPlant( + final typCtl=ctl.typ, + final nAirHan=ctl.nAirHan, + final nEquZon=ctl.nEquZon, + dat( + have_senDpHeaWatLoc=ctl.have_senDpHeaWatLoc, + nSenDpHeaWatRem=ctl.nSenDpHeaWatRem, + have_senVHeaWatSec=ctl.have_senVHeaWatSec)); + + Buildings.Templates.HeatingPlants.HotWater.Components.BoilerGroup boiCon( + redeclare final package Medium = Medium, + final typMod=typMod, + final nBoi=nBoiCon, + final is_con=true, + final typArrPumHeaWatPri=typArrPumHeaWatPriCon, + final dat=dat.boiCon, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal) + if have_boiCon + "Condensing boilers" + annotation (Placement(transformation(extent={{-220,-260},{-140,-120}}))); + + Buildings.Templates.HeatingPlants.HotWater.Components.BoilerGroup boiNon( + redeclare final package Medium=Medium, + final typMod=typMod, + final nBoi=nBoiNon, + final is_con=false, + final typArrPumHeaWatPri=typArrPumHeaWatPriNon, + final dat=dat.boiNon, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal) + if have_boiNon + "Non-condensing boilers" + annotation (Placement(transformation(extent={{-220,-120},{-140,20}}))); + + // Primary HW loop - Condensing boilers + Buildings.Templates.Components.Routing.SingleToMultiple inlBoiCon( + redeclare final package Medium = Medium, + final nPorts=nBoiCon, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_offset=900, + icon_dy=-300, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) if have_boiCon + "Condensing boiler inlet manifold" + annotation (Placement(transformation(extent={{-120,-250},{-140,-230}}))); + Buildings.Templates.Components.Routing.MultipleToMultiple inlPumHeaWatPriCon( + redeclare final package Medium = Medium, + final nPorts_b=nPumHeaWatPriCon, + final have_comLeg= + typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered, + final nPorts_a=nBoiCon, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_xinl=-400, + icon_dy=-300) if have_boiCon + "Primary HW pumps inlet manifold" + annotation (Placement(transformation(extent={{-110,-150},{-90,-130}}))); + Buildings.Templates.Components.Pumps.Multiple pumHeaWatPriCon( + redeclare final package Medium = Medium, + final nPum=nPumHeaWatPriCon, + final have_var=have_varPumHeaWatPriCon, + final have_varCom=true, + final dat=dat.pumHeaWatPriCon, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + icon_dy=-300) if have_boiCon + "Primary HW pumps - Condensing boilers" + annotation (Placement(transformation(extent={{-90,-150},{-70,-130}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumHeaWatPriCon( + redeclare final package Medium = Medium, + final nPorts=nPumHeaWatPriCon, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_dy=-300) if have_boiCon + "Primary HW pumps outlet manifold" + annotation (Placement(transformation(extent={{-70,-150},{-50,-130}}))); + Buildings.Templates.Components.Valves.TwoWayModulating valHeaWatMinBypCon( + redeclare final package Medium = Medium, + final dat=dat.valHeaWatMinBypCon, + final allowFlowReversal=allowFlowReversal) if have_valHeaWatMinBypCon + "HW minimum flow bypass valve - Condensing boilers" + annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={60,-190}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatPriSupCon_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatPriCon and ctl.locSenVHeaWatPri == + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Supply, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_boiCon + "Primary HW volume flow rate - Condensing boilers" + annotation (Placement(transformation(extent={{-40,-150},{-20,-130}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatPriRetCon_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatPriCon and ctl.locSenVHeaWatPri == + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return, + final text_flip=true, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) + if have_boiCon + "Primary HW volume flow rate - Condensing boilers" + annotation (Placement(transformation(extent={{-20,-250},{-40,-230}}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatPriSupCon( + redeclare final package Medium = Medium, + final have_sen=ctl.have_senTHeaWatPriSupCon, + final text_flip=false, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_boiCon + "Primary HW supply temperature - Condensing boilers" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={10,-140}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatPlaRetCon( + redeclare final package Medium = Medium, + final have_sen=ctl.have_senTHeaWatPlaRetCon, + final text_flip=true, + final m_flow_nominal=mHeaWatPriCon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) + if have_boiCon + "Plant HW return temperature - Condensing boilers" + annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={10,-240}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatBypCon_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=true, + final have_sen=have_varPumHeaWatPriCon + and typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + and ctl.typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDecoupler, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.Supply) + if have_bypHeaWatFixCon + "Decoupler HW volume flow rate / Fixed HW bypass - Condensing boilers" + annotation (Placement( + transformation( + extent={{10,10},{-10,-10}}, + rotation=90, + origin={60,-170}))); + Buildings.Templates.Components.Routing.Junction junInlBoiCon( + redeclare final package Medium = Medium, + final tau=tau, + final m_flow_nominal=mHeaWat_flow_nominal*{1,-1,1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(1E3, 3), + final portFlowDirection_1=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=Modelica.Fluid.Types.PortFlowDirection.Bidirectional, + icon_pipe1=Buildings.Templates.Components.Types.IconPipe.Return, + icon_pipe2=if have_boiCon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.None, + icon_pipe3=if have_bypHeaWatFixCon or have_valHeaWatMinBypCon then + (if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.Supply) else + Buildings.Templates.Components.Types.IconPipe.None) + "Fluid junction" + annotation (Placement(transformation( + extent={{10,10},{-10,-10}}, + rotation=0, + origin={60,-240}))); + Buildings.Templates.Components.Routing.Junction junOutBoiCon( + redeclare final package Medium = Medium, + final tau=tau, + final m_flow_nominal=mHeaWat_flow_nominal*{-1,-1,1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(0, 3), + final portFlowDirection_1=Modelica.Fluid.Types.PortFlowDirection.Bidirectional, + final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + icon_pipe1=if have_bypHeaWatFixCon or have_valHeaWatMinBypCon then + (if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.Supply) else + Buildings.Templates.Components.Types.IconPipe.None, + icon_pipe2=if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.Supply, + icon_pipe3=if have_boiCon then Buildings.Templates.Components.Types.IconPipe.Supply + else Buildings.Templates.Components.Types.IconPipe.None) + "Fluid junction" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=-90, + origin={60,-140}))); + + Buildings.Templates.Components.Sensors.Temperature THeaWatIntSup( + redeclare final package Medium = Medium, + final have_sen=typ == Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.Supply) + "Intermediate HW supply temperature" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={60,-120}))); + + // Primary HW loop - Non-condensing boilers + Buildings.Templates.Components.Routing.SingleToMultiple inlBoiNon( + redeclare final package Medium = Medium, + final nPorts=nBoiNon, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_offset=900, + icon_dy=-300, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) if have_boiNon + "Non-condensing boiler inlet manifold" + annotation (Placement(transformation(extent={{-120,-110},{-140,-90}}))); + Buildings.Templates.Components.Routing.MultipleToMultiple inlPumHeaWatPriNon( + redeclare final package Medium = Medium, + final nPorts_b=nPumHeaWatPriNon, + final have_comLeg= + typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Headered, + final nPorts_a=nBoiNon, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_xinl=-400, + icon_dy=-300) if have_boiNon + "Primary HW pumps inlet manifold" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Buildings.Templates.Components.Pumps.Multiple pumHeaWatPriNon( + redeclare final package Medium = Medium, + final nPum=nPumHeaWatPriNon, + final have_var=have_varPumHeaWatPriNon, + final have_varCom=true, + final dat=dat.pumHeaWatPriNon, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + icon_dy=-300) if have_boiNon + "Primary HW pumps - Non-condensing boilers" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumHeaWatPriNon( + redeclare final package Medium = Medium, + final nPorts=nPumHeaWatPriNon, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_dy=-300) if have_boiNon + "Primary HW pumps outlet manifold" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + Buildings.Templates.Components.Valves.TwoWayModulating valHeaWatMinBypNon( + redeclare final package Medium = Medium, + final dat=dat.valHeaWatMinBypNon, + final allowFlowReversal=allowFlowReversal) if have_valHeaWatMinBypNon + "HW minimum flow bypass valve - Non-condensing boilers" + annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=90, + origin={60,-50}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatPriSupNon_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatPriNon and ctl.locSenVHeaWatPri == + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Supply, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_boiNon + "Primary HW volume flow rate - Non-condensing boilers" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatPriRetNon_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatPriNon and ctl.locSenVHeaWatPri == + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return, + final text_flip=true, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) + if have_boiNon + "Primary HW volume flow rate - Non-condensing boilers" + annotation (Placement(transformation(extent={{-20,-110},{-40,-90}}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatPriSupNon( + redeclare final package Medium = Medium, + final have_sen=ctl.have_senTHeaWatPriSupNon, + final text_flip=false, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_boiNon + "Primary HW supply temperature - Non-condensing boilers" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={10,0}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatPlaRetNon( + redeclare final package Medium = Medium, + final have_sen=ctl.have_senTHeaWatPlaRetNon, + final text_flip=true, + final m_flow_nominal=mHeaWatPriNon_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) + if have_boiNon + "Plant HW return temperature - Non-condensing boilers" + annotation (Placement( + transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={10,-100}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatBypNon_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=true, + final have_sen=have_varPumHeaWatPriNon + and typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + and ctl.typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDecoupler, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_bypHeaWatFixNon + "Decoupler HW volume flow rate / Fixed HW bypass - Non-condensing boilers" + annotation (Placement( + transformation( + extent={{10,10},{-10,-10}}, + rotation=90, + origin={60,-30}))); + Buildings.Templates.Components.Routing.Junction junInlBoiNon( + redeclare final package Medium=Medium, + final tau=tau, + final m_flow_nominal=mHeaWat_flow_nominal*{1,1,-1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(1E3, 3), + final portFlowDirection_1=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=Modelica.Fluid.Types.PortFlowDirection.Bidirectional, + final portFlowDirection_3=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + icon_pipe1=if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.Supply, + icon_pipe2=if have_bypHeaWatFixNon or have_valHeaWatMinBypNon then + Buildings.Templates.Components.Types.IconPipe.Supply else + Buildings.Templates.Components.Types.IconPipe.None, + icon_pipe3=if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Return + else Buildings.Templates.Components.Types.IconPipe.None) + "Fluid junction" + annotation ( + Placement( + transformation( + extent={{-10,10},{10,-10}}, + rotation=90, + origin={60,-100}))); + Buildings.Templates.Components.Routing.Junction junOutBoiNon( + redeclare final package Medium=Medium, + final tau=tau, + final m_flow_nominal=mHeaWat_flow_nominal*{1,-1,-1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(0, 3), + final portFlowDirection_1=if allowFlowReversal + then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=if allowFlowReversal + then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=if allowFlowReversal + then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + icon_pipe1=if have_boiNon then Buildings.Templates.Components.Types.IconPipe.Supply + else Buildings.Templates.Components.Types.IconPipe.None, + icon_pipe2=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_pipe3=if have_bypHeaWatFixNon or have_valHeaWatMinBypNon then + Buildings.Templates.Components.Types.IconPipe.Supply else + Buildings.Templates.Components.Types.IconPipe.None) + "Fluid junction" + annotation ( + Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={60,0}))); + + // Secondary HW loop + Buildings.Templates.Components.Routing.SingleToMultiple inlPumHeaWatSec( + redeclare final package Medium=Medium, + final nPorts=nPumHeaWatSec, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_dy=-300) + if have_pumHeaWatSec + "Secondary HW pumps inlet manifold" + annotation (Placement(transformation(extent={{100,-10},{120,10}}))); + Buildings.Templates.Components.Pumps.Multiple pumHeaWatSec( + redeclare final package Medium=Medium, + final nPum=nPumHeaWatSec, + final have_var=true, + final have_varCom=true, + final dat=dat.pumHeaWatSec, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + icon_dy=-300) + if have_pumHeaWatSec + "Secondary HW pumps" + annotation (Placement(transformation(extent={{120,-10},{140,10}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumHeaWatSec( + redeclare final package Medium=Medium, + final nPorts=nPumHeaWatSec, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics, + final tau=tau, + final allowFlowReversal=allowFlowReversal, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + icon_dy=-300) + if have_pumHeaWatSec + "Secondary HW pumps outlet manifold" + annotation (Placement(transformation(extent={{140,-10},{160,10}}))); + Buildings.Templates.Components.Routing.PassThroughFluid supHeaWat( + redeclare final package Medium=Medium, + final allowFlowReversal=allowFlowReversal) + if not have_pumHeaWatSec + "HW supply line - Without secondary HW pumps" + annotation (Placement(transformation(extent={{120,-10},{140,10}}))); + Buildings.Templates.Components.Sensors.DifferentialPressure dpHeaWatLoc( + redeclare final package Medium=Medium, + final have_sen=ctl.have_senDpHeaWatLoc, + final allowFlowReversal=allowFlowReversal, + final text_rotation=90) + "Local HW differential pressure sensor" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={260,-120}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatSecSup_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatSec and ctl.locSenVHeaWatSec == + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Supply, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + "Secondary HW volume flow rate" + annotation (Placement(transformation(extent={{180,-10},{200,10}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatSecRet_flow( + redeclare final package Medium = Medium, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatSec and ctl.locSenVHeaWatSec == + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return, + final text_flip=true, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) + "Secondary HW volume flow rate" + annotation (Placement(transformation(extent={{240,-250},{220,-230}}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatSecRet( + redeclare final package Medium = Medium, + final have_sen=ctl.have_senTHeaWatSecRet, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return) + "Secondary HW return temperature" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=0, + origin={190,-240}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatSecSup( + redeclare final package Medium = Medium, + final have_sen=ctl.have_senTHeaWatSecSup, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + "Secondary HW supply temperature" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={228,0}))); + + // Controls + replaceable Buildings.Templates.HeatingPlants.HotWater.Components.Controls.Guideline36 ctl + constrainedby + Buildings.Templates.HeatingPlants.HotWater.Components.Interfaces.PartialController( + final dat=dat.ctl, + final have_boiCon=have_boiCon, + final have_boiNon=have_boiNon, + final nBoiCon=nBoiCon, + final nBoiNon=nBoiNon, + final typPumHeaWatPriCon=typPumHeaWatPriCon, + final typPumHeaWatPriNon=typPumHeaWatPriNon, + final typPumHeaWatSec=typPumHeaWatSec, + final nPumHeaWatPriCon=nPumHeaWatPriCon, + final nPumHeaWatPriNon=nPumHeaWatPriNon, + final typArrPumHeaWatPriCon=typArrPumHeaWatPriCon, + final typArrPumHeaWatPriNon=typArrPumHeaWatPriNon, + final nPumHeaWatSec=nPumHeaWatSec, + final have_valHeaWatMinBypCon=have_valHeaWatMinBypCon, + final have_valHeaWatMinBypNon=have_valHeaWatMinBypNon) + "Plant controller" + annotation ( + Dialog(group="Controls"), + Placement(transformation(extent={{-10,130},{10,150}}))); + +equation + /* Control point connection - start */ + + connect(bus, boiCon.bus); + connect(bus, boiNon.bus); + connect(bus.pumHeaWatPriCon, pumHeaWatPriCon.bus); + connect(bus.pumHeaWatPriNon, pumHeaWatPriNon.bus); + connect(bus.valHeaWatMinByp, valHeaWatMinBypCon.bus); + connect(bus.valHeaWatMinByp, valHeaWatMinBypNon.bus); + connect(bus.pumHeaWatSec, pumHeaWatSec.bus); + connect(dpHeaWatLoc.y, bus.dpHeaWatLoc); + connect(VHeaWatPriSupCon_flow.y, bus.VHeaWatPriCon_flow); + connect(VHeaWatPriRetCon_flow.y, bus.VHeaWatPriCon_flow); + connect(VHeaWatPriSupNon_flow.y, bus.VHeaWatPriNon_flow); + connect(VHeaWatPriRetNon_flow.y, bus.VHeaWatPriNon_flow); + connect(VHeaWatSecSup_flow.y, bus.VHeaWatSec_flow); + connect(VHeaWatSecRet_flow.y, bus.VHeaWatSec_flow); + connect(VHeaWatBypCon_flow.y, bus.VHeaWatBypCon_flow); + connect(VHeaWatBypNon_flow.y, bus.VHeaWatBypNon_flow); + connect(THeaWatPriSupCon.y, bus.THeaWatPriSupCon); + connect(THeaWatPlaRetCon.y, bus.THeaWatPlaRetCon); + connect(THeaWatPriSupNon.y, bus.THeaWatPriSupNon); + connect(THeaWatPlaRetNon.y, bus.THeaWatPlaRetNon); + connect(THeaWatSecSup.y, bus.THeaWatSecSup); + connect(THeaWatSecRet.y, bus.THeaWatSecRet); + connect(THeaWatIntSup.y, bus.THeaWatIntSup); + + /* Control point connection - stop */ + + connect(dpHeaWatLoc.port_b, port_a) + annotation (Line( + points={{260,-130},{260,-240},{300,-240}}, + color={0,0,0}, + visible=ctl.have_senDpHeaWatLoc)); + connect(pumHeaWatPriNon.ports_b, outPumHeaWatPriNon.ports_a) + annotation (Line( + points={{-70,0},{-70,0}}, color={0,127,255})); + connect(port_a, VHeaWatSecRet_flow.port_a) + annotation (Line(points={{300,-240},{240,-240}}, color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(VHeaWatSecRet_flow.port_b, THeaWatSecRet.port_a) + annotation (Line(points={{220,-240},{200,-240}}, color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(port_b, dpHeaWatLoc.port_a) + annotation (Line( + points={{300,0},{260,0},{260,-110}}, + color={0,0,0}, + visible=ctl.have_senDpHeaWatLoc)); + connect(pumHeaWatPriCon.ports_b, outPumHeaWatPriCon.ports_a) + annotation (Line(points={{-70,-140},{-70,-140}}, color={0,127,255})); + connect(inlPumHeaWatPriCon.ports_b, pumHeaWatPriCon.ports_a) + annotation (Line(points={{-90,-140},{-90,-140}}, color={0,127,255})); + connect(boiCon.ports_bHeaWat, inlPumHeaWatPriCon.ports_a) + annotation (Line( + points={{-140,-140},{-110,-140}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiCon)); + connect(THeaWatIntSup.port_b, junInlBoiNon.port_1) + annotation (Line(points={{60,-110},{60,-110}}, color={0,127,255})); + connect(inlBoiNon.ports_b, boiNon.ports_aHeaWat) + annotation (Line(points={{-140,-100},{-140,-100}}, color={0,127,255})); + connect(inlBoiCon.ports_b, boiCon.ports_aHeaWat) + annotation (Line(points={{-140,-240},{-140,-240}}, color={0,127,255})); + connect(junOutBoiCon.port_2, THeaWatIntSup.port_a) + annotation (Line(points={{60,-130},{60,-130}}, color={0,127,255})); + connect(outPumHeaWatSec.port_b, VHeaWatSecSup_flow.port_a) + annotation (Line( + points={{160,0},{180,0}}, + color={0,0,0}, + thickness=0.5, + visible=have_pumHeaWatSec)); + connect(pumHeaWatSec.ports_a, inlPumHeaWatSec.ports_b) + annotation (Line(points={{120,0},{120,0}}, color={0,127,255})); + connect(pumHeaWatSec.ports_b, outPumHeaWatSec.ports_a) + annotation (Line(points={{140,0},{140,0}}, color={0,127,255})); + connect(VHeaWatPriSupCon_flow.port_b, THeaWatPriSupCon.port_a) + annotation (Line( + points={{-20,-140},{0,-140}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiCon)); + connect(inlPumHeaWatPriNon.ports_b, pumHeaWatPriNon.ports_a) + annotation (Line(points={{-90,0},{-90,0}}, color={0,127,255})); + connect(VHeaWatSecSup_flow.port_b, THeaWatSecSup.port_a) + annotation (Line(points={{200,0},{218,0}}, color={0,0,0}, + thickness=0.5)); + connect(THeaWatSecSup.port_b, port_b) + annotation (Line(points={{238,0},{300,0}}, color={0,0,0}, + thickness=0.5)); + connect(bus, ctl.bus) annotation (Line( + points={{-300,140},{-10,140}}, + color={255,204,51}, + thickness=0.5)); + connect(THeaWatPlaRetCon.port_b, VHeaWatPriRetCon_flow.port_a) + annotation (Line( + points={{0,-240},{-20,-240}}, + color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash, + visible=have_boiCon)); + connect(supHeaWat.port_b, VHeaWatSecSup_flow.port_a) + annotation (Line( + points={{140,0},{180,0}}, + color={0,0,0}, + thickness=0.5, + visible=not have_pumHeaWatSec)); + connect(busAirHan, ctl.busAirHan) annotation (Line( + points={{300,180},{280,180},{280,146},{10,146}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{6,3},{6,3}}, + horizontalAlignment=TextAlignment.Left)); + connect(busEquZon, ctl.busEquZon) annotation (Line( + points={{300,100},{280,100},{280,134},{10,134}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{6,3},{6,3}}, + horizontalAlignment=TextAlignment.Left)); + connect(VHeaWatPriRetCon_flow.port_b, inlBoiCon.port_a) + annotation (Line( + points={{-40,-240},{-120,-240}}, + color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash, + visible=have_boiCon)); + connect(junOutBoiCon.port_1, valHeaWatMinBypCon.port_a) + annotation (Line( + points={{60,-150},{60,-180}}, + color={0,0,0}, + visible=have_valHeaWatMinBypCon, + pattern=if have_boiNon then LinePattern.Dash else LinePattern.Solid, + thickness=0.5)); + connect(THeaWatSecRet.port_b, junInlBoiCon.port_1) annotation (Line(points={{180, + -240},{70,-240}}, color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(junOutBoiNon.port_2, inlPumHeaWatSec.port_a) + annotation (Line( + points={{70,0},{100,0}}, + color={0,0,0}, + thickness=0.5, + visible=have_pumHeaWatSec)); + connect(junOutBoiNon.port_2, supHeaWat.port_a) annotation (Line( + points={{70,0},{120,0}}, + color={0,0,0}, + thickness=0.5, + visible=not have_pumHeaWatSec)); + connect(THeaWatPriSupCon.port_b, junOutBoiCon.port_3) + annotation (Line( + points={{20,-140},{50,-140}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiCon)); + connect(outPumHeaWatPriCon.port_b, VHeaWatPriSupCon_flow.port_a) + annotation (Line( + points={{-50,-140},{-40,-140}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiCon)); + connect(junOutBoiCon.port_1, VHeaWatBypCon_flow.port_a) + annotation (Line( + points={{60,-150},{60,-160}}, + color={0,0,0}, + visible=have_bypHeaWatFixCon, + pattern=if have_boiNon then LinePattern.Dash else LinePattern.Solid, + thickness=0.5)); + connect(outPumHeaWatPriNon.port_b, VHeaWatPriSupNon_flow.port_a) annotation (Line( + points={{-50,0},{-40,0}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon)); + connect(VHeaWatPriSupNon_flow.port_b, THeaWatPriSupNon.port_a) + annotation (Line( + points={{-20,0},{0,0}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon)); + connect(junInlBoiNon.port_3, THeaWatPlaRetNon.port_a) + annotation (Line( + points={{50,-100},{20,-100}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon, + pattern=LinePattern.Dash)); + connect(THeaWatPlaRetNon.port_b, VHeaWatPriRetNon_flow.port_a) + annotation (Line( + points={{0,-100},{-20,-100}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon, + pattern=LinePattern.Dash)); + connect(VHeaWatPriRetNon_flow.port_b, inlBoiNon.port_a) + annotation (Line( + points={{-40,-100},{-120,-100}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon, + pattern=LinePattern.Dash)); + connect(VHeaWatBypNon_flow.port_b, junInlBoiNon.port_2) + annotation (Line( + points={{60,-40},{60,-90}}, + color={0,0,0}, + thickness=0.5, + visible=have_bypHeaWatFixNon)); + connect(valHeaWatMinBypNon.port_b, junInlBoiNon.port_2) + annotation (Line( + points={{60,-60},{60,-90}}, + color={0,0,0}, + thickness=0.5, + visible=have_valHeaWatMinBypNon)); + connect(junInlBoiCon.port_2, THeaWatPlaRetCon.port_a) + annotation (Line( + points={{50,-240},{20,-240}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=0.5, + visible=have_boiCon)); + connect(junInlBoiCon.port_3, valHeaWatMinBypCon.port_b) + annotation (Line( + points={{60,-230},{60,-200}}, + color={0,0,0}, + visible=have_valHeaWatMinBypCon, + pattern=if have_boiNon then LinePattern.Dash else LinePattern.Solid, + thickness=0.5)); + connect(junInlBoiCon.port_3, VHeaWatBypCon_flow.port_b) annotation (Line( + points={{60,-230},{60,-180}}, + color={0,0,0}, + visible=have_bypHeaWatFixCon, + pattern=if have_boiNon then LinePattern.Dash else LinePattern.Solid, + thickness=0.5)); + connect(valHeaWatMinBypNon.port_a, junOutBoiNon.port_3) + annotation (Line( + points={{60,-40},{60,-10}}, + color={0,0,0}, + thickness=0.5, + visible=have_valHeaWatMinBypNon)); + connect(VHeaWatBypNon_flow.port_a, junOutBoiNon.port_3) annotation (Line( + points={{60,-20},{60,-10}}, + color={0,0,0}, + thickness=0.5, + visible=have_bypHeaWatFixNon)); + connect(THeaWatPriSupNon.port_b, junOutBoiNon.port_1) + annotation (Line( + points={{20,0},{50,0}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon)); + connect(boiNon.ports_bHeaWat, inlPumHeaWatPriNon.ports_a) + annotation (Line( + points={{-140,0},{-110,0}}, + color={0,0,0}, + thickness=0.5, + visible=have_boiNon)); + annotation ( + Documentation(info=" +

+This template represents a hot water plant with boilers. +

+

+The possible equipment configurations are enumerated in the table below. +If any default is provided, it is displayed in bold characters. +The user may refer to ASHRAE (2021) for further details. +

+ + + + + + + + + + + + + + + + + + + + + + +
Configuration parameterOptionsNotes
Type of boiler +Condensing
+Non-condensing
+Hybrid (both condensing and non-condensing boilers) +
Type of primary HW pumps +Constant speed
+Variable speed
+Constant speed, provided with boiler with factory controls
+Variable speed, provided with boiler with factory controls +
+In case of hybrid plants, the type of primary HW pumps is specified +separately for the condensing boiler group and the non-condensing boiler group. +
Type of primary HW pump arrangement +Headered
+Dedicated +
+If the primary HW pumps are provided with the boilers, they are necessarily +configured in a dedicated arrangement and this option is not available. +
Type of secondary HW pumps +None (primary-only)
+Variable speed, centralized +
+Constant speed secondary pumps are not supported as they are generally not +advisable on any boiler system (see section 5.21.7.11 in ASHRAE, 2021 for +further explanations).
+In case of hybrid plants, the primary-only option is not available.
+Centralized secondary pumps refers to configurations with a single group +of secondary pumps that is typically integrated into the plant.
+Distributed secondary pumps with multiple secondary +loops served by dedicated secondary pumps are currently not supported. +This limitation stems from the Guideline 36 controller implementation in + +Buildings.Controls.OBC.ASHRAE.PrimarySystem.BoilerPlant.Controller. +
Controller +ASHRAE Guideline 36 controller +An open loop controller is also available for validation purposes only.
+

Control points

+

+Some input control points are required in addition to the ones already connected +inside this model, see the documentation of + +Buildings.Templates.HeatingPlants.HotWater.Components.Controls.Guideline36. +

+

References

+ +", revisions=" + +"), Diagram(graphics={Rectangle( + extent={{260,-240},{261,0}}, + lineColor={0,0,0}, + visible=ctl.have_senDpHeaWatLoc)})); +end BoilerPlant; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/BoilerGroup.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/BoilerGroup.mo new file mode 100644 index 00000000000..0d26a909657 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/BoilerGroup.mo @@ -0,0 +1,496 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components; +model BoilerGroup "Boiler group" + replaceable package Medium = Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium"; + + parameter Integer nBoi(final min=0) + "Number of boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.Components.Types.BoilerHotWaterModel typMod + "Type of boiler model" + annotation (Evaluate=true); + parameter Boolean is_con + "Set to true for condensing boiler, false for non-condensing boiler" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPri + "Type of primary HW pump arrangement" + annotation (Evaluate=true, Dialog(group="Configuration")); + + final parameter Buildings.Templates.Components.Types.Valve typValBoiIso= + if typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated then + Buildings.Templates.Components.Types.Valve.None + else Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + "Type of boiler HW isolation valve"; + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Data.BoilerGroup dat( + final nBoi=nBoi, + final typMod=typMod) + "Parameter record for boiler group" + annotation (Placement(transformation(extent={{-180,160},{-160,180}}))); + final parameter Buildings.Templates.Components.Data.BoilerHotWater datBoi[nBoi]( + final typMod=fill(typMod, nBoi), + each final fue=dat.fue, + final mHeaWat_flow_nominal=mHeaWatBoi_flow_nominal, + final cap_nominal=capBoi_nominal, + final dpHeaWat_nominal=if typValBoiIso==Buildings.Templates.Components.Types.Valve.None then + dat.dpHeaWatBoi_nominal else fill(0, nBoi), + final THeaWatSup_nominal=dat.THeaWatBoiSup_nominal, + final per=dat.per) + "Parameter record of each boiler"; + final parameter Buildings.Templates.Components.Data.Valve datValBoiIso[nBoi]( + final typ=fill(typValBoiIso, nBoi), + final m_flow_nominal=mHeaWatBoi_flow_nominal, + dpValve_nominal=fill(Buildings.Templates.Data.Defaults.dpValIso, nBoi), + dpFixed_nominal=if typValBoiIso<>Buildings.Templates.Components.Types.Valve.None then + dat.dpHeaWatBoi_nominal else fill(0, nBoi)) + "Parallel boilers HW bypass valve parameters" + annotation (Dialog(enable=false)); + + final parameter Modelica.Units.SI.MassFlowRate mHeaWatBoi_flow_nominal[nBoi]= + dat.mHeaWatBoi_flow_nominal + "HW mass flow rate - Each boiler"; + final parameter Modelica.Units.SI.HeatFlowRate capBoi_nominal[nBoi]= + dat.capBoi_nominal + "Heating capacity - Each boiler"; + final parameter Modelica.Units.SI.PressureDifference dpHeaWatBoi_nominal[nBoi]= + dat.dpHeaWatBoi_nominal + "HW pressure drop - Each boiler"; + final parameter Modelica.Units.SI.Temperature THeaWatBoiSup_nominal[nBoi]= + dat.THeaWatBoiSup_nominal + "HW supply temperature - Each boiler"; + + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.DynamicFreeInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab = "Dynamics", group="Conservation equations")); + parameter Boolean allowFlowReversal=true + "= true to allow flow reversal, false restricts to design direction (port_a -> port_b)" + annotation (Dialog(tab="Assumptions"), Evaluate=true); + + Modelica.Fluid.Interfaces.FluidPorts_b ports_bHeaWat[nBoi]( + redeclare each final package Medium = Medium, + each m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0), + each h_outflow(start=Medium.h_default, nominal=Medium.h_default)) + "HW supply" + annotation (Placement(transformation(extent={{190,80},{210,160}}), + iconTransformation( + extent={{-10,-40},{10,40}}, + rotation=0, + origin={400,500}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aHeaWat[nBoi]( + redeclare each final package Medium = Medium, + each m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0), + each h_outflow(start=Medium.h_default, nominal=Medium.h_default)) + "HW return" + annotation (Placement(transformation(extent={{190,-140},{210,-60}}), + iconTransformation( + extent={{-10,-40},{10,40}}, + rotation=0, + origin={400,-500}))); + Buildings.Templates.HeatingPlants.HotWater.Interfaces.Bus bus + "Plant control bus" + annotation (Placement(transformation(extent={{-20,180},{20,220}}), + iconTransformation(extent={{-20,680},{20,720}}))); + + Buildings.Templates.Components.Boilers.HotWaterPolynomial boiPol[nBoi]( + redeclare each final package Medium = Medium, + each final is_con=is_con, + final dat=datBoi, + each final allowFlowReversal=allowFlowReversal, + each final energyDynamics=energyDynamics) + if typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial + "Boiler - Polynomial" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Templates.Components.Boilers.HotWaterPolynomial boiTab[nBoi]( + redeclare each final package Medium = Medium, + each final is_con=is_con, + final dat=datBoi, + each final allowFlowReversal=allowFlowReversal, + each final energyDynamics=energyDynamics) + if typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Table + "Boiler - Table" + annotation (Placement(transformation(extent={{-10,-60},{10,-40}}))); + + Buildings.Templates.Components.Valves.TwoWayTwoPosition valBoiIso[nBoi]( + redeclare each final package Medium=Medium, + final dat=datValBoiIso, + each final allowFlowReversal=allowFlowReversal) + if typValBoiIso==Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + "Boiler isolation valve" + annotation (Placement(transformation(extent={{150,110},{170,130}}))); + Buildings.Templates.Components.Routing.PassThroughFluid pas[nBoi]( + redeclare each final package Medium=Medium) + if typValBoiIso==Buildings.Templates.Components.Types.Valve.None + "No boiler isolation valve" + annotation (Placement(transformation(extent={{150,90},{170,110}}))); + +protected + Buildings.Templates.Components.Interfaces.Bus busBoiCon[nBoi] if is_con + "Boiler control bus - Condensing boilers" + annotation (Placement( + transformation(extent={{-60,140},{-20,180}}),iconTransformation(extent={ + {-350,6},{-310,46}}))); + Buildings.Templates.Components.Interfaces.Bus busBoiNon[nBoi] if not is_con + "Boiler control bus - Non-condensing boilers" + annotation (Placement( + transformation(extent={{-100,140},{-60,180}}), + iconTransformation(extent={{-350,6},{-310,46}}))); + Buildings.Templates.Components.Interfaces.Bus busValBoiNonIso[nBoi] + if not is_con "Boiler isolation valve control bus - Non-condensing boilers" + annotation (Placement(transformation(extent={{80,140},{120,180}}), + iconTransformation(extent={{-350,6},{-310,46}}))); +protected + Buildings.Templates.Components.Interfaces.Bus busValBoiConIso[nBoi] if is_con + "Boiler isolation valve control bus - Condensing boilers" annotation ( + Placement(transformation(extent={{140,140},{180,180}}), + iconTransformation(extent={{-350,6},{-310,46}}))); +equation + connect(ports_aHeaWat, boiPol.port_a) annotation (Line(points={{200,-100},{-20, + -100},{-20,0},{-10,0}}, color={0,127,255})); + connect(boiPol.port_b, valBoiIso.port_a) annotation (Line(points={{10,0},{20,0}, + {20,120},{150,120}}, color={0,127,255})); + connect(valBoiIso.port_b, ports_bHeaWat) + annotation (Line(points={{170,120},{200,120}}, color={0,127,255})); + connect(pas.port_b, ports_bHeaWat) annotation (Line(points={{170,100},{180, + 100},{180,120},{200,120}}, color={0,127,255})); + connect(boiPol.port_b, pas.port_a) annotation (Line(points={{10,0},{20,0},{20, + 100},{150,100}}, color={0,127,255})); + connect(busBoiCon, boiPol.bus) annotation (Line( + points={{-40,160},{-40,-40},{0,-40},{0,10}}, + color={255,204,51}, + thickness=0.5)); + connect(bus.boiCon, busBoiCon) annotation (Line( + points={{0,200},{0,180},{-40,180},{-40,160}}, + color={255,204,51}, + thickness=0.5)); + connect(bus.boiNon, busBoiNon) annotation (Line( + points={{0,200},{0,180},{-80,180},{-80,160}}, + color={255,204,51}, + thickness=0.5)); + connect(busBoiNon, boiPol.bus) annotation (Line( + points={{-80,160},{-80,10},{0,10}}, + color={255,204,51}, + thickness=0.5)); + connect(valBoiIso.bus, busValBoiConIso) annotation (Line( + points={{160,130},{160,160}}, + color={255,204,51}, + thickness=0.5)); + connect(busValBoiNonIso, valBoiIso.bus) annotation (Line( + points={{100,160},{100,130},{160,130}}, + color={255,204,51}, + thickness=0.5)); + connect(bus.valBoiNonIso, busValBoiNonIso) annotation (Line( + points={{0,200},{0,180},{100,180},{100,160}}, + color={255,204,51}, + thickness=0.5)); + connect(bus.valBoiConIso, busValBoiConIso) annotation (Line( + points={{0,200},{4,200},{4,184},{160,184},{160,160}}, + color={255,204,51}, + thickness=0.5)); + connect(ports_aHeaWat, boiTab.port_a) annotation (Line(points={{200,-100},{-20, + -100},{-20,-50},{-10,-50}}, color={0,127,255})); + connect(boiTab.port_b, pas.port_a) annotation (Line(points={{10,-50},{20,-50}, + {20,100},{150,100}}, color={0,127,255})); + connect(boiTab.port_b, valBoiIso.port_a) annotation (Line(points={{10,-50},{ + 20,-50},{20,120},{150,120}}, + color={0,127,255})); + connect(busBoiCon, boiTab.bus) annotation (Line( + points={{-40,160},{-40,10},{0,10},{0,-40}}, + color={255,204,51}, + thickness=0.5), Text( + string="%first", + index=-1, + extent={{-3,6},{-3,6}}, + horizontalAlignment=TextAlignment.Right)); + connect(busBoiNon, boiTab.bus) annotation (Line( + points={{-80,160},{-80,-40},{0,-40}}, + color={255,204,51}, + thickness=0.5)); + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false, + extent={{-400,-700},{400,700}}), graphics={ + Line( + points={{200,500},{400,500}}, + color={0,0,0}, + pattern=LinePattern.Solid, + thickness=5), + Line( + visible=nBoi >= 2, + points={{200,200},{400,200}}, + color={0,0,0}, + pattern=LinePattern.Solid, + thickness=5), + Line( + visible=nBoi >= 3, + points={{200,-100},{400,-100}}, + color={0,0,0}, + pattern=LinePattern.Solid, + thickness=5), + Line( + visible=nBoi >= 4, + points={{200,-400},{400,-400}}, + color={0,0,0}, + pattern=LinePattern.Solid, + thickness=5), + Text( + extent={{-151,-712},{149,-752}}, + textColor={0,0,255}, + textString="%name"), + Bitmap( + visible=nBoi >= 1, + extent={{-280,390},{-160,510}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg"), + Bitmap( + visible=typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi>=1, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=-90, + origin={300,500}), + Bitmap( + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 1, + extent={{260,560},{340,640}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap( + visible=nBoi >= 2, + extent={{-280,90},{-160,212}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg"), + Bitmap( + visible=typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi>=2, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=-90, + origin={300,200}), + Bitmap( + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 2, + extent={{260,260},{340,340}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap( + visible=nBoi >= 3, + extent={{-280,-212},{-160,-92}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg"), + Bitmap( + visible=typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi>=3, + extent={{260,-40},{340,40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap( + visible=typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi>=3, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=-90, + origin={300,-100}), + Bitmap( + visible=nBoi >= 4, + extent={{-280,-510},{-160,-390}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg"), + Bitmap( + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 4, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=-90, + origin={300,-400}), + Bitmap( + visible=typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi>=4, + extent={{260,-340},{340,-260}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Rectangle( + extent={{200,540},{-160,360}}, + lineColor={0,0,0}, + lineThickness=1), + Text( + visible=is_con, + extent={{-160,520},{200,480}}, + textColor={0,0,0}, + textString="CON"), + Text( + extent={{-160,420},{200,380}}, + textColor={0,0,0}, + textString="BOI-1"), + Line( + points={{200,400},{400,400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5), + Rectangle( + extent={{200,240},{-160,60}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nBoi >= 2), + Text( + visible=nBoi >= 2 and is_con, + extent={{-160,220},{200,180}}, + textColor={0,0,0}, + textString="CON"), + Text( + visible=nBoi >= 2, + extent={{-160,120},{200,80}}, + textColor={0,0,0}, + textString="BOI-2"), + Line( + visible=nBoi >= 2, + points={{200,100},{400,100}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5), + Rectangle( + extent={{200,-60},{-160,-240}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nBoi >= 3), + Text( + visible=nBoi >= 3 and is_con, + extent={{-160,-80},{200,-120}}, + textColor={0,0,0}, + textString="CON"), + Text( + visible=nBoi >= 3, + extent={{-160,-180},{200,-220}}, + textColor={0,0,0}, + textString="BOI-3"), + Line( + points={{200,-200},{400,-200}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nBoi >= 3), + Rectangle( + visible=nBoi >= 4, + extent={{200,-360},{-160,-540}}, + lineColor={0,0,0}, + lineThickness=1), + Text( + visible=nBoi >= 4 and is_con, + extent={{-160,-380},{200,-420}}, + textColor={0,0,0}, + textString="CON"), + Text( + visible=nBoi >= 4, + extent={{-160,-480},{200,-520}}, + textColor={0,0,0}, + textString="BOI-4"), + Line( + points={{200,-500},{400,-500}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nBoi >= 4), + Line( + points={{300,562},{300,500}}, + color={0,0,0}, + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 1), + Line( + points={{300,262},{300,200}}, + color={0,0,0}, + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 2), + Line( + points={{300,-38},{300,-100}}, + color={0,0,0}, + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 3), + Line( + points={{300,-338},{300,-400}}, + color={0,0,0}, + visible=typArrPumHeaWatPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nBoi >= 4)}), + Diagram(coordinateSystem(extent={{-200,-180},{200,200}})), + Documentation(info=" +

+This model represents a group of hot water boilers. +

+

+Modeling features and limitations: +

+ +

Control points

+

+The following input and output points are available. +

+ +", revisions=" + +")); +end BoilerGroup; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/Guideline36.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/Guideline36.mo new file mode 100644 index 00000000000..11a95361ffd --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/Guideline36.mo @@ -0,0 +1,415 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Controls; +block Guideline36 "Guideline 36 controller" + extends + Buildings.Templates.HeatingPlants.HotWater.Components.Interfaces.PartialController( + final typ=Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36); + + // FIXME: Are primary-only non-condensing boiler systems supported? + final parameter Boolean have_priOnl = + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "Is the boiler plant a primary-only, condensing boiler plant?"; + + // FIXME: How are the following configurations supported? + // - Hybrid plant with dedicated non-condensing boiler pumps and headered condensing boiler pumps (see for instance Figure A-27 in G36) + // - Dedicated pump provided with boiler with factory controls + final parameter Boolean have_heaPriPum = + typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered or + typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Headered + "True: Headered primary hot water pumps; + False: Dedicated primary hot water pumps"; + + final parameter Boolean have_varPriPum = have_varPumHeaWatPriCon or have_varPumHeaWatPriNon + "True: Variable-speed primary pumps; + False: Fixed-speed primary pumps"; + + final parameter Boolean have_secFloSen = have_senVHeaWatSec + "True: Flowrate sensor in secondary loop; + False: Flowrate sensor in decoupler"; + + final parameter Boolean have_priSecTemSen = have_senTHeaWatPriSupCon or have_senTHeaWatPriSupNon + "True: Temperature sensors in primary and secondary loops; + False: Temperature sensors in boiler supply and secondary loop"; + + // Only variable speed secondary pumps are supported in the template. + final parameter Boolean have_varSecPum = true + "True: Variable-speed secondary pumps; + False: Fixed-speed secondary pumps"; + + final parameter Integer nBoi = nBoiCon + nBoiNon + "Number of boilers"; + + // Concatenation with array-comprehension to be CDL-compliant. + final parameter Integer boiTyp[nBoi] = { + if i<=nBoiCon then Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.BoilerTypes.condensingBoiler + else Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.BoilerTypes.nonCondensingBoiler + for i in 1:nBoi} + "Boiler type"; + + final parameter Integer nSta = size(staMat, 1) + "Number of boiler plant stages"; + + final parameter Integer staMat[:, nBoi] = dat.sta + "Staging matrix with stage as row index and boiler as column index"; + + /* FIXME: For hybrid plants, how to specify the number of pumps for condensing and non-condensing boilers? + To support integrated pumps with factory controls in the template, I suggest + to use the same control logic as implemented here but maybe with separate + dedicated output connectors. + This would make it clear that those are not AO/DO points of the controller + but only used for simulation purposes. + */ + final parameter Integer nPumPri = + nPumHeaWatPriCon + nPumHeaWatPriNon + "Number of primary pumps in the boiler plant loop"; + + final parameter Integer nSenPri = nSenDpHeaWatRem + "Total number of remote differential pressure sensors in primary loop" + annotation(Dialog(tab="General", + group="Boiler plant configuration parameters", + enable = have_remDPRegPri or have_locDPRegPri)); + + parameter Integer nPumPri_nominal( + final max=nPumPri, + final min=1) = nPumPri + "Number of primary HW pumps that operate at design conditions"; + + final parameter Integer nPumSec = nPumHeaWatSec + "Total number of secondary hot water pumps"; + + final parameter Integer nSenSec = nSenDpHeaWatRem + "Total number of remote differential pressure sensors in secondary loop"; + + parameter Integer nPumSec_nominal( + final max=nPumSec) = nPumSec + "Number of secondary HW pumps that operate at design conditions"; + + // FIXME: This should rather be an input point. + parameter Real schTab[:,2] = [0,1;6,1;18,1;24,1] + "Boiler plant enable schedule"; + + // FIXME: this should not be exposed in the controller but rather computed with size() as below. + final parameter Integer nSchRow = size(schTab, 1) + "Number of rows to be created for plant schedule table" + annotation(Dialog(tab="Plant enable/disable parameters")); + + final parameter Real TOutLoc = dat.TOutLck + "Boiler lock-out temperature for outdoor air" + annotation(Dialog(tab="Plant enable/disable parameters")); + + // Concatenation with array-comprehension to be CDL-compliant. + final parameter Real boiDesCap[nBoi] = { + if i<=nBoiCon then dat.capBoiCon_nominal[i] + else dat.capBoiNon_nominal[i-nBoiCon] for i in 1:nBoi} + "Design boiler capacities vector"; + + final parameter Real boiFirMin[nBoi] = { + if i<=nBoiCon then dat.ratFirBoiCon_min[i] + else dat.ratFirBoiNon_min[i-nBoiCon] for i in 1:nBoi} + "Boiler minimum firing ratio"; + + final parameter Real minFloSet[nBoi] = { + if i<=nBoiCon then dat.ratFirBoiCon_min[i] + else dat.ratFirBoiNon_min[i-nBoiCon] for i in 1:nBoi} + "Design minimum hot water flow through each boiler"; + + final parameter Real maxFloSet[nBoi] = { + if i<=nBoiCon then dat.VHeaWatBoiCon_flow_nominal[i] + else dat.VHeaWatBoiNon_flow_nominal[i-nBoiCon] for i in 1:nBoi} + "Design HW volume flow rate - Each boiler"; + + final parameter Real TPlaHotWatSetMax=dat.THeaWatSup_nominal + "Design (highest) HW supply temperature setpoint"; + + final parameter Real TConBoiHotWatSetMax=dat.THeaWatConSup_nominal + "Design (highest) HW supply temperature setpoint for condensing boilers"; + + // FIXME: Missing enable condition. + final parameter Real minPumSpePri=dat.yPumHeaWatPri_min + "Minimum pump speed"; + + // FIXME: Missing enable condition: only required for primary-only plants with headered variable speed pumps using differential pressure pump speed control, see G36 3.1.8.4. + final parameter Real VHotWatPri_flow_nominal = + max(dat.VHeaWatPriCon_flow_nominal, dat.VHeaWatPriNon_flow_nominal) + "Plant design hot water flow rate through primary loop"; + + // FIXME: Missing enable condition: only required for primary-only hot water plants with a minimum flow bypass valve, see G36 3.1.8.2. + final parameter Real boiDesFlo[nBoi] = { + if i<=nBoiCon then dat.VHeaWatBoiCon_flow_nominal[i] + else dat.VHeaWatBoiNon_flow_nominal[i-nBoiCon] for i in 1:nBoi} + "Vector of design flowrates for all boilers in plant"; + + final parameter Real maxLocDpPri = dat.dpHeaWatLocSet_nominal + "Maximum primary loop local differential pressure setpoint"; + + // FIXME: Duplicate parameter + Missing enable condition. + final parameter Real minSecPumSpe = dat.yPumHeaWatSec_min + "Minimum secondary pump speed"; + + // FIXME: Duplicate parameter + Missing enable condition. + final parameter Real minPumSpeSec = dat.yPumHeaWatSec_min + "Minimum pump speed"; + + // FIXME: Missing enable condition. + final parameter Real minPriPumSpeSta[nSta] = dat.yPumHeaWatPriSta_min + "Vector of minimum primary pump speed for each stage"; + + // FIXME: Missing enable condition: only required for primary-secondary plants with a flow meter in the secondary loop, see G36 3.1.8.4. + final parameter Real VHotWatSec_flow_nominal = dat.VHeaWatSec_flow_nominal + "Secondary loop design hot water flow rate"; + + final parameter Real maxLocDpSec = dat.dpHeaWatLocSet_nominal + "Maximum hot water loop local differential pressure setpoint in secondary loop"; + + final parameter Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes + speConTypPri = + if typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then ( + if have_senDpHeaWatLoc then + Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.localDP + else Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.remoteDP) + else ( + if typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDecoupler or + typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDifference + then Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.flowrate + else Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature) + "Primary pump speed regulation method"; + + final parameter Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes + speConTypSec = if have_senDpHeaWatLoc then + Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes.localDP + else Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes.remoteDP + "Secondary pump speed regulation method"; + + Guideline36Plugin ctl( + final have_priOnl=have_priOnl, + final have_heaPriPum=have_heaPriPum, + final have_varPriPum=have_varPriPum, + final have_secFloSen=have_secFloSen, + final have_priSecTemSen=have_priSecTemSen, + final have_varSecPum=have_varSecPum, + final nBoi=nBoi, + final boiTyp=boiTyp, + final nSta=nSta, + final staMat=staMat, + final nPumPri=nPumPri, + final nSenPri=nSenPri, + final nPumPri_nominal=nPumPri_nominal, + final nPumSec=nPumSec, + final nSenSec=nSenSec, + final nPumSec_nominal=nPumSec_nominal, + final schTab=schTab, + final nSchRow=nSchRow, + final TOutLoc=TOutLoc, + final boiDesCap=boiDesCap, + final boiFirMin=boiFirMin, + final minFloSet=minFloSet, + final maxFloSet=maxFloSet, + final TPlaHotWatSetMax=TPlaHotWatSetMax, + final TConBoiHotWatSetMax=TConBoiHotWatSetMax, + final minPumSpePri=minPumSpePri, + final VHotWatPri_flow_nominal=VHotWatPri_flow_nominal, + final boiDesFlo=boiDesFlo, + final maxLocDpPri=maxLocDpPri, + final minSecPumSpe=minSecPumSpe, + final minPumSpeSec=minPumSpeSec, + final minPriPumSpeSta=minPriPumSpeSta, + final VHotWatSec_flow_nominal=VHotWatSec_flow_nominal, + final maxLocDpSec=maxLocDpSec) + "Plant controller" + annotation (Placement(transformation(extent={{60,-34},{80,34}}))); + + Buildings.Controls.OBC.CDL.Integers.MultiSum reqHeaWatPlaAirHan( + final nin=nAirHan) + "Sum of HW plant requests from AHU" + annotation (Placement(transformation(extent={{-80,-70},{-60,-50}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqHeaWatPlaEquZon( + final nin=nEquZon) + "Sum of HW plant requests from zone equipment" + annotation (Placement(transformation(extent={{-80,-100},{-60,-80}}))); + Buildings.Controls.OBC.CDL.Integers.Add reqHeaWatPla + "Sum of HW plant requests from all served units" + annotation (Placement(transformation(extent={{-40,-80},{-20,-60}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqHeaWatResAirHan( + final nin=nAirHan) + "Sum of HW reset requests from AHU" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqHeaWatResEquZon( + final nin=nEquZon) + "Sum of HW reset requests from zone equipment" + annotation (Placement(transformation(extent={{-80,-40},{-60,-20}}))); + Buildings.Controls.OBC.CDL.Integers.Add reqHeaWatRes + "Sum of HW reset requests from all served units" + annotation (Placement(transformation(extent={{-40,-40},{-20,-20}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.Constant FIXME_uBoi[nBoi](each k=true) + "Not an input point per G36 4.11.1: this should be removed." + annotation (Placement(transformation(extent={{-100,350},{-80,370}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant FIXME_uBoiAva[nBoi](each + k=true) "Not an input point per G36 4.11.1: this should be removed." + annotation (Placement(transformation(extent={{-100,310},{-80,330}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant FIXME_TSupPri(k= + Buildings.Templates.Data.Defaults.THeaWatSup) + "Which sensor is that: primary loop or secondary loop? Missing Boolean condition & support for hybrid plants" + annotation (Placement(transformation(extent={{-100,270},{-80,290}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant FIXME_TRetPri(k= + Buildings.Templates.Data.Defaults.THeaWatRet) + "Missing Boolean condition & support for hybrid plants" + annotation (Placement(transformation(extent={{-100,230},{-80,250}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant FIXME_VHotWatPri_flow(k=1E-2) + "Missing Boolean condition & support for hybrid plants" + annotation (Placement(transformation(extent={{-100,190},{-80,210}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant FIXME_uHotWatIsoVal[nBoi](each k=1) + "This point should be optional. If present, there should rather be 2 Boolean input points (DI)." + annotation (Placement(transformation(extent={{-100,150},{-80,170}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant FIXME_uBypValPos(k=0) "Not an input point per G36 4.11.1: this should be removed. +" annotation (Placement(transformation(extent={{-100,110},{-80,130}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant FIXME_uPriPumSpe[nPumPri]( + each k=0.5) "Not an input point per G36 4.11.1: this should be removed. +" annotation (Placement(transformation(extent={{-100,70},{-80,90}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold FIXME_yHotWatIsoValCon[nBoiCon]( + each t=1E-2, each h=5E-3) + if have_boiCon and + typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered + "Should be a DO point (Boolean)" + annotation (Placement(transformation(extent={{120,10},{140,30}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold FIXME_yHotWatIsoValNon[nBoiNon]( + each t=1E-2, each h=5E-3) + if have_boiNon and + typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Headered + "Should be a DO point (Boolean)" + annotation (Placement(transformation(extent={{120,-30},{140,-10}}))); + +initial equation + assert(nAirHan + nEquZon > 0, + "In "+ getInstanceName() + ": "+ + "The plant model requires at least one air handler or one zone equipment " + + "generating HW plant requests and HW reset requests."); + +equation + /* Control point connection - start */ + + // Inputs from plant control bus + connect(FIXME_uBoiAva.y, ctl.uBoiAva); + connect(FIXME_uBoi.y, ctl.uBoi); + connect(busPumHeaWatPriCon.y1_actual, ctl.uPriPum[1:nBoiCon]); + connect(busPumHeaWatPriNon.y1_actual, ctl.uPriPum[(nBoiCon+1):(nBoiCon+nBoiNon)]); + connect(busPumHeaWatSec.y1_actual, ctl.uSecPum); + + connect(busAirHan.reqHeaWatRes, reqHeaWatResAirHan.u); + connect(busEquZon.reqHeaWatRes, reqHeaWatResEquZon.u); + connect(busAirHan.reqHeaWatPla, reqHeaWatPlaAirHan.u); + connect(busEquZon.reqHeaWatPla, reqHeaWatPlaEquZon.u); + + connect(bus.TOut, ctl.TOut); + connect(FIXME_TSupPri.y, ctl.TSupPri); + connect(FIXME_TRetPri.y, ctl.TRetPri); + connect(FIXME_VHotWatPri_flow.y, ctl.VHotWatPri_flow); + connect(bus.dpHeaWatRem, ctl.dpHotWatPri_rem); + connect(bus.THeaWatSecRet, ctl.TRetSec); + connect(bus.VHeaWatSec_flow, ctl.VHotWatSec_flow); + connect(bus.VHeaWatByp_flow, ctl.VHotWatDec_flow); + connect(bus.THeaWatSecSup, ctl.TSupSec); + connect(busBoiCon.T, ctl.TSupBoi[1:nBoiCon]); + connect(busBoiNon.T, ctl.TSupBoi[(nBoiCon+1):(nBoiCon+nBoiNon)]); + connect(bus.dpHeaWatRem, ctl.dpHotWatSec_rem); + connect(bus.dpHeaWatLoc, ctl.dpHotWatPri_loc); + connect(bus.dpHeaWatLoc, ctl.dpHotWatSec_loc); + connect(FIXME_uHotWatIsoVal.y, ctl.uHotWatIsoVal); + connect(FIXME_uBypValPos.y, ctl.uBypValPos); + connect(FIXME_uPriPumSpe.y, ctl.uPriPumSpe); + + // Outputs to plant control bus + connect(ctl.yBoi[1:nBoiCon], busBoiCon.y1); + connect(ctl.yBoi[(nBoiCon+1):(nBoiCon+nBoiNon)], busBoiNon.y1); + connect(ctl.yPriPum[1:nBoiCon], busPumHeaWatPriCon.y1); + connect(ctl.yPriPum[(nBoiCon+1):(nBoiCon+nBoiNon)], busPumHeaWatPriNon.y1); + connect(ctl.yPriPumSpe, busPumHeaWatPriCon.y); + connect(ctl.yPriPumSpe, busPumHeaWatPriNon.y); + connect(ctl.ySecPum, busPumHeaWatSec.y1); + connect(ctl.ySecPumSpe, busPumHeaWatSec.y); + connect(ctl.yBypValPos, busValHeaWatMinByp.y); + connect(ctl.yBypValPos, busValHeaWatMinByp.y); + connect(ctl.TBoiHotWatSupSet[1:nBoiCon], busBoiCon.THeaWatSupSet); + connect(ctl.TBoiHotWatSupSet[(nBoiCon+1):(nBoiCon+nBoiNon)], busBoiNon.THeaWatSupSet); + + connect(FIXME_yHotWatIsoValCon.y, busValBoiConIso.y1); + connect(FIXME_yHotWatIsoValNon.y, busValBoiNonIso.y1); + /* Control point connection - stop */ + + connect(reqHeaWatResAirHan.y, reqHeaWatRes.u1) annotation (Line(points={{-58,0}, + {-50,0},{-50,-24},{-42,-24}}, color={255,127,0})); + connect(reqHeaWatResEquZon.y, reqHeaWatRes.u2) annotation (Line(points={{-58,-30}, + {-50,-30},{-50,-36},{-42,-36}}, color={255,127,0})); + connect(reqHeaWatPlaAirHan.y, reqHeaWatPla.u1) annotation (Line(points={{-58,-60}, + {-50,-60},{-50,-64},{-42,-64}}, color={255,127,0})); + connect(reqHeaWatPlaEquZon.y, reqHeaWatPla.u2) annotation (Line(points={{-58,-90}, + {-50,-90},{-50,-76},{-42,-76}}, color={255,127,0})); + connect(reqHeaWatPla.y, ctl.plaReq) annotation (Line(points={{-18,-70},{0,-70}, + {0,29},{58,29}}, color={255,127,0})); + connect(reqHeaWatRes.y, ctl.TSupResReq) annotation (Line(points={{-18,-30},{-4, + -30},{-4,32},{58,32}}, color={255,127,0})); + connect(ctl.yHotWatIsoVal[1:nBoiCon], FIXME_yHotWatIsoValCon.u) annotation ( + Line(points={{82,2},{100,2},{100,20},{118,20}}, color={0,0,127})); + connect(ctl.yHotWatIsoVal[(nBoiCon + 1):(nBoiCon + nBoiNon)], + FIXME_yHotWatIsoValNon.u) annotation (Line(points={{82,2},{100,2},{100,-20}, + {118,-20}}, color={0,0,127})); + annotation (Documentation(info=" +

Description

+

+This is an implementation of the control sequence specified in ASHRAE (2021) +for hot water plants. +It is based on + +Buildings.Controls.OBC.ASHRAE.PrimarySystem.BoilerPlant.Controller. +

+

Details

+

+For hybrid plants, units shall be indexed so that condensing boilers have the +lowest indices and non-condensing boilers have the highest indices. +

+

+Distributed secondary pumps are currently not supported. +This limitation stems from the Guideline 36 controller implementation in + +Buildings.Controls.OBC.ASHRAE.PrimarySystem.BoilerPlant.Controller. +

+

Control points

+

+The Guideline 36 control sequence requires the following input points in +addition to the ones from the HW plant model. +

+ +

References

+ +", revisions=" + +")); +end Guideline36; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/Guideline36Plugin.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/Guideline36Plugin.mo new file mode 100644 index 00000000000..e11e9bd3229 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/Guideline36Plugin.mo @@ -0,0 +1,1182 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Controls; +block Guideline36Plugin + "Placeholder class to prepare G36 controller integration" + + parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType_priPum= Buildings.Controls.OBC.CDL.Types.SimpleController.PI + "Type of controller" + annotation (Dialog(tab="Primary pump control parameters", group="PID parameters")); + + parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType_bypVal= Buildings.Controls.OBC.CDL.Types.SimpleController.PI + "Type of controller" + annotation(Dialog(tab="Bypass valve control parameters")); + + parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType_secPum= Buildings.Controls.OBC.CDL.Types.SimpleController.PI + "Type of controller" + annotation(Dialog(tab="Secondary pump control parameters", group="PID parameters")); + + parameter Boolean have_priOnl = false + "Is the boiler plant a primary-only, condensing boiler plant?" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Boolean have_heaPriPum = true + "True: Headered primary hot water pumps; + False: Dedicated primary hot water pumps" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Boolean have_varPriPum = false + "True: Variable-speed primary pumps; + False: Fixed-speed primary pumps" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Boolean have_secFloSen=false + "True: Flowrate sensor in secondary loop; + False: Flowrate sensor in decoupler" + annotation(Dialog(tab="General", + group="Boiler plant configuration parameters", + enable = not have_priOnl)); + + parameter Boolean have_priSecTemSen=false + "True: Temperature sensors in primary and secondary loops; + False: Temperature sensors in boiler supply and secondary loop" + annotation (Dialog(tab="Primary pump control parameters", + group="General parameters", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Boolean have_varSecPum = false + "True: Variable-speed secondary pumps; + False: Fixed-speed secondary pumps" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Integer nIgnReq( + final min=0) = 0 + "Number of hot-water requests to be ignored before enabling boiler plant loop" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Integer nSchRow( + final min=1) = 4 + "Number of rows to be created for plant schedule table" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Integer nBoi + "Number of boilers" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Integer boiTyp[nBoi]={ + Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.BoilerTypes.condensingBoiler, + Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.BoilerTypes.nonCondensingBoiler} + "Boiler type" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Integer nSta + "Number of boiler plant stages" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Integer staMat[nSta, nBoi] + "Staging matrix with stage as row index and boiler as column index" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Integer nPumPri + "Number of primary pumps in the boiler plant loop" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Integer nHotWatResReqIgn = 2 + "Number of hot-water supply temperature reset requests to be ignored" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Integer nSenPri + "Total number of remote differential pressure sensors in primary loop" + annotation(Dialog(tab="General", + group="Boiler plant configuration parameters", + enable = have_remDPRegPri or have_locDPRegPri)); + + parameter Integer numIgnReq = 0 + "Number of ignored requests" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable= speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Integer nPumPri_nominal( + final max=nPumPri, + final min=1) = nPumPri + "Total number of pumps that operate at design conditions" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Integer nPumSec + "Total number of secondary hot water pumps" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Integer nSenSec + "Total number of remote differential pressure sensors in secondary loop" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Integer nPumSec_nominal( + final max=nPumSec) = nPumSec + "Total number of pumps that operate at design conditions in secondary loop" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Real schTab[nSchRow,2] = [0,1;6,1;18,1;24,1] + "Table defining schedule for enabling plant" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Real TOutLoc( + final unit="K", + displayUnit="K") = 300 + "Boiler lock-out temperature for outdoor air" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Real locDt( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 1 + "Temperature deadband for boiler lockout" + annotation(Dialog(tab="Plant enable/disable parameters", group="Advanced")); + + parameter Real plaOffThrTim( + final unit="s", + displayUnit="s") = 900 + "Minimum time for which the plant has to stay off once it has been disabled" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Real plaOnThrTim( + final unit="s", + displayUnit="s") = plaOffThrTim + "Minimum time for which the boiler plant has to stay on once it has been enabled" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Real staOnReqTim( + final unit="s", + displayUnit="s") = 180 + "Time-limit for receiving hot-water requests to maintain enabled plant on" + annotation(Dialog(tab="Plant enable/disable parameters")); + + parameter Real boiDesCap[nBoi] + "Design boiler capacities vector" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Real boiFirMin[nBoi] + "Boiler minimum firing ratio" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Real delStaCha( + final unit="s", + displayUnit="s", + final quantity="Time") = 600 + "Hold period for each stage change" + annotation(Dialog(tab="Staging setpoint parameters", group="General parameters")); + + parameter Real avePer( + final unit="s", + displayUnit="s", + final quantity="Time") = 300 + "Time period for the capacity requirement rolling average" + annotation(Dialog(tab="Staging setpoint parameters", group="Capacity requirement calculation parameters")); + + parameter Real fraNonConBoi( + final unit="1", + displayUnit="1") = 0.9 + "Fraction of current stage design capacity at which efficiency condition is + satisfied for non-condensing boilers" + annotation(Dialog(tab="Staging setpoint parameters", group="Efficiency condition parameters")); + + parameter Real fraConBoi( + final unit="1", + displayUnit="1") = 1.5 + "Fraction of higher stage design capacity at which efficiency condition is + satisfied for condensing boilers" + annotation(Dialog(tab="Staging setpoint parameters", group="Efficiency condition parameters")); + + parameter Real delEffCon( + final unit="s", + displayUnit="s", + final quantity="Time") = 600 + "Enable delay for heating capacity requirement condition" + annotation(Dialog(tab="Staging setpoint parameters", group="Efficiency condition parameters")); + + parameter Real TDif( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 10 + "Required temperature difference between setpoint and measured temperature" + annotation(Dialog(tab="Staging setpoint parameters", group="Failsafe condition parameters")); + + parameter Real delFaiCon( + final unit="s", + displayUnit="s", + final quantity="Time") = 900 + "Enable delay for temperature condition" + annotation(Dialog(tab="Staging setpoint parameters", group="Failsafe condition parameters")); + + parameter Real sigDif( + final unit="1", + displayUnit="1") = 0.1 + "Signal hysteresis deadband for flowrate measurements" + annotation (Dialog(tab="Staging setpoint parameters", group="Advanced")); + + parameter Real TDifHys( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 1 + "Temperature deadband for hysteresis loop" + annotation (Dialog(tab="Staging setpoint parameters", group="Advanced")); + + parameter Real fraMinFir( + final unit="1", + displayUnit="1") = 1.1 + "Fraction of boiler minimum firing rate that required capacity needs to be + to initiate stage-down process" + annotation(Dialog(tab="Staging setpoint parameters", group="Staging down parameters")); + + parameter Real delMinFir( + final unit="s", + displayUnit="s", + final quantity="Time") = 300 + "Delay for staging based on minimum firing rate of current stage" + annotation(Dialog(tab="Staging setpoint parameters", group="Staging down parameters")); + + parameter Real fraDesCap( + final unit="1", + displayUnit="1") = 0.8 + "Fraction of design capacity of next lower stage that heating capacity needs + to be for staging down" + annotation(Dialog(tab="Staging setpoint parameters", group="Staging down parameters")); + + parameter Real delDesCapNonConBoi( + final unit="s", + displayUnit="s", + final quantity="Time") = 600 + "Enable delay for capacity requirement condition for non-condensing boilers" + annotation(Dialog(tab="Staging setpoint parameters", group="Staging down parameters")); + + parameter Real delDesCapConBoi( + final unit="s", + displayUnit="s", + final quantity="Time") = 300 + "Enable delay for capacity requirement condition for condensing boilers" + annotation(Dialog(tab="Staging setpoint parameters", group="Staging down parameters")); + + parameter Real delBypVal( + final unit="s", + displayUnit="s", + final quantity="Time") = 300 + "Enable delay for bypass valve condition for primary-only plants" + annotation ( + Evaluate=true, + Dialog( + enable=have_priOnl, + tab="Staging setpoint parameters", + group="Staging down parameters")); + + parameter Real TCirDif( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 3 + "Required return water temperature difference between primary and secondary + circuits for staging down" + annotation ( + Evaluate=true, + Dialog( + enable=not + (have_priOnl), + tab="Staging setpoint parameters", + group="Staging down parameters")); + + parameter Real delTRetDif( + final unit="s", + displayUnit="s", + final quantity="Time") = 300 + "Enable delay for measured hot water return temperature difference condition" + annotation ( + Evaluate=true, + Dialog( + enable=not + (have_priOnl), + tab="Staging setpoint parameters", + group="Staging down parameters")); + + parameter Real bypValClo( + final unit="1", + displayUnit="1") = 0 + "Adjustment for signal received when bypass valve is closed" + annotation ( + Evaluate=true, + Dialog( + enable=have_priOnl, + tab="Staging setpoint parameters", + group="Advanced")); + + parameter Real dTemp( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 0.1 + "Hysteresis deadband for measured temperatures" + annotation (Dialog(tab="Staging setpoint parameters", group="Advanced")); + + parameter Real minFloSet[nBoi] + "Design minimum hot water flow through each boiler" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Real maxFloSet[nBoi] + "Design maximum hot water flow through each boiler" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Real bypSetRat( + final unit="m3/s2", + displayUnit="m3/s2", + final min=0) = 0.001 + "Rate at which to reset bypass valve setpoint during stage change" + annotation(Dialog(tab="Staging setpoint parameters", group="General parameters")); + + parameter Real TPlaHotWatSetMax( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 353.15 + "The maximum allowed hot-water setpoint temperature for the plant" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real TConBoiHotWatSetMax( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 353.15 + "The maximum allowed hot water setpoint temperature for condensing boilers" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real TConBoiHotWatSetOff( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = -10 + "The offset for hot water setpoint temperature for condensing boilers in + non-condensing stage type" + annotation(Dialog(tab="Supply temperature reset parameters", group="General parameters")); + + parameter Real THotWatSetMinNonConBoi( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 341.48 + "The minimum allowed hot-water setpoint temperature for non-condensing boilers" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real THotWatSetMinConBoi( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 305.37 + "The minimum allowed hot-water setpoint temperature for condensing boilers" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real delTimVal( + final unit="s", + displayUnit="s", + final quantity="Time") = 600 + "Delay time" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real samPerVal( + final unit="s", + displayUnit="s", + final quantity="Time") = 300 + "Sample period" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real triAmoVal( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = -2 + "Setpoint trim value" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real resAmoVal( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 3 + "Setpoint respond value" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real maxResVal( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 7 + "Setpoint maximum respond value" + annotation(Dialog(tab="Supply temperature reset parameters", group="Trim-and-Respond Logic parameters")); + + parameter Real holTimVal( + final unit="s", + displayUnit="s", + final quantity="Time") = 600 + "Minimum setpoint hold time for stage change process" + annotation(Dialog(tab="Supply temperature reset parameters", group="General parameters")); + + parameter Real TMinSupNonConBoi( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 333.2 + "Minimum supply temperature required for non-condensing boilers" + annotation(Dialog(tab="General", group="Boiler plant configuration parameters")); + + parameter Real delProSupTemSet( + final unit="s", + displayUnit="s", + final quantity="time")=300 + "Process time-out for hot water supply temperature setpoint reset" + annotation (Dialog(tab="Staging process parameters",group="Time and delay parameters")); + + parameter Real delEnaMinFloSet( + final unit="s", + displayUnit="s", + final quantity="time")=60 + "Enable delay after minimum flow setpoint is achieved in bypass valve" + annotation (Dialog(tab="Staging process parameters",group="Time and delay parameters")); + + parameter Real chaIsoValRat( + final unit="1/s", + displayUnit="1/s") = 1/60 + "Rate at which to slowly change isolation valve position, should be determined + in the field" + annotation (Dialog(tab="Staging process parameters",group="Time and delay parameters")); + + parameter Real chaIsoValTim( + final unit="s", + displayUnit="s", + final quantity="time") = 1/chaIsoValRat + "Time to slowly change isolation valve position from fully closed to fully open, + should be determined in the field" + annotation (Dialog(tab="Staging process parameters", group="Time and delay parameters")); + + parameter Real delPreBoiEna( + final unit="s", + displayUnit="s", + final quantity="time") = 30 + "Time delay after valve and pump change process has been completed before + starting boiler change process" + annotation (Dialog(tab="Staging process parameters",group="Time and delay parameters")); + + parameter Real boiChaProOnTim( + final unit="s", + displayUnit="s", + final quantity="time") = 300 + "Enabled boiler operation time to indicate if it is proven on during a staging + process where one boiler is turned on and the other is turned off" + annotation (Dialog(tab="Staging process parameters",group="Time and delay parameters")); + + parameter Real delBoiEna( + final unit="s", + displayUnit="s", + final quantity="time") = 180 + "Time delay after boiler change process has been completed before turning off + excess valves and pumps" + annotation (Dialog(tab="Staging process parameters",group="Time and delay parameters")); + + parameter Real k_bypVal( + final min=0, + final unit="1", + displayUnit="1") = 1 + "Gain of controller" + annotation(Dialog(tab="Bypass valve control parameters")); + + parameter Real Ti_bypVal( + final min=0, + final unit="s", + displayUnit="s", + final quantity="time") = 0.5 + "Time constant of integrator block" + annotation(Dialog(tab="Bypass valve control parameters")); + + parameter Real Td_bypVal( + final min=0, + final unit="s", + displayUnit="s", + final quantity="time") = 0.1 + "Time constant of derivative block" + annotation(Dialog(tab="Bypass valve control parameters")); + + parameter Real minPumSpePri( + final unit="1", + displayUnit="1", + final min=0, + final max=maxPumSpePri) = 0.1 + "Minimum pump speed" + annotation (Dialog(tab="Primary pump control parameters", group="General parameters", enable=have_varPriPum)); + + parameter Real maxPumSpePri( + final unit="1", + displayUnit="1", + final min=minPumSpePri, + final max=1) = 1 + "Maximum pump speed" + annotation (Dialog(tab="Primary pump control parameters", group="General parameters", enable=have_varPriPum)); + + parameter Real VHotWatPri_flow_nominal( + final min=1e-6, + final unit="m3/s", + displayUnit="m3/s", + final quantity="VolumeFlowRate") + "Plant design hot water flow rate through primary loop" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Real boiDesFlo[nBoi]( + each final min=1e-6, + each final unit="m3/s", + each displayUnit="m3/s") + "Vector of design flowrates for all boilers in plant" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Real maxLocDpPri( + final unit="Pa", + displayUnit="Pa", + final quantity="PressureDifference", + final min=1e-6) = 5*6894.75 + "Maximum primary loop local differential pressure setpoint" + annotation (Dialog(tab="Primary pump control parameters", group="DP-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.localDP + or speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.remoteDP)); + + parameter Real minLocDpPri( + final unit="Pa", + displayUnit="Pa", + final quantity="PressureDifference", + final min=1e-6) = 5*6894.75 + "Minimum primary loop local differential pressure setpoint" + annotation (Dialog(tab="Primary pump control parameters", + group="DP-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.localDP + or speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.remoteDP)); + + parameter Real offTimThr_priPum( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 180 + "Threshold to check lead boiler off time" + annotation (Dialog(tab="Primary pump control parameters", group="Pump staging parameters")); + + parameter Real timPer_priPum( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 600 + "Delay time period for enabling and disabling lag pumps" + annotation (Dialog(tab="Primary pump control parameters", group="Pump staging parameters")); + + parameter Real staCon_priPum( + final unit="1", + displayUnit="1") = -0.03 + "Constant used in the staging equation" + annotation (Dialog(tab="Primary pump control parameters", group="Pump staging parameters")); + + parameter Real relFloHys_priPum( + final unit="1", + displayUnit="1") = 0.01 + "Constant value used in hysteresis for checking relative flow rate" + annotation (Dialog(tab="Primary pump control parameters", group="Pump staging parameters")); + + parameter Real delTim_priPum( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 900 + "Delay time" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real samPer_priPum( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 120 + "Sample period of component" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real triAmo_priPum( + final unit="1", + displayUnit="1") = -0.02 + "Trim amount" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real resAmo_priPum( + final unit="1", + displayUnit="1") = 0.03 + "Respond amount" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real maxRes_priPum( + final unit="1", + displayUnit="1") = 0.06 + "Maximum response per time interval" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real twoReqLimLow_priPum( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 1.2 + "Lower limit of hysteresis loop sending two requests" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real twoReqLimHig_priPum( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 2 + "Higher limit of hysteresis loop sending two requests" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real oneReqLimLow_priPum( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 0.2 + "Lower limit of hysteresis loop sending one request" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real oneReqLimHig_priPum( + final unit="K", + displayUnit="K", + final quantity="TemperatureDifference") = 1 + "Higher limit of hysteresis loop sending one request" + annotation (Dialog(tab="Primary pump control parameters", + group="Temperature-based speed regulation", + enable = speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature)); + + parameter Real k_priPum( + final unit="1", + displayUnit="1", + final min=0) = 1 + "Gain of controller" + annotation (Dialog(tab="Primary pump control parameters", group="PID parameters")); + + parameter Real Ti_priPum( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 0.5 + "Time constant of integrator block" + annotation (Dialog(tab="Primary pump control parameters", group="PID parameters")); + + parameter Real Td_priPum( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 0.1 + "Time constant of derivative block" + annotation (Dialog(tab="Primary pump control parameters", group="PID parameters")); + + parameter Real TRetSet( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 333.15 + "Minimum hot water return temperature for optimal non-condensing boiler performance" + annotation(Dialog(tab="Condensation control parameters")); + + parameter Real TRetMinAll( + final unit="K", + displayUnit="K", + final quantity="ThermodynamicTemperature") = 330.35 + "Minimum allowed hot water return temperature for non-condensing boiler" + annotation(Dialog(tab="Condensation control parameters")); + + parameter Real minSecPumSpe( + final unit="1", + displayUnit="1", + final min=0, + final max=1) = 0 + "Minimum secondary pump speed" + annotation(Dialog(tab="Condensation control parameters")); + + parameter Real minPriPumSpeSta[nSta]( + final unit=fill("1",nSta), + displayUnit=fill("1",nSta), + final min=fill(0,nSta), + final max=fill(1,nSta)) + "Vector of minimum primary pump speed for each stage" + annotation(Dialog(group="Boiler plant configuration parameters")); + + parameter Real minPumSpeSec( + final unit="1", + displayUnit="1", + final min=0, + final max=maxPumSpeSec) = 0.1 + "Minimum pump speed" + annotation (Dialog(tab="Secondary pump control parameters", + group="General parameters", + enable=have_varSecPum)); + + parameter Real maxPumSpeSec( + final unit="1", + displayUnit="1", + final min=minPumSpeSec, + final max=1) = 1 + "Maximum pump speed" + annotation (Dialog(tab="Secondary pump control parameters", + group="General parameters", + enable=have_varSecPum)); + + parameter Real VHotWatSec_flow_nominal( + final unit="m3/s", + displayUnit="m3/s", + final quantity="VolumeFlowRate") = 0.5 + "Secondary loop design hot water flow rate" + annotation (Dialog(group="Boiler plant configuration parameters")); + + parameter Real maxLocDpSec( + final unit="Pa", + displayUnit="Pa", + final quantity="PressureDifference", + final min=1e-6) = 5*6894.75 + "Maximum hot water loop local differential pressure setpoint in secondary loop" + annotation (Dialog(tab="Secondary pump control parameters", group="DP-based speed regulation", + enable = speConTypSec == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.localDP)); + + parameter Real minLocDpSec( + final unit="Pa", + displayUnit="Pa", + final quantity="PressureDifference", + final min=1e-6) = 5*6894.75 + "Minimum hot water loop local differential pressure setpoint in secondary loop" + annotation (Dialog(tab="Secondary pump control parameters", + group="DP-based speed regulation", + enable = speConTypSec == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.localDP)); + + parameter Real offTimThr( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 180 + "Threshold to check lead boiler off time" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and have_secFloSen)); + + parameter Real timPerSec( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 600 + "Delay time period for enabling and disabling secondary lag pumps" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and have_secFloSen)); + + parameter Real staConSec( + final unit="1", + displayUnit="1") = -0.03 + "Constant used in the staging equation" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and have_secFloSen)); + + parameter Real speLim( + final unit="1", + displayUnit="1") = 0.9 + "Speed limit with longer enable delay for enabling next lag pump" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and not have_secFloSen)); + + parameter Real speLim1( + final unit="1", + displayUnit="1") = 0.99 + "Speed limit with shorter enable delay for enabling next lag pump" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and not have_secFloSen)); + + parameter Real speLim2( + final unit="1", + displayUnit="1") = 0.4 + "Speed limit for disabling last lag pump" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and not have_secFloSen)); + + parameter Real timPer1( + final unit="s", + displayUnit="s", + final quantity="time") = 300 + "Delay time period for enabling next lag pump at speed limit speLim" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and not have_secFloSen)); + + parameter Real timPer2( + final unit="s", + displayUnit="s", + final quantity="time") = 60 + "Delay time period for enabling next lag pump at speed limit speLim1" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and not have_secFloSen)); + + parameter Real timPer3( + final unit="s", + displayUnit="s", + final quantity="time") = 600 + "Delay time period for disabling last lag pump" + annotation (Dialog(tab="Secondary pump control parameters", + group="Pump staging parameters", + enable=have_varSecPum and not have_secFloSen)); + + parameter Real k_sec( + final unit="1", + displayUnit="1", + final min=0) = 1 + "Gain of controller" + annotation (Dialog(tab="Secondary pump control parameters", + group="PID parameters", + enable=have_varSecPum)); + + parameter Real Ti_sec( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 0.5 + "Time constant of integrator block" + annotation (Dialog(tab="Secondary pump control parameters", + group="PID parameters", + enable=have_varSecPum)); + + parameter Real Td_sec( + final unit="s", + displayUnit="s", + final quantity="time", + final min=0) = 0.1 + "Time constant of derivative block" + annotation (Dialog(tab="Secondary pump control parameters", + group="PID parameters", + enable=have_varSecPum)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes + speConTypPri = Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.remoteDP + "Primary pump speed regulation method" + annotation (Dialog(group="Boiler plant configuration parameters", enable=have_varPriPum)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes + speConTypSec = Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes.remoteDP + "Secondary pump speed regulation method" + annotation (Dialog(group="Boiler plant configuration parameters", enable=have_varSecPum)); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uBoiAva[nBoi] + "Boiler availability status signal" + annotation (Placement(transformation(extent={{-440,70},{-400,110}}), + iconTransformation(extent={{-140,60},{-100,100}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uBoi[nBoi] + "Boiler status vector from plant" + annotation (Placement(transformation(extent={{-440,-360},{-400,-320}}), + iconTransformation(extent={{-140,-190},{-100,-150}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uPriPum[nPumPri] + "Primary pump proven on signal from plant" + annotation (Placement(transformation(extent={{-440,-400},{-400,-360}}), + iconTransformation(extent={{-140,-220},{-100,-180}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uSecPum[nPumSec] if not have_priOnl + "Secondary pump proven on signal" + annotation (Placement(transformation(extent={{-440,-440},{-400,-400}}), + iconTransformation(extent={{-140,-250},{-100,-210}}))); + + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput plaReq + "Plant requests" + annotation (Placement(transformation(extent={{-440,350},{-400,390}}), + iconTransformation(extent={{-140,270},{-100,310}}))); + + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput TSupResReq + "Hot water supply temperature reset requests" + annotation (Placement(transformation(extent={{-440,380},{-400,420}}), + iconTransformation(extent={{-140,300},{-100,340}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput TOut( + final unit="K", + displayUnit="degC", + final quantity="ThermodynamicTemperature") + "Measured outdoor air temperature" + annotation (Placement(transformation(extent={{-440,310},{-400,350}}), + iconTransformation(extent={{-140,240},{-100,280}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput TSupPri( + final unit="K", + displayUnit="degC", + final quantity="ThermodynamicTemperature") + "Measured hot water supply temperature" + annotation (Placement(transformation(extent={{-440,270},{-400,310}}), + iconTransformation(extent={{-140,210},{-100,250}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput TRetPri( + final unit="K", + displayUnit="degC", + final quantity="ThermodynamicTemperature") + "Measured hot water primary return temperature" + annotation (Placement(transformation(extent={{-440,230},{-400,270}}), + iconTransformation(extent={{-140,180},{-100,220}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput VHotWatPri_flow( + final unit="m3/s", + displayUnit="m3/s", + final quantity="VolumeFlowRate") + "Measured hot water primary circuit flowrate" + annotation (Placement(transformation(extent={{-440,190},{-400,230}}), + iconTransformation(extent={{-140,150},{-100,190}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHotWatPri_rem[nSenPri]( + final unit=fill("Pa", nSenPri), + displayUnit=fill("Pa", nSenPri), + final quantity=fill("PressureDifference", nSenPri)) if have_varPriPum and (have_remDPRegPri or have_locDPRegPri) + "Measured differential pressure between hot water supply and return in primary circuit" + annotation (Placement(transformation(extent={{-440,110},{-400,150}}), + iconTransformation(extent={{-140,90},{-100,130}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput TRetSec( + final unit="K", + displayUnit="degC", + final quantity="ThermodynamicTemperature") if not have_priOnl + "Measured hot water secondary return temperature" + annotation (Placement(transformation(extent={{-440,150},{-400,190}}), + iconTransformation(extent={{-140,120},{-100,160}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput VHotWatSec_flow( + final unit="m3/s", + displayUnit="m3/s", + final quantity="VolumeFlowRate") if not have_priOnl and have_secFloSen + "Measured hot water secondary circuit flowrate" + annotation (Placement(transformation(extent={{-440,-70},{-400,-30}}), + iconTransformation(extent={{-140,30},{-100,70}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput VHotWatDec_flow( + final unit="m3/s", + displayUnit="m3/s", + final quantity="VolumeFlowRate") if not have_priOnl and have_varPriPum + and have_floRegPri and not have_secFloSen + "Measured hot water flowrate through decoupler leg" + annotation (Placement(transformation(extent={{-440,-110},{-400,-70}}), + iconTransformation(extent={{-140,0},{-100,40}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput TSupSec( + final unit="K", + displayUnit="degC", + final quantity="ThermodynamicTemperature") if not have_priOnl and + have_varPriPum and have_temRegPri and have_priSecTemSen + "Measured hot water supply temperature in secondary circuit" + annotation (Placement(transformation(extent={{-440,-150},{-400,-110}}), + iconTransformation(extent={{-140,-40},{-100,0}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput TSupBoi[nBoi]( + final unit=fill("K", nBoi), + displayUnit=fill("degC", nBoi), + final quantity=fill("ThermodynamicTemperature", nBoi)) if not have_priOnl + and have_varPriPum and have_temRegPri and not have_priSecTemSen + "Measured hot water supply temperature at boiler outlets" + annotation (Placement(transformation(extent={{-440,-190},{-400,-150}}), + iconTransformation(extent={{-140,-70},{-100,-30}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHotWatSec_rem[nSenSec]( + final unit=fill("Pa", nSenSec), + displayUnit=fill("Pa", nSenSec), + final quantity=fill("PressureDifference", nSenSec)) if not + have_priOnl and have_varSecPum and (have_remDPRegSec or have_locDPRegSec) + "Measured differential pressure between hot water supply and return in secondary circuit" + annotation (Placement(transformation(extent={{-440,-230},{-400,-190}}), + iconTransformation(extent={{-140,-100},{-100,-60}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHotWatPri_loc( + final unit="Pa", + displayUnit="Pa", + final quantity="PressureDifference") if have_varPriPum and have_locDPRegPri + "Measured differential pressure between hot water supply and return in primary circuit" + annotation (Placement(transformation(extent={{-440,-270},{-400,-230}}), + iconTransformation(extent={{-140,-130},{-100,-90}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHotWatSec_loc( + final unit="Pa", + displayUnit="Pa", + final quantity="PressureDifference") if not have_priOnl and + have_varSecPum and have_locDPRegSec + "Measured differential pressure between hot water supply and return in secondary circuit" + annotation (Placement(transformation(extent={{-440,-310},{-400,-270}}), + iconTransformation(extent={{-140,-160},{-100,-120}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput uHotWatIsoVal[nBoi]( + final unit=fill("1",nBoi), + displayUnit=fill("1",nBoi)) if have_heaPriPum + "Measured boiler isolation valve position signals from plant" + annotation (Placement(transformation(extent={{-440,-480},{-400,-440}}), + iconTransformation(extent={{-140,-280},{-100,-240}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput uBypValPos( + final unit="1", + displayUnit="1") if have_priOnl + "Measured bypass valve position signal from plant" + annotation (Placement(transformation(extent={{-440,-520},{-400,-480}}), + iconTransformation(extent={{-140,-310},{-100,-270}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealInput uPriPumSpe[nPumPri]( + final unit=fill("1",nBoi), + displayUnit=fill("1",nBoi)) if not have_priOnl + "Measured primary pump speed signal from plant" + annotation (Placement(transformation(extent={{-440,-560},{-400,-520}}), + iconTransformation(extent={{-140,-340},{-100,-300}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yBoi[nBoi] + "Boiler status vector" + annotation (Placement(transformation(extent={{400,200},{440,240}}), + iconTransformation(extent={{100,80},{140,120}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yPriPum[nPumPri] + "Primary pump enable status vector" + annotation (Placement(transformation(extent={{400,-130},{440,-90}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput ySecPum[nPumSec] if not have_priOnl + "Secondary pump enable status vector" + annotation (Placement(transformation(extent={{400,-340},{440,-300}}), + iconTransformation(extent={{100,-160},{140,-120}}))); + + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput yPla + "Plant enable signal" + annotation (Placement(transformation(extent={{400,300},{440,340}}), + iconTransformation(extent={{100,160},{140,200}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealOutput TPlaHotWatSupSet + "Plant hot water supply temperature setpoint" + annotation (Placement(transformation(extent={{400,240},{440,280}}), + iconTransformation(extent={{100,120},{140,160}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yHotWatIsoVal[nBoi]( + final unit=fill("1",nBoi), + displayUnit=fill("1",nBoi)) if have_heaPriPum + "Boiler hot water isolation valve position vector" + annotation (Placement(transformation(extent={{400,120},{440,160}}), + iconTransformation(extent={{100,0},{140,40}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPriPumSpe( + final unit="1", + displayUnit="1") if have_varPriPum + "Primary pump speed" + annotation (Placement(transformation(extent={{400,-170},{440,-130}}), + iconTransformation(extent={{100,-120},{140,-80}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yBypValPos( + final unit="1", + displayUnit="1") if have_priOnl + "Bypass valve position" + annotation (Placement(transformation(extent={{400,-30},{440,10}}), + iconTransformation(extent={{100,-40},{140,0}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealOutput ySecPumSpe( + final unit="1", + displayUnit="1") if not have_priOnl and have_varSecPum + "Secondary pump speed vector" + annotation (Placement(transformation(extent={{400,-390},{440,-350}}), + iconTransformation(extent={{100,-200},{140,-160}}))); + + Buildings.Controls.OBC.CDL.Interfaces.RealOutput TBoiHotWatSupSet[nBoi] + "Boiler hot water supply temperature setpoint vector" + annotation (Placement(transformation(extent={{400,170},{440,210}}), + iconTransformation(extent={{100,40},{140,80}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Boi[nBoi]( + each table=[0,0; 1,1; 2,0], + each timeScale=1000, + each period=2000) "Boiler Enable signal" + annotation (Placement(transformation(extent={{280,210},{300,230}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSup(k= + TPlaHotWatSetMax) "HW supply temperature set point" + annotation (Placement(transformation(extent={{280,250},{300,270}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep(final nout=nBoi) + "Replicate signal" + annotation (Placement(transformation(extent={{360,180},{380,200}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Pla( + table=[0,0; 1,1; 2,0], + timeScale=1000, + period=2000) "Plant Enable signal" + annotation (Placement(transformation(extent={{280,310},{300,330}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[nBoi] + annotation (Placement(transformation(extent={{340,130},{360,150}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant zero(k=0) "Constant" + annotation (Placement(transformation(extent={{340,-20},{360,0}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumPri[nPumPri]( + each table=[0,0; 1,1; 2,0], + each timeScale=1000, + each period=2000) "Primary pump Enable signal" + annotation (Placement(transformation(extent={{280,-120},{300,-100}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant one(k=1) "Constant" + annotation (Placement(transformation(extent={{340,-160},{360,-140}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumSec[nPumSec]( + each table=[0,0; 1,1; 2,0], + each timeScale=1000, + each period=2000) "Secondary pump Enable signal" + annotation (Placement(transformation(extent={{280,-330},{300,-310}}))); +protected + parameter Boolean have_remDPRegPri = (speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.remoteDP) + "Boolean flag for primary pump speed control with remote differential pressure"; + + parameter Boolean have_locDPRegPri = (speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.localDP) + "Boolean flag for primary pump speed control with local differential pressure"; + + parameter Boolean have_temRegPri = (speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.temperature) + "Boolean flag for primary pump speed control with temperature readings"; + + parameter Boolean have_floRegPri = (speConTypPri == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.PrimaryPumpSpeedControlTypes.flowrate) + "Boolean flag for primary pump speed control with flowrate readings"; + + parameter Boolean have_remDPRegSec = (speConTypSec == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes.remoteDP) + "Boolean flag for secondary pump speed control with remote differential pressure"; + + parameter Boolean have_locDPRegSec = (speConTypSec == Buildings.Templates.HeatingPlants.HotWater.Components.Controls.TypesTmp.SecondaryPumpSpeedControlTypes.localDP) + "Boolean flag for secondary pump speed control with local differential pressure"; + + parameter Integer staInd[nSta]={i for i in 1:nSta} + "Staging indices starting at 1"; + + parameter Integer priPumInd[nPumPri]={i for i in 1:nPumPri} + "Vector of primary pump indices up to total number of primary pumps"; + + parameter Integer secPumInd[nPumSec]={i for i in 1:nPumSec} + "Vector of secondary pump indices up to total number of secondary pumps"; + +equation + + connect(y1Boi.y[1], yBoi) + annotation (Line(points={{302,220},{420,220}}, color={255,0,255})); + connect(THeaWatSup.y, rep.u) annotation (Line(points={{302,260},{340,260},{ + 340,190},{358,190}}, color={0,0,127})); + connect(rep.y, TBoiHotWatSupSet) annotation (Line(points={{382,190},{420,190}}, + color={0,0,127})); + connect(y1Pla.y[1], yPla) annotation (Line(points={{302,320},{420,320}}, + color={255,0,255})); + connect(y1Boi.y[1], booToRea.u) annotation (Line(points={{302,220},{320,220},{ + 320,140},{338,140}}, color={255,0,255})); + connect(booToRea.y, yHotWatIsoVal) + annotation (Line(points={{362,140},{420,140}}, color={0,0,127})); + connect(zero.y, yBypValPos) + annotation (Line(points={{362,-10},{420,-10}}, color={0,0,127})); + connect(y1PumPri.y[1], yPriPum) + annotation (Line(points={{302,-110},{420,-110}}, color={255,0,255})); + connect(one.y, yPriPumSpe) + annotation (Line(points={{362,-150},{420,-150}}, color={0,0,127})); + connect(one.y, ySecPumSpe) annotation (Line(points={{362,-150},{380,-150},{380, + -370},{420,-370}}, color={0,0,127})); + connect(y1PumSec.y[1], ySecPum) annotation (Line(points={{302,-320},{351,-320}, + {351,-320},{420,-320}}, color={255,0,255})); + connect(THeaWatSup.y, TPlaHotWatSupSet) + annotation (Line(points={{302,260},{420,260}}, color={0,0,127})); + annotation (Diagram(coordinateSystem(extent={{-400,-600},{400,600}})), Icon( + coordinateSystem(extent={{-100,-340},{100,340}})), + Documentation(info=" +

+FIXME: This class is for temporary use only. +It aims at providing the outside connectors and parameters of the +G36 controller while the comments at + +are being addressed. +

+")); +end Guideline36Plugin; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/OpenLoop.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/OpenLoop.mo new file mode 100644 index 00000000000..ecf06d20ddc --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/OpenLoop.mo @@ -0,0 +1,157 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Controls; +block OpenLoop + extends + Buildings.Templates.HeatingPlants.HotWater.Components.Interfaces.PartialController( + final typ=Buildings.Templates.HeatingPlants.HotWater.Types.Controller.OpenLoop); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Con_default[nBoiCon]( + each table=[0,0; 1,1; 2,0], + each timeScale=1000, + each period=2000) + "Default Enable signal for all condensing units" + annotation (Placement(transformation(extent={{-140,270},{-120,290}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Non_default[nBoiNon]( + each table=[0,0; 1,1; 2,0], + each timeScale=1000, + each period=2000) + "Default Enable signal for all non-condensing units" + annotation (Placement(transformation(extent={{-80,270},{-60,290}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1BoiCon[nBoiCon]( + table=y1Con_default.table, + timeScale=y1Con_default.timeScale, + period=y1Con_default.period) if have_boiCon + "Boiler Enable signal - Condensing Boilers" + annotation (Placement(transformation(extent={{-120,190},{-140,210}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatConSupSet( + y(final unit="K", displayUnit="degC"), final k=dat.THeaWatConSup_nominal) + if have_boiCon + "HW supply temperature set point - Condensing Boilers" + annotation (Placement(transformation(extent={{-120,230},{-140,250}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep( + final nout=nBoiCon) if have_boiCon + "Replicate signal" + annotation (Placement(transformation(extent={{-150,230},{-170,250}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1ValBoiConIso[nBoiCon]( + table=y1Con_default.table, + timeScale=y1Con_default.timeScale, + period=y1Con_default.period) if have_boiCon + "Boiler isolation valve opening signal - Condensing Boilers" + annotation (Placement(transformation(extent={{-120,130},{-140,150}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1BoiNon[nBoiNon]( + table=y1Non_default.table, + timeScale=y1Non_default.timeScale, + period=y1Non_default.period) if have_boiNon + "Boiler Enable signal - Non-condensing Boilers" + annotation (Placement(transformation(extent={{-60,170},{-80,190}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet( + y(final unit="K", displayUnit="degC"), final k=dat.THeaWatSup_nominal) + if have_boiNon + "HW supply temperature set point" + annotation (Placement(transformation(extent={{-60,210},{-80,230}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep1( + final nout=nBoiNon) if have_boiNon + "Replicate signal" + annotation (Placement(transformation(extent={{-90,210},{-110,230}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1ValBoiNonIso[nBoiNon]( + table=y1Non_default.table, + timeScale=y1Non_default.timeScale, + period=y1Non_default.period) if have_boiNon + "Boiler isolation valve opening signal - Non-condensing Boilers" + annotation (Placement(transformation(extent={{-60,110},{-80,130}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumHeaWatPriCon[ + nPumHeaWatPriCon]( + table=y1Con_default.table, + timeScale=y1Con_default.timeScale, + period=y1Con_default.period) if have_boiCon + "Primary HW pump Enable signal - Condensing Boilers" + annotation (Placement(transformation(extent={{-120,90},{-140,110}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumHeaWatPriCon( + y(final unit="1"), k=1) if have_boiCon and have_varPumHeaWatPriCon + "Primary HW pump speed signal - Condensing Boilers" + annotation (Placement(transformation(extent={{-120,50},{-140,70}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumHeaWatPriNon[ + nPumHeaWatPriNon]( + table=y1Non_default.table, + timeScale=y1Non_default.timeScale, + period=y1Non_default.period) if have_boiNon + "Primary HW pump Enable signal - Non-condensing Boilers" + annotation (Placement(transformation(extent={{-60,70},{-80,90}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumHeaWatPriNon( + y(final unit="1"), k=1) if have_boiNon and have_varPumHeaWatPriNon + "Primary HW pump speed signal - Non-condensing Boilers" + annotation (Placement(transformation(extent={{-60,30},{-80,50}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumHeaWatSec[nPumHeaWatSec]( + each table=[0,0; 1,1; 2,0], + each timeScale=1000, + each period=2000) + if typPumHeaWatSec == Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Secondary HW pump Enable signal" + annotation (Placement(transformation(extent={{-120,-50},{-140,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumHeaWatSec( + y(final unit="1"), k=1) + if typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Secondary HW pump speed signal" + annotation (Placement(transformation(extent={{-120,-90},{-140,-70}}))); + + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yValHeaWatMinByp( + y(final unit="1"), k=0) if have_valHeaWatMinBypCon or have_valHeaWatMinBypNon + "HW minimum flow bypass valve opening signal" + annotation (Placement(transformation(extent={{-120,10},{-140,30}}))); +equation + connect(y1PumHeaWatPriCon.y[1], busPumHeaWatPriCon.y1) + annotation (Line(points={{-142,100},{-240,100},{-240,80}}, + color={255,0,255})); + connect(yPumHeaWatPriCon.y, busPumHeaWatPriCon.y) + annotation (Line(points={{-142,60},{-240,60},{-240,80}}, color={0,0,127})); + connect(y1PumHeaWatSec.y[1], busPumHeaWatSec.y1) + annotation (Line(points={{-142,-40},{-200,-40}}, color={255,0,255})); + connect(yPumHeaWatSec.y, busPumHeaWatSec.y) annotation (Line(points={{-142, + -80},{-200,-80},{-200,-40}}, + color={0,0,127})); + connect(y1PumHeaWatPriNon.y[1], busPumHeaWatPriNon.y1) + annotation (Line(points={{-82,80},{-160,80}}, color={255,0,255})); + connect(y1ValBoiNonIso.y[1], busValBoiNonIso.y1) + annotation (Line(points={{-82,120},{-160,120}}, color={255,0,255})); + connect(yPumHeaWatPriNon.y, busPumHeaWatPriNon.y) + annotation (Line(points={{-82,40},{-160,40},{-160,80}}, color={0,0,127})); + connect(y1BoiCon.y[1], busBoiCon.y1) annotation (Line(points={{-142,200},{ + -240,200},{-240,160}}, + color={255,0,255})); + connect(THeaWatConSupSet.y, rep.u) + annotation (Line(points={{-142,240},{-148,240}}, color={0,0,127})); + connect(rep.y, busBoiCon.THeaWatSupSet) annotation (Line(points={{-172,240},{ + -240,240},{-240,160}}, + color={0,0,127})); + connect(THeaWatSupSet.y, rep1.u) + annotation (Line(points={{-82,220},{-88,220}}, color={0,0,127})); + connect(rep1.y, busBoiNon.THeaWatSupSet) annotation (Line(points={{-112,220}, + {-160,220},{-160,160}},color={0,0,127})); + connect(y1BoiNon.y[1], busBoiNon.y1) annotation (Line(points={{-82,180},{-160, + 180},{-160,160}}, color={255,0,255})); + connect(y1ValBoiConIso.y[1], busValBoiConIso.y1) annotation (Line(points={{-142, + 140},{-240,140},{-240,120}}, color={255,0,255})); + connect(yValHeaWatMinByp.y, busValHeaWatMinByp.y) annotation (Line(points={{ + -142,20},{-194,20},{-194,40},{-200,40}}, color={0,0,127})); + annotation ( + defaultComponentName="ctl", Documentation(info=" +

+This is an open loop controller providing control inputs +for the plant model + +Buildings.Templates.HeatingPlants.HotWater.BoilerPlant. +It is only used for testing purposes. +

+", revisions=" + +")); +end OpenLoop; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/TypesTmp.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/TypesTmp.mo new file mode 100644 index 00000000000..fa62a66a39b --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/TypesTmp.mo @@ -0,0 +1,61 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Controls; +package TypesTmp + "Temporary type definitions to prepare G36 controller integration" + + package BoilerTypes + "Definitions for boiler types" + + constant Integer condensingBoiler = 1 + "Condensing boiler"; + + constant Integer nonCondensingBoiler = 2 + "Non-condensing boiler"; + + annotation ( + Documentation(info=" +

+ This package provides constants that indicate the boiler type based on the + presence of flue gas heat recovery. + The boiler types are enumerated in an order that enables identification of stage + type as condensing or non-condensing. +

+ ", + revisions=" + + "), + Icon(graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)})); + end BoilerTypes; + + type PrimaryPumpSpeedControlTypes = enumeration( + localDP "Pump speed regulated to maintain local differential pressure setpoint", + remoteDP "Pump speed regulated to maintain remote differential pressure setpoint", + flowrate "Pump speed regulated to maintain flowrate through decoupler", + temperature "Pump speed regulated to maintain temperature difference between + primary and secondary loops") + "Definitions for primary pump speed control types"; + type SecondaryPumpSpeedControlTypes = enumeration( + localDP "Pump speed regulated to maintain local differential pressure setpoint", + remoteDP "Pump speed regulated to maintain remote differential pressure setpoint") + "Definitions for secondary pump speed control types"; + annotation (Documentation(info=" +

+FIXME: Temporary files to be deleted after merging +issue2180_BoilerPlant_MainController_oct_2021. +

+")); +end TypesTmp; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/package.mo new file mode 100644 index 00000000000..805ad7f09a5 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/package.mo @@ -0,0 +1,12 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components; +package Controls "Controllers" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info=" +

+All control blocks that form the control sequence of a system are instantiated +into one single class, a so-called control section. +This package contains such control sections for hot water plant models. +

+")); +end Controls; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/package.order b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/package.order new file mode 100644 index 00000000000..1fff8ab7291 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Controls/package.order @@ -0,0 +1,4 @@ +Guideline36 +Guideline36Plugin +OpenLoop +TypesTmp diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Data/BoilerGroup.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/BoilerGroup.mo new file mode 100644 index 00000000000..b6635cec13a --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/BoilerGroup.mo @@ -0,0 +1,97 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Data; +record BoilerGroup "Record for boiler group model" + extends Modelica.Icons.Record; + + parameter Integer nBoi(final min=0) + "Number of boilers (as installed)" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.BoilerHotWaterModel typMod + "Type of boiler model (same model for all boilers)" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Buildings.Fluid.Data.Fuels.Generic fue + "Fuel type" + annotation (choicesAllMatching = true); + parameter Modelica.Units.SI.MassFlowRate mHeaWatBoi_flow_nominal[nBoi]( + each final min=0) + "HW mass flow rate - Each boiler" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpHeaWatBoi_nominal[nBoi]( + each final min=0, + each start=Buildings.Templates.Data.Defaults.dpHeaWatBoi) + "HW pressure drop - Each boiler" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.HeatFlowRate capBoi_nominal[nBoi]( + each final min=0) + "Heating capacity - Each boiler" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.Temperature THeaWatBoiSup_nominal[nBoi]( + each final min=260) + "(Highest) HW supply temperature - Each boiler" + annotation(Dialog(group="Nominal condition")); + // To avoid missing support for zero-sized record in case of nBoi=0 we use max(nBoi, 1). + replaceable parameter Buildings.Fluid.Boilers.Data.Generic per[max(nBoi, 1)] + constrainedby Buildings.Fluid.Boilers.Data.Generic( + each fue=fue, + Q_flow_nominal=if nBoi>0 then capBoi_nominal else {0}, + TIn_nominal=if nBoi>0 then THeaWatBoiSup_nominal - + capBoi_nominal / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq ./ mHeaWatBoi_flow_nominal + else {Buildings.Templates.Data.Defaults.THeaWatRet}, + m_flow_nominal=if nBoi>0 then mHeaWatBoi_flow_nominal else {0}, + dp_nominal=if nBoi>0 then dpHeaWatBoi_nominal else {0}) + "Boiler performance data - Each boiler" + annotation ( + Dialog(enable=typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Table), + choicesAllMatching=true); + + parameter Buildings.Fluid.Types.EfficiencyCurves effCur= + Buildings.Fluid.Types.EfficiencyCurves.Constant + "Curve used to compute the efficiency (same curve type for all boilers)" + annotation (Dialog(enable= + typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial)); + parameter Real a[nBoi, :] = fill({0.9}, nBoi) + "Coefficients for efficiency curve - Each boiler" + annotation (Dialog(enable= + typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial)); + parameter Modelica.Units.SI.Temperature T_nominal[nBoi]=THeaWatBoiSup_nominal + "Temperature used to compute nominal efficiency (only used if efficiency curve depends on temperature) - Each boiler" + annotation (Dialog(enable= + typMod==Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial and + (effCur==Buildings.Fluid.Types.EfficiencyCurves.QuadraticLinear))); + + annotation ( + defaultComponentName="datBoi", + Documentation(info=" +

+This record provides the set of sizing and operating parameters for +boiler group models that can be found within + +Buildings.Templates.HeatingPlants.HotWater.Components.BoilerGroups. +

+

+Within this class, the design values declared at the top-level +are propagated by default to the performance data record per +under the assumption that the nominal conditions used for assessing the +performance data match the design conditions. +

+

+Note that, among those propagated parameters, the only meaningful parameter +is the chiller capacity that should be consistent with the value +used for performance assessment. +Regarding the nominal value of the condenser cooling fluid, it may +only yield a warning if an inconsistent value is used. +All other propagated parameters have no impact on the +computation of the chiller performance and are informative +only inside the performance data record. +

+

+The validation model + +Buildings.Templates.ChilledWaterPlants.Components.Validation.RecordChillerGroup +illustrates how the default bindings from this class may be +overwritten when redeclaring the performance data record, +and how different performance curves may be assigned to each chiller +inside the same group. +

+")); +end BoilerGroup; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Data/Controller.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/Controller.mo new file mode 100644 index 00000000000..cb8d11d8b21 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/Controller.mo @@ -0,0 +1,237 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Data; +record Controller "Record for plant controller" + extends Modelica.Icons.Record; + + parameter Buildings.Templates.HeatingPlants.HotWater.Types.Controller typ + "Type of controller" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_boiCon + "Set to true if the plant includes condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_boiNon + "Set to true if the plant includes non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nBoiCon + "Number of condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nBoiNon + "Number of non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nPumHeaWatPriCon + "Number of primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nPumHeaWatPriNon + "Number of primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_varPumHeaWatPriCon + "Set to true for variable speed primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_varPumHeaWatPriNon + "Set to true for variable speed primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary typPumHeaWatSec + "Type of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Integer nPumHeaWatSec + "Number of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_valHeaWatMinBypCon + "Set to true if the plant has a HW minimum flow bypass valve - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_valHeaWatMinBypNon + "Set to true if the plant has a HW minimum flow bypass valve - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_senDpHeaWatLoc + "Set to true for local HW differential pressure sensor hardwired to plant controller" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nSenDpHeaWatRem + "Number of remote HW differential pressure sensors used for HW pump speed control" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_senVHeaWatSec + "Set to true if secondary loop is equipped with a flow meter" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriCon + "Type of primary HW pump arrangement - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriNon + "Type of primary HW pump arrangement - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.Temperature THeaWatSup_nominal( + displayUnit="degC", + start=Buildings.Templates.Data.Defaults.THeaWatSup, + final min=273.15) + "Design (highest) HW supply temperature setpoint" + annotation(Dialog(group="Temperature setpoints")); + parameter Modelica.Units.SI.Temperature THeaWatConSup_nominal( + displayUnit="degC", + start=Buildings.Templates.Data.Defaults.THeaWatSup, + final min=273.15) + "Design (highest) HW supply temperature setpoint for condensing boilers" + annotation(Dialog(group="Temperature setpoints", enable=have_boiCon and have_boiNon)); + parameter Modelica.Units.SI.Temperature TOutLck( + displayUnit="degC", + final min=273.15)=Buildings.Templates.Data.Defaults.TOutBoiLck + "Outdoor air lockout temperature above which the plant is prevented from operating" + annotation(Dialog(group="Temperature setpoints", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatBoiCon_flow_nominal[nBoiCon]( + start=fill(0.1, nBoiCon), + displayUnit=fill("L/s", nBoiCon), + final min=fill(0, nBoiCon)) + "Design HW volume flow rate - Each condensing boiler" + annotation(Dialog(group="Boiler flow setpoints", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiCon and have_valHeaWatMinBypCon)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatBoiCon_flow_min[nBoiCon]( + start=fill(0.1, nBoiCon), + displayUnit=fill("L/s", nBoiCon), + final min=fill(0, nBoiCon)) + "Minimum HW volume flow rate - Each condensing boiler" + annotation(Dialog(group="Boiler flow setpoints", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiCon)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatBoiNon_flow_nominal[nBoiNon]( + start=fill(0.1, nBoiNon), + displayUnit=fill("L/s", nBoiNon), + final min=fill(0, nBoiNon)) + "Design HW volume flow rate - Each non-condensing boiler" + annotation(Dialog(group="Boiler flow setpoints", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiNon + and have_valHeaWatMinBypNon)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatBoiNon_flow_min[nBoiNon]( + start=fill(0.1, nBoiNon), + displayUnit=fill("L/s", nBoiNon), + final min=fill(0, nBoiNon)) + "Minimum HW volume flow rate - Each non-condensing boiler" + annotation(Dialog(group="Boiler flow setpoints", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiNon)); + parameter Real ratFirBoiCon_min[nBoiCon]( + start=fill(0.2, nBoiCon), + final unit=fill("1", nBoiCon)) + "Boiler minimum firing rate before cycling" + annotation(Dialog(group="Minimum boiler firing rate", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiCon)); + parameter Real ratFirBoiNon_min[nBoiNon]( + start=fill(0.2, nBoiNon), + final unit=fill("1", nBoiNon)) + "Boiler minimum firing rate before cycling" + annotation(Dialog(group="Minimum boiler firing rate", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiCon)); + parameter Modelica.Units.SI.HeatFlowRate capBoiCon_nominal[nBoiCon]( + start=fill(1, nBoiCon), + final min=fill(0, nBoiCon)) + "Design capacity - Each condensing boiler" + annotation(Dialog(group="Capacity", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + parameter Modelica.Units.SI.HeatFlowRate capBoiNon_nominal[nBoiNon]( + start=fill(1, nBoiNon), + final min=fill(0, nBoiNon)) + "Design capacity - Each non-condensing boiler" + annotation(Dialog(group="Capacity", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatPriCon_flow_nominal( + start=0.01, + displayUnit="L/s", + final min=0) + "Design primary HW volume flow rate - Condensing boilers" + annotation(Dialog(group="Capacity", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiCon and + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None and + have_varPumHeaWatPriCon and typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatPriNon_flow_nominal( + start=0.01, + displayUnit="L/s", + final min=0) + "Design primary HW volume flow rate - Non-condensing boilers" + annotation(Dialog(group="Capacity", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_boiNon and + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None and + have_varPumHeaWatPriNon and typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatSec_flow_nominal( + start=0.01, + displayUnit="L/s", + final min=0) + "Design secondary HW volume flow rate" + annotation(Dialog(group="Capacity", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None and + have_senVHeaWatSec)); + + parameter Modelica.Units.SI.PressureDifference dpHeaWatRemSet_nominal[nSenDpHeaWatRem]( + start=fill(Buildings.Templates.Data.Defaults.dpHeaWatSet_max, nSenDpHeaWatRem), + final min=fill(0, nSenDpHeaWatRem)) + "Design (maximum) HW differential pressure setpoint - Remote sensor" + annotation(Dialog(group="Information provided by testing, adjusting, and balancing contractor", + enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + ((have_varPumHeaWatPriCon or have_varPumHeaWatPriNon) and + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None or + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None))); + parameter Modelica.Units.SI.PressureDifference dpHeaWatLocSet_nominal( + start=Buildings.Templates.Data.Defaults.dpHeaWatLocSet_max, + final min=0) + "Design (maximum) HW differential pressure setpoint - Local sensor" + annotation(Dialog(group="Information provided by testing, adjusting, and balancing contractor", + enable=typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_senDpHeaWatLoc)); + parameter Real yPumHeaWatPri_min( + final unit="1", + final min=0, + final max=1)=0.1 + "Primary HW pump minimum speed" + annotation(Dialog(group="Information provided by testing, adjusting, and balancing contractor", + enable=typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + (have_varPumHeaWatPriCon or have_varPumHeaWatPriNon) and + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None)); + parameter Real yPumHeaWatSec_min( + final unit="1", + final min=0, + final max=1)=0.1 + "Secondary HW pump minimum speed" + annotation(Dialog(group="Information provided by testing, adjusting, and balancing contractor", + enable=typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None)); + parameter Real yPumHeaWatPriSta_min[nSta]( + each final unit="1", + each final min=0, + each final max=1, + each start=0.3) + "Primary HW pump speed delivering minimum flow through boilers - Each plant stage" + annotation(Dialog(group="Information provided by testing, adjusting, and balancing contractor", + enable=typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + (have_varPumHeaWatPriCon or have_varPumHeaWatPriNon) and + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None)); + + // FIXME: How are interchangeable units (lead/lag alternated) specified? + parameter Integer sta[:, nBoiCon + nBoiNon]( + each final min=0, + each final max=1) + "Staging matrix with plant stage as row index and boiler as column index (starting with condensing boilers): 0 for disabled, 1 for enabled" + annotation (Dialog(group="Plant staging")); + final parameter Integer nSta(start=1) = size(sta, 1) + "Number of plant stages" + annotation (Evaluate=true, Dialog(group="Plant staging")); + + annotation ( + defaultComponentName="datCtl", + Documentation(info=" +

+This record provides the set of sizing and operating parameters for +HW plant controllers that can be found within + +Buildings.Templates.HeatingPlants.HotWater.Components.Controls. +

+

+For hybrid plants, units shall be indexed so that condensing boilers have the +lowest indices and non-condensing boilers have the highest indices. +

+")); +end Controller; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Data/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/package.mo new file mode 100644 index 00000000000..c1ab0af4cb4 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components; +package Data "Records for design and operating parameters" + extends Modelica.Icons.MaterialPropertiesPackage; + annotation (Documentation(info=" +

+This package provides records for design and operating parameters. +

+")); +end Data; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Data/package.order b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/package.order new file mode 100644 index 00000000000..dce44713d13 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Data/package.order @@ -0,0 +1,2 @@ +BoilerGroup +Controller diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/PartialController.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/PartialController.mo new file mode 100644 index 00000000000..968a315282a --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/PartialController.mo @@ -0,0 +1,294 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Interfaces; +block PartialController + parameter Buildings.Templates.HeatingPlants.HotWater.Types.Controller typ + "Type of controller" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_boiCon + "Set to true if the plant includes condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_boiNon + "Set to true if the plant includes non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Integer nBoiCon(start=0, final min=0) + "Number of condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiCon)); + parameter Integer nBoiNon(start=0, final min=0) + "Number of non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiNon)); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary typPumHeaWatPriCon( + start=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable) + "Type of primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiCon)); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary typPumHeaWatPriNon( + start=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable) + "Type of primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiNon)); + final parameter Boolean have_varPumHeaWatPriCon= + typPumHeaWatPriCon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable or + typPumHeaWatPriCon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable + "Set to true for variable speed primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + final parameter Boolean have_varPumHeaWatPriNon= + typPumHeaWatPriNon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable or + typPumHeaWatPriNon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable + "Set to true for variable speed primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary typPumHeaWatSec + "Type of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Integer nPumHeaWatPriCon=nBoiCon + "Number of primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiCon)); + parameter Integer nPumHeaWatPriNon=nBoiNon + "Number of primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiNon)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriCon( + start=Buildings.Templates.Components.Types.PumpArrangement.Headered) + "Type of primary HW pump arrangement - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiCon)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriNon( + start=Buildings.Templates.Components.Types.PumpArrangement.Headered) + "Type of primary HW pump arrangement - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=have_boiNon)); + parameter Integer nPumHeaWatSec(start=0) + "Number of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None)); + parameter Boolean have_valHeaWatMinBypCon + "Set to true if the plant has a HW minimum flow bypass valve - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_valHeaWatMinBypNon + "Set to true if the plant has a HW minimum flow bypass valve - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + + parameter Integer nAirHan( + final min=if typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 + and nEquZon==0 then 1 else 0, + start=0) + "Number of air handling units served by the plant" + annotation(Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + parameter Integer nEquZon( + final min=if typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + nAirHan==0 then 1 else 0, + start=0) + "Number of terminal units (zone equipment) served by the plant" + annotation(Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement typMeaCtlHeaWatPri( + start=Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.TemperatureSupplySensor) + "Type of sensors for variable speed primary pumps control in primary-secondary plants" + annotation (Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None and + (have_varPumHeaWatPriCon or have_varPumHeaWatPriNon))); + + final parameter Boolean have_senVHeaWatPriCon= + have_boiCon and ( + if have_varPumHeaWatPriCon and + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then + typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDifference + else typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None) + "Set to true for primary HW flow sensor - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + final parameter Boolean have_senVHeaWatPriNon= + have_boiNon and ( + if have_varPumHeaWatPriNon and + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then + typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDifference + else typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None) + "Set to true for primary HW flow sensor - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation locSenVHeaWatPri= + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return + "Location of primary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_senVHeaWatPriCon or have_senVHeaWatPriNon)); + final parameter Boolean have_senVHeaWatSec= + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None and + typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDifference + "Set to true for secondary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation locSenVHeaWatSec= + Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return + "Location of secondary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 and + have_senVHeaWatSec)); + + final parameter Boolean have_senTHeaWatPriSupCon= + have_boiCon and ( + if typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then + typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.TemperatureSupplySensor + else have_varPumHeaWatPriCon) + "Set to true for primary HW supply temperature sensor - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + final parameter Boolean have_senTHeaWatPriSupNon= + have_boiNon and ( + if typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then + typMeaCtlHeaWatPri==Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.TemperatureSupplySensor + else have_varPumHeaWatPriNon) + "Set to true for primary HW supply temperature sensor - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + + final parameter Boolean have_senTHeaWatPlaRetCon= + have_boiCon and typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "Set to true for plant HW return temperature sensor - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + final parameter Boolean have_senTHeaWatPlaRetNon=have_boiNon + "Set to true for plant HW return temperature sensor - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration")); + + final parameter Boolean have_senTHeaWatSecSup= + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "Set to true for secondary HW supply temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + + final parameter Boolean have_senTHeaWatSecRet= + typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "Set to true for secondary HW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + + parameter Boolean have_senDpHeaWatLoc=false + "Set to true for local HW differential pressure sensor hardwired to plant or pump controller" + annotation (Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + parameter Integer nSenDpHeaWatRem( + final min=if typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36 + then 1 else 0)=1 + "Number of remote HW differential pressure sensors used for HW pump speed control" + annotation (Evaluate=true, Dialog(group="Configuration", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Controller.Guideline36)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Data.Controller dat( + final typ=typ, + final have_boiCon=have_boiCon, + final have_boiNon=have_boiNon, + final nBoiCon=nBoiCon, + final nBoiNon=nBoiNon, + final have_varPumHeaWatPriCon=have_varPumHeaWatPriCon, + final have_varPumHeaWatPriNon=have_varPumHeaWatPriNon, + final typArrPumHeaWatPriCon=typArrPumHeaWatPriCon, + final typArrPumHeaWatPriNon=typArrPumHeaWatPriNon, + final typPumHeaWatSec=typPumHeaWatSec, + final nPumHeaWatPriCon=nPumHeaWatPriCon, + final nPumHeaWatPriNon=nPumHeaWatPriNon, + final nPumHeaWatSec=nPumHeaWatSec, + final have_valHeaWatMinBypCon=have_valHeaWatMinBypCon, + final have_valHeaWatMinBypNon=have_valHeaWatMinBypNon, + final have_senDpHeaWatLoc=have_senDpHeaWatLoc, + final nSenDpHeaWatRem=nSenDpHeaWatRem, + final have_senVHeaWatSec=have_senVHeaWatSec) + "Parameter record for controller"; + + Buildings.Templates.HeatingPlants.HotWater.Interfaces.Bus bus + "Plant control bus" annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={-260,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={-100,0}))); + Buildings.Templates.AirHandlersFans.Interfaces.Bus busAirHan[nAirHan] + if nAirHan>0 + "Air handling unit control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={260,140}), iconTransformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,60}))); + Buildings.Templates.ZoneEquipment.Interfaces.Bus busEquZon[nEquZon] + if nEquZon>0 + "Terminal unit control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={260,-140}), + iconTransformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,-60}))); + +protected + Buildings.Templates.Components.Interfaces.Bus busBoiCon[nBoiCon] + if have_boiCon "Boiler control bus - Condensing boilers" annotation ( + Placement(transformation(extent={{-260,140},{-220,180}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busBoiNon[nBoiNon] if have_boiNon + "Boiler control bus - Non-condensing boilers" + annotation (Placement(transformation(extent={{-180,140},{-140,180}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValBoiConIso[nBoiCon] + if have_boiCon "Boiler isolation valve control bus - Condensing boilers" + annotation (Placement(transformation(extent={{-260,100},{-220,140}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValBoiNonIso[nBoiNon] if have_boiNon + "Boiler isolation valve control bus - Non-condensing boilers" + annotation (Placement(transformation(extent={{-180,100},{-140,140}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatPriCon + if have_boiCon "Primary HW pump control bus - Condensing boilers" + annotation (Placement(transformation(extent={{-260,60},{-220,100}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatPriNon if have_boiNon + "Primary HW pump control bus - Condensing boilers" + annotation (Placement(transformation(extent={{-180,60},{-140,100}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatSec + if typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Secondary HW pump control bus" + annotation (Placement(transformation(extent={{-220,-60},{-180,-20}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValHeaWatMinByp + if have_valHeaWatMinBypCon or have_valHeaWatMinBypNon + "HW minimum flow bypass valve control bus" + annotation (Placement(transformation(extent={{-220,20},{-180,60}}), + iconTransformation(extent={{-466,50},{-426,90}}))); +equation + connect(busBoiCon, bus.boiCon) annotation (Line( + points={{-240,160},{-220,160},{-220,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busValBoiConIso, bus.valBoiConIso) annotation (Line( + points={{-240,120},{-220,120},{-220,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busPumHeaWatPriCon, bus.pumHeaWatPriCon) annotation (Line( + points={{-240,80},{-220,80},{-220,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busPumHeaWatSec, bus.pumHeaWatSec) annotation (Line( + points={{-200,-40},{-200,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busPumHeaWatPriNon, bus.pumHeaWatPriNon) annotation (Line( + points={{-160,80},{-180,80},{-180,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busValBoiNonIso, bus.valBoiNonIso) annotation (Line( + points={{-160,120},{-180,120},{-180,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busBoiNon, bus.boiNon) annotation (Line( + points={{-160,160},{-180,160},{-180,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busValHeaWatMinByp, bus.valHeaWatMinByp) annotation (Line( + points={{-200,40},{-200,0},{-260,0}}, + color={255,204,51}, + thickness=0.5)); + annotation (Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false, extent={{-260,-380},{260,380}})), + Documentation(info=" +

+This partial class provides a standard interface for boiler plant controllers. +

+", revisions=" + +")); +end PartialController; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/package.mo new file mode 100644 index 00000000000..f56eac414bd --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components; +package Interfaces "Interface classes" + extends Modelica.Icons.InterfacesPackage; + annotation (Documentation(info=" +

+This package contains interface classes. +

+")); +end Interfaces; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/package.order b/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/package.order new file mode 100644 index 00000000000..d2438eaafd8 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Interfaces/package.order @@ -0,0 +1 @@ +PartialController diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mo new file mode 100644 index 00000000000..22533b6f6f4 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mo @@ -0,0 +1,187 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Validation; +model BoilerGroupPolynomial "Validation model for boiler group" + extends Modelica.Icons.Example; + + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium"; + + parameter Integer nBoi(final min=0) = 3 + "Number of boilers"; + final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal= + sum(datBoi.mHeaWatBoi_flow_nominal) + "HW mass flow rate" + annotation (Dialog(group="Nominal condition")); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Data.BoilerGroup datBoi( + final typMod=boi.typMod, + final nBoi=nBoi, + fue=Buildings.Fluid.Data.Fuels.NaturalGasLowerHeatingValue(), + mHeaWatBoi_flow_nominal=datBoi.capBoi_nominal/ + (Buildings.Templates.Data.Defaults.THeaWatSup - Buildings.Templates.Data.Defaults.THeaWatRet) / + Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + capBoi_nominal=fill(1000E3, nBoi), + dpHeaWatBoi_nominal=fill(Buildings.Templates.Data.Defaults.dpHeaWatBoi, nBoi), + THeaWatBoiSup_nominal=fill(Buildings.Templates.Data.Defaults.THeaWatSup, nBoi)) + "Design and operating parameters" + annotation (Placement(transformation(extent={{100,100},{120,120}}))); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumHeaWatPri( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nBoi, + final m_flow_nominal=fill(mHeaWat_flow_nominal/datPumHeaWatPri.nPum, datPumHeaWatPri.nPum), + dp_nominal=datBoi.dpHeaWatBoi_nominal .+ + Buildings.Templates.Data.Defaults.dpValChe .+ + Buildings.Templates.Data.Defaults.dpValIso) + "Parameter record for primary HW pumps" + annotation (Placement(transformation(extent={{100,60},{120,80}}))); + parameter Modelica.Units.SI.Time tau=10 + "Time constant at nominal flow" + annotation (Dialog(tab="Dynamics", group="Nominal condition")); + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.FixedInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab = "Dynamics", group="Conservation equations")); + + Buildings.Templates.HeatingPlants.HotWater.Components.BoilerGroup boi( + redeclare final package Medium=Medium, + final nBoi=nBoi, + typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial, + final is_con=true, + typArrPumHeaWatPri=Buildings.Templates.Components.Types.PumpArrangement.Headered, + final dat=datBoi, + final energyDynamics=energyDynamics) + "Boiler group" + annotation (Placement(transformation(extent={{-120,-100},{-40,20}}))); + Buildings.Templates.Components.Pumps.Multiple pumHeaWatPri( + have_var=false, + have_valChe=true, + final nPum=nBoi, + final dat=datPumHeaWatPri, + final energyDynamics=energyDynamics, + final tau=tau) + "Primary HW pumps" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Templates.Components.Routing.MultipleToMultiple inlPumHeaWatPri( + redeclare final package Medium=Medium, + final nPorts_a=nBoi, + final have_comLeg=boi.typArrPumHeaWatPri==Buildings.Templates.Components.Types.PumpArrangement.Headered, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics) + "Primary HW pumps inlet manifold" + annotation (Placement(transformation(extent={{-30,-10},{-10,10}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumHeaWatPri( + redeclare final package Medium=Medium, + final nPorts=nBoi, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics) + "Primary HW pumps outlet manifold" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + Fluid.Sensors.TemperatureTwoPort THeaWatSup( + redeclare final package Medium=Medium, + final m_flow_nominal=mHeaWat_flow_nominal) + "HW supply temperature" + annotation (Placement(transformation(extent={{60,-10},{80,10}}))); + Fluid.Sensors.MassFlowRate mHeaWat_flow( + redeclare final package Medium=Medium) "HW mass flow rate" + annotation (Placement(transformation(extent={{90,-10},{110,10}}))); + Fluid.Sources.Boundary_pT bouHeaWat( + redeclare final package Medium = Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_min, + T=Buildings.Templates.Data.Defaults.THeaWatRet, + nPorts=2) "Boundary conditions for HW distribution system" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}, + rotation=-90, + origin={60,-100}))); + Fluid.Sensors.TemperatureTwoPort THeaWatRet( + redeclare final package Medium =Medium, + final m_flow_nominal=mHeaWat_flow_nominal) + "HW return temperature" + annotation (Placement(transformation(extent={{30,-90},{10,-70}}))); + Buildings.Templates.Components.Routing.SingleToMultiple inlBoi( + redeclare final package Medium = Medium, + final nPorts=nBoi, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics) + "Boiler group inlet manifold" + annotation (Placement(transformation(extent={{-10,-90},{-30,-70}}))); + Controls.OpenLoop ctl( + final have_boiCon=true, + final have_boiNon=false, + final nBoiCon=nBoi, + final nBoiNon=0, + final typPumHeaWatPriCon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable, + final typArrPumHeaWatPriCon=boi.typArrPumHeaWatPri, + final typPumHeaWatSec=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None, + have_valHeaWatMinBypCon=false, + have_valHeaWatMinBypNon=false, + dat( + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSup, + sta={fill(0, nBoi)})) + "Controller" + annotation (Placement(transformation(extent={{-10,110},{10,130}}))); + + Buildings.Templates.HeatingPlants.HotWater.Interfaces.Bus busPla + "Plant control bus" + annotation (Placement(transformation(extent={{-100,60},{-60,100}}), + iconTransformation(extent={{-310,60},{-270,100}}))); + +equation + connect(inlPumHeaWatPri.ports_b, pumHeaWatPri.ports_a) + annotation (Line(points={{-10,0},{0,0}}, color={0,127,255})); + connect(boi.ports_bHeaWat, inlPumHeaWatPri.ports_a) + annotation (Line(points={{-40,2.85714},{-36,2.85714},{-36,0},{-30,0}}, + color={0,127,255})); + connect(outPumHeaWatPri.port_b, THeaWatSup.port_a) + annotation (Line(points={{50,0},{60,0}}, color={0,127,255})); + connect(THeaWatSup.port_b, mHeaWat_flow.port_a) + annotation (Line(points={{80,0},{90,0}}, color={0,127,255})); + connect(inlBoi.ports_b, boi.ports_aHeaWat) + annotation (Line(points={{-30,-80},{-36,-80},{-36,-82.8571},{-40,-82.8571}}, + color={0,127,255})); + connect(THeaWatRet.port_b, inlBoi.port_a) + annotation (Line(points={{10,-80},{-10,-80}}, color={0,127,255})); + connect(ctl.bus, busPla) annotation (Line( + points={{-10,120},{-80,120},{-80,80}}, + color={255,204,51}, + thickness=0.5)); + connect(pumHeaWatPri.ports_b, outPumHeaWatPri.ports_a) + annotation (Line(points={{20,0},{30,0}}, color={0,127,255})); + connect(mHeaWat_flow.port_b, bouHeaWat.ports[1]) annotation (Line(points={{110,0}, + {120,0},{120,-80},{59,-80},{59,-90}}, color={0,127,255})); + connect(bouHeaWat.ports[2], THeaWatRet.port_a) annotation (Line(points={{61,-90}, + {61,-80},{30,-80}}, color={0,127,255})); + connect(busPla, boi.bus) annotation (Line( + points={{-80,80},{-80,20}}, + color={255,204,51}, + thickness=0.5)); + connect(busPla.pumHeaWatPriCon, pumHeaWatPri.bus) annotation (Line( + points={{-80,80},{10,80},{10,10}}, + color={255,204,51}, + thickness=0.5)); + annotation ( + Diagram(coordinateSystem(extent={{-140,-140},{140,140}})), + experiment( + StopTime=2000, + Tolerance=1e-06), + __Dymola_Commands(file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupPolynomial.mos" + "Simulate and plot"), + Documentation(info=" +

+This model validates the boiler group model + +Buildings.Templates.HeatingPlants.HotWater.Components.BoilerGroup +in the case where a polynomial is used to represent the boiler efficiency. +The HW supply temperature setpoint, the HW return temperature and the +primary HW pump speed are fixed at their design value when the boilers are +enabled. +

+

+The model illustrates a bug in Dymola (#SR01004314-01). +The parameter bindings for pumHeaWatPri.dat are not properly interpreted +and the start value is used for all those parameters without any warning being issued. +Hence, the total HW flow rate differs from its design value. +OCT properly propagates the parameter values from the composite component binding. +

+")); +end BoilerGroupPolynomial; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mo new file mode 100644 index 00000000000..86876b9bf3f --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mo @@ -0,0 +1,32 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components.Validation; +model BoilerGroupTable "Validation model for boiler group" + extends Buildings.Templates.HeatingPlants.HotWater.Components.Validation.BoilerGroupPolynomial( + boi(typMod=Buildings.Templates.Components.Types.BoilerHotWaterModel.Table)); + annotation ( + Diagram(coordinateSystem(extent={{-220,-220},{220,220}})), + experiment( + StopTime=2000, + Tolerance=1e-06), + __Dymola_Commands(file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/HeatingPlants/HotWater/Components/Validation/BoilerGroupTable.mos" + "Simulate and plot"), + Documentation(info=" +

+This model validates the boiler group model + +Buildings.Templates.HeatingPlants.HotWater.Components.BoilerGroup +in the case where a lookup table is used to represent the boiler efficiency. +The HW supply temperature setpoint, the HW return temperature and the +primary HW pump speed are fixed at their design value when the boilers are +enabled. +

+

+The model illustrates a bug in Dymola (#SR01004314-01). +The parameter bindings for pumHeaWatPri.dat are not properly interpreted +and the start value is used for all those parameters without any warning being issued. +Hence, the total HW flow rate differs from its design value. +OCT properly propagates the parameter values from the composite component binding. +

+")); + +end BoilerGroupTable; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/package.mo new file mode 100644 index 00000000000..f33755e12f3 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/package.mo @@ -0,0 +1,12 @@ +within Buildings.Templates.HeatingPlants.HotWater.Components; +package Validation "Package with validation models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info=" +

+This package contains validation models for the classes within + +Buildings.Templates.HeatingPlants.HotWater.Components. +

+")); +end Validation; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/package.order b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/package.order new file mode 100644 index 00000000000..dd4566c1fb5 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/Validation/package.order @@ -0,0 +1,2 @@ +BoilerGroupPolynomial +BoilerGroupTable diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Components/package.mo new file mode 100644 index 00000000000..26773e61981 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/package.mo @@ -0,0 +1,13 @@ +within Buildings.Templates.HeatingPlants.HotWater; +package Components "Package with component models" + extends Modelica.Icons.VariantsPackage; + + annotation (Documentation(info=" +

+This package contains component models that are used in the templates +within + +Buildings.Templates.HeatingPlants.HotWater. +

+")); +end Components; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Components/package.order b/Buildings/Templates/HeatingPlants/HotWater/Components/package.order new file mode 100644 index 00000000000..9de18d36d82 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Components/package.order @@ -0,0 +1,5 @@ +BoilerGroup +Controls +Data +Validation +Interfaces diff --git a/Buildings/Templates/HeatingPlants/HotWater/Data/BoilerPlant.mo b/Buildings/Templates/HeatingPlants/HotWater/Data/BoilerPlant.mo new file mode 100644 index 00000000000..e6d57912ef8 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Data/BoilerPlant.mo @@ -0,0 +1,174 @@ +within Buildings.Templates.HeatingPlants.HotWater.Data; +record BoilerPlant "Record for HW plant model" + extends Modelica.Icons.Record; + + parameter Boolean have_boiCon + "Set to true if the plant includes condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_boiNon + "Set to true if the plant includes non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nBoiCon + "Number of condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nBoiNon + "Number of non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.BoilerHotWaterModel typMod + "Type of boiler model" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary typPumHeaWatSec + "Type of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nPumHeaWatPriCon + "Number of primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nPumHeaWatPriNon + "Number of primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nPumHeaWatSec + "Number of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_valHeaWatMinBypCon + "Set to true if the condensing boiler group has a HW minimum flow bypass valve" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_valHeaWatMinBypNon + "Set to true if the non-condensing boiler group has a HW minimum flow bypass valve" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_senDpHeaWatLoc + "Set to true for local HW differential pressure sensor hardwired to plant controller" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Integer nSenDpHeaWatRem + "Number of remote HW differential pressure sensors used for HW pump speed control" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_senVHeaWatSec + "Set to true if secondary loop is equipped with a flow meter" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriCon + "Type of primary HW pump arrangement - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriNon + "Type of primary HW pump arrangement - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_varPumHeaWatPriCon + "Set to true for variable speed primary HW pumps - Condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean have_varPumHeaWatPriNon + "Set to true for variable speed primary HW pumps - Non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.Controller typCtl + "Type of controller" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.Density rho_default= + Modelica.Media.Water.ConstantPropertyLiquidWater.d_const + "HW default density" + annotation(Dialog(enable=false)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Data.Controller ctl( + final typ=typCtl, + final have_boiCon=have_boiCon, + final have_boiNon=have_boiNon, + final nBoiCon=nBoiCon, + final nBoiNon=nBoiNon, + final nPumHeaWatPriCon=nPumHeaWatPriCon, + final nPumHeaWatPriNon=nPumHeaWatPriNon, + final have_varPumHeaWatPriCon=have_varPumHeaWatPriCon, + final have_varPumHeaWatPriNon=have_varPumHeaWatPriNon, + final typPumHeaWatSec=typPumHeaWatSec, + final nPumHeaWatSec=nPumHeaWatSec, + final have_valHeaWatMinBypCon=have_valHeaWatMinBypCon, + final have_valHeaWatMinBypNon=have_valHeaWatMinBypNon, + final have_senDpHeaWatLoc=have_senDpHeaWatLoc, + final nSenDpHeaWatRem=nSenDpHeaWatRem, + final have_senVHeaWatSec=have_senVHeaWatSec, + final typArrPumHeaWatPriCon=typArrPumHeaWatPriCon, + final typArrPumHeaWatPriNon=typArrPumHeaWatPriNon) + "Controller" + annotation(Dialog(group="Controls")); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Data.BoilerGroup boiCon( + final nBoi=nBoiCon, + final typMod=typMod, + capBoi_nominal=ctl.capBoiCon_nominal, + THeaWatBoiSup_nominal=fill(if have_boiCon and have_boiNon then ctl.THeaWatConSup_nominal + else ctl.THeaWatSup_nominal, nBoiCon)) + "Condensing boilers" + annotation(Dialog(group="Boilers", enable=have_boiCon)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Components.Data.BoilerGroup boiNon( + final nBoi=nBoiNon, + final typMod=typMod, + capBoi_nominal=ctl.capBoiNon_nominal, + THeaWatBoiSup_nominal=fill(ctl.THeaWatSup_nominal, nBoiNon)) + "Non-condensing boilers" + annotation(Dialog(group="Boilers", enable=have_boiNon)); + + parameter Buildings.Templates.Components.Data.PumpMultiple pumHeaWatPriCon( + final nPum=nPumHeaWatPriCon, + final rho_default=rho_default, + final typ=if have_boiCon then Buildings.Templates.Components.Types.Pump.Multiple + else Buildings.Templates.Components.Types.Pump.None, + m_flow_nominal=fill(if have_boiCon then sum(boiCon.mHeaWatBoi_flow_nominal) / + max(nPumHeaWatPriCon, 1) else 0, nPumHeaWatPriCon)) + "Primary HW pumps - Condensing boilers" + annotation(Dialog(group="Primary HW loop", enable=have_boiCon)); + parameter Buildings.Templates.Components.Data.PumpMultiple pumHeaWatPriNon( + final nPum=nPumHeaWatPriNon, + final rho_default=rho_default, + final typ=if have_boiNon then Buildings.Templates.Components.Types.Pump.Multiple + else Buildings.Templates.Components.Types.Pump.None, + m_flow_nominal=fill(if have_boiNon then sum(boiNon.mHeaWatBoi_flow_nominal) / + max(nPumHeaWatPriNon, 1) else 0, nPumHeaWatPriNon)) + "Primary HW pumps - Non-condensing boilers" + annotation(Dialog(group="Primary HW loop", enable=have_boiNon)); + parameter Buildings.Templates.Components.Data.Valve valHeaWatMinBypCon( + final typ=Buildings.Templates.Components.Types.Valve.TwoWayModulating, + m_flow_nominal= + if have_valHeaWatMinBypCon then max(ctl.VHeaWatBoiCon_flow_min) * rho_default + else 0, + dpValve_nominal=Buildings.Templates.Data.Defaults.dpValBypMin) + "HW minimum flow bypass valve - Condensing boilers" + annotation(Dialog(group="Primary HW loop", enable=have_valHeaWatMinBypCon)); + parameter Buildings.Templates.Components.Data.Valve valHeaWatMinBypNon( + final typ=Buildings.Templates.Components.Types.Valve.TwoWayModulating, + m_flow_nominal= + if have_valHeaWatMinBypNon then max(ctl.VHeaWatBoiNon_flow_min) * rho_default + else 0, + dpValve_nominal=Buildings.Templates.Data.Defaults.dpValBypMin) + "HW minimum flow bypass valve - Non-condensing boilers" + annotation(Dialog(group="Primary HW loop", enable=have_valHeaWatMinBypNon)); + + parameter Buildings.Templates.Components.Data.PumpMultiple pumHeaWatSec( + final nPum=nPumHeaWatSec, + final rho_default=rho_default, + final typ=if typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + then Buildings.Templates.Components.Types.Pump.Multiple + else Buildings.Templates.Components.Types.Pump.None) + "Secondary HW pumps" + annotation(Dialog(group="Secondary HW loop", + enable=typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized)); + + annotation ( + defaultComponentName="dat", + Documentation(info=" +

+This record provides the set of sizing and operating parameters for +the boiler plant model + +Buildings.Templates.HeatingPlants.HotWater.BoilerPlant. +

+

+Most of the parameters should be assigned through the sub-record +dedicated to the controller. +All parameters that are also needed to parameterize other plant +components are propagated from the controller sub-record +to the corresponding equipment sub-records. +Note that those parameter bindings are not final so they may be +overwritten in case a component is parameterized at nominal +conditions that differ from the design conditions specified +in the controller sub-record. +

+")); + +end BoilerPlant; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Data/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Data/package.mo new file mode 100644 index 00000000000..1064ba2d9be --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Data/package.mo @@ -0,0 +1,10 @@ +within Buildings.Templates.HeatingPlants.HotWater; +package Data "Records for design and operating parameters" + extends Modelica.Icons.MaterialPropertiesPackage; + + annotation (Documentation(info=" +

+This package provides records for design and operating parameters. +

+")); +end Data; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Data/package.order b/Buildings/Templates/HeatingPlants/HotWater/Data/package.order new file mode 100644 index 00000000000..52bc0217dee --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Data/package.order @@ -0,0 +1 @@ +BoilerPlant diff --git a/Buildings/Templates/HeatingPlants/HotWater/Interfaces/Bus.mo b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/Bus.mo new file mode 100644 index 00000000000..db93fb03275 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/Bus.mo @@ -0,0 +1,14 @@ +within Buildings.Templates.HeatingPlants.HotWater.Interfaces; +expandable connector Bus "Control bus for HW plant" + extends Modelica.Icons.SignalBus; + + annotation ( + defaultComponentName="bus", Documentation(info=" +

+This expandable connector provides a standard interface for +all control signals of the hot water plant models within + +Buildings.Templates.HeatingPlants.HotWater. +

+")); +end Bus; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Interfaces/PartialBoilerPlant.mo b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/PartialBoilerPlant.mo new file mode 100644 index 00000000000..bce1292ab3e --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/PartialBoilerPlant.mo @@ -0,0 +1,478 @@ +within Buildings.Templates.HeatingPlants.HotWater.Interfaces; +partial model PartialBoilerPlant + "Interface class for HW boiler plant" + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium"; + + parameter Buildings.Templates.HeatingPlants.HotWater.Types.Boiler typ + "Type of boilers" + annotation (Evaluate=true, Dialog(group="Boilers")); + parameter Buildings.Templates.Components.Types.BoilerHotWaterModel typMod= + Buildings.Templates.Components.Types.BoilerHotWaterModel.Polynomial + "Type of boiler model" + annotation (Evaluate=true, Dialog(group="Boilers")); + + final parameter Boolean have_boiCon = + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing + or typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid + "Set to true if the plant includes condensing boilers" + annotation (Evaluate=true); + final parameter Boolean have_boiNon= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing + or typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid + "Set to true if the plant includes non-condensing boilers" + annotation (Evaluate=true); + + parameter Integer nBoiCon_select(start=0) + "Number of condensing boilers" + annotation (Evaluate=true, Dialog(group="Boilers", + enable=have_boiCon)); + parameter Integer nBoiNon_select(start=0) + "Number of non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Boilers", + enable=have_boiNon)); + final parameter Integer nBoiCon = if have_boiCon then nBoiCon_select else 0 + "Number of condensing boilers" + annotation (Evaluate=true, Dialog(group="Boilers")); + final parameter Integer nBoiNon = if have_boiNon then nBoiNon_select else 0 + "Number of non-condensing boilers" + annotation (Evaluate=true, Dialog(group="Boilers")); + + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary typPumHeaWatPriCon( + start=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable) + "Type of primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers", + enable=have_boiCon)); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary typPumHeaWatPriNon( + start=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable) + "Type of primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers", + enable=have_boiNon)); + + final parameter Boolean have_bypHeaWatFixCon= + if typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing then + typPumHeaWatSec <> Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + else true + "Set to true if the condensing boiler group has a fixed HW bypass" + annotation(Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers")); + final parameter Boolean have_bypHeaWatFixNon= + if typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing then + typPumHeaWatSec <> Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + else true + "Set to true if the non-condensing boiler group has a fixed HW bypass" + annotation(Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers")); + // FIXME: Add condition for boilers with non-zero minimum flow. + final parameter Boolean have_valHeaWatMinBypCon= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Condensing and + have_varPumHeaWatPriCon and + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "Set to true if the condensing boiler group has a HW minimum flow bypass valve" + annotation(Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers")); + // FIXME: Add condition for boilers with non-zero minimum flow. + final parameter Boolean have_valHeaWatMinBypNon= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing and + have_varPumHeaWatPriNon and + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "Set to true if the non-condensing boiler group has a HW minimum flow bypass valve" + annotation(Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers")); + + parameter Integer nPumHeaWatPriCon_select( + start=0, + final min=0)=nBoiCon + "Number of primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers", + enable=have_boiCon and + typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + final parameter Integer nPumHeaWatPriCon= + if have_boiCon then ( + if typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Headered + then nPumHeaWatPriCon_select + else nBoiCon) + else 0 + "Number of primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers")); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriCon_select( + start=Buildings.Templates.Components.Types.PumpArrangement.Headered) + "Type of primary HW pump arrangement" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers", + enable=have_boiCon and + typPumHeaWatPriCon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable and + typPumHeaWatPriCon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryConstant)); + final parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriCon= + if have_boiCon and + typPumHeaWatPriCon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable and + typPumHeaWatPriCon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryConstant + then typArrPumHeaWatPriCon_select else + Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Type of primary HW pump arrangement" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers")); + final parameter Boolean have_varPumHeaWatPriCon= + typPumHeaWatPriCon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable or + typPumHeaWatPriCon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable + "Set to true for variable speed primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Condensing boilers")); + + parameter Integer nPumHeaWatPriNon_select( + start=0, + final min=0)=nBoiNon + "Number of primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers", + enable=have_boiNon and + typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + final parameter Integer nPumHeaWatPriNon= + if have_boiNon then ( + if typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Headered + then nPumHeaWatPriNon_select + else nBoiNon) + else 0 + "Number of primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers", + enable=have_boiNon and + typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriNon_select( + start=Buildings.Templates.Components.Types.PumpArrangement.Headered) + "Type of primary HW pump arrangement" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers", + enable=have_boiNon and + typPumHeaWatPriNon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable and + typPumHeaWatPriNon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryConstant)); + final parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumHeaWatPriNon= + if have_boiNon and + typPumHeaWatPriNon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable and + typPumHeaWatPriNon<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryConstant then + typArrPumHeaWatPriNon_select else Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Type of primary HW pump arrangement" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers")); + final parameter Boolean have_varPumHeaWatPriNon= + typPumHeaWatPriNon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.FactoryVariable or + typPumHeaWatPriNon==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable + "Set to true for variable speed primary HW pumps" + annotation (Evaluate=true, Dialog(group="Primary HW loop - Non-condensing boilers")); + + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary typPumHeaWatSec1_select( + start=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None) + "Type of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Secondary HW loop", enable= + typ<>Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid), + choices( + choice=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + "No secondary pumps (primary-only)", + choice=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Variable secondary centralized")); + parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary typPumHeaWatSec2_select= + Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Type of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Secondary HW loop", enable= + typ==Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid), + choices( + choice=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Variable secondary centralized")); + final parameter Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary typPumHeaWatSec= + if typ<>Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid then typPumHeaWatSec1_select + else typPumHeaWatSec2_select + "Type of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Secondary HW loop")); + final parameter Boolean have_pumHeaWatSec= + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + "Set to true if the plant includes secondary HW pumps" + annotation(Evaluate=true, Dialog(group="Secondary HW loop")); + parameter Integer nPumHeaWatSec( + start=1, + final min=0)=if have_pumHeaWatSec then max(nBoiCon, nBoiNon) else 0 + "Number of secondary HW pumps" + annotation (Evaluate=true, Dialog(group="Secondary HW loop", + enable=have_pumHeaWatSec)); + parameter Integer nLooHeaWatSec=1 + "Number of secondary HW loops for distributed secondary distribution" + annotation (Evaluate=true, Dialog(group="Secondary HW loop", enable= + typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Distributed)); + + parameter Buildings.Templates.HeatingPlants.HotWater.Types.Controller typCtl + "Type of controller" + annotation (Evaluate=true, Dialog(group="Controls")); + parameter Integer nAirHan + "Number of air handling units served by the plant" + annotation(Evaluate=true, Dialog(group="Controls")); + parameter Integer nEquZon + "Number of terminal units (zone equipment) served by the plant" + annotation(Evaluate=true, Dialog(group="Controls")); + + // See derived class for additional bindings of parameters not defined at top-level. + parameter Buildings.Templates.HeatingPlants.HotWater.Data.BoilerPlant dat( + final have_boiCon=have_boiCon, + final have_boiNon=have_boiNon, + final nBoiCon=nBoiCon, + final nBoiNon=nBoiNon, + final typMod=typMod, + final typPumHeaWatSec=typPumHeaWatSec, + final nPumHeaWatPriCon=nPumHeaWatPriCon, + final nPumHeaWatPriNon=nPumHeaWatPriNon, + final nPumHeaWatSec=nPumHeaWatSec, + final have_valHeaWatMinBypCon=have_valHeaWatMinBypCon, + final have_valHeaWatMinBypNon=have_valHeaWatMinBypNon, + final typArrPumHeaWatPriCon=typArrPumHeaWatPriCon, + final typArrPumHeaWatPriNon=typArrPumHeaWatPriNon, + final have_varPumHeaWatPriCon=have_varPumHeaWatPriCon, + final have_varPumHeaWatPriNon=have_varPumHeaWatPriNon, + final typCtl=typCtl, + final rho_default=rho_default) + "Design and operating parameters" + annotation (Placement(transformation(extent={{-280,240},{-260,260}}))); + + final parameter Modelica.Units.SI.MassFlowRate mHeaWatPriCon_flow_nominal= + sum(dat.pumHeaWatPriCon.m_flow_nominal) + "Primary HW mass flow rate - Condensing boilers"; + final parameter Modelica.Units.SI.MassFlowRate mHeaWatPriNon_flow_nominal= + sum(dat.pumHeaWatPriNon.m_flow_nominal) + "Primary HW mass flow rate - Non-condensing boilers"; + // FIXME: How to assign HW flow in case of distributed secondary pumps? + final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal= + if typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None + then (if have_boiCon then mHeaWatPriCon_flow_nominal else mHeaWatPriNon_flow_nominal) + elseif typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized + then sum(dat.pumHeaWatSec.m_flow_nominal) + else max(mHeaWatPriCon_flow_nominal, mHeaWatPriNon_flow_nominal) + "HW mass flow rate (total, distributed to consumers)"; + final parameter Modelica.Units.SI.HeatFlowRate cap_nominal= + (if have_boiCon then sum(dat.boiCon.capBoi_nominal) else 0) + + (if have_boiNon then sum(dat.boiNon.capBoi_nominal) else 0) + "Heating capacity (total)"; + final parameter Modelica.Units.SI.Temperature THeaWatSup_nominal= + dat.ctl.THeaWatSup_nominal + "Maximum HW supply temperature"; + + parameter Modelica.Units.SI.Time tau=30 + "Time constant at nominal flow" + annotation (Dialog(tab="Dynamics", group="Nominal condition")); + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.DynamicFreeInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab = "Dynamics", group="Conservation equations")); + + parameter Boolean allowFlowReversal=true + "= true to allow flow reversal, false restricts to design direction (port_a -> port_b)" + annotation (Dialog(tab="Assumptions"), Evaluate=true); + parameter Boolean show_T = false + "= true, if actual temperature at port is computed" + annotation(Dialog(tab="Advanced",group="Diagnostics")); + + final parameter Medium.Density rho_default= + Medium.density(sta_default) + "HW default density"; + final parameter Medium.ThermodynamicState sta_default= + Medium.setState_pTX( + T=Buildings.Templates.Data.Defaults.THeaWatSup, + p=Medium.p_default, + X=Medium.X_default) + "HW default state"; + + Modelica.Fluid.Interfaces.FluidPort_a port_a( + redeclare final package Medium = Medium, + m_flow(min=if allowFlowReversal then -Modelica.Constants.inf else 0), + h_outflow(start=Medium.h_default, nominal=Medium.h_default)) + "HW return" + annotation (Placement(transformation(extent={{290,-250},{310,-230}}), + iconTransformation(extent={{192,-110},{212,-90}}))); + Modelica.Fluid.Interfaces.FluidPort_b port_b( + redeclare final package Medium = Medium, + m_flow(max=if allowFlowReversal then +Modelica.Constants.inf else 0), + h_outflow(start = Medium.h_default, nominal = Medium.h_default)) + "HW supply" + annotation (Placement(transformation(extent={{290,-10},{310,10}}), + iconTransformation(extent={{192,-10},{212,10}}))); + Buildings.Templates.HeatingPlants.HotWater.Interfaces.Bus bus + "Plant control bus" annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={-300,140}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=90, + origin={-200,100}))); + Buildings.Templates.AirHandlersFans.Interfaces.Bus busAirHan[nAirHan] + if nAirHan>0 + "Air handling unit control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={300,180}), iconTransformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={200,140}))); + Buildings.Templates.ZoneEquipment.Interfaces.Bus busEquZon[nEquZon] + if nEquZon>0 + "Terminal unit control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={300,100}), + iconTransformation(extent={{-20,-20},{20,20}}, + rotation=-90, + origin={202,60}))); + + Modelica.Units.SI.MassFlowRate m_flow(start=_m_flow_start)=port_a.m_flow + "Mass flow rate from port_a to port_b (m_flow > 0 is design flow direction)"; + + Modelica.Units.SI.PressureDifference dp( + start=_dp_start, + displayUnit="Pa")=port_a.p - port_b.p + "Pressure difference between port_a and port_b"; + + Medium.ThermodynamicState sta_a= + if allowFlowReversal then + Medium.setState_phX(port_a.p, + noEvent(actualStream(port_a.h_outflow)), + noEvent(actualStream(port_a.Xi_outflow))) + else + Medium.setState_phX(port_a.p, + noEvent(inStream(port_a.h_outflow)), + noEvent(inStream(port_a.Xi_outflow))) + if show_T "Medium properties in port_a"; + + Medium.ThermodynamicState sta_b= + if allowFlowReversal then + Medium.setState_phX(port_b.p, + noEvent(actualStream(port_b.h_outflow)), + noEvent(actualStream(port_b.Xi_outflow))) + else + Medium.setState_phX(port_b.p, + noEvent(port_b.h_outflow), + noEvent(port_b.Xi_outflow)) + if show_T "Medium properties in port_b"; + +protected + final parameter Modelica.Units.SI.MassFlowRate _m_flow_start=0 + "Start value for m_flow, used to avoid a warning if not set in m_flow, and to avoid m_flow.start in parameter window"; + final parameter Modelica.Units.SI.PressureDifference _dp_start( + displayUnit="Pa")=0 + "Start value for dp, used to avoid a warning if not set in dp, and to avoid dp.start in parameter window"; + +initial equation + if have_boiCon and typArrPumHeaWatPriCon==Buildings.Templates.Components.Types.PumpArrangement.Dedicated then + assert(nPumHeaWatPriCon==nBoiCon, + "In " + getInstanceName() + ": " + + "In case of dedicated pumps, the number of primary HW pumps (=" + + String(nPumHeaWatPriCon) + ") must be equal to the number of boilers (=" + + String(nBoiCon) + ")."); + end if; + if have_boiNon and typArrPumHeaWatPriNon==Buildings.Templates.Components.Types.PumpArrangement.Dedicated then + assert(nPumHeaWatPriNon==nBoiNon, + "In " + getInstanceName() + ": " + + "In case of dedicated pumps, the number of primary HW pumps (=" + + String(nPumHeaWatPriNon) + ") must be equal to the number of boilers (=" + + String(nBoiNon) + ")."); + end if; + + annotation ( + defaultComponentName="plaHeaWat", + Icon(coordinateSystem(preserveAspectRatio=false, + extent={{-200,-200},{200,200}}), + graphics={ + Rectangle( + extent={{-200,200},{200,-200}}, + lineColor={0,0,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-60,-60},{50,-60},{50,0}}, + color={238,46,47}, + thickness=5), + Ellipse( + extent={{-40,-40},{0,-80}}, + lineColor={0,0,0}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}), + Line( + points={{-60,100},{50,100},{50,0},{200,0}}, + color={238,46,47}, + thickness=5), + Rectangle( + extent={{-180,-40},{-60,-120}}, + lineColor={0,0,255}, + pattern=LinePattern.None, + fillColor={95,95,95}, + fillPattern=FillPattern.Solid), + Text( + extent={{-149,-214},{151,-254}}, + textColor={0,0,255}, + textString="%name"), + Polygon( + points={{-121,-90},{-133,-108},{-107,-108},{-121,-90}}, + pattern=LinePattern.None, + smooth=Smooth.None, + fillColor={255,255,0}, + fillPattern=FillPattern.Solid, + lineColor={0,0,0}), + Rectangle( + extent={{-180,120},{-60,40}}, + lineColor={0,0,255}, + pattern=LinePattern.None, + fillColor={95,95,95}, + fillPattern=FillPattern.Solid), + Polygon( + points={{-121,70},{-133,52},{-107,52},{-121,70}}, + pattern=LinePattern.None, + smooth=Smooth.None, + fillColor={255,255,0}, + fillPattern=FillPattern.Solid, + lineColor={0,0,0}), + Ellipse( + extent={{130,20},{170,-20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}, + startAngle=0, + endAngle=360, + visible=typPumHeaWatSec == Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized), + Polygon( + points={{150,19},{150,-19},{169,0},{150,19}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255}, + visible=typPumHeaWatSec == Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized), + Line( + points={{200,-100},{-60,-100}}, + color={238,46,47}, + pattern=LinePattern.Dash, + thickness=5), + Ellipse( + extent={{-40,120},{0,80}}, + lineColor={0,0,0}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}), + Polygon( + points={{-20,119},{-20,81},{-1,100},{-20,119}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255}), + Line( + points={{-60,60},{20,60},{20,-98}}, + color={238,46,47}, + thickness=5, + pattern=LinePattern.Dash), + Line( + points={{102,-2},{102,-102}}, + color={238,46,47}, + thickness=5), + Polygon( + points={{-20,-41},{-20,-79},{-1,-60},{-20,-41}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255})}), + Diagram(coordinateSystem( + preserveAspectRatio=false, + extent={{-300,-300},{300,300}})), + Documentation(revisions=" + +", info=" +

+This partial class provides a standard interface for hot water boiler +plant models. +

+")); +end PartialBoilerPlant; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Interfaces/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/package.mo new file mode 100644 index 00000000000..be090ec8256 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.HeatingPlants.HotWater; +package Interfaces "Interface classes" + extends Modelica.Icons.InterfacesPackage; + annotation (Documentation(info=" +

+This package contains interface classes. +

+")); +end Interfaces; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Interfaces/package.order b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/package.order new file mode 100644 index 00000000000..2ac17ff9a12 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Interfaces/package.order @@ -0,0 +1,2 @@ +Bus +PartialBoilerPlant diff --git a/Buildings/Templates/HeatingPlants/HotWater/Types.mo b/Buildings/Templates/HeatingPlants/HotWater/Types.mo new file mode 100644 index 00000000000..da6faf20c30 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Types.mo @@ -0,0 +1,41 @@ +within Buildings.Templates.HeatingPlants.HotWater; +package Types "Package with type definitions" + extends Modelica.Icons.TypesPackage; +type Boiler = enumeration( + Condensing "Condensing boilers only", + Hybrid "Condensing and non-condensing boilers (hybrid plant)", + NonCondensing "Non-condensing boilers only") + "Enumeration to specify the type of boilers"; +type Controller = enumeration( + Guideline36 + "Guideline 36 controller for boiler plant", + OpenLoop + "Open loop controller") + "Enumeration to configure the plant controller"; +type PrimaryOverflowMeasurement = enumeration( + FlowDecoupler "Flow meter in the decoupler", + FlowDifference "Primary and secondary loop flow meters", + TemperatureSupplySensor "Delta-T with single HWST sensor measuring combined flow of all boilers", + TemperatureBoilerSensor "Delta-T with weighted average of HWST of all boilers proven on") + "Enumeration to configure the sensors for variable speed primary pumps control in primary-secondary plants"; +type PumpsPrimary = enumeration( + FactoryConstant "Primary pump provided with boiler with factory controls - Constant speed", + FactoryVariable "Primary pump provided with boiler with factory controls - Variable speed", + Constant "Constant speed pump", + Variable "Variable speed pump") + "Enumeration to specify the type of primary HW pumps"; +type PumpsSecondary = enumeration( + None "No secondary pumps (primary-only)", + Centralized "Variable secondary centralized", + Distributed "Variable secondary distributed") + "Enumeration to specify the type of secondary HW pumps"; +type SensorLocation = enumeration( + Return "Sensor in the return line", + Supply "Sensor in the supply line") + "Enumeration to specify the sensor location"; + annotation (Documentation(info=" +

+This package contains type definitions. +

+")); +end Types; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/BoilerPlant.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/BoilerPlant.mo new file mode 100644 index 00000000000..c08266ba3be --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/BoilerPlant.mo @@ -0,0 +1,64 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation; +model BoilerPlant + "Validation of boiler plant template with G36 controls" + extends + Buildings.Templates.HeatingPlants.HotWater.Validation.BoilerPlantOpenLoop( + BOI( + typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.Hybrid, + nBoiCon_select=2, + nBoiNon_select=2, + typPumHeaWatPriCon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable, + typPumHeaWatPriNon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Constant, + typArrPumHeaWatPriCon_select=Buildings.Templates.Components.Types.PumpArrangement.Headered, + typPumHeaWatSec2_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.Centralized, + redeclare + Buildings.Templates.HeatingPlants.HotWater.Components.Controls.Guideline36 + ctl( + nAirHan=1, + nEquZon=0, + typMeaCtlHeaWatPri=Buildings.Templates.HeatingPlants.HotWater.Types.PrimaryOverflowMeasurement.FlowDifference, + locSenVHeaWatPri=Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return, + locSenVHeaWatSec=Buildings.Templates.HeatingPlants.HotWater.Types.SensorLocation.Return, + have_senDpHeaWatLoc=true))); + + UserProject.AirHandlerControlPoints sigAirHan[BOI.nAirHan] + "AHU control points" + annotation (Placement(transformation(extent={{-90,50},{-70,70}}))); + UserProject.BASControlPoints sigBAS "BAS control points" + annotation (Placement(transformation(extent={{-90,10},{-70,30}}))); + UserProject.DistributionControlPoints sigDis(nSenDpHeaWatRem=BOI.ctl.nSenDpHeaWatRem) + "HW distribution system control points" + annotation (Placement(transformation(extent={{-90,-30},{-70,-10}}))); +equation + connect(sigAirHan.bus, BOI.busAirHan) annotation (Line( + points={{-70,60},{-20,60},{-20,4}}, + color={255,204,51}, + thickness=0.5)); + connect(sigBAS.bus, BOI.bus) annotation (Line( + points={{-70,20},{-60,20},{-60,0}}, + color={255,204,51}, + thickness=0.5)); + connect(sigDis.bus, BOI.bus) annotation (Line( + points={{-70,-20},{-60,-20},{-60,0}}, + color={255,204,51}, + thickness=0.5)); +annotation ( + experiment( + StartTime=0, + StopTime=2000, + Tolerance=1e-06), Documentation(info=" +

+This is a validation model for the boiler plant model + +Buildings.Templates.HeatingPlants.HotWater.BoilerPlant +with closed-loop controls as implemented within + +Buildings.Templates.HeatingPlants.HotWater.Components.Controls.Guideline36. +

+

+A Python script is provided with this model to test all supported system +configurations, see +Buildings/Resources/Scripts/travis/templates/BoilerPlant.py. +

+")); +end BoilerPlant; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/BoilerPlantOpenLoop.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/BoilerPlantOpenLoop.mo new file mode 100644 index 00000000000..2d01004b995 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/BoilerPlantOpenLoop.mo @@ -0,0 +1,106 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation; +model BoilerPlantOpenLoop + "Validation of boiler plant template with open-loop controls" + extends Modelica.Icons.Example; + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium"; + + replaceable parameter + Buildings.Templates.HeatingPlants.HotWater.Validation.UserProject.Data.AllSystems + datAll + "Design and operating parameters" + annotation (Placement(transformation(extent={{70,70},{90,90}}))); + + parameter Modelica.Units.SI.Time tau=10 + "Time constant at nominal flow" + annotation (Dialog(tab="Dynamics", group="Nominal condition")); + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.FixedInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab = "Dynamics", group="Conservation equations")); + + inner Buildings.Templates.HeatingPlants.HotWater.BoilerPlant BOI( + redeclare final package Medium = Medium, + redeclare replaceable Buildings.Templates.HeatingPlants.HotWater.Components.Controls.OpenLoop ctl, + typ=Buildings.Templates.HeatingPlants.HotWater.Types.Boiler.NonCondensing, + nBoiNon_select=2, + typPumHeaWatPriNon=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsPrimary.Variable, + typArrPumHeaWatPriNon_select=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + typPumHeaWatSec1_select=Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None, + final energyDynamics=energyDynamics, + final tau=tau, + final dat=datAll._BOI) + "Boiler plant" + annotation (Placement(transformation(extent={{-60,-30},{-20,10}}))); + + Fluid.Sources.Boundary_pT bou( + redeclare final package Medium=Medium, + p=200000, + T=Buildings.Templates.Data.Defaults.THeaWatRet, + nPorts=2) + "Boundary conditions for HW distribution system" + annotation (Placement(transformation(extent={{90,-30},{70,-10}}))); + + Buildings.Fluid.FixedResistances.PressureDrop res( + redeclare final package Medium = Medium, + m_flow_nominal=BOI.mHeaWat_flow_nominal, + dp_nominal=datAll._BOI.ctl.dpHeaWatLocSet_nominal) + "Flow resistance of HW distribution system" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + + Fluid.Sensors.TemperatureTwoPort THeaWatRet( + redeclare final package Medium =Medium, + final m_flow_nominal=BOI.mHeaWat_flow_nominal) + "HW return temperature" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={20,-40}))); + Fluid.Sensors.VolumeFlowRate VHeaWat_flow( + redeclare final package Medium =Medium, + final m_flow_nominal=BOI.mHeaWat_flow_nominal) + "HW volume flow rate" + annotation (Placement(transformation(extent={{60,-50},{40,-30}}))); +equation + connect(res.port_b, bou.ports[1]) + annotation (Line(points={{40,0},{70,0},{70,-21}}, color={0,127,255})); + connect(BOI.port_b, res.port_a) + annotation (Line(points={{-19.8,-10},{0,-10},{0,0},{20,0}}, + color={0,127,255})); + connect(BOI.port_a, THeaWatRet.port_b) annotation (Line(points={{-19.8,-20},{ + 0,-20},{0,-40},{10,-40}}, color={0,127,255})); + connect(THeaWatRet.port_a, VHeaWat_flow.port_b) + annotation (Line(points={{30,-40},{40,-40}}, color={0,127,255})); + connect(VHeaWat_flow.port_a, bou.ports[2]) + annotation (Line(points={{60,-40},{70,-40},{70,-19}}, color={0,127,255})); + annotation ( + experiment( + StartTime=0, + StopTime=2000, + Tolerance=1e-06), + Icon(coordinateSystem(preserveAspectRatio=false)), Diagram( + coordinateSystem(preserveAspectRatio=false, extent={{-100,-100},{100, + 100}})), + Documentation(revisions=" + +", info=" +

+This is a validation model for the boiler plant model + +Buildings.Templates.HeatingPlants.HotWater.BoilerPlant +with open-loop controls. +

+

+It is intended to check that the plant model is well-defined for +various plant configurations. +However, due to the open-loop controls a correct physical behavior +is not expected. +

+")); +end BoilerPlantOpenLoop; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/AirHandlerControlPoints.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/AirHandlerControlPoints.mo new file mode 100644 index 00000000000..224b3d8e72c --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/AirHandlerControlPoints.mo @@ -0,0 +1,32 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation.UserProject; +block AirHandlerControlPoints + "Emulation of AHU control points" + extends Modelica.Blocks.Icons.Block; + + Buildings.Templates.AirHandlersFans.Interfaces.Bus bus + "AHU control bus" + annotation (Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,0}))); + Controls.OBC.CDL.Integers.Sources.Constant reqHeaWatRes(k=0) + "HW reset request" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Controls.OBC.CDL.Integers.Sources.Constant reqHeaWatPla(k=1) + "HW plant request" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); +equation + connect(reqHeaWatRes.y, bus.reqHeaWatRes) annotation (Line(points={{12,0},{ + 100,0}}, color={255,127,0})); + connect(reqHeaWatPla.y, bus.reqHeaWatPla) annotation (Line(points={{12,-40},{ + 80,-40},{80,0},{100,0}}, color={255,127,0})); + annotation (Documentation(info=" +

+This class generates signals typically provided by the AHU controller. +It is aimed for validation purposes only. +

+")); +end AirHandlerControlPoints; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/BASControlPoints.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/BASControlPoints.mo new file mode 100644 index 00000000000..91e7db95227 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/BASControlPoints.mo @@ -0,0 +1,28 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation.UserProject; +block BASControlPoints "Emulation of control points from the BAS" + extends Modelica.Blocks.Icons.Block; + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TOut( + k=10+273.15) + "Outdoor air temperature" + annotation (Placement(transformation(extent={{-8,-10},{12,10}}))); + + Interfaces.Bus bus "HW plant control bus" + annotation (Placement( + transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,0}))); +equation + connect(TOut.y, bus.TOut); + annotation ( + defaultComponentName="sigBAS", + Documentation(info=" +

+This class generates signals typically provided by the BAS. +It is aimed for validation purposes only. +

+")); +end BASControlPoints; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/AllSystems.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/AllSystems.mo new file mode 100644 index 00000000000..5a5fdfc477e --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/AllSystems.mo @@ -0,0 +1,94 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation.UserProject.Data; +class AllSystems + "Design and operating parameters for testing purposes" + extends Buildings.Templates.Data.AllSystems( + ashCliZon=Buildings.Controls.OBC.ASHRAE.G36.Types.ASHRAEClimateZone.Not_Specified, + + stdVen=Buildings.Controls.OBC.ASHRAE.G36.Types.VentilationStandard.ASHRAE62_1, + + stdEne=Buildings.Controls.OBC.ASHRAE.G36.Types.EnergyStandard.ASHRAE90_1, + sysUni=Buildings.Templates.Types.Units.SI); + + // The following instance name matches the system tag. + outer Buildings.Templates.HeatingPlants.HotWater.BoilerPlant BOI; + + parameter Buildings.Templates.HeatingPlants.HotWater.Data.BoilerPlant _BOI( + final have_boiCon=BOI.have_boiCon, + final have_boiNon=BOI.have_boiNon, + final nBoiCon=BOI.nBoiCon, + final nBoiNon=BOI.nBoiNon, + final typMod=BOI.typMod, + final typPumHeaWatSec=BOI.typPumHeaWatSec, + final nPumHeaWatPriCon=BOI.nPumHeaWatPriCon, + final nPumHeaWatPriNon=BOI.nPumHeaWatPriNon, + final nPumHeaWatSec=BOI.nPumHeaWatSec, + final have_valHeaWatMinBypCon=BOI.have_valHeaWatMinBypCon, + final have_valHeaWatMinBypNon=BOI.have_valHeaWatMinBypNon, + final have_senDpHeaWatLoc=BOI.ctl.have_senDpHeaWatLoc, + final nSenDpHeaWatRem=BOI.ctl.nSenDpHeaWatRem, + final have_senVHeaWatSec=BOI.ctl.have_senVHeaWatSec, + final typArrPumHeaWatPriCon=BOI.typArrPumHeaWatPriCon, + final typArrPumHeaWatPriNon=BOI.typArrPumHeaWatPriNon, + final have_varPumHeaWatPriCon=BOI.have_varPumHeaWatPriCon, + final have_varPumHeaWatPriNon=BOI.have_varPumHeaWatPriNon, + final typCtl=BOI.typCtl, + final rho_default=BOI.rho_default, + boiCon( + fue=Buildings.Fluid.Data.Fuels.NaturalGasHigherHeatingValue(), + dpHeaWatBoi_nominal=fill(Buildings.Templates.Data.Defaults.dpHeaWatBoi, BOI.nBoiCon), + mHeaWatBoi_flow_nominal=_BOI.ctl.capBoiCon_nominal / + Buildings.Utilities.Psychrometrics.Constants.cpWatLiq ./ + (_BOI.ctl.THeaWatConSup_nominal - Buildings.Templates.Data.Defaults.THeaWatRet)), + boiNon( + fue=Buildings.Fluid.Data.Fuels.NaturalGasHigherHeatingValue(), + dpHeaWatBoi_nominal=fill(Buildings.Templates.Data.Defaults.dpHeaWatBoi, BOI.nBoiNon), + mHeaWatBoi_flow_nominal=_BOI.ctl.capBoiNon_nominal / + Buildings.Utilities.Psychrometrics.Constants.cpWatLiq ./ + (_BOI.ctl.THeaWatSup_nominal - Buildings.Templates.Data.Defaults.THeaWatRet)), + ctl( + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSup, + THeaWatConSup_nominal=Buildings.Templates.Data.Defaults.THeaWatConSup, + TOutLck=Buildings.Templates.Data.Defaults.TOutBoiLck, + VHeaWatBoiCon_flow_nominal=_BOI.boiCon.mHeaWatBoi_flow_nominal / + _BOI.rho_default, + VHeaWatBoiCon_flow_min=0.1 * _BOI.ctl.VHeaWatBoiCon_flow_nominal, + VHeaWatBoiNon_flow_nominal=_BOI.boiNon.mHeaWatBoi_flow_nominal / + _BOI.rho_default, + VHeaWatBoiNon_flow_min=0.1 * _BOI.ctl.VHeaWatBoiNon_flow_nominal, + ratFirBoiCon_min=fill(0.2, BOI.nBoiCon), + ratFirBoiNon_min=fill(0.2, BOI.nBoiNon), + capBoiCon_nominal=fill(1E6, BOI.nBoiCon), + capBoiNon_nominal=fill(1E6, BOI.nBoiNon), + VHeaWatPriCon_flow_nominal=sum(_BOI.ctl.VHeaWatBoiCon_flow_nominal), + VHeaWatPriNon_flow_nominal=sum(_BOI.ctl.VHeaWatBoiNon_flow_nominal), + VHeaWatSec_flow_nominal= + max(_BOI.ctl.VHeaWatPriCon_flow_nominal, _BOI.ctl.VHeaWatPriNon_flow_nominal) / 1.1, + dpHeaWatLocSet_nominal=Buildings.Templates.Data.Defaults.dpHeaWatLocSet_max, + dpHeaWatRemSet_nominal=fill(Buildings.Templates.Data.Defaults.dpHeaWatSet_max, + BOI.ctl.nSenDpHeaWatRem), + yPumHeaWatPri_min=0.1, + yPumHeaWatSec_min=0.1, + yPumHeaWatPriSta_min=fill(0.1, size(_BOI.ctl.sta, 1)), + sta=if BOI.have_boiCon and BOI.have_boiNon then + [0,0,0,0; 1,0,1,0; 1,1,1,1] else [0,0; 1,0; 1,1]), + pumHeaWatPriCon( + dp_nominal=fill(max(_BOI.boiCon.dpHeaWatBoi_nominal) * 1.5, BOI.nPumHeaWatPriCon) + + fill((if _BOI.typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then + _BOI.ctl.dpHeaWatLocSet_nominal else 0), BOI.nPumHeaWatPriCon)), + pumHeaWatPriNon( + dp_nominal=fill(max(_BOI.boiNon.dpHeaWatBoi_nominal) * 1.5, BOI.nPumHeaWatPriNon) + + fill((if _BOI.typPumHeaWatSec==Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None then + _BOI.ctl.dpHeaWatLocSet_nominal else 0), BOI.nPumHeaWatPriNon)), + pumHeaWatSec( + dp_nominal=fill(_BOI.ctl.dpHeaWatLocSet_nominal, BOI.nPumHeaWatSec), + m_flow_nominal=1.1 / max(1, BOI.nPumHeaWatSec) * + fill(max(sum(_BOI.pumHeaWatPriCon.m_flow_nominal), sum(_BOI.pumHeaWatPriNon.m_flow_nominal)), + BOI.nPumHeaWatSec))) + "HW plant parameters"; + annotation (Documentation(info=" +

+This class provides system parameters for the validation +of the boiler plant model. +

+")); +end AllSystems; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/package.mo new file mode 100644 index 00000000000..d8a14b83b9b --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/package.mo @@ -0,0 +1,10 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation.UserProject; +package Data "Package with classes for storing system parameters" + extends Modelica.Icons.MaterialPropertiesPackage; + annotation (Documentation(info=" +

+This package provides design and operating parameters +that are used for validation purposes. +

+")); +end Data; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/package.order b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/package.order new file mode 100644 index 00000000000..3831742ec60 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/Data/package.order @@ -0,0 +1 @@ +AllSystems diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/DistributionControlPoints.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/DistributionControlPoints.mo new file mode 100644 index 00000000000..fc7683151ba --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/DistributionControlPoints.mo @@ -0,0 +1,32 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation.UserProject; +block DistributionControlPoints + "Emulation of control points from HW distribution system" + extends Modelica.Blocks.Icons.Block; + + parameter Integer nSenDpHeaWatRem + "Number of remote HW differential pressure sensors used for HW pump speed control" + annotation (Evaluate=true, Dialog(group="Configuration")); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpHeaWatRem[nSenDpHeaWatRem]( + each k=Buildings.Templates.Data.Defaults.dpHeaWatSet_max) + "HW differential pressure used for HW pump speed control" + annotation (Placement(transformation(extent={{-8,-10},{12,10}}))); + Interfaces.Bus bus "CHW plant control bus" annotation (Placement( + transformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,0}), iconTransformation( + extent={{-20,-20},{20,20}}, + rotation=-90, + origin={100,0}))); +equation + connect(dpHeaWatRem.y, bus.dpHeaWatRem) + annotation (Line(points={{14,0},{100, + 0}}, color={0,0,127})); + annotation (Documentation(info=" +

+This class generates signals typically yielded by sensors +from the HW distribution system. +It is aimed for validation purposes only. +

+")); +end DistributionControlPoints; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/package.mo new file mode 100644 index 00000000000..e8f3b277357 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.HeatingPlants.HotWater.Validation; +package UserProject "Package of user classes generated from templates" + extends Modelica.Icons.VariantsPackage; + annotation (Documentation(info=" +

+This package contains classes used for validation purposes. +

+")); +end UserProject; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/package.order b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/package.order new file mode 100644 index 00000000000..ef08383e01b --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/UserProject/package.order @@ -0,0 +1,4 @@ +AirHandlerControlPoints +BASControlPoints +DistributionControlPoints +Data diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/package.mo b/Buildings/Templates/HeatingPlants/HotWater/Validation/package.mo new file mode 100644 index 00000000000..06be49a2ada --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/package.mo @@ -0,0 +1,19 @@ +within Buildings.Templates.HeatingPlants.HotWater; +package Validation "Package with validation models" + extends Modelica.Icons.ExamplesPackage; + + annotation (Documentation(info=" +

+This package contains models validating the templates within + +Buildings.Templates.HeatingPlants.HotWater +for various system configurations. +

+

+The models also illustrate the parameterization of the whole +HVAC system using a class derived from + +Buildings.Templates.Data.AllSystems. +

+")); +end Validation; diff --git a/Buildings/Templates/HeatingPlants/HotWater/Validation/package.order b/Buildings/Templates/HeatingPlants/HotWater/Validation/package.order new file mode 100644 index 00000000000..81b366b685d --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/Validation/package.order @@ -0,0 +1,3 @@ +BoilerPlant +BoilerPlantOpenLoop +UserProject diff --git a/Buildings/Templates/HeatingPlants/HotWater/package.mo b/Buildings/Templates/HeatingPlants/HotWater/package.mo new file mode 100644 index 00000000000..8f5437e5751 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/package.mo @@ -0,0 +1,8 @@ +within Buildings.Templates.HeatingPlants; +package HotWater "Hot water plants" + annotation (Documentation(info=" +

+This package contains templates for hot water plants. +

+")); +end HotWater; diff --git a/Buildings/Templates/HeatingPlants/HotWater/package.order b/Buildings/Templates/HeatingPlants/HotWater/package.order new file mode 100644 index 00000000000..a7e68148e34 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/HotWater/package.order @@ -0,0 +1,6 @@ +BoilerPlant +Components +Data +Types +Validation +Interfaces diff --git a/Buildings/Templates/HeatingPlants/package.mo b/Buildings/Templates/HeatingPlants/package.mo new file mode 100644 index 00000000000..334ef6dcce8 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/package.mo @@ -0,0 +1,6 @@ +within Buildings.Templates; +package HeatingPlants "Heating plants" + annotation (Documentation(info=" +

This package contains templates for heating plants.

+")); +end HeatingPlants; diff --git a/Buildings/Templates/HeatingPlants/package.order b/Buildings/Templates/HeatingPlants/package.order new file mode 100644 index 00000000000..9943005d896 --- /dev/null +++ b/Buildings/Templates/HeatingPlants/package.order @@ -0,0 +1 @@ +HotWater diff --git a/Buildings/Templates/UsersGuide.mo b/Buildings/Templates/UsersGuide.mo index e556264e84b..1679fee620d 100644 --- a/Buildings/Templates/UsersGuide.mo +++ b/Buildings/Templates/UsersGuide.mo @@ -53,13 +53,17 @@ The following abbreviations are used in that package.
AHUAir handling unit AOAnalog output (integer or real) CHWChilled water +CTCooling tower CWCondenser water DHWDomestic hot water DIDigital input (Boolean) DODigital output (Boolean) DOASDedicated outdoor air system DPDifferential pressure -HHWHeating hot water +FCUFan coil unit +DPDifferential pressure +HWHot water (heating) +MSMotor starter OAOutdoor air VAVVariable air volume VFDVariable frequency drive @@ -96,11 +100,11 @@ or a terminal unit (refer to Buildings.Templates.UsersGuide.Conventions for the definition of a system). A template is a self-contained model that can be reconfigured -by redeclaring some of its components or modifying some +by redeclaring some of its components or modifying some structural parameters. Such configuration does not require any further modification of the template. -In particular, all connect clauses between replaceable components +In particular, all connect clauses between replaceable components are resolved internally without user intervention. The same applies to sensors that are required for a specific control option and instantiated only when that option is selected. @@ -144,22 +148,22 @@ that originate from the zone equipment controller. If the controller selected for the zone equipment does not generate such requests, the simulation model will be singular. Selecting controllers from the same reference—e.g., -ASHRAE (2021)—is the safest way +ASHRAE (2021)—is the safest way to ensure consistency throughout the HVAC system model.

Model parameters

-Each template contains an instance dat of a record class that +Each template contains an instance dat of a record class that contains all design and operating parameters for parameterizing the subcomponents of the template. -For example, the multiple-zone VAV template +For example, the multiple-zone VAV template Buildings.Templates.AirHandlersFans.VAVMultiZone contains an instance of the record class Buildings.Templates.AirHandlersFans.Data.VAVMultiZone which contains the parameters for configuring the heating coil component, -as an instance of the record class +as an instance of the record class Buildings.Templates.Components.Data.Coil. All design and operating parameters should be assigned through this record instance @@ -170,22 +174,22 @@ In addition to these parameters, the record class also contains the configuratio parameters that define the system layout and control options. These configuration parameters are bound to the values that are assigned via the template's parameter dialog. -In this way, only the set of parameters needed for the particular system layout +In this way, only the set of parameters needed for the particular system layout for which the template is configured is displayed in the parameter dialog. Note that these configuration parameters are disabled in the record class -to avoid any modification by the user and preserve the bindings with the +to avoid any modification by the user and preserve the bindings with the template parameters.

-When creating a model for a complete HVAC system with multiple instances of +When creating a model for a complete HVAC system with multiple instances of different templates, the class -Buildings.Templates.Data.AllSystems +Buildings.Templates.Data.AllSystems. can be used at the top level of the model to assign all design and operating parameters. -This class allows the use of Modelica outer components to retrieve the configuration +This class allows the use of Modelica outer components to retrieve the configuration parameter values for each template instance based on the instance name. Thus, it is the avatar in the modeling environment of an HVAC project datasheet. -The validation models within +The validation models within Buildings.Templates.AirHandlersFans.Validation illustrate the use of this class. diff --git a/Buildings/Templates/package.order b/Buildings/Templates/package.order index 9c28253a22a..6bd3f292a98 100644 --- a/Buildings/Templates/package.order +++ b/Buildings/Templates/package.order @@ -1,6 +1,7 @@ UsersGuide AirHandlersFans Components +HeatingPlants ZoneEquipment Data Types