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. +
++See the documentation of + +Buildings.Templates.Components.Interfaces.BoilerHotWater. +
+", revisions=" ++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. +
++See the documentation of + +Buildings.Templates.Components.Interfaces.BoilerHotWater. +
++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=" ++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.
+
+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. +
+per
or
+only its component per.pressure
.
+In this case the elements per[i]
may differ one from another.
+This is the recommended approach for unequally sized units
+such as dedicated pumps.per
.
+In this case the elements per[i]
are all equal to the redeclared
+record instance.
+This is the recommended approach for equally sized units
+such as headered pumps.+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. +
++The following input and output points are available. +
+y1
:
+DO signal, with a dimensionality of zero
+THeaWatSupSet
:
+AO signal, with a dimensionality of zero
+y_actual
:
+AI signal, with a dimensionality of zero
+THeaWatSup
:
+AI signal, with a dimensionality of zero
++This partial class provides a standard interface for pump models. +
+", revisions=" ++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=" ++This partial class provides a standard interface for +single pump models. +
+", revisions=" +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
.
+
+The following input and output points are available. +
+y1
:
+DO signal dedicated to each unit, with a dimensionality of one
+y
for variable speed pumps only:
+have_varCom
: AO signal common to all units,
+with a dimensionality of zero
+not have_varCom
: AO signal dedicated to each unit,
+with a dimensionality of one
+y1_actual
:
+DI signal dedicated to each unit, with a dimensionality of one
++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=" +
+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
.
+
+The following input and output points are available. +
+y1
:
+DO signal
+y
for variable speed pumps only:
+AO signal
+y1_actual
:
+DI signal
++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=" ++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 +
+TConEnt_nominal
+when redeclaring the performance data record per
,
+QEva_flow_nominal
,
++This model validates the parameter propagation within the record class + +Buildings.Templates.Components.Data.BoilerHotWater. +It illustrates +
+datBoiTabLoc.per.effCur
) or by the means of a record redeclaration
+(datBoiTabRed.per.effCur
) or record binding (datBoiTab.per.effCur
),
+datBoiTabRed.per
,
+datBoiTab.per
.
+Note that Dymola (as of version 2023.x) does not support a direct binding
+with a record function and requires a local instance of the record as illustrated
+in this model.
++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]
.
+
+This package defines some constants that are either +
++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 parameter | Options | Notes |
---|---|---|
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. | +
+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. +
++This model represents a group of hot water boilers. +
++Modeling features and limitations: +
+is_con
.
+In order to represent a hybrid plant with both condensing and non-condensing
+boilers, two instances of this model must be used.
+typMod
which is based on the enumeration
+
+Buildings.Templates.Components.Types.BoilerHotWaterModel.
+However, the boiler characteristics such as the design capacity
+and HW flow rate may be different from one unit to another.
+typArrPumHeaWatPri
.
++The following input and output points are available. +
+boiCon[:]
(resp. boiNon[:]
) storing all signals
+dedicated to each condensing boiler (resp. non-condensing boiler), with a
+dimensionality of one
+boi(Con|Non)[:].y1
:
+DO signal dedicated to each unit, with a dimensionality of one
+boi(Con|Non)[:].THeaWatSupSet
:
+AO signal dedicated to each unit, with a dimensionality of one
+boi(Con|Non)[:].y_actual
:
+AI signal dedicated to each unit, with a dimensionality of one
+boi(Con|Non)[:].THeaWatSup
:
+AI signal dedicated to each unit, with a dimensionality of one
+valBoiConIso[:]
(resp. valBoiNonIso[:]
)
+storing all signals dedicated to each condensing boiler (resp. non-condensing boiler)
+isolation valve (if any), with a dimensionality of one
+valBoi(Con|Non)Iso[:].y1
:
+DO signal dedicated to each unit, with a dimensionality of one
+valBoi(Con|Non)Iso[:].y1_actual
:
+DI signal dedicated to each unit, with a dimensionality of one
+valBoi(Con|Non)Iso[:].y0_actual
:
+DI signal dedicated to each unit, with a dimensionality of one
++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. +
++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. +
++The Guideline 36 control sequence requires the following input points in +addition to the ones from the HW plant model. +
+TOut
:
+AI signal with a dimensionality of zerodpHeaWatRem
:
+AI signal with a dimensionality of one, the number of remote
+sensors is specified by the parameter nSenDpHeaWatRem
.busAirHan[:]
(resp. busEquZon[:]
),
+with a dimensionality of one
+bus(AirHan|EquZon)[:].reqHeaWatPla
:
+AI signal (Integer), with a dimensionality of one
+bus(AirHan|EquZon)[:].reqHeaWatRes
:
+AI signal (Integer), with a dimensionality of one+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=" ++ 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=" +
+FIXME: Temporary files to be deleted after merging
+issue2180_BoilerPlant_MainController_oct_2021
.
+
+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=" ++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.
+
+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.
+
+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=" ++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
.
+
+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.
-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