From f1607e121016b6ce7aaa15983595ce9e9028d6d8 Mon Sep 17 00:00:00 2001 From: Antoine Gautier Date: Fri, 5 Apr 2024 18:18:40 +0200 Subject: [PATCH] =?UTF-8?q?Templates=20=E2=80=A2=20AWHP=20plant=20(#3770)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added template models for air to water heat pump plants. --------- Co-authored-by: Michael Wetter --- .../Fluid/HeatPumps/EquationFitReversible.mo | 12 +- .../Components/Actuators/MotorStarter.svg | 304 ++++ .../Components/Boilers/ControllerOnboard.svg | 298 ++++ .../Templates/Components/Pumps/Single.svg | 73 + .../Components/Sensors/ProbeInWell.svg | 20 +- .../Templates/Components/Valves/Check.svg | 82 + .../Templates/Components/Valves/ThreeWay.svg | 49 +- .../Templates/Components/Valves/TwoWay.svg | 44 +- ...s_Controls_Validation_MultipleCommands.txt | 14 + ...nts_Controls_Validation_StatusEmulator.txt | 13 + ...atPumps_Validation_HeatPumpEquationFit.txt | 42 + ...emplates_Components_Validation_Dampers.txt | 10 +- ...s_Templates_Components_Validation_Fans.txt | 2 +- ...mponents_Validation_PumpMultipleRecord.txt | 18 + ..._Templates_Components_Validation_Pumps.txt | 45 + ...Templates_Components_Validation_Valves.txt | 6 +- ...ts_Controls_Enabling_Validation_Enable.txt | 16 + ...ntrols_HeatPumps_Validation_AirToWater.txt | 54 + ...Validation_ControlDifferentialPressure.txt | 24 + ...idation_ResetLocalDifferentialPressure.txt | 14 + ...mps_Generic_Validation_StagingHeadered.txt | 24 + ...neric_Validation_StagingHeaderedDeltaP.txt | 11 + ..._Primary_Validation_EnableLeadHeadered.txt | 17 + ...ry_Validation_VariableSpeedNoDpControl.txt | 31 + ...ntrols_Setpoints_Validation_PlantReset.txt | 23 + ...ation_Validation_EquipmentAvailability.txt | 14 + ...ingRotation_Validation_EquipmentEnable.txt | 19 + ...ingRotation_Validation_EventSequencing.txt | 23 + ...StagingRotation_Validation_SortRuntime.txt | 21 + ...gRotation_Validation_StageAvailability.txt | 19 + ...Rotation_Validation_StageChangeCommand.txt | 16 + ...ingRotation_Validation_StageCompletion.txt | 15 + ...ontrols_Utilities_Validation_CountTrue.txt | 10 + ...ls_Utilities_Validation_FirstTrueIndex.txt | 10 + ...Controls_Utilities_Validation_HoldReal.txt | 12 + ...ols_Utilities_Validation_LastTrueIndex.txt | 10 + ...s_Utilities_Validation_MultiMaxInteger.txt | 9 + ...s_Utilities_Validation_MultiMinInteger.txt | 9 + ...tilities_Validation_PlaceholderInteger.txt | 11 + ...tilities_Validation_PlaceholderLogical.txt | 11 + ...s_Utilities_Validation_PlaceholderReal.txt | 11 + ...s_Utilities_Validation_SortWithIndices.txt | 33 + ...ntrols_Utilities_Validation_StageIndex.txt | 19 + ...ls_Utilities_Validation_TimerWithReset.txt | 27 + ...lities_Validation_TrueArrayConditional.txt | 17 + ...nts_Validation_HeatPumpGroupAirToWater.txt | 38 + ...nents_Validation_PumpsPrimaryDedicated.txt | 43 + ..._Components_Validation_ValvesIsolation.txt | 39 + ...Plants_HeatPumps_Validation_AirToWater.txt | 67 + .../Resources/Scripts/BuildingsPy/conf.yml | 42 + .../Controls/Validation/MultipleCommands.mos | 26 + .../Controls/Validation/StatusEmulator.mos | 19 + .../Validation/HeatPumpEquationFit.mos | 86 + .../Validation/PumpMultipleRecord.mos | 31 + .../Templates/Components/Validation/Pumps.mos | 89 + .../Controls/Enabling/Validation/Enable.mos | 30 + .../HeatPumps/Validation/AirToWater.mos | 112 ++ .../ControlDifferentialPressure.mos | 47 + .../ResetLocalDifferentialPressure.mos | 22 + .../Generic/Validation/StagingHeadered.mos | 55 + .../Validation/StagingHeaderedDeltaP.mos | 22 + .../Primary/Validation/EnableLeadHeadered.mos | 39 + .../Validation/VariableSpeedNoDpControl.mos | 65 + .../Setpoints/Validation/PlantReset.mos | 37 + .../Validation/EquipmentAvailability.mos | 19 + .../Validation/EquipmentEnable.mos | 42 + .../Validation/EventSequencing.mos | 39 + .../Validation/SortRuntime.mos | 34 + .../Validation/StageAvailability.mos | 28 + .../Validation/StageChangeCommand.mos | 30 + .../Validation/StageCompletion.mos | 22 + .../Utilities/Validation/CountTrue.mos | 12 + .../Utilities/Validation/FirstTrueIndex.mos | 12 + .../Utilities/Validation/HoldReal.mos | 20 + .../Utilities/Validation/LastTrueIndex.mos | 12 + .../Utilities/Validation/MultiMaxInteger.mos | 12 + .../Utilities/Validation/MultiMinInteger.mos | 12 + .../Validation/PlaceholderInteger.mos | 13 + .../Validation/PlaceholderLogical.mos | 13 + .../Utilities/Validation/PlaceholderReal.mos | 13 + .../Utilities/Validation/SortWithIndices.mos | 6 + .../Utilities/Validation/StageIndex.mos | 56 + .../Utilities/Validation/TimerWithReset.mos | 10 + .../Validation/TrueArrayConditional.mos | 27 + .../Validation/HeatPumpGroupAirToWater.mos | 64 + .../Validation/PumpsPrimaryDedicated.mos | 69 + .../Components/Validation/ValvesIsolation.mos | 62 + .../HeatPumps/Validation/AirToWater.mos | 137 ++ ...s.Controls.Validation.MultipleCommands.mos | 9 + ...nts.Controls.Validation.StatusEmulator.mos | 7 + ...atPumps.Validation.HeatPumpEquationFit.mos | 36 + ...mponents.Validation.PumpMultipleRecord.mos | 13 + ....Templates.Components.Validation.Pumps.mos | 34 + ...ts.Controls.Enabling.Validation.Enable.mos | 11 + ...ntrols.HeatPumps.Validation.AirToWater.mos | 48 + ...Validation.ControlDifferentialPressure.mos | 18 + ...idation.ResetLocalDifferentialPressure.mos | 8 + ...mps.Generic.Validation.StagingHeadered.mos | 19 + ...neric.Validation.StagingHeaderedDeltaP.mos | 6 + ....Primary.Validation.EnableLeadHeadered.mos | 11 + ...ry.Validation.VariableSpeedNoDpControl.mos | 26 + ...ntrols.Setpoints.Validation.PlantReset.mos | 18 + ...ation.Validation.EquipmentAvailability.mos | 9 + ...ingRotation.Validation.EquipmentEnable.mos | 14 + ...ingRotation.Validation.EventSequencing.mos | 18 + ...StagingRotation.Validation.SortRuntime.mos | 16 + ...gRotation.Validation.StageAvailability.mos | 14 + ...Rotation.Validation.StageChangeCommand.mos | 10 + ...ingRotation.Validation.StageCompletion.mos | 10 + ...ontrols.Utilities.Validation.CountTrue.mos | 5 + ...ls.Utilities.Validation.FirstTrueIndex.mos | 5 + ...Controls.Utilities.Validation.HoldReal.mos | 7 + ...ols.Utilities.Validation.LastTrueIndex.mos | 5 + ...s.Utilities.Validation.MultiMaxInteger.mos | 4 + ...s.Utilities.Validation.MultiMinInteger.mos | 4 + ...tilities.Validation.PlaceholderInteger.mos | 6 + ...tilities.Validation.PlaceholderLogical.mos | 6 + ...s.Utilities.Validation.PlaceholderReal.mos | 6 + ...s.Utilities.Validation.SortWithIndices.mos | 28 + ...ntrols.Utilities.Validation.StageIndex.mos | 14 + ...ls.Utilities.Validation.TimerWithReset.mos | 24 + ...lities.Validation.TrueArrayConditional.mos | 12 + ...nts.Validation.HeatPumpGroupAirToWater.mos | 27 + ...nents.Validation.PumpsPrimaryDedicated.mos | 37 + ....Components.Validation.ValvesIsolation.mos | 31 + ...Plants.HeatPumps.Validation.AirToWater.mos | 57 + .../Templates/Components/Actuators/Damper.mo | 17 +- .../Templates/Components/Actuators/Valve.mo | 39 +- .../Components/Controls/MultipleCommands.mo | 4 +- .../Components/Controls/StatusEmulator.mo | 88 + .../Controls/Validation/MultipleCommands.mo | 31 + .../Controls/Validation/StatusEmulator.mo | 28 + .../Components/Controls/Validation/package.mo | 12 + .../Controls/Validation/package.order | 2 + .../Components/Controls/package.order | 2 + .../Templates/Components/Data/HeatPump.mo | 195 ++ .../Templates/Components/Data/PumpMultiple.mo | 90 + .../Templates/Components/Data/PumpSingle.mo | 50 + .../Templates/Components/Data/package.order | 3 + .../Components/HeatPumps/AirToWater.mo | 67 + .../Validation/HeatPumpEquationFit.mo | 427 +++++ .../HeatPumps/Validation/package.mo | 9 + .../HeatPumps/Validation/package.order | 1 + .../Components/HeatPumps/WaterToWater.mo | 40 + .../Templates/Components/HeatPumps/package.mo | 9 + .../Components/HeatPumps/package.order | 3 + .../Components/Interfaces/PartialHeatPump.mo | 235 +++ .../Interfaces/PartialHeatPumpEquationFit.mo | 196 ++ .../Components/Interfaces/PartialPump.mo | 97 + .../Interfaces/PartialPumpMultiple.mo | 220 +++ .../Interfaces/PartialPumpSingle.mo | 48 + .../Components/Interfaces/PartialSensor.mo | 22 +- .../Components/Interfaces/package.order | 5 + .../Templates/Components/Pumps/Multiple.mo | 179 ++ .../Templates/Components/Pumps/Single.mo | 148 ++ .../Templates/Components/Pumps/package.mo | 15 + .../Templates/Components/Pumps/package.order | 2 + .../Templates/Components/Routing/Junction.mo | 56 + .../Components/Routing/MultipleToMultiple.mo | 94 +- .../Components/Routing/MultipleToSingle.mo | 50 +- .../Components/Routing/PassThroughFluid.mo | 21 +- .../Components/Routing/SingleToMultiple.mo | 47 +- .../Components/Routing/package.order | 1 + .../Components/Sensors/Temperature.mo | 16 +- .../Components/Sensors/VolumeFlowRate.mo | 8 +- Buildings/Templates/Components/Types.mo | 21 + .../Templates/Components/Validation/Coils.mo | 7 +- .../Validation/PumpMultipleRecord.mo | 96 + .../Templates/Components/Validation/Pumps.mo | 349 ++++ .../Components/Validation/package.order | 2 + Buildings/Templates/Components/package.order | 2 + Buildings/Templates/Data/Defaults.mo | 165 ++ Buildings/Templates/Data/package.order | 1 + .../Plants/Controls/Enabling/Enable.mo | 286 +++ .../Controls/Enabling/Validation/Enable.mo | 99 ++ .../Controls/Enabling/Validation/package.mo | 29 + .../Enabling/Validation/package.order | 1 + .../Plants/Controls/Enabling/package.mo | 44 + .../Plants/Controls/Enabling/package.order | 2 + .../Plants/Controls/HeatPumps/AirToWater.mo | 1582 +++++++++++++++++ .../HeatPumps/Validation/AirToWater.mo | 381 ++++ .../Controls/HeatPumps/Validation/package.mo | 27 + .../HeatPumps/Validation/package.order | 1 + .../Plants/Controls/HeatPumps/package.mo | 8 + .../Plants/Controls/HeatPumps/package.order | 2 + .../Generic/ControlDifferentialPressure.mo | 233 +++ .../Generic/ResetLocalDifferentialPressure.mo | 153 ++ .../Controls/Pumps/Generic/StagingHeadered.mo | 352 ++++ .../Pumps/Generic/StagingHeaderedDeltaP.mo | 230 +++ .../Validation/ControlDifferentialPressure.mo | 152 ++ .../ResetLocalDifferentialPressure.mo | 97 + .../Generic/Validation/StagingHeadered.mo | 181 ++ .../Validation/StagingHeaderedDeltaP.mo | 138 ++ .../Pumps/Generic/Validation/package.mo | 29 + .../Pumps/Generic/Validation/package.order | 4 + .../Plants/Controls/Pumps/Generic/package.mo | 8 + .../Controls/Pumps/Generic/package.order | 5 + .../Pumps/Primary/EnableLeadHeadered.mo | 199 +++ .../Primary/Validation/EnableLeadHeadered.mo | 96 + .../Validation/VariableSpeedNoDpControl.mo | 129 ++ .../Pumps/Primary/Validation/package.mo | 29 + .../Pumps/Primary/Validation/package.order | 2 + .../Pumps/Primary/VariableSpeedNoDpControl.mo | 281 +++ .../Plants/Controls/Pumps/Primary/package.mo | 8 + .../Controls/Pumps/Primary/package.order | 3 + .../Plants/Controls/Pumps/package.mo | 43 + .../Plants/Controls/Pumps/package.order | 2 + .../Plants/Controls/Setpoints/PlantReset.mo | 261 +++ .../Setpoints/Validation/PlantReset.mo | 97 + .../Controls/Setpoints/Validation/package.mo | 29 + .../Setpoints/Validation/package.order | 1 + .../Plants/Controls/Setpoints/package.mo | 27 + .../Plants/Controls/Setpoints/package.order | 2 + .../StagingRotation/EquipmentAvailability.mo | 239 +++ .../StagingRotation/EquipmentEnable.mo | 312 ++++ .../StagingRotation/EventSequencing.mo | 405 +++++ .../Controls/StagingRotation/SortRuntime.mo | 315 ++++ .../StagingRotation/StageAvailability.mo | 158 ++ .../StagingRotation/StageChangeCommand.mo | 458 +++++ .../StagingRotation/StageCompletion.mo | 158 ++ .../Validation/EquipmentAvailability.mo | 94 + .../Validation/EquipmentEnable.mo | 134 ++ .../Validation/EventSequencing.mo | 117 ++ .../StagingRotation/Validation/SortRuntime.mo | 148 ++ .../Validation/StageAvailability.mo | 77 + .../Validation/StageChangeCommand.mo | 200 +++ .../Validation/StageCompletion.mo | 86 + .../StagingRotation/Validation/package.mo | 29 + .../StagingRotation/Validation/package.order | 7 + .../Controls/StagingRotation/package.mo | 43 + .../Controls/StagingRotation/package.order | 8 + Buildings/Templates/Plants/Controls/Types.mo | 28 + .../Plants/Controls/Utilities/CountTrue.mo | 62 + .../Controls/Utilities/FirstTrueIndex.mo | 81 + .../Plants/Controls/Utilities/HoldReal.mo | 81 + .../Controls/Utilities/LastTrueIndex.mo | 62 + .../Controls/Utilities/MultiMaxInteger.mo | 57 + .../Controls/Utilities/MultiMinInteger.mo | 57 + .../Controls/Utilities/PIDWithEnable.mo | 205 +++ .../Controls/Utilities/PlaceholderInteger.mo | 82 + .../Controls/Utilities/PlaceholderLogical.mo | 95 + .../Controls/Utilities/PlaceholderReal.mo | 82 + .../Controls/Utilities/SortWithIndices.mo | 104 ++ .../Plants/Controls/Utilities/StageIndex.mo | 480 +++++ .../Controls/Utilities/TimerWithReset.mo | 143 ++ .../Utilities/TrueArrayConditional.mo | 80 + .../Utilities/Validation/CountTrue.mo | 56 + .../Utilities/Validation/FirstTrueIndex.mo | 59 + .../Controls/Utilities/Validation/HoldReal.mo | 62 + .../Utilities/Validation/LastTrueIndex.mo | 59 + .../Utilities/Validation/MultiMaxInteger.mo | 50 + .../Utilities/Validation/MultiMinInteger.mo | 50 + .../Validation/PlaceholderInteger.mo | 70 + .../Validation/PlaceholderLogical.mo | 71 + .../Utilities/Validation/PlaceholderReal.mo | 67 + .../Utilities/Validation/SortWithIndices.mo | 113 ++ .../Utilities/Validation/StageIndex.mo | 145 ++ .../Utilities/Validation/TimerWithReset.mo | 120 ++ .../Validation/TrueArrayConditional.mo | 70 + .../Controls/Utilities/Validation/package.mo | 29 + .../Utilities/Validation/package.order | 13 + .../Plants/Controls/Utilities/package.mo | 48 + .../Plants/Controls/Utilities/package.order | 15 + .../Templates/Plants/Controls/package.mo | 47 + .../Templates/Plants/Controls/package.order | 7 + .../Templates/Plants/HeatPumps/AirToWater.mo | 766 ++++++++ .../Components/Controls/AirToWater.mo | 332 ++++ .../HeatPumps/Components/Controls/OpenLoop.mo | 209 +++ .../HeatPumps/Components/Controls/package.mo | 13 + .../Components/Controls/package.order | 2 + .../HeatPumps/Components/Data/Controller.mo | 229 +++ .../Components/Data/HeatPumpGroup.mo | 185 ++ .../HeatPumps/Components/Data/package.mo | 11 + .../HeatPumps/Components/Data/package.order | 2 + .../Components/HeatPumpGroups/AirToWater.mo | 40 + .../Components/HeatPumpGroups/package.mo | 11 + .../Components/HeatPumpGroups/package.order | 1 + .../Interfaces/PartialController.mo | 264 +++ .../Interfaces/PartialHeatPumpGroup.mo | 331 ++++ .../Components/Interfaces/package.mo | 11 + .../Components/Interfaces/package.order | 2 + .../Components/PumpsPrimaryDedicated.mo | 868 +++++++++ .../Validation/HeatPumpGroupAirToWater.mo | 386 ++++ .../Validation/PumpsPrimaryDedicated.mo | 694 ++++++++ .../Components/Validation/ValvesIsolation.mo | 482 +++++ .../Components/Validation/package.mo | 13 + .../Components/Validation/package.order | 3 + .../HeatPumps/Components/ValvesIsolation.mo | 1229 +++++++++++++ .../Plants/HeatPumps/Components/package.mo | 14 + .../Plants/HeatPumps/Components/package.order | 7 + .../HeatPumps/Configuration/HeatPumpPlant.mo | 138 ++ .../Plants/HeatPumps/Configuration/package.mo | 9 + .../HeatPumps/Configuration/package.order | 1 + .../Plants/HeatPumps/Data/HeatPumpPlant.mo | 127 ++ .../Plants/HeatPumps/Data/package.mo | 11 + .../Plants/HeatPumps/Data/package.order | 1 + .../Plants/HeatPumps/Interfaces/Bus.mo | 16 + .../Interfaces/PartialHeatPumpPlant.mo | 772 ++++++++ .../Plants/HeatPumps/Interfaces/package.mo | 9 + .../Plants/HeatPumps/Interfaces/package.order | 2 + Buildings/Templates/Plants/HeatPumps/Types.mo | 48 + .../Plants/HeatPumps/Validation/AirToWater.mo | 386 ++++ .../Validation/UserProject/Data/AllSystems.mo | 84 + .../Validation/UserProject/Data/package.mo | 12 + .../Validation/UserProject/Data/package.order | 1 + .../Validation/UserProject/package.mo | 11 + .../Validation/UserProject/package.order | 1 + .../Plants/HeatPumps/Validation/package.mo | 18 + .../Plants/HeatPumps/Validation/package.order | 2 + .../Templates/Plants/HeatPumps/package.mo | 9 + .../Templates/Plants/HeatPumps/package.order | 7 + Buildings/Templates/Plants/package.mo | 10 + Buildings/Templates/Plants/package.order | 2 + .../Utilities/computeBalancingPressureDrop.mo | 49 + Buildings/Templates/Utilities/package.mo | 27 + Buildings/Templates/Utilities/package.order | 1 + Buildings/Templates/package.order | 2 + 317 files changed, 25900 insertions(+), 140 deletions(-) create mode 100644 Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg create mode 100644 Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg create mode 100644 Buildings/Resources/Images/Templates/Components/Pumps/Single.svg create mode 100644 Buildings/Resources/Images/Templates/Components/Valves/Check.svg create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Components_Controls_Validation_MultipleCommands.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Components_Controls_Validation_StatusEmulator.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Components_HeatPumps_Validation_HeatPumpEquationFit.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Components_Validation_PumpMultipleRecord.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Components_Validation_Pumps.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Enabling_Validation_Enable.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_HeatPumps_Validation_AirToWater.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Pumps_Generic_Validation_ControlDifferentialPressure.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Pumps_Generic_Validation_ResetLocalDifferentialPressure.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Pumps_Generic_Validation_StagingHeadered.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Pumps_Generic_Validation_StagingHeaderedDeltaP.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Pumps_Primary_Validation_EnableLeadHeadered.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Pumps_Primary_Validation_VariableSpeedNoDpControl.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Setpoints_Validation_PlantReset.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_EquipmentAvailability.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_EquipmentEnable.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_EventSequencing.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_SortRuntime.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_StageAvailability.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_StageChangeCommand.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_StagingRotation_Validation_StageCompletion.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_CountTrue.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_FirstTrueIndex.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_HoldReal.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_LastTrueIndex.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_MultiMaxInteger.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_MultiMinInteger.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_PlaceholderInteger.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_PlaceholderLogical.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_PlaceholderReal.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_SortWithIndices.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_StageIndex.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_TimerWithReset.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_Controls_Utilities_Validation_TrueArrayConditional.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_HeatPumps_Components_Validation_HeatPumpGroupAirToWater.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_HeatPumps_Components_Validation_PumpsPrimaryDedicated.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_HeatPumps_Components_Validation_ValvesIsolation.txt create mode 100644 Buildings/Resources/ReferenceResults/Dymola/Buildings_Templates_Plants_HeatPumps_Validation_AirToWater.txt create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Components/Controls/Validation/MultipleCommands.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Components/Controls/Validation/StatusEmulator.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Components/HeatPumps/Validation/HeatPumpEquationFit.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/PumpMultipleRecord.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/Pumps.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Enabling/Validation/Enable.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/HeatPumps/Validation/AirToWater.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/ControlDifferentialPressure.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/ResetLocalDifferentialPressure.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeadered.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeaderedDeltaP.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Primary/Validation/EnableLeadHeadered.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Primary/Validation/VariableSpeedNoDpControl.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Setpoints/Validation/PlantReset.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/EquipmentAvailability.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/EquipmentEnable.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/EventSequencing.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/SortRuntime.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/StageAvailability.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/StageChangeCommand.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/StageCompletion.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/CountTrue.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/FirstTrueIndex.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/HoldReal.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/LastTrueIndex.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/MultiMaxInteger.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/MultiMinInteger.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/PlaceholderInteger.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/PlaceholderLogical.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/PlaceholderReal.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/SortWithIndices.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/StageIndex.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/TimerWithReset.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/TrueArrayConditional.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Components/Validation/HeatPumpGroupAirToWater.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Components/Validation/PumpsPrimaryDedicated.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Components/Validation/ValvesIsolation.mos create mode 100644 Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Validation/AirToWater.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Components.Controls.Validation.MultipleCommands.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Components.Controls.Validation.StatusEmulator.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Components.HeatPumps.Validation.HeatPumpEquationFit.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Components.Validation.PumpMultipleRecord.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Components.Validation.Pumps.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Enabling.Validation.Enable.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.HeatPumps.Validation.AirToWater.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Pumps.Generic.Validation.ControlDifferentialPressure.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Pumps.Generic.Validation.ResetLocalDifferentialPressure.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Pumps.Generic.Validation.StagingHeadered.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Pumps.Generic.Validation.StagingHeaderedDeltaP.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Pumps.Primary.Validation.EnableLeadHeadered.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Pumps.Primary.Validation.VariableSpeedNoDpControl.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Setpoints.Validation.PlantReset.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.EquipmentAvailability.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.EquipmentEnable.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.EventSequencing.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.SortRuntime.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.StageAvailability.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.StageChangeCommand.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.StagingRotation.Validation.StageCompletion.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.CountTrue.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.FirstTrueIndex.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.HoldReal.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.LastTrueIndex.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.MultiMaxInteger.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.MultiMinInteger.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.PlaceholderInteger.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.PlaceholderLogical.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.PlaceholderReal.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.SortWithIndices.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.StageIndex.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.TimerWithReset.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.Controls.Utilities.Validation.TrueArrayConditional.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.HeatPumps.Components.Validation.HeatPumpGroupAirToWater.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.HeatPumps.Components.Validation.PumpsPrimaryDedicated.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.HeatPumps.Components.Validation.ValvesIsolation.mos create mode 100644 Buildings/Resources/Scripts/OpenModelica/compareVars/Buildings.Templates.Plants.HeatPumps.Validation.AirToWater.mos create mode 100644 Buildings/Templates/Components/Controls/StatusEmulator.mo create mode 100644 Buildings/Templates/Components/Controls/Validation/MultipleCommands.mo create mode 100644 Buildings/Templates/Components/Controls/Validation/StatusEmulator.mo create mode 100644 Buildings/Templates/Components/Controls/Validation/package.mo create mode 100644 Buildings/Templates/Components/Controls/Validation/package.order create mode 100644 Buildings/Templates/Components/Data/HeatPump.mo create mode 100644 Buildings/Templates/Components/Data/PumpMultiple.mo create mode 100644 Buildings/Templates/Components/Data/PumpSingle.mo create mode 100644 Buildings/Templates/Components/HeatPumps/AirToWater.mo create mode 100644 Buildings/Templates/Components/HeatPumps/Validation/HeatPumpEquationFit.mo create mode 100644 Buildings/Templates/Components/HeatPumps/Validation/package.mo create mode 100644 Buildings/Templates/Components/HeatPumps/Validation/package.order create mode 100644 Buildings/Templates/Components/HeatPumps/WaterToWater.mo create mode 100644 Buildings/Templates/Components/HeatPumps/package.mo create mode 100644 Buildings/Templates/Components/HeatPumps/package.order create mode 100644 Buildings/Templates/Components/Interfaces/PartialHeatPump.mo create mode 100644 Buildings/Templates/Components/Interfaces/PartialHeatPumpEquationFit.mo create mode 100644 Buildings/Templates/Components/Interfaces/PartialPump.mo create mode 100644 Buildings/Templates/Components/Interfaces/PartialPumpMultiple.mo create mode 100644 Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo create mode 100644 Buildings/Templates/Components/Pumps/Multiple.mo create mode 100644 Buildings/Templates/Components/Pumps/Single.mo create mode 100644 Buildings/Templates/Components/Pumps/package.mo create mode 100644 Buildings/Templates/Components/Pumps/package.order create mode 100644 Buildings/Templates/Components/Routing/Junction.mo create mode 100644 Buildings/Templates/Components/Validation/PumpMultipleRecord.mo create mode 100644 Buildings/Templates/Components/Validation/Pumps.mo create mode 100644 Buildings/Templates/Data/Defaults.mo create mode 100644 Buildings/Templates/Plants/Controls/Enabling/Enable.mo create mode 100644 Buildings/Templates/Plants/Controls/Enabling/Validation/Enable.mo create mode 100644 Buildings/Templates/Plants/Controls/Enabling/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Enabling/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/Enabling/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Enabling/package.order create mode 100644 Buildings/Templates/Plants/Controls/HeatPumps/AirToWater.mo create mode 100644 Buildings/Templates/Plants/Controls/HeatPumps/Validation/AirToWater.mo create mode 100644 Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/HeatPumps/package.mo create mode 100644 Buildings/Templates/Plants/Controls/HeatPumps/package.order create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/ControlDifferentialPressure.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/ResetLocalDifferentialPressure.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeadered.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeaderedDeltaP.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ControlDifferentialPressure.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ResetLocalDifferentialPressure.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeadered.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeaderedDeltaP.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Generic/package.order create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/EnableLeadHeadered.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/EnableLeadHeadered.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/VariableSpeedNoDpControl.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/VariableSpeedNoDpControl.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/Primary/package.order create mode 100644 Buildings/Templates/Plants/Controls/Pumps/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Pumps/package.order create mode 100644 Buildings/Templates/Plants/Controls/Setpoints/PlantReset.mo create mode 100644 Buildings/Templates/Plants/Controls/Setpoints/Validation/PlantReset.mo create mode 100644 Buildings/Templates/Plants/Controls/Setpoints/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Setpoints/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/Setpoints/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Setpoints/package.order create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/EquipmentAvailability.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/EquipmentEnable.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/EventSequencing.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/SortRuntime.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/StageAvailability.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/StageChangeCommand.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/StageCompletion.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentAvailability.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentEnable.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/EventSequencing.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/SortRuntime.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageAvailability.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageChangeCommand.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageCompletion.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/StagingRotation/package.order create mode 100644 Buildings/Templates/Plants/Controls/Types.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/CountTrue.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/FirstTrueIndex.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/HoldReal.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/LastTrueIndex.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/MultiMaxInteger.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/MultiMinInteger.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/PIDWithEnable.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/PlaceholderInteger.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/PlaceholderLogical.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/PlaceholderReal.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/SortWithIndices.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/StageIndex.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/TimerWithReset.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/TrueArrayConditional.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/CountTrue.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/FirstTrueIndex.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/HoldReal.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/LastTrueIndex.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMaxInteger.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMinInteger.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderInteger.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderLogical.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderReal.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/SortWithIndices.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/StageIndex.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/TimerWithReset.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/TrueArrayConditional.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/Validation/package.order create mode 100644 Buildings/Templates/Plants/Controls/Utilities/package.mo create mode 100644 Buildings/Templates/Plants/Controls/Utilities/package.order create mode 100644 Buildings/Templates/Plants/Controls/package.mo create mode 100644 Buildings/Templates/Plants/Controls/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/AirToWater.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Controls/AirToWater.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Controls/OpenLoop.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Controls/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Controls/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Data/Controller.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Data/HeatPumpGroup.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Data/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Data/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/AirToWater.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialController.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialHeatPumpGroup.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/PumpsPrimaryDedicated.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Validation/HeatPumpGroupAirToWater.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Validation/PumpsPrimaryDedicated.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Validation/ValvesIsolation.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Validation/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/Validation/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/ValvesIsolation.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Components/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Configuration/HeatPumpPlant.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Configuration/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Configuration/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Data/HeatPumpPlant.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Data/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Data/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Interfaces/Bus.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Interfaces/PartialHeatPumpPlant.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Interfaces/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Interfaces/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Types.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/AirToWater.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/AllSystems.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/Validation/package.order create mode 100644 Buildings/Templates/Plants/HeatPumps/package.mo create mode 100644 Buildings/Templates/Plants/HeatPumps/package.order create mode 100644 Buildings/Templates/Plants/package.mo create mode 100644 Buildings/Templates/Plants/package.order create mode 100644 Buildings/Templates/Utilities/computeBalancingPressureDrop.mo create mode 100644 Buildings/Templates/Utilities/package.mo create mode 100644 Buildings/Templates/Utilities/package.order diff --git a/Buildings/Fluid/HeatPumps/EquationFitReversible.mo b/Buildings/Fluid/HeatPumps/EquationFitReversible.mo index bd434a44ade..110fced63d1 100644 --- a/Buildings/Fluid/HeatPumps/EquationFitReversible.mo +++ b/Buildings/Fluid/HeatPumps/EquationFitReversible.mo @@ -56,6 +56,13 @@ model EquationFitReversible output Real PLR(min=0, nominal=1, unit="1") = equFit.PLR "Part load ratio"; + + Buildings.Controls.OBC.CDL.Utilities.Assert aleMes( + message="uMod cannot be -1 if reverseCycle is false.") + if not per.reverseCycle + "Generate alert message if control input is not valid" + annotation (Placement(transformation(extent={{-52,-90},{-32,-70}}))); + protected constant Modelica.Units.SI.SpecificEnergy h1_default= Medium1.specificEnthalpy_pTX( @@ -117,11 +124,6 @@ protected "Indicator, outputs true if in cooling mode" annotation (Placement(transformation(extent={{-80,-90},{-60,-70}}))); - Buildings.Controls.OBC.CDL.Utilities.Assert aleMes(message="uMod = -1 (cooling) is not allowed as reverseCycle is false.") - if not per.reverseCycle - "Generate alert message if control input is not valid" - annotation (Placement(transformation(extent={{-52,-90},{-32,-70}}))); - equation connect(equFit.QSou_flow,QSou_flow) annotation (Line(points={{11,-2},{32,-2},{32,-88},{110,-88}}, color={0,0,127})); 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/Sensors/ProbeInWell.svg b/Buildings/Resources/Images/Templates/Components/Sensors/ProbeInWell.svg index 29cc872049b..228bc49c3df 100644 --- a/Buildings/Resources/Images/Templates/Components/Sensors/ProbeInWell.svg +++ b/Buildings/Resources/Images/Templates/Components/Sensors/ProbeInWell.svg @@ -8,7 +8,7 @@ version="1.1" id="svg19564" sodipodi:docname="ProbeInWell.svg" - inkscape:version="1.2.2 (732a01da63, 2022-12-09)" + inkscape:version="1.3.2 (091e20e, 2023-11-25)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -25,13 +25,13 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="0.5989195" - inkscape:cx="-124.39067" - inkscape:cy="224.57108" - inkscape:window-width="1920" - inkscape:window-height="1028" - inkscape:window-x="-6" - inkscape:window-y="-6" - inkscape:window-maximized="1" + inkscape:cx="-123.55584" + inkscape:cy="223.73625" + inkscape:window-width="1880" + inkscape:window-height="1027" + inkscape:window-x="46" + inkscape:window-y="25" + inkscape:window-maximized="0" inkscape:current-layer="svg19564" /> @@ -54,8 +54,8 @@ id="rect9041" width="61.494431" height="104.5187" - x="69.252785" - y="47.74065" /> + x="69.252762" + y="94.978653" /> + + + + + + + + + + + + + + + + + + + diff --git a/Buildings/Resources/Images/Templates/Components/Valves/ThreeWay.svg b/Buildings/Resources/Images/Templates/Components/Valves/ThreeWay.svg index f66b2a0f944..c560eae7a03 100644 --- a/Buildings/Resources/Images/Templates/Components/Valves/ThreeWay.svg +++ b/Buildings/Resources/Images/Templates/Components/Valves/ThreeWay.svg @@ -8,7 +8,7 @@ version="1.1" id="svg1985" sodipodi:docname="ThreeWay.svg" - inkscape:version="1.2.2 (732a01da63, 2022-12-09)" + inkscape:version="1.3.2 (091e20e, 2023-11-25)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -22,17 +22,34 @@ inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" - showgrid="false" + showgrid="true" inkscape:zoom="1.1978389" inkscape:cx="439.54158" - inkscape:cy="295.94965" - inkscape:window-width="1920" - inkscape:window-height="1028" - inkscape:window-x="-6" - inkscape:window-y="-6" - inkscape:window-maximized="1" + inkscape:cy="296.36707" + inkscape:window-width="1392" + inkscape:window-height="1027" + inkscape:window-x="46" + inkscape:window-y="25" + inkscape:window-maximized="0" inkscape:current-layer="svg1985" - inkscape:document-units="mm" /> + inkscape:document-units="mm"> + + + + diff --git a/Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg b/Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg index e21401b50b9..74a7459328e 100644 --- a/Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg +++ b/Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg @@ -8,7 +8,7 @@ version="1.1" id="svg1985" sodipodi:docname="TwoWay.svg" - inkscape:version="1.2.2 (732a01da63, 2022-12-09)" + inkscape:version="1.3.2 (091e20e, 2023-11-25)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -22,17 +22,34 @@ inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" - showgrid="false" - inkscape:zoom="0.59891944" - inkscape:cx="242.93751" - inkscape:cy="459.99508" - inkscape:window-width="1920" - inkscape:window-height="1028" - inkscape:window-x="-6" - inkscape:window-y="-6" + showgrid="true" + inkscape:zoom="0.84906002" + inkscape:cx="289.73217" + inkscape:cy="268.53225" + inkscape:window-width="1880" + inkscape:window-height="1027" + inkscape:window-x="46" + inkscape:window-y="25" inkscape:window-maximized="1" inkscape:current-layer="svg1985" - inkscape:document-units="mm" /> + inkscape:document-units="mm"> + + + Buildings.Templates.Components.Types.Damper.None)); + parameter Boolean from_dp = false + "= true, use m_flow = f(dp) else dp = f(m_flow)" + annotation (Evaluate=true, Dialog(tab="Advanced", + enable=typ<>Buildings.Templates.Components.Types.Damper.None)); + parameter Boolean linearized = false + "= true, use linear relation between m_flow and dp for any flow rate" + annotation(Evaluate=true, Dialog(tab="Advanced", + enable=typ<>Buildings.Templates.Components.Types.Damper.None and + typ<>Buildings.Templates.Components.Types.Damper.PressureIndependent)); + parameter Buildings.Templates.Components.Types.DamperBlades typBla= if typ==Buildings.Templates.Components.Types.Damper.TwoPosition then Buildings.Templates.Components.Types.DamperBlades.Opposed @@ -75,7 +85,9 @@ model Damper "Multiple-configuration damper" final init=init, final y_start=y_start, final allowFlowReversal=allowFlowReversal, - final show_T=show_T) + final show_T=show_T, + final from_dp=from_dp, + final linearized=linearized) if typ==Buildings.Templates.Components.Types.Damper.Modulating or typ==Buildings.Templates.Components.Types.Damper.TwoPosition "Damper with exponential characteristic" @@ -90,7 +102,8 @@ model Damper "Multiple-configuration damper" final init=init, final y_start=y_start, final allowFlowReversal=allowFlowReversal, - final show_T=show_T) + final show_T=show_T, + final from_dp=from_dp) if typ==Buildings.Templates.Components.Types.Damper.PressureIndependent "Pressure independent damper" annotation (Placement(transformation(extent={{50,-10},{70,10}}))); diff --git a/Buildings/Templates/Components/Actuators/Valve.mo b/Buildings/Templates/Components/Actuators/Valve.mo index 1bf9dde3091..d7caac83624 100644 --- a/Buildings/Templates/Components/Actuators/Valve.mo +++ b/Buildings/Templates/Components/Actuators/Valve.mo @@ -148,6 +148,18 @@ model Valve "Multiple-configuration valve" typ==Buildings.Templates.Components.Types.Valve.ThreeWayTwoPosition), __ctrlFlow(enable=false)); + parameter Boolean from_dp = false + "= true, use m_flow = f(dp) else dp = f(m_flow)" + annotation (Evaluate=true, Dialog(tab="Advanced", + enable=typ<>Buildings.Templates.Components.Types.Valve.None)); + parameter Boolean linearized = false + "= true, use linear relation between m_flow and dp for any flow rate" + annotation(Evaluate=true, Dialog(tab="Advanced", + enable=typ<>Buildings.Templates.Components.Types.Valve.None and + (if typ==Buildings.Templates.Components.Types.Valve.TwoWayModulating then + chaTwo<>Buildings.Templates.Components.Types.ValveCharacteristicTwoWay.PressureIndependent + else true))); + parameter Integer text_rotation = 0 "Text rotation angle in icon layer" annotation(Dialog(tab="Graphics", enable=false)); @@ -230,7 +242,9 @@ model Valve "Multiple-configuration valve" final init=init, final y_start=y_start, final allowFlowReversal=allowFlowReversal, - final show_T=show_T) + final show_T=show_T, + final from_dp=from_dp, + final linearized=linearized) if is_twoWay and chaTwo==Buildings.Templates.Components.Types.ValveCharacteristicTwoWay.EqualPercentage "Two-way valve with equal percentage characteristic" @@ -251,7 +265,9 @@ model Valve "Multiple-configuration valve" final init=init, final y_start=y_start, final allowFlowReversal=allowFlowReversal, - final show_T=show_T) + final show_T=show_T, + final from_dp=from_dp, + final linearized=linearized) if is_twoWay and chaTwo==Buildings.Templates.Components.Types.ValveCharacteristicTwoWay.Linear "Two-way valve with linear characteristic" @@ -272,7 +288,8 @@ model Valve "Multiple-configuration valve" final init=init, final y_start=y_start, final allowFlowReversal=allowFlowReversal, - final show_T=show_T) + final show_T=show_T, + final from_dp=from_dp) if is_twoWay and chaTwo==Buildings.Templates.Components.Types.ValveCharacteristicTwoWay.PressureIndependent "Pressure independent two-way valve" @@ -294,7 +311,9 @@ model Valve "Multiple-configuration valve" final init=init, final y_start=y_start, final allowFlowReversal=allowFlowReversal, - final show_T=show_T) + final show_T=show_T, + final from_dp=from_dp, + final linearized=linearized) if is_twoWay and chaTwo==Buildings.Templates.Components.Types.ValveCharacteristicTwoWay.Table "Pressure independent two-way valve" @@ -325,7 +344,9 @@ model Valve "Multiple-configuration valve" else Modelica.Fluid.Types.PortFlowDirection.Leaving, final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional - else Modelica.Fluid.Types.PortFlowDirection.Entering) + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final from_dp=from_dp, + final linearized={linearized, linearized}) if is_thrWay and chaThr==Buildings.Templates.Components.Types.ValveCharacteristicThreeWay.EqualPercentageLinear "Three-way valve with equal percentage and linear characteristics" @@ -353,7 +374,9 @@ model Valve "Multiple-configuration valve" final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional else Modelica.Fluid.Types.PortFlowDirection.Leaving, final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional - else Modelica.Fluid.Types.PortFlowDirection.Entering) + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final from_dp=from_dp, + final linearized={linearized, linearized}) if is_thrWay and chaThr==Buildings.Templates.Components.Types.ValveCharacteristicThreeWay.Linear "Three-way valve with linear characteristics" @@ -383,7 +406,9 @@ model Valve "Multiple-configuration valve" final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional else Modelica.Fluid.Types.PortFlowDirection.Leaving, final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional - else Modelica.Fluid.Types.PortFlowDirection.Entering) + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final from_dp=from_dp, + final linearized={linearized, linearized}) if is_thrWay and chaThr==Buildings.Templates.Components.Types.ValveCharacteristicThreeWay.Table "Three-way valve with table-specified characteristics" diff --git a/Buildings/Templates/Components/Controls/MultipleCommands.mo b/Buildings/Templates/Components/Controls/MultipleCommands.mo index 0be6ad00d19..f3d8bd0ac38 100644 --- a/Buildings/Templates/Components/Controls/MultipleCommands.mo +++ b/Buildings/Templates/Components/Controls/MultipleCommands.mo @@ -59,7 +59,9 @@ equation color={255,0,255})); connect(y1One, mulOr.y) annotation (Line(points={{120,60},{-38,60}}, color={255,0,255})); - annotation (Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100}, + annotation ( + defaultComponentName="conCom", + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100}, {100,100}}), graphics={ Rectangle( extent={{-100,-100},{100,100}}, diff --git a/Buildings/Templates/Components/Controls/StatusEmulator.mo b/Buildings/Templates/Components/Controls/StatusEmulator.mo new file mode 100644 index 00000000000..d5748ff650d --- /dev/null +++ b/Buildings/Templates/Components/Controls/StatusEmulator.mo @@ -0,0 +1,88 @@ +within Buildings.Templates.Components.Controls; +block StatusEmulator "Block that emulates the status of an equipment" + parameter Modelica.Units.SI.Time yLim=0.5 + "Value of filtered signal above which the equipment reports on status"; + parameter Modelica.Units.SI.Time riseTime=10 + "Rise time of the filter (time to reach 99.6 % of the speed)"; + parameter Modelica.Blocks.Types.Init initType=Modelica.Blocks.Types.Init.InitialOutput + "Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)" + annotation ( + Evaluate=true, + Dialog(group="Initialization")); + parameter Real y_start=0.0 + "Initial value of output (remaining states are in steady state)" + annotation(Dialog(enable=initType == Modelica.Blocks.Types.Init.InitialOutput, group= + "Initialization")); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1 "Equipment run command" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1_actual + "Equipment status" annotation (Placement(transformation(extent={{100,-20},{140, + 20}}), iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea(final realTrue=1, + final realFalse=0) "Convert to real" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + Fluid.BaseClasses.ActuatorFilter fil( + final f=fCut, + final initType=initType, + final y_start=y_start) + "Filter signal" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr(final t=yLim) + "Compare filtered signal to zero to trigger true status" + annotation (Placement(transformation(extent={{50,-10},{70,10}}))); +protected + final parameter Modelica.Units.SI.Frequency fCut=5/(2*Modelica.Constants.pi* + riseTime) "Cut-off frequency of filter"; +equation + connect(y1, booToRea.u) + annotation (Line(points={{-120,0},{-72,0}}, color={255,0,255})); + connect(booToRea.y,fil. u) + annotation (Line(points={{-48,0},{-12,0}}, color={0,0,127})); + connect(greThr.y, y1_actual) annotation (Line(points={{72,0},{120,0}}, + color={255,0,255})); + connect(fil.y, greThr.u) + annotation (Line(points={{11,0},{48,0}}, color={0,0,127})); + annotation ( + defaultComponentName="sta", + Icon(coordinateSystem(preserveAspectRatio=false, extent={{-100,-100}, + {100,100}}), graphics={ + Rectangle( + extent={{-100,-100},{100,100}}, + lineColor={0,0,127}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation(info=" +

+This block emulates the status of an equipment, i.e., +the current on/off state as reported by the hardware itself. +

+

+The implementation is based on + +Buildings.Fluid.BaseClasses.ActuatorFilter +and the model is configured with yLim=0.5 so that +the delay between the on command and the on status is +equal to the delay between the off command and the off status +(about 2 s with the default parameter settings). +Note that this delay may not be representative of the actual +dynamics of certain equipment such as chillers or heat pumps. +In addition, this block uses the equipment command signal to +generate the status signal, which in turn can lead to inconsistencies +with certain equipment that run cyclically at low load and +where the status then comes and goes. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end StatusEmulator; diff --git a/Buildings/Templates/Components/Controls/Validation/MultipleCommands.mo b/Buildings/Templates/Components/Controls/Validation/MultipleCommands.mo new file mode 100644 index 00000000000..697a16215f5 --- /dev/null +++ b/Buildings/Templates/Components/Controls/Validation/MultipleCommands.mo @@ -0,0 +1,31 @@ +within Buildings.Templates.Components.Controls.Validation; +model MultipleCommands "Validation model for converter of multiple commands" + extends Modelica.Icons.Example; + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse y1[3]( + width={0.5,0.6,0.4}, + each period=600, + shift={100,200,300}) + "Enable command" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Components.Controls.MultipleCommands conCom(nUni=3) + "Converter of multiple commands" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); +equation + connect(y1.y, conCom.y1) + annotation (Line(points={{-58,0},{-12,0}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Controls/Validation/MultipleCommands.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StopTime=2000.0), + Documentation(info=" +

+This model validates + +Buildings.Templates.Components.Controls.MultipleCommands. +

+")); +end MultipleCommands; diff --git a/Buildings/Templates/Components/Controls/Validation/StatusEmulator.mo b/Buildings/Templates/Components/Controls/Validation/StatusEmulator.mo new file mode 100644 index 00000000000..e16ad5a62e1 --- /dev/null +++ b/Buildings/Templates/Components/Controls/Validation/StatusEmulator.mo @@ -0,0 +1,28 @@ +within Buildings.Templates.Components.Controls.Validation; +model StatusEmulator "Validation model for status emulator" + extends Modelica.Icons.Example; + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse y1(period=10) + "Enable command" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Components.Controls.StatusEmulator sta(y_start=1) + "Generate status" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); +equation + connect(y1.y, sta.y1) + annotation (Line(points={{-58,0},{-12,0}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Controls/Validation/StatusEmulator.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StopTime=50.0), + Documentation(info=" +

+This model validates + +Buildings.Templates.Components.Controls.StatusEmulator. +

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

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

+")); +end Validation; diff --git a/Buildings/Templates/Components/Controls/Validation/package.order b/Buildings/Templates/Components/Controls/Validation/package.order new file mode 100644 index 00000000000..2134d98ddf7 --- /dev/null +++ b/Buildings/Templates/Components/Controls/Validation/package.order @@ -0,0 +1,2 @@ +MultipleCommands +StatusEmulator diff --git a/Buildings/Templates/Components/Controls/package.order b/Buildings/Templates/Components/Controls/package.order index 2dc29dcab9c..55af62bc1e9 100644 --- a/Buildings/Templates/Components/Controls/package.order +++ b/Buildings/Templates/Components/Controls/package.order @@ -1 +1,3 @@ MultipleCommands +StatusEmulator +Validation diff --git a/Buildings/Templates/Components/Data/HeatPump.mo b/Buildings/Templates/Components/Data/HeatPump.mo new file mode 100644 index 00000000000..0ac75bdbb64 --- /dev/null +++ b/Buildings/Templates/Components/Data/HeatPump.mo @@ -0,0 +1,195 @@ +within Buildings.Templates.Components.Data; +record HeatPump "Record for heat pump model" + extends Modelica.Icons.Record; + + parameter Buildings.Templates.Components.Types.HeatPump typ + "Equipment type" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Boolean is_rev + "Set to true for reversible heat pumps, false for heating only" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + parameter Buildings.Templates.Components.Types.HeatPumpModel typMod + "Type of heat pump model" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + // Default fluid properties + parameter Modelica.Units.SI.SpecificHeatCapacity cpHeaWat_default= + Buildings.Utilities.Psychrometrics.Constants.cpWatLiq + "HW default specific heat capacity" + annotation (Dialog(group="Configuration", enable=false)); + /* + cpChiWat_default is for internal use only. + It is the same as cpChiWat_default for reversible HP. + Non-reversible HP that can be controlled to produce either HW or CHW + shall be modeled with chiller components (as a chiller/heater). + */ + final parameter Modelica.Units.SI.SpecificHeatCapacity cpChiWat_default= + cpHeaWat_default + "CHW default specific heat capacity"; + parameter Modelica.Units.SI.SpecificHeatCapacity cpSou_default= + if typ==Buildings.Templates.Components.Types.HeatPump.AirToWater then + Buildings.Utilities.Psychrometrics.Constants.cpAir else + Buildings.Utilities.Psychrometrics.Constants.cpWatLiq + "Source fluid default specific heat capacity" + annotation (Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal( + final min=0) + "HW mass flow rate" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpHeaWat_nominal( + min=0, + start=Buildings.Templates.Data.Defaults.dpChiWatChi) + "Pressure drop at design HW mass flow rate" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.HeatFlowRate capHea_nominal + "Heating capacity" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.Temperature THeaWatSup_nominal( + final min=273.15) + "(Highest) HW supply temperature" + annotation(Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.Temperature THeaWatRet_nominal= + THeaWatSup_nominal-abs(capHea_nominal)/cpHeaWat_default/mHeaWat_flow_nominal + "HW return temperature" + annotation(Dialog(group="Nominal condition")); + + parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal( + start=0, + final min=0) + "CHW mass flow rate" + annotation(Dialog(group="Nominal condition", enable=is_rev)); + final parameter Modelica.Units.SI.PressureDifference dpChiWat_nominal= + dpHeaWat_nominal * (mChiWat_flow_nominal/mHeaWat_flow_nominal)^2 + "Pressure drop at design CHW mass flow rate" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.HeatFlowRate capCoo_nominal( + start=0) + "Cooling capacity" + annotation(Dialog(group="Nominal condition", enable=is_rev)); + parameter Modelica.Units.SI.Temperature TChiWatSup_nominal( + start=Buildings.Templates.Data.Defaults.TChiWatSup, + final min=253.15) + "(Lowest) CHW supply temperature" + annotation(Dialog(group="Nominal condition", enable=is_rev)); + final parameter Modelica.Units.SI.Temperature TChiWatRet_nominal= + if is_rev then + TChiWatSup_nominal+abs(capCoo_nominal)/cpChiWat_default/mChiWat_flow_nominal + else Buildings.Templates.Data.Defaults.TChiWatRet + "CHW return temperature" + annotation(Dialog(group="Nominal condition", enable=is_rev)); + parameter Modelica.Units.SI.Temperature TSouHea_nominal( + start=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + final min=220) + "OAT or source fluid supply temperature (evaporator entering) in heating mode" + annotation(Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.MassFlowRate mSouWwHea_flow_nominal( + start=mHeaWat_flow_nominal, + final min=0) + "Source fluid mass flow rate in heating mode" + annotation(Dialog(group="Nominal condition", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + parameter Modelica.Units.SI.PressureDifference dpSouWwHea_nominal( + min=0, + start=Buildings.Templates.Data.Defaults.dpChiWatChi) + "Source fluid pressure drop in heating mode" + annotation (Dialog(group="Nominal condition", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + final parameter Modelica.Units.SI.MassFlowRate mSouHea_flow_nominal= + if typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater then + mSouWwHea_flow_nominal else + Buildings.Templates.Data.Defaults.mAirFloByCapChi * abs(capHea_nominal) + "Source fluid mass flow rate in heating mode"; + final parameter Modelica.Units.SI.PressureDifference dpSouHea_nominal= + if typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater then + dpSouWwHea_nominal else Buildings.Templates.Data.Defaults.dpAirChi + "Source fluid pressure drop in heating mode"; + parameter Modelica.Units.SI.Temperature TSouCoo_nominal( + start=Buildings.Templates.Data.Defaults.TOutHpCoo, + final min=273.15) + "OAT or source fluid supply temperature (condenser entering) in cooling mode" + annotation(Dialog(group="Nominal condition", + enable=is_rev)); + parameter Modelica.Units.SI.MassFlowRate mSouWwCoo_flow_nominal( + start=mChiWat_flow_nominal, + final min=0) + "Source fluid mass flow rate in cooling mode" + annotation(Dialog(group="Nominal condition", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater and + is_rev)); + final parameter Modelica.Units.SI.MassFlowRate mSouCoo_flow_nominal= + if typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater then + mSouWwCoo_flow_nominal else + Buildings.Templates.Data.Defaults.mAirFloByCapChi * abs(capCoo_nominal) + "Source fluid mass flow rate in cooling mode"; + final parameter Modelica.Units.SI.PressureDifference dpSouCoo_nominal= + dpSouHea_nominal * (mSouCoo_flow_nominal/mSouHea_flow_nominal)^2 + "Source fluid pressure drop in cooling mode"; + replaceable parameter + Buildings.Fluid.HeatPumps.Data.EquationFitReversible.Generic perFit( + dpHeaLoa_nominal=dpHeaWat_nominal, + dpHeaSou_nominal=dpSouHea_nominal, + hea( + Q_flow=abs(capHea_nominal), + P=0, + mLoa_flow=mHeaWat_flow_nominal, + mSou_flow=mSouHea_flow_nominal, + coeQ={1,0,0,0,0}, + coeP={1,0,0,0,0}, + TRefLoa=THeaWatRet_nominal, + TRefSou=TSouHea_nominal), + coo( + Q_flow=if is_rev then -abs(capCoo_nominal) else -1, + P=0, + mLoa_flow=mChiWat_flow_nominal, + mSou_flow=mSouCoo_flow_nominal, + coeQ={1,0,0,0,0}, + coeP={1,0,0,0,0}, + TRefLoa=TChiWatRet_nominal, + TRefSou=TSouCoo_nominal)) constrainedby + Buildings.Fluid.HeatPumps.Data.EquationFitReversible.Generic + "Performance data - Equation fit model" + annotation ( + Dialog(enable=typMod == Buildings.Templates.Components.Types.HeatPumpModel.EquationFit), + choicesAllMatching=true, + Placement(transformation(extent={{-8,-40},{8,-24}}))); + +annotation ( + defaultComponentPrefixes="parameter", + defaultComponentName="dat", + Documentation(info=" +

+This record provides the set of sizing and operating parameters for +heat pump models that can be found within + +Buildings.Templates.Components.HeatPumps. +

+

Performance data for the equation fit model

+

When using +typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, +the design values declared at the top-level +are propagated by default to the performance data record per +under the assumption that the reference conditions used for assessing the +performance data match the design conditions. +This avoids duplicate parameter assignments when manually entering +the performance curve coefficients. +

+

+Note that this propagation does not persist when redeclaring or +reassigning the record. +This is because the equation fit method uses reference values that +must match the ones used to compute the performance curve coefficients. +

+

+Also note that placeholders values are assigned to the performance curves, +the reference source temperature and the input power in +cooling mode to avoid assigning these parameters in case of non-reversible +heat pumps. +These values are unrealistic and must be overwritten for reversible heat pumps, which +is always the case when redeclaring or +reassigning the performance record per. +Models that use this record will issue a warning if these placeholders values +are not overwritten in case of reversible heat pumps. +

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

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

+

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

+

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

+
    +
  • Assign the whole subrecord 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.
  • +
  • Redeclare the component 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..4442b7755b2 --- /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 Buildings.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..4c65b6dc152 100644 --- a/Buildings/Templates/Components/Data/package.order +++ b/Buildings/Templates/Components/Data/package.order @@ -1,4 +1,7 @@ Coil Damper Fan +HeatPump +PumpMultiple +PumpSingle Valve diff --git a/Buildings/Templates/Components/HeatPumps/AirToWater.mo b/Buildings/Templates/Components/HeatPumps/AirToWater.mo new file mode 100644 index 00000000000..d5ac01bd975 --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/AirToWater.mo @@ -0,0 +1,67 @@ +within Buildings.Templates.Components.HeatPumps; +model AirToWater + "Air-to-water heat pump - Equation fit model" + extends Buildings.Templates.Components.Interfaces.PartialHeatPumpEquationFit( + redeclare final package MediumSou=MediumAir, + final typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + final allowFlowReversalSou=false); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter mAir_flow( + final k=mSouHea_flow_nominal) + "Air mass flow rate" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=-90, + origin={60,-60}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal y1Rea + "Convert on/off command into real" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=-90, + origin={60,90}))); + Fluid.Movers.BaseClasses.IdealSource floSou( + redeclare final package Medium=MediumAir, + final m_flow_small=1E-4 * mSouHea_flow_nominal, + final allowFlowReversal=allowFlowReversalSou, + final control_m_flow=true, + final control_dp=false) + "Air flow source" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={80,-90}))); +equation + connect(y1Rea.y, mAir_flow.u) + annotation (Line(points={{60,78},{60,-48}},color={0,0,127})); + connect(floSou.port_b, TSouEnt.port_a) + annotation (Line(points={{80,-80},{80,-20},{40,-20}},color={0,127,255})); + connect(port_aSou, floSou.port_a) + annotation (Line(points={{80,-140},{80,-100}},color={0,127,255})); + connect(mAir_flow.y, floSou.m_flow_in) + annotation (Line(points={{60,-72},{60,-96},{72,-96}},color={0,0,127})); + connect(bus.y1, y1Rea.u) + annotation (Line(points={{0,160},{0,110},{60,110},{60,102}},color={255,204,51},thickness=0.5)); + annotation ( + defaultComponentName="hp", + Documentation( + info=" +

+This is a model for an air-to-water heat pump where the capacity +and input power are computed based on the equation fit method. +The model can be configured to represent either a non-reversible heat pump +(is_rev=false) or a reversible heat pump (is_rev=true). +This model uses + +Buildings.Fluid.HeatPumps.EquationFitReversible, +which the user may refer to for the modeling assumptions. +

+

Control points

+

+Refer to the documentation of the interface class + +Buildings.Templates.Components.Interfaces.PartialHeatPumpEquationFit +for a description of the available control input and output +variables. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end AirToWater; diff --git a/Buildings/Templates/Components/HeatPumps/Validation/HeatPumpEquationFit.mo b/Buildings/Templates/Components/HeatPumps/Validation/HeatPumpEquationFit.mo new file mode 100644 index 00000000000..d61e7670dae --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/Validation/HeatPumpEquationFit.mo @@ -0,0 +1,427 @@ +within Buildings.Templates.Components.HeatPumps.Validation; +model HeatPumpEquationFit + "Validation model for heat pump component with equation fit model" + extends Modelica.Icons.Example; + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW or CHW 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.HeatPump datHpAwNrv( + final cpHeaWat_default=hpAwNrv.cpHeaWat_default, + final cpSou_default=hpAwNrv.cpSou_default, + final typ=hpAwNrv.typ, + final is_rev=hpAwNrv.is_rev, + final typMod=hpAwNrv.typMod, + mHeaWat_flow_nominal=datHpAw.capHea_nominal/abs(datHpAw.THeaWatSup_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWat_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHea_nominal=500E3, + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TSouHea_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + perFit(hea( + P=datHpAwNrv.capHea_nominal/Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={-4.2670305442,-0.7381077035,6.0049480456,0,0}, + coeP={-4.9107455513,5.3665308366,0.5447612754,0,0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpHeaLow))) + "Non-reversible AWHP parameters" + annotation (Placement(transformation(extent={{120,100},{140,120}}))); + + parameter Buildings.Templates.Components.Data.HeatPump datHpAw( + final cpHeaWat_default=hpAw.cpHeaWat_default, + final cpSou_default=hpAw.cpSou_default, + final typ=hpAw.typ, + final is_rev=hpAw.is_rev, + final typMod=hpAw.typMod, + mHeaWat_flow_nominal=datHpAw.capHea_nominal/abs(datHpAw.THeaWatSup_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWat_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHea_nominal=500E3, + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + mChiWat_flow_nominal=datHpAw.capCoo_nominal/abs(datHpAw.TChiWatSup_nominal - + Buildings.Templates.Data.Defaults.TChiWatRet)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + capCoo_nominal=500E3, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + TSouCoo_nominal=Buildings.Templates.Data.Defaults.TOutHpCoo, + TSouHea_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + perFit(hea( + P=datHpAw.capHea_nominal/Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={-4.2670305442,-0.7381077035,6.0049480456,0,0}, + coeP={-4.9107455513,5.3665308366,0.5447612754,0,0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpHeaLow), coo( + P=datHpAw.capCoo_nominal/Buildings.Templates.Data.Defaults.COPHpAwCoo, + coeQ={-2.2545246871,6.9089257665,-3.6548225094,0,0}, + coeP={-5.8086010402,1.6894933858,5.1167787436,0,0}, + TRefLoa=Buildings.Templates.Data.Defaults.TChiWatRet, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpCoo))) + "Reversible AWHP parameters parameters" + annotation (Placement(transformation(extent={{120,22},{140,42}}))); + + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSupSet(k=datHpAw.TChiWatSup_nominal, + y(final unit="K", displayUnit="degC")) "CHWST setpoint" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-80,120}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet(k=datHpAw.THeaWatSup_nominal, + y(final unit="K", displayUnit="degC")) "HW supply temperature setpoint" + annotation (Placement(transformation(extent={{-90,150},{-70,170}}))); + AirToWater hpAw( + is_rev=true, + show_T=true, + redeclare final package MediumHeaWat = Medium, + final dat=datHpAw, + final energyDynamics=energyDynamics) "Reversible AWHP" + annotation (Placement(transformation(extent={{100,-10},{120,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin THeaWatRet( + amplitude=datHpAw.THeaWatSup_nominal - datHpAw.THeaWatRet_nominal, + freqHz=3/3000, + y(final unit="K", displayUnit="degC"), + offset=datHpAw.THeaWatRet_nominal, + startTime=0) "HW return temperature value" + annotation (Placement(transformation(extent={{-90,72},{-70,92}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1( + table=[ + 0, 0; + 0.5, 1], + timeScale=1000, + period=3000) + "Heat pump Enable signal" + annotation (Placement(transformation(extent={{-180,130},{-160,150}}))); + Fluid.Sensors.TemperatureTwoPort TSup(redeclare final package Medium = Medium, + final m_flow_nominal=datHpAw.mChiWat_flow_nominal) "Supply temperature" + annotation (Placement(transformation(extent={{130,-10},{150,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Hea( + table=[ + 0, 0; + 2, 1], + timeScale=1000, + period=3000) + "Heat pump heating mode signal" + annotation (Placement(transformation(extent={{-180,90},{-160,110}}))); + Buildings.Controls.OBC.CDL.Reals.Switch TSetAct( + y(final unit="K", + displayUnit="degC")) + "Active supply temperature setpoint" + annotation (Placement(transformation(extent={{-40,90},{-20,110}}))); + Fluid.Sources.Boundary_pT sup( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=3) + "Boundary condition at distribution system supply" + annotation (Placement(transformation(extent={{190,30},{170,50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin TChiWatRet( + amplitude=datHpAw.TChiWatRet_nominal - datHpAw.TChiWatSup_nominal, + freqHz=3/3000, + y(final unit="K", displayUnit="degC"), + offset=datHpAw.TChiWatRet_nominal, + startTime=0) "CHW return temperature value" + annotation (Placement(transformation(extent={{-90,30},{-70,50}}))); + Fluid.Sources.Boundary_pT inlHp( + redeclare final package Medium = Medium, + use_p_in=true, + use_T_in=true, + nPorts=3) "Boundary conditions of CHW/HW at HP inlet" + annotation (Placement(transformation(extent={{10,-10},{30,10}}))); + Buildings.Controls.OBC.CDL.Reals.Switch TRetAct + "Active return temperature" + annotation (Placement(transformation(extent={{-40,50},{-20,70}}))); + Buildings.Controls.OBC.CDL.Reals.Switch pInl_rel + "Active inlet gaupe pressure" + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pHeaWatInl( + k=sup.p + hpAw.dpHeaWat_nominal) + "HW inlet pressure" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pChiWatInl( + k=sup.p + hpAw.dpChiWat_nominal) + "CHW inlet pressure" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={-80,-40}))); + BoundaryConditions.WeatherData.ReaderTMY3 weaDat( + filNam=Modelica.Utilities.Files.loadResource( + "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos")) + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0, + origin={180,140}))); + Fluid.Sensors.TemperatureTwoPort TRet(redeclare final package Medium = Medium, + final m_flow_nominal=datHpAw.mChiWat_flow_nominal) "Return temperature" + annotation (Placement(transformation(extent={{50,-10},{70,10}}))); + AirToWater hpAwNrv( + is_rev=false, + final energyDynamics=energyDynamics, + final dat=datHpAwNrv) "Non reversible AWHP" + annotation (Placement(transformation(extent={{100,70},{120,90}}))); + Fluid.Sensors.TemperatureTwoPort TRet1(redeclare final package Medium = + Medium, final m_flow_nominal=datHpAw.mChiWat_flow_nominal) + "Return temperature" + annotation (Placement(transformation(extent={{50,70},{70,90}}))); + Fluid.Sensors.TemperatureTwoPort TSup1(redeclare final package Medium = + Medium, final m_flow_nominal=datHpAw.mChiWat_flow_nominal) + "Supply temperature" + annotation (Placement(transformation(extent={{130,70},{150,90}}))); + WaterToWater hpWw( + is_rev=true, + show_T=true, + redeclare final package MediumHeaWat = Medium, + final dat=datHpWw, + final energyDynamics=energyDynamics, + have_preDroChiHeaWat=false, + have_preDroSou=false) + "Reversible WWHP - CHW/HW and source fluid pressure drops computed externally" + annotation (Placement(transformation(extent={{100,-90},{120,-70}}))); + parameter Data.HeatPump datHpWw( + final cpHeaWat_default=hpWw.cpHeaWat_default, + final cpSou_default=hpWw.cpSou_default, + final typ=hpWw.typ, + final is_rev=hpWw.is_rev, + final typMod=hpWw.typMod, + mHeaWat_flow_nominal=datHpAw.capHea_nominal/abs(datHpAw.THeaWatSup_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWat_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHea_nominal=500E3, + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + mChiWat_flow_nominal=datHpAw.capCoo_nominal/abs(datHpAw.TChiWatSup_nominal - + Buildings.Templates.Data.Defaults.TChiWatRet)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + capCoo_nominal=500E3, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + TSouCoo_nominal=Buildings.Templates.Data.Defaults.TSouHpCoo, + TSouHea_nominal=Buildings.Templates.Data.Defaults.TSouHpHea, + dpSouWwHea_nominal=Buildings.Templates.Data.Defaults.dpChiWatChi, + mSouWwCoo_flow_nominal=datHpWw.mSouWwHea_flow_nominal, + mSouWwHea_flow_nominal=datHpWw.mHeaWat_flow_nominal, + perFit(hea( + P=datHpAw.capHea_nominal/Buildings.Templates.Data.Defaults.COPHpWwHea, + coeQ={-4.2670305442,-0.7381077035,6.0049480456,0,0}, + coeP={-4.9107455513,5.3665308366,0.5447612754,0,0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TSouHpHea), coo( + P=datHpAw.capCoo_nominal/Buildings.Templates.Data.Defaults.COPHpWwCoo, + coeQ={-2.2545246871,6.9089257665,-3.6548225094,0,0}, + coeP={-5.8086010402,1.6894933858,5.1167787436,0,0}, + TRefLoa=Buildings.Templates.Data.Defaults.TChiWatRet, + TRefSou=Buildings.Templates.Data.Defaults.TSouHpCoo))) + "Reversible WWHP parameters parameters" + annotation (Placement(transformation(extent={{120,-60},{140,-40}}))); + + Fluid.Sensors.TemperatureTwoPort TRet2(redeclare final package Medium = + Medium, final m_flow_nominal=datHpAw.mChiWat_flow_nominal) + "Return temperature" + annotation (Placement(transformation(extent={{50,-90},{70,-70}}))); + Fluid.Sensors.TemperatureTwoPort TSup2(redeclare final package Medium = + Medium, final m_flow_nominal=datHpAw.mChiWat_flow_nominal) + "Supply temperature" + annotation (Placement(transformation(extent={{130,-90},{150,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp TSouHea( + y(final unit="K", displayUnit="degC"), + height=4, + duration=500, + offset=datHpWw.TSouHea_nominal, + startTime=2400) "Source fluid supply temperature value" + annotation (Placement(transformation(extent={{-92,-90},{-72,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp TSouCoo( + y(final unit="K", displayUnit="degC"), + height=-4, + duration=500, + offset=datHpWw.TSouCoo_nominal, + startTime=1400) "Source fluid supply temperature value" + annotation (Placement(transformation(extent={{-92,-130},{-72,-110}}))); + Buildings.Controls.OBC.CDL.Reals.Switch TSouAct + "Active source fluid supply temperature" + annotation (Placement(transformation(extent={{-40,-92},{-20,-72}}))); + Buildings.Controls.OBC.CDL.Reals.Switch pInl_rel1 + "Active inlet gaupe pressure" + annotation (Placement(transformation(extent={{-40,-150},{-20,-130}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pSouInlHea(k=retSou.p + + hpWw.dpSouHea_nominal) "Source fluid inlet pressure" + annotation (Placement(transformation(extent={{-130,-130},{-110,-110}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pSouInlCoo(k=retSou.p + + hpWw.dpSouCoo_nominal) "Source fluid inlet pressure" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-120,-160}))); + Fluid.Sources.Boundary_pT inlHpSou( + redeclare final package Medium = Medium, + use_p_in=true, + use_T_in=true, + nPorts=1) "Boundary conditions or source side fluid at HP inlet" + annotation (Placement(transformation(extent={{10,-110},{30,-90}}))); + Fluid.Sources.Boundary_pT retSou( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=1) + "Boundary condition at source system return" + annotation (Placement(transformation(extent={{190,-130},{170,-110}}))); + Fluid.FixedResistances.PressureDrop res( + redeclare final package Medium = Medium, + final m_flow_nominal=datHpWw.mHeaWat_flow_nominal, + final dp_nominal=datHpWw.dpHeaWat_nominal) + "CHW/HW pressure drop computed externally" + annotation (Placement(transformation(extent={{70,-90},{90,-70}}))); + Fluid.FixedResistances.PressureDrop resSou( + redeclare final package Medium = Medium, + final m_flow_nominal=datHpWw.mSouWwHea_flow_nominal, + final dp_nominal=datHpWw.dpSouWwHea_nominal) + "Source fluid pressure drop computed externally" + annotation (Placement(transformation(extent={{70,-110},{90,-90}}))); +protected + Interfaces.Bus bus "HP control bus" + annotation (Placement(transformation(extent={{60,20},{100,60}}), + iconTransformation(extent={{-276,6},{-236,46}}))); +protected + Interfaces.Bus bus1 "HP control bus" + annotation (Placement(transformation(extent={{60,100},{100,140}}), + iconTransformation(extent={{-276,6},{-236,46}}))); +protected + Interfaces.Bus bus2 "HP control bus" + annotation (Placement(transformation(extent={{60,-60},{100,-20}}), + iconTransformation(extent={{-276,6},{-236,46}}))); +equation + connect(y1Hea.y[1], TSetAct.u2) + annotation (Line(points={{-158,100},{-42,100}},color={255,0,255})); + connect(TChiWatSupSet.y, TSetAct.u3) + annotation (Line(points={{-68,120},{-64,120},{-64,92},{-42,92}},color={0,0,127})); + connect(THeaWatSupSet.y, TSetAct.u1) + annotation (Line(points={{-68,160},{-60,160},{-60,108},{-42,108}},color={0,0,127})); + connect(TSup.port_b, sup.ports[1]) + annotation (Line(points={{150,0},{170,0},{170,38.6667}},color={0,127,255})); + connect(THeaWatRet.y, TRetAct.u1) + annotation (Line(points={{-68,82},{-60,82},{-60,68},{-42,68}},color={0,0,127})); + connect(y1Hea.y[1], TRetAct.u2) + annotation (Line(points={{-158,100},{-50,100},{-50,60},{-42,60}},color={255,0,255})); + connect(TChiWatRet.y, TRetAct.u3) + annotation (Line(points={{-68,40},{-50,40},{-50,52},{-42,52}},color={0,0,127})); + connect(hpAw.port_b, TSup.port_a) + annotation (Line(points={{120,0},{130,0}},color={0,127,255})); + connect(TRetAct.y, inlHp.T_in) annotation (Line(points={{-18,60},{-10,60},{-10, + 4},{8,4}}, color={0,0,127})); + connect(y1Hea.y[1], bus.y1Hea) + annotation (Line(points={{-158,100},{-50,100},{-50,120},{80,120},{80,40}}, + color={255,0,255})); + connect(y1.y[1], bus.y1) + annotation (Line(points={{-158,140},{-50,140},{-50,120},{80,120},{80,40}}, + color={255,0,255})); + connect(TSetAct.y, bus.TSet) + annotation (Line(points={{-18,100},{80,100},{80,40},{80,40}}, color={0,0,127})); + connect(pInl_rel.y, inlHp.p_in) + annotation (Line(points={{-18,-20},{0,-20},{0,8},{8,8}}, color={0,0,127})); + connect(pHeaWatInl.y, pInl_rel.u1) + annotation (Line(points={{-68,0},{-58,0},{-58,-12},{-42,-12}},color={0,0,127})); + connect(pChiWatInl.y, pInl_rel.u3) + annotation (Line(points={{-68,-40},{-46,-40},{-46,-28},{-42,-28}},color={0,0,127})); + connect(y1Hea.y[1], pInl_rel.u2) + annotation (Line(points={{-158,100},{-158,100.526},{-50,100.526},{-50,-20},{-42,-20}}, + color={255,0,255})); + connect(bus, hpAw.bus) + annotation (Line(points={{80,40},{110,40},{110,10}},color={255,204,51},thickness=0.5)); + connect(weaDat.weaBus, hpAw.busWea) + annotation (Line(points={{170,140},{160,140},{160,16},{104,16},{104,10}}, + color={255,204,51},thickness=0.5)); + connect(inlHp.ports[1], TRet.port_a) annotation (Line(points={{30,-1.33333},{ + 40,-1.33333},{40,0},{50,0}}, color={0,127,255})); + connect(TRet.port_b, hpAw.port_a) + annotation (Line(points={{70,0},{100,0}},color={0,127,255})); + connect(bus1, hpAwNrv.bus) + annotation (Line(points={{80,120},{110,120},{110,90}},color={255,204,51},thickness=0.5)); + connect(y1.y[1], bus1.y1) + annotation (Line(points={{-158,140},{-50,140},{-50,120},{80,120}},color={255,0,255})); + connect(hpAwNrv.port_b, TSup1.port_a) + annotation (Line(points={{120,80},{130,80}},color={0,127,255})); + connect(TRet1.port_b, hpAwNrv.port_a) + annotation (Line(points={{70,80},{100,80}},color={0,127,255})); + connect(TSup1.port_b, sup.ports[2]) + annotation (Line(points={{150,80},{170,80},{170,40}},color={0,127,255})); + connect(inlHp.ports[2], TRet1.port_a) annotation (Line(points={{30,0},{40,0}, + {40,80},{50,80}}, color={0,127,255})); + connect(weaDat.weaBus, hpAwNrv.busWea) + annotation (Line(points={{170,140},{160,140},{160,94},{104,94},{104,90}}, + color={255,204,51},thickness=0.5)); + connect(THeaWatSupSet.y, bus1.TSet) + annotation (Line(points={{-68,160},{80,160},{80,120}}, color={0,0,127})); + connect(hpWw.port_b, TSup2.port_a) + annotation (Line(points={{120,-80},{130,-80}}, color={0,127,255})); + connect(TSup2.port_b, sup.ports[3]) + annotation (Line(points={{150,-80},{170,-80},{170,41.3333}},color={0,127,255})); + connect(inlHp.ports[3], TRet2.port_a) annotation (Line(points={{30,1.33333},{ + 30,0},{40,0},{40,-80},{50,-80}}, color={0,127,255})); + connect(bus2, hpWw.bus) annotation (Line( + points={{80,-40},{110,-40},{110,-70}}, + color={255,204,51}, + thickness=0.5)); + connect(TSouHea.y, TSouAct.u1) + annotation (Line(points={{-70,-80},{-56,-80},{-56,-74},{-42,-74}},color={0,0,127})); + connect(y1Hea.y[1], TSouAct.u2) + annotation (Line(points={{-158,100},{-50,100},{-50,-82},{-42,-82}},color={255,0,255})); + connect(TSouCoo.y, TSouAct.u3) + annotation (Line(points={{-70,-120},{-46,-120},{-46,-90},{-42,-90}},color={0,0,127})); + connect(pSouInlHea.y, pInl_rel1.u1) + annotation (Line(points={{-108,-120},{-102,-120},{-102,-140},{-60,-140},{-60,-132},{-42,-132}}, + color={0,0,127})); + connect(pSouInlCoo.y, pInl_rel1.u3) + annotation (Line(points={{-108,-160},{-60,-160},{-60,-148},{-42,-148}},color={0,0,127})); + connect(y1Hea.y[1], pInl_rel1.u2) + annotation (Line(points={{-158,100},{-50,100},{-50,-140},{-42,-140}},color={255,0,255})); + connect(retSou.ports[1], hpWw.port_bSou) annotation (Line(points={{170,-120},{ + 94,-120},{94,-90},{100,-90}}, color={0,127,255})); + connect(TSouAct.y, inlHpSou.T_in) annotation (Line(points={{-18,-82},{0,-82}, + {0,-96},{8,-96}}, color={0,0,127})); + connect(pInl_rel1.y, inlHpSou.p_in) annotation (Line(points={{-18,-140},{-20, + -140},{-20,-92},{8,-92}}, color={0,0,127})); + connect(TSetAct.y, bus2.TSet) + annotation (Line(points={{-18,100},{80,100},{80,50},{80,50},{80,-40}}, + color={0,0,127})); + connect(y1.y[1], bus2.y1) + annotation (Line(points={{-158,140},{-50,140},{-50,-40},{80,-40}},color={255,0,255})); + connect(y1Hea.y[1], bus2.y1Hea) + annotation (Line(points={{-158,100},{-50,100},{-50,-40},{80,-40}},color={255,0,255})); + connect(TRet2.port_b, res.port_a) + annotation (Line(points={{70,-80},{70,-80}}, color={0,127,255})); + connect(res.port_b, hpWw.port_a) + annotation (Line(points={{90,-80},{100,-80}}, color={0,127,255})); + connect(hpWw.port_aSou, resSou.port_b) annotation (Line(points={{120,-90},{126, + -90},{126,-100},{90,-100}}, color={0,127,255})); + connect(inlHpSou.ports[1], resSou.port_a) annotation (Line(points={{30,-100}, + {50,-100},{50,-100},{70,-100}}, color={0,127,255})); + annotation ( + Diagram( + coordinateSystem( + extent={{-200,-180},{200,180}})), + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/HeatPumps/Validation/HeatPumpEquationFit.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StartTime=10497600.0, + StopTime=10505600.0), + Documentation( + info=" +

+This model validates the models + +Buildings.Templates.Components.HeatPumps.AirToWater +and + +Buildings.Templates.Components.HeatPumps.WaterToWater +in a configuration in which the heat pump components are exposed +to a constant differential pressure and a varying +return temperature. +

+

+The AWHP model is configured to represent either a non-reversible heat pump +(suffix Nrv) or a reversible heat pump +that switches between cooling and heating mode. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end HeatPumpEquationFit; diff --git a/Buildings/Templates/Components/HeatPumps/Validation/package.mo b/Buildings/Templates/Components/HeatPumps/Validation/package.mo new file mode 100644 index 00000000000..393eb756c0b --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/Validation/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.Components.HeatPumps; +package Validation "Package with validation models" + extends Modelica.Icons.ExamplesPackage; + annotation (Documentation(info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Components/HeatPumps/Validation/package.order b/Buildings/Templates/Components/HeatPumps/Validation/package.order new file mode 100644 index 00000000000..4f21dc83d0b --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/Validation/package.order @@ -0,0 +1 @@ +HeatPumpEquationFit diff --git a/Buildings/Templates/Components/HeatPumps/WaterToWater.mo b/Buildings/Templates/Components/HeatPumps/WaterToWater.mo new file mode 100644 index 00000000000..2798e0d1610 --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/WaterToWater.mo @@ -0,0 +1,40 @@ +within Buildings.Templates.Components.HeatPumps; +model WaterToWater + "Water-to-water heat pump - Equation fit model" + extends Buildings.Templates.Components.Interfaces.PartialHeatPumpEquationFit( + final typ=Buildings.Templates.Components.Types.HeatPump.WaterToWater); +equation + connect(port_aSou, TSouEnt.port_a) + annotation (Line(points={{80,-140},{80,-20},{40,-20}},color={0,127,255})); + annotation ( + defaultComponentName="hp", + Documentation( + info=" +

+This is a model for a water-to-water heat pump where the capacity +and input power are computed based on the equation fit method. +The model can be configured with the parameter is_rev +to represent either a non-reversible heat pump (heating only) or a +reversible heat pump. +This model uses + +Buildings.Fluid.HeatPumps.EquationFitReversible, +which the user may refer to for the modeling assumptions. +

+

Control points

+

+Refer to the documentation of the interface class + +Buildings.Templates.Components.Interfaces.PartialHeatPumpEquationFit +for a description of the available control input and output +variables. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end WaterToWater; diff --git a/Buildings/Templates/Components/HeatPumps/package.mo b/Buildings/Templates/Components/HeatPumps/package.mo new file mode 100644 index 00000000000..5b1c797e920 --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.Components; +package HeatPumps "Heat pump models" + extends Modelica.Icons.VariantsPackage; + annotation (Documentation(info=" +

+This package contains models for heat pumps. +

+")); +end HeatPumps; diff --git a/Buildings/Templates/Components/HeatPumps/package.order b/Buildings/Templates/Components/HeatPumps/package.order new file mode 100644 index 00000000000..c64de8a7909 --- /dev/null +++ b/Buildings/Templates/Components/HeatPumps/package.order @@ -0,0 +1,3 @@ +AirToWater +WaterToWater +Validation diff --git a/Buildings/Templates/Components/Interfaces/PartialHeatPump.mo b/Buildings/Templates/Components/Interfaces/PartialHeatPump.mo new file mode 100644 index 00000000000..95f88a90d38 --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialHeatPump.mo @@ -0,0 +1,235 @@ +within Buildings.Templates.Components.Interfaces; +model PartialHeatPump + extends Buildings.Fluid.Interfaces.PartialTwoPortInterface( + redeclare final package Medium=MediumHeaWat, + final m_flow_nominal=max(mHeaWat_flow_nominal, mChiWat_flow_nominal)); + + replaceable package MediumHeaWat=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium" + annotation(__ctrlFlow(enable=false)); + /* + MediumChiWat is for internal use only. + It is the same as MediumHeaWat for reversible HP. + Non-reversible HP that can be controlled to produce either HW or CHW + shall be modeled with chiller components (as a chiller/heater). + */ + final package MediumChiWat=MediumHeaWat + "CHW medium"; + /* + Derived classes representing AWHP shall use: + redeclare final package MediumSou = MediumAir + */ + replaceable package MediumSou=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Source-side medium" + annotation(Dialog(enable= + typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater), + __ctrlFlow(enable=false)); + replaceable package MediumAir=Buildings.Media.Air + constrainedby Modelica.Media.Interfaces.PartialMedium + "Air medium" + annotation(Dialog(enable= + typ==Buildings.Templates.Components.Types.HeatPump.AirToWater), + __ctrlFlow(enable=false)); + + parameter Buildings.Templates.Components.Types.HeatPump typ + "Equipment type" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean is_rev + "Set to true for reversible heat pumps, false for heating only" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Buildings.Templates.Components.Types.HeatPumpModel typMod= + Buildings.Templates.Components.Types.HeatPumpModel.EquationFit + "Type of heat pump model" + annotation (Evaluate=true, Dialog(group="Configuration"), + __ctrlFlow(enable=false)); + + parameter Buildings.Templates.Components.Data.HeatPump dat( + typ=typ, + is_rev=is_rev, + typMod=typMod, + cpHeaWat_default=cpHeaWat_default, + cpSou_default=cpSou_default) + "Design and operating parameters" + annotation ( + Placement(transformation(extent={{70,140},{90,160}})), + __ctrlFlow(enable=false)); + + final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal= + dat.mHeaWat_flow_nominal + "Design HW mass flow rate"; + final parameter Modelica.Units.SI.HeatFlowRate capHea_nominal= + dat.capHea_nominal + "Design heating capacity"; + final parameter Modelica.Units.SI.HeatFlowRate QHea_flow_nominal= + abs(capHea_nominal) + "Design heating heat flow rate"; + final parameter Modelica.Units.SI.PressureDifference dpHeaWat_nominal= + dat.dpHeaWat_nominal + "Design HW pressure drop"; + final parameter Modelica.Units.SI.Temperature THeaWatSup_nominal= + dat.THeaWatSup_nominal + "Design HW supply temperature"; + final parameter Modelica.Units.SI.Temperature THeaWatRet_nominal= + dat.THeaWatRet_nominal + "Design HW return temperature"; + final parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal= + dat.mChiWat_flow_nominal + "Design CHW mass flow rate" + annotation(Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.PressureDifference dpChiWat_nominal= + dat.dpChiWat_nominal + "Design CHW pressure drop"; + final parameter Modelica.Units.SI.HeatFlowRate capCoo_nominal= + dat.capCoo_nominal + "Design cooling capacity"; + final parameter Modelica.Units.SI.HeatFlowRate QCoo_flow_nominal= + -abs(capCoo_nominal) + "Design cooling heat flow rate"; + final parameter Modelica.Units.SI.Temperature TChiWatSup_nominal= + dat.TChiWatSup_nominal + "Design CHW supply temperature"; + final parameter Modelica.Units.SI.Temperature TChiWatRet_nominal= + dat.TChiWatRet_nominal + "Design CHW return temperature"; + final parameter Modelica.Units.SI.MassFlowRate mSouHea_flow_nominal= + dat.mSouHea_flow_nominal + "Design source fluid mass flow rate in heating mode"; + final parameter Modelica.Units.SI.PressureDifference dpSouHea_nominal= + dat.dpSouHea_nominal + "Design source fluid pressure drop in heating mode"; + final parameter Modelica.Units.SI.MassFlowRate mSouCoo_flow_nominal= + dat.mSouCoo_flow_nominal + "Design source fluid mass flow rate in cooling mode"; + final parameter Modelica.Units.SI.PressureDifference dpSouCoo_nominal= + dat.dpSouCoo_nominal + "Designs source fluid pressure drop in cooling mode"; + final parameter Modelica.Units.SI.Temperature TSouCoo_nominal= + dat.TSouCoo_nominal + "Design OAT or source fluid supply temperature (condenser entering) in cooling mode"; + final parameter Modelica.Units.SI.Temperature TSouHea_nominal= + dat.TSouHea_nominal + "Design OAT or source fluid supply temperature (evaporator entering) in heating mode"; + + 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 allowFlowReversalSou = true + "Source side flow reversal: false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation(Dialog(tab="Assumptions", + enable=Buildings.Templates.Components.Types.HeatPump.WaterToWater), Evaluate=true); + parameter Boolean have_preDroChiHeaWat=true + "Set to true for CHW/HW pressure drop computed by this model, false for external computation" + annotation (Evaluate=true, + Dialog(tab="Assumptions")); + parameter Boolean have_preDroSou=true + "Set to true for source fluid pressure drop computed by this model, false for external computation" + annotation (Evaluate=true, + Dialog(tab="Assumptions", + enable=Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + + final parameter MediumHeaWat.SpecificHeatCapacity cpHeaWat_default= + MediumHeaWat.specificHeatCapacityCp(staHeaWat_default) + "HW default specific heat capacity"; + final parameter MediumHeaWat.ThermodynamicState staHeaWat_default= + MediumHeaWat.setState_pTX( + T=THeaWatSup_nominal, + p=MediumHeaWat.p_default, + X=MediumHeaWat.X_default) + "HW default state"; + final parameter MediumChiWat.SpecificHeatCapacity cpChiWat_default= + MediumChiWat.specificHeatCapacityCp(staChiWat_default) + "CHW default specific heat capacity"; + final parameter MediumChiWat.ThermodynamicState staChiWat_default= + MediumChiWat.setState_pTX( + T=TChiWatSup_nominal, + p=MediumChiWat.p_default, + X=MediumChiWat.X_default) + "CHW default state"; + final parameter MediumSou.SpecificHeatCapacity cpSou_default= + MediumSou.specificHeatCapacityCp(staSou_default) + "Source fluid default specific heat capacity"; + final parameter MediumSou.ThermodynamicState staSou_default= + MediumSou.setState_pTX( + T=TSouHea_nominal, + p=MediumSou.p_default, + X=MediumSou.X_default) + "Source fluid default state"; + + Modelica.Fluid.Interfaces.FluidPort_a port_aSou( + redeclare final package Medium = MediumSou) + "Fluid connector a (positive design flow direction is from port_a to port_b)" + annotation (Placement( + iconVisible=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater, + transformation(extent={{70,-150},{90,-130}}), + iconTransformation(extent={{90,-110},{110,-90}}))); + Modelica.Fluid.Interfaces.FluidPort_b port_bSou( + redeclare final package Medium = MediumSou) + "Fluid connector b (positive design flow direction is from port_a to port_b)" + annotation (Placement( + iconVisible=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater, + transformation(extent={{-70,-150},{-90,-130}}), + iconTransformation(extent={{-90,-110},{-110,-90}}))); + Buildings.Templates.Components.Interfaces.Bus bus + "Control bus" + annotation (Placement(transformation(extent={{-20,140},{20,180}}), + iconTransformation(extent={{-20,80},{20, 120}}))); + Buildings.BoundaryConditions.WeatherData.Bus busWea + if typ==Buildings.Templates.Components.Types.HeatPump.AirToWater + "Weather bus" + annotation (Placement(transformation(extent={{-60,-160},{-20,-120}}), + iconTransformation(extent={{-80,80},{-40,120}}))); + Fluid.Sources.Outside air(redeclare final package Medium = MediumAir, nPorts= + 2) + if typ == Buildings.Templates.Components.Types.HeatPump.AirToWater + "Outdoor air" annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=-90, + origin={0,-130}))); + + // Diagnostics + MediumSou.ThermodynamicState sta_aSou= + MediumSou.setState_phX(port_aSou.p, + noEvent(actualStream(port_aSou.h_outflow)), + noEvent(actualStream(port_aSou.Xi_outflow))) + if show_T "Source medium properties in port_aSou"; + MediumSou.ThermodynamicState sta_bSou= + MediumSou.setState_phX(port_bSou.p, + noEvent(actualStream(port_bSou.h_outflow)), + noEvent(actualStream(port_bSou.Xi_outflow))) + if show_T "Source medium properties in port_bSou"; +equation + connect(busWea, air.weaBus) annotation (Line( + points={{-40,-140},{0.2,-140}}, + color={255,204,51}, + thickness=0.5)); + connect(port_aSou, air.ports[1]) annotation (Line(points={{80,-140},{80,-120}, + {-1,-120}}, color={0,127,255})); + connect(port_bSou, air.ports[2]) annotation (Line(points={{-80,-140},{-80, + -120},{1,-120}}, color={0,127,255})); +annotation ( +Icon(graphics={ + Rectangle( + extent={{100,60},{-100,-100}}, + lineColor={0,0,0}, + lineThickness=1), + Bitmap(extent={{-20,60},{20,100}}, fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg"), + Text( extent={{-60,0},{60,-40}}, + textColor={0,0,0}, + textString="HP")}), Documentation(info=" +

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

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Diagram(coordinateSystem(extent={{-100,-140},{100,160}}))); +end PartialHeatPump; diff --git a/Buildings/Templates/Components/Interfaces/PartialHeatPumpEquationFit.mo b/Buildings/Templates/Components/Interfaces/PartialHeatPumpEquationFit.mo new file mode 100644 index 00000000000..d96af2a33bc --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialHeatPumpEquationFit.mo @@ -0,0 +1,196 @@ +within Buildings.Templates.Components.Interfaces; +model PartialHeatPumpEquationFit + "Interface for heat pump using equation fit model" + extends Buildings.Templates.Components.Interfaces.PartialHeatPump( + final typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit); + + final parameter Buildings.Fluid.HeatPumps.Data.EquationFitReversible.Generic datPerFit( + dpHeaSou_nominal = if have_preDroSou then dat.perFit.dpHeaSou_nominal else 0, + dpHeaLoa_nominal = if have_preDroChiHeaWat then dat.perFit.dpHeaLoa_nominal else 0, + hea( + TRefLoa = dat.perFit.hea.TRefLoa, + TRefSou = dat.perFit.hea.TRefSou, + Q_flow = dat.perFit.hea.Q_flow, + P = dat.perFit.hea.P, + mSou_flow = dat.perFit.hea.mSou_flow, + mLoa_flow = dat.perFit.hea.mLoa_flow, + coeQ = dat.perFit.hea.coeQ, + coeP = dat.perFit.hea.coeP), + coo( + TRefSou = dat.perFit.coo.TRefSou, + TRefLoa = dat.perFit.coo.TRefLoa, + Q_flow = dat.perFit.coo.Q_flow, + P = dat.perFit.coo.P, + coeQ = dat.perFit.coo.coeQ, + coeP = dat.perFit.coo.coeP)) + "Performance data - Equation fit model"; + + Modelica.Blocks.Routing.BooleanPassThrough y1Hea if is_rev + "Operating mode command: true=heating, false=cooling" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-80,130}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant y1HeaNonRev( + final k=true) if not is_rev + "Placeholder signal for non-reversible heat pumps" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-40,130}))); + Controls.StatusEmulator y1_actual + "Compute heat pump status" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={40,130}))); + Fluid.Sensors.MassFlowRate mChiHeaWat_flow(redeclare final package Medium = + MediumHeaWat) "CHW/HW mass flow rate" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}))); + Fluid.Sensors.TemperatureTwoPort TChiHeaWatEnt(redeclare final package Medium = + MediumHeaWat, final m_flow_nominal=max(mChiWat_flow_nominal, + mHeaWat_flow_nominal)) "CHW/HW entering temperature" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Fluid.Sensors.TemperatureTwoPort TChiHeaWatLvg(redeclare final package Medium = + MediumHeaWat, final m_flow_nominal=max(mChiWat_flow_nominal, + mHeaWat_flow_nominal)) "CHW/HW leaving temperature" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Fluid.Sensors.TemperatureTwoPort TSouEnt( + redeclare final package Medium = MediumSou, final m_flow_nominal= + mSouHea_flow_nominal) "Source fluid entering temperature" + annotation (Placement(transformation(extent={{40,-30},{20,-10}}))); + Fluid.Sensors.TemperatureTwoPort TSouLvg( + redeclare final package Medium = MediumSou, + final m_flow_nominal= + mSouHea_flow_nominal) "Source fluid leaving temperature" + annotation (Placement(transformation( + extent={{10,-10},{-10,10}}, + rotation=0, + origin={-30,-20}))); + Buildings.Fluid.HeatPumps.EquationFitReversible hp( + uMod(start=0), + redeclare final package Medium1 = MediumHeaWat, + redeclare final package Medium2 = MediumSou, + final per=datPerFit, + final energyDynamics=energyDynamics) "Heat pump" + annotation (Placement(transformation(extent={{-10,-16},{10,4}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger y1Int + "Convert on/off command into integer" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-20,90}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger y1HeaInt( + y(start=0), + final integerTrue=1, + final integerFalse=-1) + "Convert heating mode command into integer" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-80,90}))); + Buildings.Controls.OBC.CDL.Integers.Multiply mulInt + "Combine on/off and operating mode command signals" + annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={-20,50}))); +equation + /* Control point connection - start */ + /* Control point connection - stop */ + connect(bus.y1Hea, y1Hea.u) annotation (Line( + points={{0,160},{0,156},{-80,156},{-80,142}}, + color={255,204,51}, + thickness=0.5)); + connect(port_a, mChiHeaWat_flow.port_a) + annotation (Line(points={{-100,0},{-90,0}}, color={0,127,255})); + connect(mChiHeaWat_flow.port_b, TChiHeaWatEnt.port_a) + annotation (Line(points={{-70,0},{-60,0}}, color={0,127,255})); + connect(TChiHeaWatLvg.port_b, port_b) + annotation (Line(points={{90,0},{100,0}}, color={0,127,255})); + connect(TSouLvg.port_b, port_bSou) annotation (Line(points={{-40,-20},{-80,-20}, + {-80,-140}}, color={0,127,255})); + connect(y1Hea.y, y1HeaInt.u) annotation (Line(points={{-80,119},{-80,110.5},{-80, + 110.5},{-80,102}}, color={255,0,255})); + connect(y1HeaNonRev.y, y1HeaInt.u) annotation (Line(points={{-40,118},{-40,110}, + {-80,110},{-80,102}}, color={255,0,255})); + connect(y1HeaInt.y, mulInt.u2) annotation (Line(points={{-80,78},{-80,70},{-26, + 70},{-26,62}}, color={255,127,0})); + connect(y1Int.y, mulInt.u1) annotation (Line(points={{-20,78},{-20,70},{-14,70}, + {-14,62}}, color={255,127,0})); + connect(TChiHeaWatEnt.port_b, hp.port_a1) + annotation (Line(points={{-40,0},{-10,0}}, color={0,127,255})); + connect(hp.port_b1, TChiHeaWatLvg.port_a) + annotation (Line(points={{10,0},{70,0}}, color={0,127,255})); + connect(TSouLvg.port_a, hp.port_b2) annotation (Line(points={{-20,-20},{-20,-12}, + {-10,-12}}, color={0,127,255})); + connect(TSouEnt.port_b, hp.port_a2) + annotation (Line(points={{20,-20},{20,-12},{10,-12}}, color={0,127,255})); + connect(bus.y1, y1Int.u) annotation (Line( + points={{0,160},{0,110},{-20,110},{-20,102}}, + color={255,204,51}, + thickness=0.5)); + connect(bus.TSet, hp.TSet) annotation (Line( + points={{0,160},{0,86},{0,86},{0,10},{-16,10},{-16,3},{-11.4,3}}, + color={255,204,51}, + thickness=0.5)); + connect(mulInt.y, hp.uMod) + annotation (Line(points={{-20,38},{-20,-6},{-11,-6}}, color={255,127,0})); + connect(y1_actual.y1_actual, bus.y1_actual) + annotation (Line(points={{40,142},{40,156},{0,156},{0,160}}, + color={255,0,255})); + connect(bus.y1, y1_actual.y1) annotation (Line( + points={{0,160},{0,110},{40,110},{40,118}}, + color={255,204,51}, + thickness=0.5)); + annotation ( + defaultComponentName="heaPum", + Documentation(info=" +

+This is a model for an air-to-water heat pump where the capacity +and drawn power are computed based on the equation fit method. +The model can be configured with the parameter is_rev +to represent either a non-reversible heat pump (heating only) or a +reversible heat pump. +This model uses + +Buildings.Fluid.HeatPumps.EquationFitReversible, +which the user may refer to for the modeling assumptions. +

+

Control points

+

+The following input and output points are available. +

+
    +
  • +Heat pump on/off command signal y1: +DO signal, with a dimensionality of zero +
  • +
  • For reversible heat pumps only (is_rev=true), +Heat pump operating mode command signal y1Hea: +DO signal, with a dimensionality of zero
    +(y1Hea=true for heating mode, +y1Hea=false for cooling mode) +
  • +
  • +Heat pump supply temperature setpoint TSet: +AO signal, with a dimensionality of zero
    +(for reversible heat pumps, the setpoint value must be +switched externally between HW and CHW supply temperature) +
  • +
  • +Heat pump status y1_actual: +DI signal, with a dimensionality of zero +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PartialHeatPumpEquationFit; diff --git a/Buildings/Templates/Components/Interfaces/PartialPump.mo b/Buildings/Templates/Components/Interfaces/PartialPump.mo new file mode 100644 index 00000000000..1d1ab7160c3 --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialPump.mo @@ -0,0 +1,97 @@ +within Buildings.Templates.Components.Interfaces; +model PartialPump "Base class for all pump models" + parameter Buildings.Templates.Components.Types.Pump typ + "Equipment type" + annotation (Evaluate=true, Dialog(group="Configuration", enable=false)); + + parameter Boolean have_var=true + "Set to true for variable speed pump, false for constant speed pump" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + parameter Boolean have_varCom=true + "Set to true for single common speed signal, false for dedicated signals" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ==Buildings.Templates.Components.Types.Pump.Multiple and have_var)); + + parameter Boolean have_valChe=true + "Set to true to include a check valve in pump line" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Components.Types.Pump.None), + __Linkage(enable=false)); + + parameter Boolean addPowerToMedium=false + "Set to false to avoid any power (=heat and flow work) being added to medium (may give simpler equations)" + annotation(__Linkage(enable=false)); + + parameter Modelica.Units.SI.Time tau=1 + "Time constant of fluid volume for nominal flow, used if energy or mass balance is dynamic" + annotation (Dialog( + tab="Dynamics", + group="Nominal condition", + enable=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState), + __Linkage(enable=false)); + parameter Modelica.Fluid.Types.Dynamics energyDynamics= + Modelica.Fluid.Types.Dynamics.DynamicFreeInitial + "Type of energy balance: dynamic (3 initialization options) or steady state" + annotation(Evaluate=true, Dialog(tab = "Dynamics", group="Conservation equations"), + __Linkage(enable=false)); + parameter Boolean allowFlowReversal = true + "= false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation(Dialog(tab="Assumptions"), Evaluate=true, __Linkage(enable=false)); + + parameter Integer text_rotation = 0 + "Text rotation angle in icon layer" + annotation(Dialog(tab="Graphics", enable=false)); + parameter Boolean text_flip = false + "True to flip text horizontally in icon layer" + annotation(Dialog(tab="Graphics", enable=false)); + + Buildings.Templates.Components.Interfaces.Bus bus + "Control bus" + annotation ( + Placement(transformation( + extent={{-20,-20},{20,20}}, + rotation=0, + origin={0,100}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={0,100}))); + + annotation ( Documentation(info=" +

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

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

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

+", revisions=" +
    +
  • +April 28, 2023, by Antoine Gautier:
    +First implementation. +
  • +
+"), Icon(graphics={ + Text( + extent={{-149,-114},{151,-154}}, + textColor={0,0,255}, + textString="%name"), + Line( visible=typ <> Buildings.Templates.Components.Types.Pump.None and + nPum >= 2, + points={{-100,icon_dy},{100,icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=2, + points={{-50,icon_dy+60},{-50,icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=2, + extent={{-100,icon_dy-70},{0,icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=2, + extent={{20,icon_dy-40},{100,icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=2, + extent={{-100,icon_dy+60},{0,icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=2, + extent={{-100,icon_dy+60},{0,icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=3, + points={{-100,2*icon_dy},{100,2*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=3, + points={{-50,2*icon_dy+60},{-50,2*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=3, + extent={{-100,2*icon_dy-70},{0,2*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=3, + extent={{20, 2*icon_dy-40},{100, 2*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=3, + extent={{-100, 2*icon_dy+60},{0, 2*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=3, + extent={{-100, 2*icon_dy+60},{0, 2*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=4, + points={{-100, 3*icon_dy},{100, 3*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=4, + points={{-50, 3*icon_dy+60},{-50, 3*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=4, + extent={{-100, 3*icon_dy-70},{0, 3*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=4, + extent={{20, 3*icon_dy-40},{100, 3*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=4, + extent={{-100, 3*icon_dy+60},{0, 3*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=4, + extent={{-100, 3*icon_dy+60},{0, 3*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=5, + points={{-100, 4*icon_dy},{100, 4*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=5, + points={{-50, 4*icon_dy+60},{-50, 4*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=5, + extent={{-100, 4*icon_dy-70},{0, 4*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=5, + extent={{20, 4*icon_dy-40},{100, 4*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=5, + extent={{-100, 4*icon_dy+60},{0, 4*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=5, + extent={{-100, 4*icon_dy+60},{0, 4*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=6, + points={{-100, 5*icon_dy},{100, 5*icon_dy}}, + color={0,0,0}, + thickness=5), + Line( visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=6, + points={{-50, 5*icon_dy+60},{-50, 5*icon_dy+22}}, + color={0,0,0}), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and nPum>=6, + extent={{-100, 5*icon_dy-70},{0, 5*icon_dy+30}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_valChe and nPum>=6, + extent={{20, 5*icon_dy-40},{100, 5*icon_dy+40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and have_var and nPum>=6, + extent={{-100, 5*icon_dy+60},{0, 5*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Bitmap( + visible=typ<>Buildings.Templates.Components.Types.Pump.None and not have_var and nPum>=6, + extent={{-100, 5*icon_dy+60},{0, 5*icon_dy+160}}, + rotation=text_rotation, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg")})); + +end PartialPumpMultiple; diff --git a/Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo b/Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo new file mode 100644 index 00000000000..6b210d8825a --- /dev/null +++ b/Buildings/Templates/Components/Interfaces/PartialPumpSingle.mo @@ -0,0 +1,48 @@ +within Buildings.Templates.Components.Interfaces; +partial model PartialPumpSingle "Interface class for single pump" + extends Buildings.Templates.Components.Interfaces.PartialPump; + extends Buildings.Fluid.Interfaces.PartialTwoPortInterface( + redeclare replaceable package Medium=Buildings.Media.Water, + final m_flow_nominal(min=0)=dat.m_flow_nominal) + annotation(__Linkage(enable=false)); + + parameter Buildings.Templates.Components.Data.PumpSingle dat( + final typ=typ) + "Design and operating parameters" + annotation(__Linkage(enable=false)); + + final parameter Modelica.Units.SI.PressureDifference dp_nominal( + final min=0, + displayUnit="Pa")=dat.dp_nominal + "Pump head at design conditions" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None)); + + // This parameter is declared outside the parameter record dat as + // it is considered to be an advanced parameter for which a default + // value can probably be used. + parameter Modelica.Units.SI.PressureDifference dpValChe_nominal( + final min=0, + start=Buildings.Templates.Data.Defaults.dpValChe, + displayUnit="Pa")=Buildings.Templates.Data.Defaults.dpValChe + "Check valve pressure drop at design conditions" + annotation (Dialog(group="Nominal condition", + enable=typ<>Buildings.Templates.Components.Types.Pump.None + and have_valChe)); + + annotation ( + Icon(coordinateSystem(preserveAspectRatio=false)), + Documentation(info=" +

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

+", revisions=" +
    +
  • +April 28, 2023, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PartialPumpSingle; diff --git a/Buildings/Templates/Components/Interfaces/PartialSensor.mo b/Buildings/Templates/Components/Interfaces/PartialSensor.mo index a714f4d78a3..bc8a979f99b 100644 --- a/Buildings/Templates/Components/Interfaces/PartialSensor.mo +++ b/Buildings/Templates/Components/Interfaces/PartialSensor.mo @@ -1,7 +1,7 @@ within Buildings.Templates.Components.Interfaces; partial model PartialSensor "Interface class for sensor" extends Buildings.Fluid.Interfaces.PartialTwoPortInterface - annotation(__ctrlFlow(enable=false)); + annotation(__Linkage(enable=false)); parameter Boolean have_sen=true "Set to true for sensor, false for direct pass through" @@ -16,6 +16,10 @@ partial model PartialSensor "Interface class for sensor" parameter Boolean text_flip = false "True to flip text horizontally in icon layer" annotation(Dialog(tab="Graphics", enable=false)); + parameter Buildings.Templates.Components.Types.IconPipe icon_pipe = + Buildings.Templates.Components.Types.IconPipe.None + "Pipe symbol" + annotation(Dialog(tab="Graphics", enable=false)); Buildings.Controls.OBC.CDL.Interfaces.RealOutput y if have_sen "Connector for measured value" @@ -42,12 +46,16 @@ equation annotation ( Icon(coordinateSystem(preserveAspectRatio=false), - graphics={ - Line( - visible=(not have_sen) and (not isDifPreSen), - points={{-100,0},{100,0}}, - color={28,108,200}, - thickness=1)}), + graphics={Line( + visible=icon_pipe<>Buildings.Templates.Components.Types.IconPipe.None + or (not have_sen) and (not isDifPreSen), + points={{-100,0},{100,0}}, + color=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.None + then {28,108,200} else {0,0,0}, + thickness=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.None + then 1 else 5, + pattern=if icon_pipe==Buildings.Templates.Components.Types.IconPipe.Return + then LinePattern.Dash else LinePattern.Solid)}), Diagram(coordinateSystem(preserveAspectRatio=false)), Documentation(info="

diff --git a/Buildings/Templates/Components/Interfaces/package.order b/Buildings/Templates/Components/Interfaces/package.order index 7fc811573cd..c90cefc1586 100644 --- a/Buildings/Templates/Components/Interfaces/package.order +++ b/Buildings/Templates/Components/Interfaces/package.order @@ -1,4 +1,9 @@ Bus PartialCoil PartialFan +PartialHeatPump +PartialHeatPumpEquationFit +PartialPump +PartialPumpMultiple +PartialPumpSingle PartialSensor diff --git a/Buildings/Templates/Components/Pumps/Multiple.mo b/Buildings/Templates/Components/Pumps/Multiple.mo new file mode 100644 index 00000000000..31d36eae8ea --- /dev/null +++ b/Buildings/Templates/Components/Pumps/Multiple.mo @@ -0,0 +1,179 @@ +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, + final dpValve_nominal=dpValChe_nominal) + 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.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}))); + Buildings.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}))); + Controls.StatusEmulator sta[nPum] "Emulate pump status" + annotation (Placement(transformation(extent={{-10,-70},{10,-50}}))); +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(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})); + connect(sta.y1_actual, bus.y1_actual) annotation (Line(points={{12,-60},{80, + -60},{80,96},{0,96},{0,100}}, color={255,0,255})); + connect(bus.y1, sta.y1) annotation (Line( + points={{0,100},{0,88},{-80,88},{-80,-60},{-12,-60}}, + color={255,204,51}, + thickness=0.5)); + annotation ( + defaultComponentName="pum", + Documentation(info=" +

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

+

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

+

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

+

Control points

+

+The following input and output points are available. +

+
    +
  • +Pump Start/Stop command (VFD Run or motor starter contact) +y1: +DO signal dedicated to each unit, with a dimensionality of one +
  • +
  • +Pump speed command (VFD Speed) y for variable speed pumps only: +
      +
    • +If have_varCom: AO signal common to all units, +with a dimensionality of zero +
    • +
    • +If not have_varCom: AO signal dedicated to each unit, +with a dimensionality of one +
    • +
    +
  • +
  • +Pump status (through VFD interface, VFD status contact, +or current switch) y1_actual: +DI signal dedicated to each unit, with a dimensionality of one +
  • +
+

Model parameters

+

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

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

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

+

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

+

Control points

+

+The following input and output points are available. +

+
    +
  • +Pump Start/Stop command (VFD Run or motor starter contact) +y1: +DO signal +
  • +
  • +Pump speed command (VFD Speed) y for variable speed pumps only: +AO signal +
  • +
  • +Pump status (through VFD interface, VFD status contact, +or current switch) y1_actual: +DI signal +
  • +
+

Model parameters

+

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

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

+This package contains models for pumps. +

+")); +end Pumps; diff --git a/Buildings/Templates/Components/Pumps/package.order b/Buildings/Templates/Components/Pumps/package.order new file mode 100644 index 00000000000..b8bb7e28f05 --- /dev/null +++ b/Buildings/Templates/Components/Pumps/package.order @@ -0,0 +1,2 @@ +Multiple +Single diff --git a/Buildings/Templates/Components/Routing/Junction.mo b/Buildings/Templates/Components/Routing/Junction.mo new file mode 100644 index 00000000000..d7831a4cce2 --- /dev/null +++ b/Buildings/Templates/Components/Routing/Junction.mo @@ -0,0 +1,56 @@ +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)}), Documentation(info=" +

+This is a model of a flow junction with an optional fixed resistance +in each flow leg and an optional mixing volume at the junction. +This model is identical to + +Buildings.Fluid.FixedResistances.Junction +except for the icon which has been changed for better integration +into the templates. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +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/Sensors/Temperature.mo b/Buildings/Templates/Components/Sensors/Temperature.mo index 812a4f07e1e..f1265a767a2 100644 --- a/Buildings/Templates/Components/Sensors/Temperature.mo +++ b/Buildings/Templates/Components/Sensors/Temperature.mo @@ -11,13 +11,11 @@ model Temperature "Temperature sensor" Buildings.Fluid.Sensors.TemperatureTwoPort senTem( redeclare final package Medium=Medium, - final m_flow_nominal=m_flow_nominal, - final allowFlowReversal=allowFlowReversal) if have_sen + final m_flow_nominal=m_flow_nominal) if have_sen "Temperature sensor" annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - Buildings.Templates.Components.Routing.PassThroughFluid pas( - redeclare final package Medium = Medium, - final allowFlowReversal=allowFlowReversal) if not have_sen "Pass through" + Buildings.Templates.Components.Routing.PassThroughFluid pas(redeclare final + package Medium = Medium) if not have_sen "Pass through" annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); equation @@ -45,12 +43,12 @@ equation Bitmap(extent={{-100,-160},{100,40}}, visible=have_sen and typ==Buildings.Templates.Components.Types.SensorTemperature.Averaging, fileName="modelica://Buildings/Resources/Images/Templates/Components/Sensors/ProbeAveraging.svg"), - Bitmap(extent={{-100,-160},{100,40}}, - visible=have_sen and typ==Buildings.Templates.Components.Types.SensorTemperature.Standard, - fileName="modelica://Buildings/Resources/Images/Templates/Components/Sensors/ProbeStandard.svg"), Bitmap(extent={{-100,-40},{100,160}}, visible=have_sen and typ==Buildings.Templates.Components.Types.SensorTemperature.InWell, - fileName="modelica://Buildings/Resources/Images/Templates/Components/Sensors/ProbeInWell.svg")}), + fileName="modelica://Buildings/Resources/Images/Templates/Components/Sensors/ProbeInWell.svg"), + Bitmap(extent={{-100,-160},{100,40}}, + visible=have_sen and typ==Buildings.Templates.Components.Types.SensorTemperature.Standard, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Sensors/ProbeStandard.svg")}), Diagram(coordinateSystem(preserveAspectRatio=false)), Documentation(info="

diff --git a/Buildings/Templates/Components/Sensors/VolumeFlowRate.mo b/Buildings/Templates/Components/Sensors/VolumeFlowRate.mo index 4f4ed3158d0..a69f91cecf4 100644 --- a/Buildings/Templates/Components/Sensors/VolumeFlowRate.mo +++ b/Buildings/Templates/Components/Sensors/VolumeFlowRate.mo @@ -10,13 +10,11 @@ model VolumeFlowRate "Volume flow rate sensor" Buildings.Fluid.Sensors.VolumeFlowRate senVolFlo( redeclare final package Medium=Medium, - final m_flow_nominal=m_flow_nominal, - final allowFlowReversal=allowFlowReversal) if have_sen + final m_flow_nominal=m_flow_nominal) if have_sen "Volume flow rate sensor" annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); - Buildings.Templates.Components.Routing.PassThroughFluid pas( - redeclare final package Medium = Medium, - final allowFlowReversal=allowFlowReversal) if not have_sen "Pass through" + Buildings.Templates.Components.Routing.PassThroughFluid pas(redeclare final + package Medium = Medium) if not have_sen "Pass through" annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); equation diff --git a/Buildings/Templates/Components/Types.mo b/Buildings/Templates/Components/Types.mo index abcc68c0f20..b2e5f8e32c1 100644 --- a/Buildings/Templates/Components/Types.mo +++ b/Buildings/Templates/Components/Types.mo @@ -67,6 +67,16 @@ package Types "Package with type definitions" Propeller "Propeller fan") "Enumeration to specify the type of single fan"; + type HeatPump = enumeration( + AirToWater + "Air-to-water heat pump", + WaterToWater + "Water(or brine)-to-water heat pump") + "Enumeration to specify the type of heat pump"; + type HeatPumpModel = enumeration( + EquationFit + "Heat pump model based on the equation fit method") + "Enumeration to specify the heat pump model"; type IconPipe = enumeration( None "No line", @@ -75,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/Coils.mo b/Buildings/Templates/Components/Validation/Coils.mo index 437d93b1f9f..14a59d07332 100644 --- a/Buildings/Templates/Components/Validation/Coils.mo +++ b/Buildings/Templates/Components/Validation/Coils.mo @@ -129,9 +129,8 @@ model Coils "Validation model for coil components" Buildings.Controls.OBC.CDL.Reals.Sources.Constant XOut(k=0.015) "Water mass fraction in outdoor air" annotation (Placement(transformation(extent={{-130,-150},{-110,-130}}))); - Utilities.Psychrometrics.TWetBul_TDryBulXi wetBul( - redeclare final package Medium = MediumAir) - "Compute wet bulb temperature" + Buildings.Utilities.Psychrometrics.TWetBul_TDryBulXi wetBul(redeclare final + package Medium = MediumAir) "Compute wet bulb temperature" annotation (Placement(transformation(extent={{-60,-130},{-40,-110}}))); Buildings.Controls.OBC.CDL.Reals.Sources.Constant pOut(k=101325) "Outdoor pressure" @@ -143,7 +142,7 @@ model Coils "Validation model for coil components" T=coiEva.dat.datCoi.sta[1].nomVal.TEvaIn_nominal, nPorts=2) "Boundary conditions for entering air" annotation (Placement(transformation(extent={{-90,-70},{-70,-50}}))); - Utilities.Psychrometrics.X_pTphi x_pTphi(use_p_in=false) + Buildings.Utilities.Psychrometrics.X_pTphi x_pTphi(use_p_in=false) "Compute wet bulb temperature" annotation (Placement(transformation(extent={{-88,-10},{-68,10}}))); Buildings.Controls.OBC.CDL.Reals.Sources.Constant TAirEnt(k=coiEva.dat.datCoi.sta[ diff --git a/Buildings/Templates/Components/Validation/PumpMultipleRecord.mo b/Buildings/Templates/Components/Validation/PumpMultipleRecord.mo new file mode 100644 index 00000000000..21f723c721b --- /dev/null +++ b/Buildings/Templates/Components/Validation/PumpMultipleRecord.mo @@ -0,0 +1,96 @@ +within Buildings.Templates.Components.Validation; +model PumpMultipleRecord "Validation model for parameter propagation with the multiple-pump record" + extends Modelica.Icons.Example; + + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Fluid medium"; + + parameter Integer nPum( + final min=0, + start=1)=2 + "Number of pumps" + annotation (Dialog(group="Configuration", enable=false)); + + parameter Modelica.Units.SI.MassFlowRate m_flow_nominal[nPum]( + each start=1, + each final min=0)={1, 2} + "Mass flow rate - Each pump"; + final parameter Modelica.Units.SI.VolumeFlowRate V_flow_nominal[nPum]= + m_flow_nominal ./ datDef.rho_default + "Mass flow rate - Each pump"; + parameter Modelica.Units.SI.PressureDifference dp_nominal[nPum]( + each start=0, + each final min=0)={1, 2} .* 1E4 + "Total pressure rise - Each pump"; + + parameter Buildings.Templates.Components.Data.PumpMultiple datDef( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal) + "Parameter record - Default bindings for subrecord per" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + + parameter Buildings.Templates.Components.Data.PumpMultiple datRed( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal, + redeclare Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos80slash1to12 per) + "Parameter record - Redeclaration of subrecord per" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + + parameter Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos80slash1to12 per1; + parameter Buildings.Fluid.Movers.Data.Pumps.Wilo.Stratos50slash1to12 per2; + + parameter Buildings.Templates.Components.Data.PumpMultiple datAss( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal, + per={per1, per2}) + "Parameter record - Assignment of subrecord per" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + + parameter Buildings.Templates.Components.Data.PumpMultiple datPre( + final typ=Buildings.Templates.Components.Types.Pump.Multiple, + final nPum=nPum, + final m_flow_nominal=m_flow_nominal, + final dp_nominal=dp_nominal, + per(pressure( + V_flow={{0, 2, 4} * m_flow_nominal[i] / datPre.rho_default for i in 1:nPum}, + dp={{2, 1.5, 0.8} * dp_nominal[i] for i in 1:nPum}))) + "Parameter record - Assignment of pressure inside the subrecord per" + annotation (Placement(transformation(extent={{-10,-70},{10,-50}}))); + + annotation ( + experiment( + StopTime=1, + Tolerance=1e-06), + __Dymola_Commands(file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/PumpMultipleRecord.mos" + "Simulate and plot"), + Documentation(info=" +

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

+

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

+

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

+

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

+")); +end PumpMultipleRecord; diff --git a/Buildings/Templates/Components/Validation/Pumps.mo b/Buildings/Templates/Components/Validation/Pumps.mo new file mode 100644 index 00000000000..aedb697a8ae --- /dev/null +++ b/Buildings/Templates/Components/Validation/Pumps.mo @@ -0,0 +1,349 @@ +within Buildings.Templates.Components.Validation; +model Pumps "Validation model for pump components" + extends Modelica.Icons.Example; + + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Liquid medium"; + parameter Data.PumpSingle datPum( + final typ=pum1.typ, + m_flow_nominal=1, + dp_nominal=1E5) "Single pump parameters" + annotation (Placement(transformation(extent={{60,-160},{80,-140}}))); + parameter Data.PumpMultiple datPumMul( + final typ=pumMul.typ, + final nPum=pumMul.nPum, + m_flow_nominal=fill(1, datPumMul.nPum), + dp_nominal=fill(1E5, datPumMul.nPum)) + "Multiple pump parameters" + annotation (Placement(transformation(extent={{60,-42},{80,-22}}))); + 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.Components.Pumps.Multiple pumMul( + final energyDynamics=energyDynamics, + redeclare final package Medium=Medium, + nPum=2, + final dat=datPumMul) + "Two variable speed pumps in parallel with common speed command signal" + annotation (Placement(transformation(extent={{0,-70},{20,-50}}))); + Buildings.Templates.Components.Pumps.Single pum1( + final energyDynamics=energyDynamics, + redeclare final package Medium = Medium, + final dat=datPum) "Single variable speed pump" + annotation (Placement(transformation(extent={{0,-190},{20,-170}}))); + Buildings.Templates.Components.Pumps.Single pum2( + final energyDynamics=energyDynamics, + redeclare final package Medium=Medium, + final dat=datPum) "Single variable speed pump" + annotation (Placement(transformation(extent={{0,-150},{20,-130}}))); + Fluid.FixedResistances.Junction junInl( + redeclare final package Medium=Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal) * {1,-1,-1}, + final dp_nominal=fill(0,3)) + "Fluid junction" + annotation (Placement(transformation(extent={{-30,-170},{-10,-190}}))); + Fluid.FixedResistances.Junction junOut( + redeclare final package Medium=Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal) * {1,-1,1}, + final dp_nominal=fill(0,3)) + "Fluid junction" + annotation (Placement(transformation(extent={{30,-170},{50,-190}}))); + Fluid.FixedResistances.PressureDrop res( + redeclare final package Medium = Medium, + final m_flow_nominal=pum1.m_flow_nominal + pum2.m_flow_nominal, + final dp_nominal=pum1.dp_nominal - pum1.dpValChe_nominal) + "Fixed flow resistance" + annotation (Placement(transformation(extent={{70,-190},{90,-170}}))); + + Fluid.FixedResistances.Junction junInl1( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,-1}, + final dp_nominal=fill(0, 3)) + "Fluid junction" + annotation (Placement(transformation(extent={{-30,-50},{-10,-70}}))); + Fluid.FixedResistances.Junction junOut1( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,1}, + final dp_nominal=fill(0, 3)) + "Fluid junction" + annotation (Placement(transformation(extent={{30,-50},{50,-70}}))); + Fluid.FixedResistances.PressureDrop resMul( + redeclare final package Medium = Medium, + final m_flow_nominal=sum(pumMul.m_flow_nominal), + final dp_nominal=max(pumMul.dp_nominal .- pumMul.dpValChe_nominal)) + "Fixed flow resistance" + annotation (Placement(transformation(extent={{70,-70},{90,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1( + table=[ + 0, 0, 0; + 1, 1, 0; + 2, 1, 1; + 3, 0, 0], + timeScale=100, + period=300) "Pump enable signal" + annotation (Placement(transformation(extent={{-130,-52},{-110,-32}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant y(k=1) "Pump speed command" + annotation (Placement(transformation(extent={{-130,-110},{-110,-90}}))); + + Fluid.Sources.Boundary_pT bou( + redeclare final package Medium=Medium, nPorts=1) + "Pressure boundary condition" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-40,-200}))); + Fluid.Sources.Boundary_pT bou1(redeclare final package Medium = Medium, + nPorts=1) + "Pressure boundary condition" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-40,-82}))); + Buildings.Templates.Components.Pumps.Multiple pumMulCst( + have_var=false, + final energyDynamics=energyDynamics, + redeclare final package Medium = Medium, + nPum=2, + final dat=datPumMul) "Two constant speed pumps in parallel" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); + Fluid.FixedResistances.Junction junInl2( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,-1}, + final dp_nominal=fill(0, 3)) + "Fluid junction" + annotation (Placement(transformation(extent={{-30,50},{-10,30}}))); + Fluid.FixedResistances.Junction junOut2( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,1}, + final dp_nominal=fill(0, 3)) + "Fluid junction" + annotation (Placement(transformation(extent={{30,50},{50,30}}))); + Fluid.FixedResistances.PressureDrop resMulCst( + redeclare final package Medium = Medium, + final m_flow_nominal=sum(pumMulCst.m_flow_nominal), + final dp_nominal=max(pumMulCst.dp_nominal .- pumMulCst.dpValChe_nominal)) + "Fixed flow resistance" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Fluid.Sources.Boundary_pT bou2(redeclare final package Medium = Medium, + nPorts=1) + "Pressure boundary condition" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-40,20}))); + Buildings.Templates.Components.Pumps.Multiple pumMulDed( + have_varCom=false, + final energyDynamics=energyDynamics, + redeclare final package Medium = Medium, + nPum=2, + final dat=datPumMul) + "Two variable speed pumps in parallel with dedicated speed command signal" + annotation (Placement(transformation(extent={{0,130},{20,150}}))); + Fluid.FixedResistances.Junction junInl3( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,-1}, + final dp_nominal=fill(0, 3)) + "Fluid junction" + annotation (Placement(transformation(extent={{-30,150},{-10,130}}))); + Fluid.FixedResistances.Junction junOut3( + redeclare final package Medium = Medium, + final energyDynamics=energyDynamics, + final m_flow_nominal=sum(datPumMul.m_flow_nominal)*{1,-1,1}, + final dp_nominal=fill(0, 3)) + "Fluid junction" + annotation (Placement(transformation(extent={{30,150},{50,130}}))); + Fluid.FixedResistances.PressureDrop resMulDed( + redeclare final package Medium = Medium, + final m_flow_nominal=sum(pumMulDed.m_flow_nominal), + final dp_nominal=max(pumMulDed.dp_nominal .- pumMulDed.dpValChe_nominal)) + "Fixed flow resistance" + annotation (Placement(transformation(extent={{70,130},{90,150}}))); + Fluid.Sources.Boundary_pT bou3(redeclare final package Medium = Medium, + nPorts=1) + "Pressure boundary condition" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-40,120}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yDed[pumMulDed.nPum](each k + =1) "Pump speed command" + annotation (Placement(transformation(extent={{-130,140},{-110,160}}))); +protected + Interfaces.Bus bus "Pump control bus" annotation (Placement(transformation( + extent={{-80,-190},{-40,-150}}), + iconTransformation(extent={{-318,-118}, + {-278,-78}}))); + Interfaces.Bus bus1 "Pump control bus" annotation (Placement(transformation( + extent={{-80,-150},{-40,-110}}), + iconTransformation(extent={{-26,-20},{14, + 20}}))); + Interfaces.Bus bus2 "Pump control bus" annotation (Placement(transformation( + extent={{-80,-70},{-40,-30}}), + iconTransformation(extent={{-318,-118},{-278, + -78}}))); + Interfaces.Bus bus3 "Pump control bus" annotation (Placement(transformation( + extent={{-80,30},{-40,70}}), iconTransformation(extent={{-318,-118},{-278, + -78}}))); + Interfaces.Bus bus4 "Pump control bus" annotation (Placement(transformation( + extent={{-80,130},{-40,170}}), + iconTransformation(extent={{-318,-118},{-278, + -78}}))); +equation + connect(pum1.port_b, junOut.port_1) + annotation (Line(points={{20,-180},{30,-180}}, color={0,127,255})); + connect(junInl.port_2, pum1.port_a) + annotation (Line(points={{-10,-180},{0,-180}}, color={0,127,255})); + connect(junInl.port_3, pum2.port_a) annotation (Line(points={{-20,-170},{-20, + -140},{0,-140}}, color={0,127,255})); + connect(pum2.port_b, junOut.port_3) annotation (Line(points={{20,-140},{40, + -140},{40,-170}}, + color={0,127,255})); + connect(junOut.port_2, res.port_a) + annotation (Line(points={{50,-180},{70,-180}}, color={0,127,255})); + connect(res.port_b, junInl.port_1) annotation (Line(points={{90,-180},{100, + -180},{100,-120},{-40,-120},{-40,-180},{-30,-180}}, + color={0,127,255})); + connect(junOut1.port_2, resMul.port_a) + annotation (Line(points={{50,-60},{70,-60}}, color={0,127,255})); + connect(junInl1.port_2, pumMul.ports_a[1]) annotation (Line(points={{-10,-60}, + {-6,-60},{-6,-61},{0,-61}}, + color={0,127,255})); + connect(pumMul.ports_b[1], junOut1.port_1) annotation (Line(points={{20,-61}, + {26,-61},{26,-60},{30,-60}}, + color={0,127,255})); + connect(pumMul.ports_b[2], junOut1.port_3) annotation (Line(points={{20,-59}, + {20,-32},{40,-32},{40,-50}}, + color={0,127,255})); + connect(junInl1.port_3, pumMul.ports_a[2]) annotation (Line(points={{-20,-50}, + {-20,-32},{0,-32},{0,-59}}, + color={0,127,255})); + connect(resMul.port_b, junInl1.port_1) annotation (Line(points={{90,-60},{100, + -60},{100,0},{-40,0},{-40,-60},{-30,-60}}, color={0,127,255})); + connect(bus1, pum2.bus) annotation (Line( + points={{-60,-130},{10,-130}}, + color={255,204,51}, + thickness=0.5)); + connect(y1.y[2], bus1.y1) annotation (Line(points={{-108,-42},{-80,-42},{-80, + -130},{-60,-130}}, + color={255,0,255})); + connect(y.y, bus1.y) annotation (Line(points={{-108,-100},{-100,-100},{-100, + -130},{-60,-130}}, + color={0,0,127})); + connect(y1.y[1], bus.y1) annotation (Line(points={{-108,-42},{-80,-42},{-80, + -170},{-60,-170}}, + color={255,0,255})); + connect(y.y, bus.y) annotation (Line(points={{-108,-100},{-100,-100},{-100, + -170},{-60,-170}}, + color={0,0,127})); + connect(bus, pum1.bus) annotation (Line( + points={{-60,-170},{10,-170}}, + color={255,204,51}, + thickness=0.5)); + connect(bus2, pumMul.bus) annotation (Line( + points={{-60,-50},{10,-50}}, + color={255,204,51}, + thickness=0.5)); + connect(y1.y[1:2], bus2.y1) annotation (Line(points={{-108,-42},{-80,-42},{ + -80,-50},{-60,-50}}, + color={255,0,255})); + connect(y.y, bus2.y) annotation (Line(points={{-108,-100},{-100,-100},{-100, + -50},{-60,-50}}, + color={0,0,127})); + connect(bou.ports[1], junInl.port_1) annotation (Line(points={{-40,-190},{-40, + -180},{-30,-180}}, + color={0,127,255})); + connect(bou1.ports[1], junInl1.port_1) + annotation (Line(points={{-40,-72},{-40,-60},{-30,-60}}, + color={0,127,255})); + connect(junOut2.port_2, resMulCst.port_a) + annotation (Line(points={{50,40},{70,40}}, color={0,127,255})); + connect(junInl2.port_2, pumMulCst.ports_a[1]) annotation (Line(points={{-10,40}, + {-6,40},{-6,39},{0,39}}, color={0,127,255})); + connect(pumMulCst.ports_b[1], junOut2.port_1) annotation (Line(points={{20,39}, + {26,39},{26,40},{30,40}}, color={0,127,255})); + connect(pumMulCst.ports_b[2], junOut2.port_3) annotation (Line(points={{20,41}, + {20,70},{40,70},{40,50}}, color={0,127,255})); + connect(junInl2.port_3, pumMulCst.ports_a[2]) annotation (Line(points={{-20,50}, + {-20,70},{0,70},{0,41}}, color={0,127,255})); + connect(resMulCst.port_b, junInl2.port_1) annotation (Line(points={{90,40},{ + 100,40},{100,100},{-40,100},{-40,40},{-30,40}}, color={0,127,255})); + connect(bus3, pumMulCst.bus) annotation (Line( + points={{-60,50},{10,50}}, + color={255,204,51}, + thickness=0.5)); + connect(bou2.ports[1],junInl2. port_1) + annotation (Line(points={{-40,30},{-40,40},{-30,40}}, color={0,127,255})); + connect(y1.y[1:2], bus3.y1) annotation (Line(points={{-108,-42},{-80,-42},{ + -80,50},{-60,50}}, color={255,0,255})); + connect(junOut3.port_2, resMulDed.port_a) + annotation (Line(points={{50,140},{70,140}}, color={0,127,255})); + connect(junInl3.port_2, pumMulDed.ports_a[1]) annotation (Line(points={{-10,140}, + {-6,140},{-6,139},{0,139}}, color={0,127,255})); + connect(pumMulDed.ports_b[1], junOut3.port_1) annotation (Line(points={{20,139}, + {26,139},{26,140},{30,140}}, color={0,127,255})); + connect(pumMulDed.ports_b[2], junOut3.port_3) annotation (Line(points={{20,141}, + {20,170},{40,170},{40,150}}, color={0,127,255})); + connect(junInl3.port_3, pumMulDed.ports_a[2]) annotation (Line(points={{-20,150}, + {-20,170},{0,170},{0,141}}, color={0,127,255})); + connect(resMulDed.port_b, junInl3.port_1) annotation (Line(points={{90,140},{ + 100,140},{100,200},{-40,200},{-40,140},{-30,140}}, color={0,127,255})); + connect(bus4, pumMulDed.bus) annotation (Line( + points={{-60,150},{10,150}}, + color={255,204,51}, + thickness=0.5)); + connect(bou3.ports[1],junInl3. port_1) + annotation (Line(points={{-40,130},{-40,140},{-30,140}}, + color={0,127,255})); + connect(y1.y, bus4.y1) annotation (Line(points={{-108,-42},{-80,-42},{-80,150}, + {-60,150}}, color={255,0,255})); + connect(yDed.y, bus4.y) + annotation (Line(points={{-108,150},{-60,150}}, color={0,0,127})); + annotation ( + __Dymola_Commands( + file="modelica://Buildings/Resources/Scripts/Dymola/Templates/Components/Validation/Pumps.mos" + "Simulate and plot"), + experiment(Tolerance=1e-6, StopTime=300), + Diagram(coordinateSystem(extent={{-140,-220},{140,220}})), + Documentation(info=" +

+This model validates the models within + +Buildings.Templates.Components.Pumps +by connecting each pump component to a water loop with a +fixed flow resistance, which +is sized based on the pump's nominal operating point. +Two identical parallel pumps are modeled with either +one instance of + +Buildings.Templates.Components.Pumps.Multiple +or two instances of + +Buildings.Templates.Components.Pumps.Single. +The multiple pump component is configured to represent +variable speed pumps with dedicated speed command signals +(component pumMulDed), +variable speed pumps with common speed command +signal (component pumMul) or constant speed pumps +(component pumMulCst). +The single pump components (pum1 and pum2) +are configured to represent variable speed pumps. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end Pumps; diff --git a/Buildings/Templates/Components/Validation/package.order b/Buildings/Templates/Components/Validation/package.order index 07f6cebf6fd..1c996f732a4 100644 --- a/Buildings/Templates/Components/Validation/package.order +++ b/Buildings/Templates/Components/Validation/package.order @@ -1,6 +1,8 @@ Coils Dampers Fans +PumpMultipleRecord +Pumps Routing Sensors Valves diff --git a/Buildings/Templates/Components/package.order b/Buildings/Templates/Components/package.order index 7ee7d4cb40d..fcbf4ac61e6 100644 --- a/Buildings/Templates/Components/package.order +++ b/Buildings/Templates/Components/package.order @@ -2,6 +2,8 @@ Actuators Coils Controls Fans +HeatPumps +Pumps Routing Sensors Data diff --git a/Buildings/Templates/Data/Defaults.mo b/Buildings/Templates/Data/Defaults.mo new file mode 100644 index 00000000000..31727c09285 --- /dev/null +++ b/Buildings/Templates/Data/Defaults.mo @@ -0,0 +1,165 @@ +within Buildings.Templates.Data; +package Defaults + "Package with default sizing parameters" + extends Modelica.Icons.MaterialPropertiesPackage; + constant Modelica.Units.SI.Temperature TChiWatSup=7 + 273.15 + "CHW supply temperature (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TChiWatSup_max=16 + 273.15 + "Maximum CHW supply temperature (typical)"; + constant Modelica.Units.SI.Temperature TChiWatRet=12 + 273.15 + "CHW return temperature (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TConWatSup=30 + 273.15 + "CW supply temperature (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TConWatRet=35 + 273.15 + "CW return temperature (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TOutChi=35 + 273.15 + "Outdoor air temperature for air-cooled chiller (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TConEnt_min=13 + 273.15 + "Minimum condenser entering fluid temperature (air or water)"; + constant Modelica.Units.SI.Temperature TConEnt_max=45 + 273.15 + "Maximum condenser entering fluid temperature (air or water)"; + constant Modelica.Units.SI.Temperature TChiWatEcoEnt=18 + 273.15 + "WSE entering CHW temperature"; + constant Modelica.Units.SI.Temperature TChiWatEcoLvg=11 + 273.15 + "WSE leaving CHW temperature"; + constant Modelica.Units.SI.Temperature TConWatEcoEnt=9 + 273.15 + "WSE entering CW temperature"; + constant Modelica.Units.SI.Temperature TConWatEcoLvg=16 + 273.15 + "WSE leaving CW temperature"; + constant Modelica.Units.SI.Temperature TOutChiWatLck=16 + 273.15 + "Outdoor air lockout temperature below which the CHW system is prevented from operating"; + constant Modelica.Units.SI.TemperatureDifference dTLifChi_min=5 + "Minimum chiller lift at minimum load"; + constant Modelica.Units.SI.Temperature TOutDryCoo=TOutChi + "Dry cooler entering air drybulb temperature"; + constant Modelica.Units.SI.Temperature TWetBulTowEnt=24 + 273.15 + "CT entering air wetbulb temperature"; + constant Real PFanByFloConWatTow( + unit="W/(kg/s)")=340 + "CT fan power divided by CW mass flow rate"; + constant Real mConWatFloByAirTow( + unit="1")=1.45 + "CT CW mass flow rate divided by air mass flow rate"; + constant Modelica.Units.SI.PressureDifference dpConWatFriTow=1E4 + "CW flow-friction losses through open-circuit tower and piping only (without elevation head or valve)"; + constant Modelica.Units.SI.PressureDifference dpConWatStaTow=3E4 + "CW elevation head (for open cooling towers only)"; + constant Modelica.Units.SI.PressureDifference dpConWatTowClo=5E4 + "CW flow-friction losses through closed-circuit tower and piping only (without valve)"; + constant Real mAirFloByCapChi( + unit="(kg/s)/W")=1E-4 + "Air mass flow rate divided by capacity for air-cooled chiller"; + constant Real COPChiAirCoo( + unit="1")=2.99 + "Air-cooled chiller COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C OAT)"; + constant Real COPChiWatCoo( + unit="1")=5.33 + "Water-cooled chiller COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C source LWT)"; + constant Modelica.Units.SI.PressureDifference dpValIso=1E3 + "Isolation or bypass valve pressure drop"; + constant Modelica.Units.SI.PressureDifference dpValBypMin=3E4 + "Minimum flow bypass valve pressure drop at design minimum flow for the largest chiller"; + constant Modelica.Units.SI.PressureDifference dpValChe=1E4 + "Check valve pressure drop"; + constant Modelica.Units.SI.PressureDifference dpChiWatChi=4E4 + "Chiller CHW pressure drop"; + constant Modelica.Units.SI.PressureDifference dpChiWatSet_min=5 * 6894 + "Minimum CHW differential pressure setpoint used in CHW plant reset logic"; + constant Modelica.Units.SI.PressureDifference dpChiWatRemSet_max=5E4 + "Maximum CHW differential pressure setpoint remote from the CHW plant"; + constant Modelica.Units.SI.PressureDifference dpChiWatLocSet_max=15E4 + "Maximum CHW differential pressure setpoint local to the CHW plant"; + constant Modelica.Units.SI.PressureDifference dpConWatChi=4E4 + "Chiller CW pressure drop (water-cooled)"; + constant Modelica.Units.SI.PressureDifference dpAirChi=500 + "Chiller air pressure drop across condenser (air-cooled)"; + constant Modelica.Units.SI.PressureDifference dpChiWatEco=3E4 + "WSE CHW pressure drop"; + constant Modelica.Units.SI.PressureDifference dpConWatEco=3E4 + "WSE CW pressure drop"; + constant Modelica.Units.SI.PressureDifference pChiWat_rel_nominal=1.0E5 + "CHW system gauge pressure at design conditions"; + constant Modelica.Units.SI.PressureDifference pHeaWat_rel_nominal=2.5E5 + "HHW system gauge pressure at design conditions"; + constant Modelica.Units.SI.PressureDifference dpHeaWatBoi=5E3 + "Boiler HW pressure drop"; + constant Modelica.Units.SI.Temperature THeaWatSup=80 + 273.15 + "HW supply temperature"; + constant Modelica.Units.SI.Temperature THeaWatConSup=65 + 273.15 + "HW supply temperature for condensing boilers"; + constant Modelica.Units.SI.Temperature THeaWatRet=55 + 273.15 + "HW return temperature"; + constant Modelica.Units.SI.Temperature TOutHeaWatLck=21 + 273.15 + "Outdoor air lockout temperature above which the HW system is prevented from operating"; + constant Modelica.Units.SI.PressureDifference dpHeaWatSet_min=5 * 6894 + "Minimum HW differential pressure setpoint used in HW plant reset logic"; + constant Modelica.Units.SI.PressureDifference dpHeaWatRemSet_max=5E4 + "Maximum HW differential pressure setpoint remote from the HW plant"; + constant Modelica.Units.SI.PressureDifference dpHeaWatLocSet_max=15E4 + "Maximum HW differential pressure setpoint local to the CHW plant"; + constant Modelica.Units.SI.PressureDifference dpHeaWatHp=3E4 + "Heat pump HW pressure drop across condenser barrel"; + constant Modelica.Units.SI.Temperature THeaWatSupHig=60 + 273.15 + "HW supply temperature - High temperature level (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature THeaWatRetHig=50 + 273.15 + "HW return temperature - High temperature level (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature THeaWatSupMed=50 + 273.15 + "HW supply temperature - Medium temperature level (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature THeaWatRetMed=42 + 273.15 + "HW return temperature - Medium temperature level (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature THeaWatSupLow=40 + 273.15 + "HW supply temperature - Low temperature level (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature THeaWatRetLow=35 + 273.15 + "HW return temperature - Low temperature level (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TOutHpCoo=TOutChi + "Outdoor air temperature for air-to-water heat pump rating - Cooling (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TOutHpHeaHig=8 + 273.15 + "Outdoor air temperature for air-to-water heat pump rating - High heating (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TOutHpHeaLow=-8 + 273.15 + "Outdoor air temperature for air-to-water heat pump rating - Low heating (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TSouHpCoo=30 + 273.15 + "Source fluid entering temperature for water-to-water heat pump rating - Cooling (AHRI 551/591)"; + constant Modelica.Units.SI.Temperature TSouHpHea=12 + 273.15 + "Source fluid entering temperature for water-to-water heat pump rating - Heating (AHRI 551/591)"; + constant Real COPHpAwHea( + unit="1")=1.75 + "Air-to-water heat pump heating COP (ASHRAE 90.1 2022 at 50 °C HWST, -8 °C OAT)"; + constant Real COPHpAwCoo( + unit="1")=2.84 + "Air-to-water heat pump cooling COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C OAT)"; + constant Real COPHpWwHea( + unit="1")=3.61 + "Water(brine)-to-water heat pump heating COP (ASHRAE 90.1 2022 at 50 °C HWST, 7 °C source LWT)"; + constant Real COPHpWwCoo( + unit="1")=5.07 + "Water(brine)-to-water heat pump cooling COP (ASHRAE 90.1 2022 at 7 °C CHWST, 35 °C source LWT)"; + annotation ( + Documentation( + info=" +

+This package defines some constants that are either +

+
    +
  • +typical values used as default parameter values +for models inside the package + +Buildings.Templates, or +
  • +
  • +arbitrary values used for validation purposes only. +Those are typically project-specific characteristics (e.g., +chiller COP at nominal conditions) and should not +be considered as generic default values. +
  • +
+", + revisions=" +
    +
  • +November 18, 2022, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end Defaults; diff --git a/Buildings/Templates/Data/package.order b/Buildings/Templates/Data/package.order index 3831742ec60..4cd15e62047 100644 --- a/Buildings/Templates/Data/package.order +++ b/Buildings/Templates/Data/package.order @@ -1 +1,2 @@ AllSystems +Defaults diff --git a/Buildings/Templates/Plants/Controls/Enabling/Enable.mo b/Buildings/Templates/Plants/Controls/Enabling/Enable.mo new file mode 100644 index 00000000000..582094ad756 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Enabling/Enable.mo @@ -0,0 +1,286 @@ +within Buildings.Templates.Plants.Controls.Enabling; +block Enable + "Plant enable" + parameter Buildings.Templates.Plants.Controls.Types.Application typ + "Type of application" + annotation (Evaluate=true); + parameter Boolean have_inpSch=false + "Set to true to provide schedule via software input point" + annotation (Evaluate=true); + parameter Real sch[:, 2]=[ + 0, 1; + 24 * 3600, 1] + "Enable schedule" + annotation (Dialog(enable=not have_inpSch)); + parameter Real TOutLck( + final min=100, + final unit="K")=if typ == Buildings.Templates.Plants.Controls.Types.Application.Heating + then 18 + 273.15 else 15 + 273.15 + "Outdoor air lockout temperature"; + parameter Real dTOutLck( + final min=0, + final unit="K")=0.5 + "Hysteresis for outdoor air lockout temperature"; + parameter Integer nReqIgn( + min=0)=0 + "Number of ignored requests"; + parameter Real dtRun( + final min=0, + final unit="s")=15 * 60 + "Minimum runtime of enable and disable states"; + parameter Real dtReq( + final min=0, + final unit="s")=3 * 60 + "Runtime with low number of request before disabling"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Sch + if have_inpSch + "System enable via schedule" + annotation (Placement(transformation(extent={{-200,80},{-160,120}}), + iconTransformation(extent={{-140,20},{-100,60}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqPla + "Number of plant requests" annotation (Placement(transformation(extent={{-200, + -20},{-160,20}}), iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TOut( + final unit="K", + final quantity="ThermodynamicTemperature", + displayUnit="degC") + "Outdoor air temperature" + annotation (Placement(transformation(extent={{-200,-120},{-160,-80}}), + iconTransformation(extent={{-140,-60},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1 + "Enable command" + annotation (Placement(transformation(extent={{160,-20},{200,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable schEna( + final table=sch, + final period=max(sch[:, 1])) + if not have_inpSch + "Enable schedule" + annotation (Placement(transformation(extent={{-150,50},{-130,70}}))); + Buildings.Controls.OBC.CDL.Integers.GreaterThreshold greIgn( + final t=nReqIgn) + "Return true if number of requests > number of ignored requests" + annotation (Placement(transformation(extent={{-120,-10},{-100,10}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greLck( + final t=TOutLck) + if typ == Buildings.Templates.Plants.Controls.Types.Application.Cooling + "Return true if OAT > lockout temperature" + annotation (Placement(transformation(extent={{-120,-90},{-100,-70}}))); + Buildings.Controls.OBC.CDL.Reals.LessThreshold lesLck( + final t=TOutLck) + if typ == Buildings.Templates.Plants.Controls.Types.Application.Heating + "Return true if OAT < lockout temperature" + annotation (Placement(transformation(extent={{-120,-130},{-100,-110}}))); + Buildings.Controls.OBC.CDL.Logical.Pre preEna + "Left limit (in discrete-time) of enable signal" + annotation (Placement(transformation(extent={{-80,110},{-60,130}}))); + Buildings.Controls.OBC.CDL.Logical.Timer timEna( + final t=dtRun) + "Return true if system has been enabled for specified duration" + annotation (Placement(transformation(extent={{0,110},{20,130}}))); + Buildings.Controls.OBC.CDL.Logical.Not dis + "Return true if disabled" + annotation (Placement(transformation(extent={{-40,90},{-20,110}}))); + Buildings.Controls.OBC.CDL.Logical.Timer runDis( + final t=dtRun) + "Return true if system has been disabled for specified duration" + annotation (Placement(transformation(extent={{0,70},{20,90}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd mulAnd( + nin=4) + "Combine enable conditions" + annotation (Placement(transformation(extent={{50,30},{70,50}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr mulOr( + nin=3) + "Combine disable conditions" + annotation (Placement(transformation(extent={{50,-50},{70,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Not disSch + "Return true if disabled by schedule" + annotation (Placement(transformation(extent={{-80,50},{-60,70}}))); + Buildings.Controls.OBC.CDL.Integers.LessEqualThreshold lowIgn( + final t=nReqIgn) + "Return true if number of requests ≤ number of ignored requests" + annotation (Placement(transformation(extent={{-120,-50},{-100,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Timer timLowReq( + final t=dtReq) + "Return true if low number of requests for specified duration" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); + Buildings.Controls.OBC.CDL.Reals.LessThreshold lowLckHys( + final t=TOutLck - dTOutLck) + if typ == Buildings.Templates.Plants.Controls.Types.Application.Cooling + "Return true if OAT < lockout temperature - hysteresis" + annotation (Placement(transformation(extent={{-80,-110},{-60,-90}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greLckHys( + final t=TOutLck + dTOutLck) + if typ == Buildings.Templates.Plants.Controls.Types.Application.Heating + "Return true if OAT > lockout temperature + hysteresis" + annotation (Placement(transformation(extent={{-80,-150},{-60,-130}}))); + Buildings.Controls.OBC.CDL.Logical.And andRun + "Disable conditions met AND enable minimum runtime exceeded" + annotation (Placement(transformation(extent={{90,-50},{110,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Latch lat + "Clear enable signal if disable conditions are met" + annotation (Placement(transformation(extent={{120,-10},{140,10}}))); +equation + connect(nReqPla, greIgn.u) + annotation (Line(points={{-180,0},{-122,0}}, color={255,127,0})); + connect(TOut, greLck.u) + annotation (Line(points={{-180,-100},{-140,-100},{-140,-80},{-122,-80}}, + color={0,0,127})); + connect(TOut, lesLck.u) + annotation (Line(points={{-180,-100},{-140,-100},{-140,-120},{-122,-120}}, + color={0,0,127})); + connect(preEna.y, dis.u) + annotation (Line(points={{-58,120},{-50,120},{-50,100},{-42,100}},color={255,0,255})); + connect(dis.y, runDis.u) + annotation (Line(points={{-18,100},{-10,100},{-10,80},{-2,80}},color={255,0,255})); + connect(preEna.y, timEna.u) + annotation (Line(points={{-58,120},{-2,120}},color={255,0,255})); + connect(runDis.passed, mulAnd.u[1]) + annotation (Line(points={{22,72},{40,72},{40,37.375},{48,37.375}},color={255,0,255})); + connect(schEna.y[1], mulAnd.u[2]) + annotation (Line(points={{-128,60},{-100,60},{-100,39.125},{48,39.125}}, + color={255,0,255})); + connect(u1Sch, mulAnd.u[2]) + annotation (Line(points={{-180,100},{-100,100},{-100,40},{48,40},{48,39.125}}, + color={255,0,255})); + connect(greIgn.y, mulAnd.u[3]) + annotation (Line(points={{-98,0},{40,0},{40,40.875},{48,40.875}},color={255,0,255})); + connect(schEna.y[1], disSch.u) + annotation (Line(points={{-128,60},{-82,60}},color={255,0,255})); + connect(u1Sch, disSch.u) + annotation (Line(points={{-180,100},{-100,100},{-100,60},{-82,60}},color={255,0,255})); + connect(disSch.y, mulOr.u[1]) + annotation (Line(points={{-58,60},{0,60},{0,-42.3333},{48,-42.3333}},color={255,0,255})); + connect(nReqPla, lowIgn.u) annotation (Line(points={{-180,0},{-140,0},{-140,-40}, + {-122,-40}}, color={255,127,0})); + connect(lowIgn.y, timLowReq.u) + annotation (Line(points={{-98,-40},{-82,-40}},color={255,0,255})); + connect(timLowReq.passed, mulOr.u[2]) + annotation (Line(points={{-58,-48},{-40,-48},{-40,-40},{48,-40}},color={255,0,255})); + connect(greLck.y, mulAnd.u[4]) + annotation (Line(points={{-98,-80},{20,-80},{20,42.625},{48,42.625}},color={255,0,255})); + connect(lesLck.y, mulAnd.u[4]) + annotation (Line(points={{-98,-120},{20,-120},{20,42.625},{48,42.625}},color={255,0,255})); + connect(TOut, lowLckHys.u) + annotation (Line(points={{-180,-100},{-82,-100}},color={0,0,127})); + connect(lowLckHys.y, mulOr.u[3]) + annotation (Line(points={{-58,-100},{40,-100},{40,-37.6667},{48,-37.6667}}, + color={255,0,255})); + connect(TOut, greLckHys.u) + annotation (Line(points={{-180,-100},{-140,-100},{-140,-140},{-82,-140}}, + color={0,0,127})); + connect(greLckHys.y, mulOr.u[3]) + annotation (Line(points={{-58,-140},{40,-140},{40,-37.6667},{48,-37.6667}}, + color={255,0,255})); + connect(timEna.passed, andRun.u1) + annotation (Line(points={{22,112},{80,112},{80,-40},{88,-40}},color={255,0,255})); + connect(mulOr.y, andRun.u2) + annotation (Line(points={{72,-40},{76,-40},{76,-48},{88,-48}},color={255,0,255})); + connect(y1, lat.y) + annotation (Line(points={{180,0},{142,0}},color={255,0,255})); + connect(mulAnd.y, lat.u) + annotation (Line(points={{72,40},{114,40},{114,0},{118,0}},color={255,0,255})); + connect(andRun.y, lat.clr) + annotation (Line(points={{112,-40},{114,-40},{114,-6},{118,-6}},color={255,0,255})); + connect(y1, preEna.u) + annotation (Line(points={{180,0},{150,0},{150,140},{-100,140},{-100,120},{-82,120}}, + color={255,0,255})); + annotation ( + defaultComponentName="ena", + Icon( + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=0.1), + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={28,108,200}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + lineThickness=5, + borderPattern=BorderPattern.Raised), + Ellipse( + extent={{-80,80},{80,-80}}, + lineColor={28,108,200}, + fillColor={170,255,213}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-90,90},{90,-90}}, + lineColor={28,108,200}), + Rectangle( + extent={{-75,2},{75,-2}}, + lineColor={28,108,200}, + fillColor={28,108,200}, + fillPattern=FillPattern.Solid), + Text( + extent={{-66,46},{76,10}}, + textColor={28,108,200}, + textString="START"), + Text( + extent={{-66,-8},{76,-44}}, + textColor={28,108,200}, + textString="STOP"), + Text( + extent={{-150,150},{150,110}}, + textColor={0,0,255}, + textString="%name")}, + coordinateSystem( + preserveAspectRatio=false, + extent={{-100,-100},{100,100}})), + Documentation( + info=" +

+The plant is enabled when it has been disabled for at least the duration dtRun and: +

+
    +
  • +Number of plant requests > number of ignored requests nReqIgn, and +
  • +
  • +For cooling systems: outdoor air temperature > outdoor air lockout +temperature TOutLck, and +
  • +
  • +For heating systems: outdoor air temperature < outdoor air lockout +temperature TOutLck, and +
  • +
  • +The enable schedule is active. +
  • +
+

+The plant is disabled when it has been enabled for at least the duration +dtRun and: +

+
    +
  • +Number of plant requests ≤ number of ignored requests nReqIgn +for at least the duration dtReq, or +
  • +
  • +For cooling systems: outdoor air temperature < outdoor air lockout +temperature TOutLck minus hysteresis dTOutLck, or +
  • +
  • +For heating systems: outdoor air temperature > outdoor air lockout +temperature TOutLck plus hysteresis dTOutLck, or +
  • +
  • +The plant enable schedule is inactive. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Diagram( + coordinateSystem( + extent={{-160,-160},{160,160}}))); +end Enable; diff --git a/Buildings/Templates/Plants/Controls/Enabling/Validation/Enable.mo b/Buildings/Templates/Plants/Controls/Enabling/Validation/Enable.mo new file mode 100644 index 00000000000..112320152fb --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Enabling/Validation/Enable.mo @@ -0,0 +1,99 @@ +within Buildings.Templates.Plants.Controls.Enabling.Validation; +model Enable + "Validation model for system enabling logic" + Buildings.Templates.Plants.Controls.Enabling.Enable enaHea( + typ=Buildings.Templates.Plants.Controls.Types.Application.Heating, + nReqIgn=1) + "Enable heating system" + annotation (Placement(transformation(extent={{20,50},{40,70}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Pulse req( + amplitude=1, + period=60 * 20, + offset=1) + "System request" + annotation (Placement(transformation(extent={{-60,50},{-40,70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin TOut( + y(displayUnit="degC", + unit="K"), + final amplitude=12, + final freqHz=1 /(10000), + final offset=285.15) + "Outdoor air temperature" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Templates.Plants.Controls.Enabling.Enable enaCoo( + typ=Buildings.Templates.Plants.Controls.Types.Application.Cooling, + nReqIgn=1) + "Enable cooling system" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Buildings.Templates.Plants.Controls.Enabling.Enable enaCooSch( + typ=Buildings.Templates.Plants.Controls.Types.Application.Cooling, + have_inpSch=true, + nReqIgn=1) + "Enable cooling system with input schedule" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse sch( + width=0.4, + period=120 * 60, + shift=25 * 60) + "Enable schedule" + annotation (Placement(transformation(extent={{-60,-70},{-40,-50}}))); +equation + connect(req.y, enaHea.nReqPla) + annotation (Line(points={{-38,60},{18,60}}, color={255,127,0})); + connect(TOut.y, enaHea.TOut) + annotation (Line(points={{-38,0},{-20,0},{-20,56},{18,56}},color={0,0,127})); + connect(req.y, enaCoo.nReqPla) annotation (Line(points={{-38,60},{0,60},{0,0}, + {18,0}}, color={255,127,0})); + connect(TOut.y, enaCoo.TOut) + annotation (Line(points={{-38,0},{-20,0},{-20,-4},{18,-4}},color={0,0,127})); + connect(TOut.y, enaCooSch.TOut) + annotation (Line(points={{-38,0},{-20,0},{-20,-64},{18,-64}},color={0,0,127})); + connect(req.y, enaCooSch.nReqPla) annotation (Line(points={{-38,60},{0,60},{0, + -60},{18,-60}}, color={255,127,0})); + connect(sch.y, enaCooSch.u1Sch) + annotation (Line(points={{-38,-60},{-30,-60},{-30,-56},{18,-56}},color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Enabling/Validation/Enable.mos" + "Simulate and plot"), + experiment( + StopTime=7200.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false)), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Enable.Enable +in a heating configuration, in a cooling configuration, and in +a cooling configuration with the enable schedule provided via +an input point. +All these configurations have the same setting for the minimum number +of ignored requests: nReqIgn=1. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end Enable; diff --git a/Buildings/Templates/Plants/Controls/Enabling/Validation/package.mo b/Buildings/Templates/Plants/Controls/Enabling/Validation/package.mo new file mode 100644 index 00000000000..0d38c01291f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Enabling/Validation/package.mo @@ -0,0 +1,29 @@ +within Buildings.Templates.Plants.Controls.Enabling; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), + Documentation( + info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/Enabling/Validation/package.order b/Buildings/Templates/Plants/Controls/Enabling/Validation/package.order new file mode 100644 index 00000000000..bc0ba0e9217 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Enabling/Validation/package.order @@ -0,0 +1 @@ +Enable diff --git a/Buildings/Templates/Plants/Controls/Enabling/package.mo b/Buildings/Templates/Plants/Controls/Enabling/package.mo new file mode 100644 index 00000000000..0b50ad9137f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Enabling/package.mo @@ -0,0 +1,44 @@ +within Buildings.Templates.Plants.Controls; +package Enabling "Plant enable/disable" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Ellipse( + origin={10.0,10.0}, + lineColor={128,128,128}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-80.0,0.0},{-20.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={128,128,128}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,0.0},{60.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,-80.0},{60.0,-20.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={76,76,76}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{-80.0,-80.0},{-20.0,-20.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), Documentation(info=" +

+This package contains control sequences to enable or disable +chilled water or hot water plants. +

+")); +end Enabling; diff --git a/Buildings/Templates/Plants/Controls/Enabling/package.order b/Buildings/Templates/Plants/Controls/Enabling/package.order new file mode 100644 index 00000000000..ff54e1e7178 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Enabling/package.order @@ -0,0 +1,2 @@ +Enable +Validation diff --git a/Buildings/Templates/Plants/Controls/HeatPumps/AirToWater.mo b/Buildings/Templates/Plants/Controls/HeatPumps/AirToWater.mo new file mode 100644 index 00000000000..2048e9d1a06 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/HeatPumps/AirToWater.mo @@ -0,0 +1,1582 @@ +within Buildings.Templates.Plants.Controls.HeatPumps; +block AirToWater + "Controller for AWHP plant" + parameter Boolean have_heaWat + "Set to true for plants that provide HW" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Boolean have_chiWat + "Set to true for plants that provide CHW" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Boolean have_valHpInlIso + "Set to true for plants with isolation valves at heat pump inlet" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Boolean have_valHpOutIso + "Set to true for plants with isolation valves at heat pump outlet" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + final parameter Boolean have_pumHeaWatPri=have_heaWat + "Set to true for plants with primary HW pumps" + annotation (Evaluate=true); + parameter Boolean have_pumChiWatPriDed_select(start=false)=false + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true, + Dialog(enable=have_chiWat and not have_pumPriHdr, group="Plant configuration")); + final parameter Boolean have_pumChiWatPriDed= + if have_chiWat and not have_pumPriHdr then have_pumChiWatPriDed_select else false + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true); + final parameter Boolean have_pumChiWatPri= + have_chiWat and (have_pumPriHdr or have_pumChiWatPriDed) + "Set to true for plants with separate primary CHW pumps" + annotation (Evaluate=true); + parameter Boolean have_pumPriHdr + "Set to true for headered primary pumps, false for dedicated pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Boolean have_pumHeaWatPriVar(start=true)=true + "Set to true for variable speed primary HW pumps, false for constant speed pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", enable=have_heaWat)); + parameter Boolean have_pumChiWatPriVar(start=true)=true + "Set to true for variable speed primary CHW pumps, false for constant speed pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", enable=have_chiWat and + (have_pumPriHdr or have_pumChiWatPriDed))); + // Only constant primary is supported for AWHP. + final parameter Boolean have_pumPriCtlDp=false + "Set to true for primary headered variable speed pumps using ∆p pump speed control" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Boolean have_pumHeaWatSec_select(start=false) + "Set to true for plants with secondary HW pumps" + annotation (Evaluate=true, + Dialog(enable=have_heaWat,group="Plant configuration")); + final parameter Boolean have_pumHeaWatSec= + if have_heaWat then have_pumHeaWatSec_select else false + "Set to true for plants with secondary HW pumps" + annotation (Evaluate=true); + parameter Boolean have_pumChiWatSec_select(start=false) + "Set to true for plants with secondary CHW pumps" + annotation (Evaluate=true, + Dialog(enable=have_chiWat,group="Plant configuration")); + final parameter Boolean have_pumChiWatSec= + if have_chiWat then have_pumChiWatSec_select else false + "Set to true for plants with secondary CHW pumps" + annotation (Evaluate=true); + // Only headered arrangements are supported for secondary pumps. + final parameter Boolean have_pumSecHdr=true + "Set to true for headered secondary pumps, false for dedicated pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + // Only ∆p controlled variable speed pumps are supported for secondary pumps. + final parameter Boolean have_pumSecCtlDp=have_pumHeaWatSec or have_pumChiWatSec + "Set to true for secondary headered variable speed pumps using ∆p pump speed control" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + // RFE(AntoineGautier): Add option for sidestream HRC. Always excluded for now. + final parameter Boolean have_hrc( + start=false)=false + "Set to true for plants with a sidestream heat recovery chiller" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_heaWat and have_chiWat)); + parameter Boolean have_senVHeaWatPri_select(start=false) + "Set to true for plants with primary HW flow sensor" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_heaWat and not have_hrc and have_senVHeaWatSec)); + final parameter Boolean have_senVHeaWatPri=have_heaWat and + (if have_hrc or not have_senVHeaWatSec then true else have_senVHeaWatPri_select) + "Set to true for plants with primary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + // Secondary flow sensor required for secondary HW pump staging. + final parameter Boolean have_senVHeaWatSec=have_pumHeaWatSec + "Set to true for plants with secondary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + parameter Boolean have_senVChiWatPri_select(start=false) + "Set to true for plants with primary CHW flow sensor" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_chiWat and not have_hrc and have_senVChiWatSec)); + final parameter Boolean have_senVChiWatPri=have_chiWat and + (if have_hrc or not have_senVChiWatSec then true + else have_senVChiWatPri_select) + "Set to true for plants with primary CHW flow sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + // Secondary flow sensor required for secondary CHW pump staging. + final parameter Boolean have_senVChiWatSec(start=false)=have_pumChiWatSec + "Set to true for plants with secondary CHW flow sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + parameter Boolean have_senTHeaWatPriRet_select(start=false) + "Set to true for plants with primary HW return temperature sensor" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_heaWat and not have_hrc and have_senTHeaWatSecRet)); + final parameter Boolean have_senTHeaWatPriRet=have_heaWat and + (if have_hrc or not have_senTHeaWatSecRet then true else have_senTHeaWatPriRet_select) + "Set to true for plants with primary HW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + parameter Boolean have_senTChiWatPriRet_select(start=false) + "Set to true for plants with primary CHW return temperature sensor" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_chiWat and not have_hrc and have_senTChiWatSecRet)); + final parameter Boolean have_senTChiWatPriRet=have_chiWat and + (if have_hrc or not have_senTChiWatSecRet then true else have_senTChiWatPriRet_select) + "Set to true for plants with primary CHW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + // For primary-secondary plants, SHWST sensor is required for plant staging. + final parameter Boolean have_senTHeaWatSecSup=have_pumHeaWatSec + "Set to true for plants with secondary HW supply temperature sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + // For primary-secondary plants, SCHWST sensor is required for plant staging. + final parameter Boolean have_senTChiWatSecSup=have_pumChiWatSec + "Set to true for plants with secondary CHW supply temperature sensor" + annotation (Evaluate=true, Dialog(group="Sensors")); + parameter Boolean have_senTHeaWatSecRet(start=false) + "Set to true for plants with secondary HW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Sensors", enable=have_pumHeaWatSec)); + parameter Boolean have_senTChiWatSecRet(start=false) + "Set to true for plants with secondary CHW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Sensors", enable=have_pumChiWatSec)); + parameter Integer nHp(final min=1) + "Number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Integer nPumHeaWatPri( + final min=if have_pumHeaWatPri then 1 else 0, + start=0)=nHp + "Number of primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_pumHeaWatPri)); + parameter Integer nPumChiWatPri( + final min=if have_pumChiWatPri then 1 else 0, + start=if have_pumChiWatPri then nHp else 0)=if have_pumChiWatPri then nHp + else 0 + "Number of primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_pumChiWatPri)); + parameter Integer nPumHeaWatSec( + final min=if have_pumHeaWatSec then 1 else 0, + start=0)=nHp + "Number of secondary HW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_pumHeaWatSec)); + parameter Integer nPumChiWatSec( + final min=if have_pumChiWatSec then 1 else 0, + start=0)=nHp + "Number of secondary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_pumChiWatSec)); + parameter Boolean have_senDpHeaWatRemWir(start=true)=true + "Set to true for remote HW differential pressure sensor(s) hardwired to plant or pump controller" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Integer nSenDpHeaWatRem(final min=if have_heaWat and have_pumHeaWatSec + then 1 else 0, start=0) + "Number of remote HW differential pressure sensors used for HW pump speed control" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Boolean have_senDpChiWatRemWir(start=true)=true + "Set to true for remote CHW differential pressure sensor(s) hardwired to plant or pump controller" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_chiWat and have_pumChiWatSec)); + parameter Integer nSenDpChiWatRem(final min=if have_chiWat and have_pumChiWatSec + then 1 else 0, start=0) + "Number of remote CHW differential pressure sensors used for CHW pump speed control" + annotation (Evaluate=true, + Dialog(group="Sensors", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real THeaWatSup_nominal( + final min=273.15, + start=50 + 273.15, + final unit="K", + displayUnit="degC") + "Design HW supply temperature (maximum setpoint)" + annotation (Dialog(group="Information provided by designer", + enable=have_heaWat)); + parameter Real THeaWatSupSet_min( + final min=273.15, + start=25 + 273.15, + final unit="K", + displayUnit="degC") + "Minimum value to which the HW supply temperature can be reset" + annotation (Dialog(group="Information provided by designer", + enable=have_heaWat)); + parameter Real TOutHeaWatLck( + final min=273.15, + start=21 + 273.15, + final unit="K", + displayUnit="degC")=294.15 + "Outdoor air lockout temperature above which the HW loop is prevented from operating" + annotation (Dialog(group="Information provided by designer", + enable=have_heaWat)); + parameter Real capHeaHp_nominal[nHp]( + final min=fill(0, nHp), + start=fill(1, nHp), + final unit=fill("W", nHp)) + "Design heating capacity - Each heat pump" + annotation (Dialog(group="Information provided by designer", + enable=have_heaWat)); + parameter Real VHeaWatSec_flow_nominal( + final min=0, + start=1E-6, + final unit="m3/s") + "Design secondary HW volume flow rate" + annotation (Evaluate=true, + Dialog(group="Information provided by designer", + enable=have_heaWat and have_pumHeaWatSec and have_pumSecCtlDp)); + parameter Real dpHeaWatRemSet_max[nSenDpHeaWatRem]( + final min=fill(0, nSenDpHeaWatRem), + start=fill(5E4, nSenDpHeaWatRem), + final unit=fill("Pa", nSenDpHeaWatRem)) + "Maximum HW differential pressure setpoint - Remote sensor" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real dpHeaWatRemSet_min( + final min=0, + start=5*6894, + final unit="Pa")=5*6894 + "Minimum value to which the HW differential pressure can be reset - Remote sensor" + annotation (Dialog(group= + "Information provided by designer", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real yPumHeaWatPriSet( + final max=1, + final min=0, + start=1, + final unit="1") + "Primary pump speed providing design heat pump flow in heating mode" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=have_heaWat and have_pumHeaWatPriVar)); + parameter Real TChiWatSup_nominal( + final min=273.15, + start=7 + 273.15, + final unit="K", + displayUnit="degC") + "Design CHW supply temperature (minimum setpoint)" + annotation (Dialog(group="Information provided by designer", + enable=have_chiWat)); + parameter Real TChiWatSupSet_max( + final min=273.15, + start=15 + 273.15, + final unit="K", + displayUnit="degC") + "Maximum value to which the CHW supply temperature can be reset" + annotation (Dialog(group="Information provided by designer", + enable=have_chiWat)); + parameter Real TOutChiWatLck( + final min=273.15, + start=16 + 273.15, + final unit="K", + displayUnit="degC")=289.15 + "Outdoor air lockout temperature below which the CHW loop is prevented from operating" + annotation (Dialog(group="Information provided by designer", + enable=have_chiWat)); + parameter Real capCooHp_nominal[nHp]( + final min=fill(0, nHp), + start=fill(1, nHp), + final unit=fill("W", nHp)) + "Design cooling capacity - Each heat pump" + annotation (Dialog(group="Information provided by designer", + enable=have_chiWat)); + parameter Real VChiWatSec_flow_nominal( + final min=0, + start=1E-6, + final unit="m3/s") + "Design secondary CHW volume flow rate" + annotation (Evaluate=true, + Dialog(group="Information provided by designer", + enable=have_chiWat and have_pumChiWatSec and have_pumSecCtlDp)); + parameter Real dpChiWatRemSet_max[nSenDpChiWatRem]( + final min=fill(0, nSenDpChiWatRem), + start=fill(5E4, nSenDpChiWatRem), + final unit=fill("Pa", nSenDpChiWatRem)) + "Maximum CHW differential pressure setpoint - Remote sensor" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real dpChiWatRemSet_min( + final min=0, + start=5*6894, + final unit="Pa")=5*6894 + "Minimum value to which the CHW differential pressure can be reset - Remote sensor" + annotation (Dialog(group= + "Information provided by designer", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real yPumChiWatPriSet( + final max=1, + final min=0, + start=1, + final unit="1") + "Primary pump speed providing design heat pump flow in cooling mode" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=have_chiWat and have_pumChiWatPriVar)); + parameter Real cp_default( + final min=0, + final unit="J/(kg.K)")=4184 + "Default specific heat capacity used to compute required capacity" + annotation (Evaluate=true, + Dialog(group="Information provided by designer")); + parameter Real rho_default( + final min=0, + final unit="kg/m3")=996 + "Default density used to compute required capacity" + annotation (Evaluate=true, + Dialog(group="Information provided by designer")); + parameter Boolean have_inpSch=false + "Set to true to provide schedule via software input point" + annotation (Dialog(group="Plant enable"), + Evaluate=true); + parameter Real schHea[:, 2](start=[0,1; 24*3600,1])=[0,1; 24*3600,1] + "Heating mode enable schedule" + annotation (Dialog(enable=not have_inpSch,group="Plant enable")); + parameter Real schCoo[:, 2](start=[0,1; 24*3600,1])=[0,1; 24*3600,1] + "Cooling mode enable schedule" + annotation (Dialog(enable=not have_inpSch,group="Plant enable")); + parameter Integer nReqIgnHeaWat(final min=0)=0 + "Number of ignored HW plant requests" + annotation (Dialog(tab="Advanced",group="Plant enable")); + parameter Integer nReqIgnChiWat(final min=0)=0 + "Number of ignored CHW plant requests" + annotation (Dialog(tab="Advanced",group="Plant enable")); + parameter Real dTOutLck( + final min=0, + final unit="K")=0.5 + "Hysteresis for outdoor air lockout temperature" + annotation (Dialog(tab="Advanced",group="Plant enable")); + parameter Real dtRunEna( + final min=0, + final unit="s")=15*60 + "Minimum runtime of enable and disable states" + annotation (Dialog(tab="Advanced",group="Plant enable")); + parameter Real dtReqDis( + final min=0, + final unit="s")=3*60 + "Runtime with low number of request before disabling" + annotation (Dialog(tab="Advanced",group="Plant enable")); + parameter Real staEqu[:, nHp]( + each final max=1, + each final min=0, + each final unit="1") + "Staging matrix – Equipment required for each stage" + annotation (Dialog(group="Equipment staging and rotation")); + final parameter Integer nSta( + final min=1)=size(staEqu, 1) + "Number of stages" + annotation (Evaluate=true); + final parameter Integer nEquAlt( + final min=0)=max({sum({(if staEqu[i, j] > 0 and staEqu[i, j] < 1 then 1 else 0) for j in 1:nHp}) for i in 1:nSta}) + "Number of lead/lag alternate equipment" + annotation (Evaluate=true); + parameter Integer idxEquAlt[nEquAlt]( + each final min=1) + "Indices of lead/lag alternate equipment" + annotation (Evaluate=true, + Dialog(group="Equipment staging and rotation")); + parameter Real dtVal( + final min=0, + start=90, + final unit="s")=90 + "Nominal valve timing" + annotation (Dialog(tab="Advanced",group="Equipment staging and rotation", + enable=have_valHpInlIso or have_valHpOutIso)); + parameter Real dtHp( + final min=0, + final unit="s")=180 + annotation (Dialog(tab="Advanced",group="Equipment staging and rotation")); + parameter Real plrSta( + final max=1, + final min=0, + start=0.9, + final unit="1")=0.9 + "Staging part load ratio" + annotation (Dialog(group="Equipment staging and rotation")); + parameter Real dtRunSta( + final min=0, + final unit="s", + displayUnit="min")=900 + "Minimum runtime of each stage" + annotation (Dialog(tab="Advanced",group="Equipment staging and rotation")); + parameter Real dtOff( + final min=0, + final unit="s")=900 + "Off time required before equipment is deemed available again" + annotation (Dialog(tab="Advanced",group="Equipment staging and rotation")); + parameter Real dtRunPumSta( + final min=0, + start=600, + final unit="s")=600 + "Runtime before triggering stage command" + annotation (Dialog(tab="Advanced",group="Pump staging", + enable=have_pumPriHdr and have_pumPriCtlDp or have_pumSecHdr and have_pumSecCtlDp)); + parameter Real dVOffUpPumSta( + final max=1, + final min=0, + start=0.03, + final unit="1")=0.03 + "Stage up flow point offset" + annotation (Dialog(tab="Advanced",group="Pump staging", + enable=have_pumPriHdr and have_pumPriCtlDp or have_pumSecHdr and have_pumSecCtlDp)); + parameter Real dVOffDowPumSta( + final max=1, + final min=0, + start=0.03, + final unit="1")=dVOffUpPumSta + "Stage down flow point offset" + annotation (Dialog(tab="Advanced",group="Pump staging", + enable=have_pumPriHdr and have_pumPriCtlDp or have_pumSecHdr and have_pumSecCtlDp)); + parameter Real dtHol( + final min=0, + final unit="s")=900 + "Minimum hold time during stage change" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec or have_chiWat and have_pumChiWatSec)); + parameter Real resDpHeaWat_max( + final max=1, + final min=0, + final unit="1")=0.5 + "Upper limit of plant reset interval for HW differential pressure reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real resTHeaWatSup_min( + final max=1, + final min=0, + final unit="1")=resDpHeaWat_max + "Lower limit of plant reset interval for HW supply temperature reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real resDpChiWat_max( + final max=1, + final min=0, + final unit="1")=0.5 + "Upper limit of plant reset interval for CHW differential pressure reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real resTChiWatSup_min( + final max=1, + final min=0, + final unit="1")=resDpChiWat_max + "Lower limit of plant reset interval for CHW supply temperature reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real res_init( + final max=1, + final min=0, + final unit="1")=1 + "Initial reset value" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec or have_chiWat and have_pumChiWatSec)); + parameter Real res_min( + final max=1, + final min=0, + final unit="1")=0 + "Minimum reset value" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec or have_chiWat and have_pumChiWatSec)); + parameter Real res_max( + final max=1, + final min=0, + final unit="1")=1 + "Maximum reset value" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec or have_chiWat and have_pumChiWatSec)); + parameter Real dtDel( + final min=100*1E-15, + final unit="s")=900 + "Delay time before the reset begins" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec or have_chiWat and have_pumChiWatSec)); + parameter Real dtResHeaWat( + final min=1E-3, + final unit="s")=300 + "Reset period for HW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Integer nReqResIgnHeaWat(final min=0)=2 + "Number of ignored requests for HW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real triHeaWat( + final max=0, + final unit="1")=-0.02 + "Trim amount for HW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real rspHeaWat( + final min=0, + final unit="1")=0.03 + "Respond amount for HW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real rspHeaWat_max( + final min=0, + final unit="1")=0.07 + "Maximum response per reset period for HW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_heaWat and have_pumHeaWatSec)); + parameter Real dtResChiWat( + final min=1E-3, + final unit="s")=300 + "Reset period for CHW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Integer nReqResIgnChiWat(final min=0)=2 + "Number of ignored requests for CHW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real triChiWat( + final max=0, + final unit="1")=-0.02 + "Trim amount for CHW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real rspChiWat( + final min=0, + final unit="1")=0.03 + "Respond amount for CHW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real rspChiWat_max( + final min=0, + final unit="1")=0.07 + "Maximum response per reset period for CHW plant reset" + annotation (Dialog(tab="Advanced",group="Plant reset", + enable=have_chiWat and have_pumChiWatSec)); + parameter Real yPumHeaWatSec_min( + final max=1, + final min=0, + start=0.1, + final unit="1")=0.1 + "Minimum pump speed" + annotation (Dialog(tab="Advanced",group="Secondary HW pumps", + enable=have_pumHeaWatSec)); + parameter Real kPumHeaWatSec( + final min=100*Buildings.Controls.OBC.CDL.Constants.eps, + start=1)=1 + "Gain of controller" + annotation (Dialog(tab="Advanced",group="Secondary HW pumps", + enable=have_pumHeaWatSec)); + parameter Real TiPumHeaWatSec( + final min=100*Buildings.Controls.OBC.CDL.Constants.eps, + start=60, + final unit="s")=60 + "Time constant of integrator block" + annotation (Dialog(tab="Advanced",group="Secondary HW pumps", + enable=have_pumHeaWatSec)); + parameter Real yPumChiWatSec_min( + final max=1, + final min=0, + start=0.1, + final unit="1")=0.1 + "Minimum pump speed" + annotation (Dialog(tab="Advanced",group="Secondary CHW pumps", + enable=have_pumChiWatSec)); + parameter Real kPumChiWatSec( + final min=100*Buildings.Controls.OBC.CDL.Constants.eps, + start=1)=1 + "Gain of controller" + annotation (Dialog(tab="Advanced",group="Secondary CHW pumps", + enable=have_pumChiWatSec)); + parameter Real TiPumChiWatSec( + final min=100*Buildings.Controls.OBC.CDL.Constants.eps, + start=60, + final unit="s")=60 + "Time constant of integrator block" + annotation (Dialog(tab="Advanced",group="Secondary CHW pumps", + enable=have_pumChiWatSec)); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1AvaHp[nHp](each k=true) + "Heat pump available signal – Block does not handle faulted equipment yet" + annotation (Placement(transformation(extent={{-250,250},{-230,270}}), + iconTransformation(extent={{-240,220},{-200,260}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqPlaHeaWat + if have_heaWat + "Number of HW plant requests" annotation (Placement(transformation(extent={ + {-300,320},{-260,360}}), iconTransformation(extent={{-240,120},{-200, + 160}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TOut( + final unit="K", + final quantity="ThermodynamicTemperature", + displayUnit="degC") + "Outdoor air temperature" + annotation (Placement(transformation(extent={{-300,60},{-260,100}}), + iconTransformation(extent={{-240,20},{-200,60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1SchHea + if have_heaWat and have_inpSch + "Heating mode enable via schedule" + annotation (Placement(transformation(extent={{-300,360},{-260,400}}), + iconTransformation(extent={{-240,300},{-200,340}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqPlaChiWat + if have_chiWat + "Number of CHW plant requests" annotation (Placement(transformation(extent= + {{-300,300},{-260,340}}), iconTransformation(extent={{-240,100},{-200, + 140}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1SchCoo + if have_chiWat and have_inpSch + "Cooling mode enable via schedule" + annotation (Placement(transformation(extent={{-300,340},{-260,380}}), + iconTransformation(extent={{-240,280},{-200,320}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqResHeaWat + if have_heaWat + "Sum of HW reset requests of all heating loads served" + annotation (Placement(transformation(extent={{-300,-360},{-260,-320}}), + iconTransformation(extent={{-240,80},{-200,120}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqResChiWat + if have_chiWat + "Sum of CHW reset requests of all heating loads served" + annotation (Placement(transformation(extent={{-300,-380},{-260,-340}}), + iconTransformation(extent={{-240,60},{-200,100}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumHeaWatPri_actual[nPumHeaWatPri] + if have_heaWat and have_pumHeaWatPri + "Primary HW pump status" + annotation (Placement(transformation(extent={{-300,180},{-260,220}}), + iconTransformation(extent={{-240,220},{-200,260}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumChiWatPri_actual[nPumChiWatPri] + if have_chiWat and have_pumChiWatPri + "Primary CHW pump status" + annotation (Placement(transformation(extent={{-300,160},{-260,200}}), + iconTransformation(extent={{-240,200},{-200,240}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumHeaWatSec_actual[nPumHeaWatSec] + if have_heaWat and have_pumHeaWatSec + "Secondary HW pump status" + annotation (Placement(transformation(extent={{-300,140},{-260,180}}), + iconTransformation(extent={{-240,180},{-200,220}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumChiWatSec_actual[nPumChiWatSec] + if have_chiWat and have_pumChiWatSec + "Secondary CHW pump status" + annotation (Placement(transformation(extent={{-300,120},{-260,160}}), + iconTransformation(extent={{-240,160},{-200,200}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatPriRet( + final unit="K", + displayUnit="degC") if have_heaWat and have_senTHeaWatPriRet + "Primary HW return temperature" + annotation (Placement(transformation(extent={{-300,20},{-260,60}}), + iconTransformation(extent={{-240,-20},{-200,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput VHeaWatPri_flow( + final unit="m3/s") if have_heaWat and have_senVHeaWatPri + "Primary HW volume flow rate" + annotation (Placement(transformation(extent={{-300,0},{-260,40}}), + iconTransformation(extent={{-240,-40},{-200,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHeaWatLoc( + final unit="Pa") + if have_heaWat and not have_senDpHeaWatRemWir + "Local HW differential pressure" + annotation (Placement(transformation(extent={{-300,-260},{-260,-220}}), + iconTransformation(extent={{-240,-280},{-200,-240}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHeaWatLocSet[nSenDpHeaWatRem]( + each final unit="Pa") + if have_heaWat and not have_senDpHeaWatRemWir + "Local HW differential pressure setpoint output from each of the remote loops" + annotation (Placement(transformation(extent={{-300,-240},{-260,-200}}), + iconTransformation(extent={{-240,-260},{-200,-220}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpHeaWatRem[nSenDpHeaWatRem]( + each final unit="Pa") + if have_heaWat and have_senDpHeaWatRemWir + "Remote HW differential pressure" + annotation (Placement(transformation(extent={{-300,-220},{-260,-180}}), + iconTransformation(extent={{-240,-240},{-200,-200}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpChiWatLoc( + final unit="Pa") + if have_chiWat and not have_senDpChiWatRemWir + "Local CHW differential pressure" + annotation (Placement(transformation(extent={{-300,-320},{-260,-280}}), + iconTransformation(extent={{-240,-340},{-200,-300}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpChiWatLocSet[nSenDpChiWatRem]( + each final unit="Pa") + if have_chiWat and not have_senDpChiWatRemWir + "Local CHW differential pressure setpoint output from each of the remote loops" + annotation (Placement(transformation(extent={{-300,-300},{-260,-260}}), + iconTransformation(extent={{-240,-320},{-200,-280}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpChiWatRem[nSenDpChiWatRem]( + each final unit="Pa") + if have_chiWat and have_senDpChiWatRemWir + "Remote CHW differential pressure" + annotation (Placement(transformation(extent={{-300,-280},{-260,-240}}), + iconTransformation(extent={{-240,-300},{-200,-260}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValHeaWatHpInlIso[nHp] + if have_heaWat and have_valHpInlIso + "Heat pump inlet HW inlet isolation valve command" annotation (Placement( + transformation(extent={{260,300},{300,340}}), iconTransformation(extent + ={{200,180},{240,220}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValHeaWatHpOutIso[nHp] + if have_heaWat and have_valHpOutIso + "Heat pump outlet HW isolation valve command" annotation (Placement( + transformation(extent={{260,280},{300,320}}), iconTransformation(extent + ={{200,160},{240,200}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValChiWatHpInlIso[nHp] + if have_chiWat and have_valHpInlIso + "Heat pump inlet CHW isolation valve command" annotation (Placement( + transformation(extent={{260,260},{300,300}}), iconTransformation(extent + ={{200,140},{240,180}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValChiWatHpOutIso[nHp] + if have_chiWat and have_valHpOutIso + "Heat pump outlet CHW isolation valve command" annotation (Placement( + transformation(extent={{260,240},{300,280}}), iconTransformation(extent + ={{200,120},{240,160}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumHeaWatPri[nPumHeaWatPri] + if have_pumHeaWatPri + "Primary HW pump start command" + annotation (Placement(transformation(extent={{260,180},{300,220}}), + iconTransformation(extent={{200,80},{240,120}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumChiWatPri[nPumChiWatPri] + if have_pumChiWatPri and have_chiWat + "Primary CHW pump start command" + annotation (Placement(transformation(extent={{260,160},{300,200}}), + iconTransformation(extent={{200,60},{240,100}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumHeaWatSec[nPumHeaWatSec] + if have_pumHeaWatSec + "Secondary HW pump start command" + annotation (Placement(transformation(extent={{260,140},{300,180}}), + iconTransformation(extent={{200,20},{240,60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumChiWatSec[nPumChiWatSec] + if have_pumChiWatSec and have_chiWat + "Secondary CHW pump start command" + annotation (Placement(transformation(extent={{260,120},{300,160}}), + iconTransformation(extent={{200,0},{240,40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Hp[nHp] + "Heat pump enable command" + annotation (Placement(transformation(extent={{260,360},{300,400}}), + iconTransformation(extent={{200,240},{240,280}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1HeaHp[nHp] + if have_heaWat and have_chiWat + "Heat pump heating/cooling mode command: true=heating, false=cooling" + annotation (Placement(transformation(extent={{260,340},{300,380}}), + iconTransformation(extent={{200,220},{240,260}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput dpHeaWatRemSet[nSenDpHeaWatRem]( + each final min=0, + each final unit="Pa") if have_heaWat + "HW differential pressure setpoint" + annotation (Placement(transformation(extent={{260,-80},{300,-40}}), + iconTransformation(extent={{200,-180},{240,-140}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput dpChiWatRemSet[nSenDpChiWatRem]( + each final min=0, + each final unit="Pa") if have_chiWat + "CHW differential pressure setpoint" + annotation (Placement(transformation(extent={{260,-100},{300,-60}}), + iconTransformation(extent={{200,-200},{240,-160}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumHeaWatPriHdr( + final unit="1") + if have_heaWat and have_pumHeaWatPriVar and have_pumPriHdr + "Primary headered HW pump speed command" + annotation (Placement(transformation(extent={{260,80},{300,120}}), + iconTransformation(extent={{200,-40},{240,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumChiWatPriHdr( + final unit="1") if have_chiWat and have_pumChiWatPri and + have_pumChiWatPriVar and have_pumPriHdr + "Primary headered CHW pump speed command" + annotation (Placement(transformation(extent={{260,60},{300,100}}), + iconTransformation(extent={{200,-60},{240,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumHeaWatSec( + final unit="1") + if have_heaWat and have_pumHeaWatSec + "Primary HW pump speed command" + annotation (Placement(transformation(extent={{260,-20},{300,20}}), + iconTransformation(extent={{200,-120},{240,-80}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumChiWatSec( + final unit="1") + if have_chiWat and have_pumChiWatSec + "Primary CHW pump speed command" + annotation (Placement(transformation(extent={{260,-40},{300,0}}), + iconTransformation(extent={{200,-140},{240,-100}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput TChiWatSupSet( + final unit="K", + displayUnit="degC") if have_chiWat + "CHW supply temperature setpoint" + annotation (Placement(transformation(extent={{260,-200},{300,-160}}), + iconTransformation(extent={{200,-280},{240,-240}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput THeaWatSupSet( + final unit="K", + displayUnit="degC") if have_heaWat + "HW supply temperature setpoint" + annotation (Placement(transformation(extent={{260,-180},{300,-140}}), + iconTransformation(extent={{200,-260},{240,-220}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatPriRet( + final unit="K", + displayUnit="degC") if have_chiWat and have_senTChiWatPriRet + "Primary CHW return temperature" + annotation (Placement(transformation(extent={{-300,-40},{-260,0}}), + iconTransformation(extent={{-240,-80},{-200,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput VChiWatPri_flow( + final unit="m3/s") if have_chiWat and have_senVChiWatPri + "Primary CHW volume flow rate" + annotation (Placement(transformation(extent={{-300,-60},{-260,-20}}), + iconTransformation(extent={{-240,-100},{-200,-60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Hp_actual[nHp] + "Heat pump status" + annotation (Placement(transformation(extent={{-300,280},{-260,320}}), + iconTransformation(extent={{-240,240},{-200,280}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumHeaWatPriDed[nPumHeaWatPri]( + each final unit="1") + if have_heaWat and have_pumHeaWatPriVar and not have_pumPriHdr + "Primary dedicated HW pump speed command" + annotation (Placement(transformation(extent={{260,40},{300,80}}), + iconTransformation(extent={{200,-80},{240,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumChiWatPriDed[nPumChiWatPri]( + each final unit="1") + if have_chiWat and have_pumChiWatPriDed and have_pumChiWatPriVar + "Primary dedicated CHW pump speed command" + annotation (Placement(transformation(extent={{260,20},{300,60}}), + iconTransformation(extent={{200,-100},{240,-60}}))); + Enabling.Enable enaHea( + final typ=Buildings.Templates.Plants.Controls.Types.Application.Heating, + final TOutLck=TOutHeaWatLck, + final dTOutLck=dTOutLck, + final dtReq=dtReqDis, + final dtRun=dtRunEna, + final have_inpSch=have_inpSch, + final nReqIgn=nReqIgnHeaWat, + final sch=schHea) + if have_heaWat + "Heating mode enable" + annotation (Placement(transformation(extent={{-110,350},{-90,370}}))); + Utilities.StageIndex idxStaHea( + final nSta=nSta, + final dtRun=dtRunSta) + if have_heaWat + "Compute heating stage index" + annotation (Placement(transformation(extent={{-10,350},{10,370}}))); + StagingRotation.StageAvailability avaStaHea( + final staEqu=staEqu) + if have_heaWat + "Evaluate heating stage availability" + annotation (Placement(transformation(extent={{-110,320},{-90,340}}))); + StagingRotation.EquipmentEnable enaEquHea( + final staEqu=staEqu) + if have_heaWat + "Compute enable command for equipment in heating mode" + annotation (Placement(transformation(extent={{40,350},{60,370}}))); + StagingRotation.EventSequencing seqEve[nHp]( + each final have_heaWat=have_heaWat, + each final have_chiWat=have_chiWat, + each final have_valInlIso=have_valHpInlIso, + each final have_valOutIso=have_valHpOutIso, + each final have_pumHeaWatPri=have_pumHeaWatPri, + each final have_pumChiWatPri=have_pumChiWatPri, + each final have_pumHeaWatSec=have_pumHeaWatSec, + each final have_pumChiWatSec=have_pumChiWatSec, + each final dtVal=dtVal, + each final dtOff=dtHp) "Event sequencing" + annotation (Placement(transformation(extent={{140,284},{160,312}}))); + StagingRotation.StageAvailability avaStaCoo( + final staEqu=staEqu) + if have_chiWat + "Evaluate cooling stage availability" + annotation (Placement(transformation(extent={{-110,60},{-90,80}}))); + StagingRotation.StageChangeCommand chaStaHea( + final have_inpPlrSta=false, + final plrSta=plrSta, + final staEqu=staEqu, + final capEqu=capHeaHp_nominal, + final dtRun=dtRunSta, + final cp_default=cp_default, + final rho_default=rho_default) + if have_heaWat + "Generate heating stage transition command" + annotation (Placement(transformation(extent={{-40,308},{-20,332}}))); + StagingRotation.SortRuntime sorRunTimHea( + idxEquAlt=idxEquAlt, + nin=nHp) + if have_heaWat + "Sort lead/lag alternate equipment by staging runtime – Heating mode" + annotation (Placement(transformation(extent={{-40,280},{-20,300}}))); + Enabling.Enable enaCoo( + final typ=Buildings.Templates.Plants.Controls.Types.Application.Cooling, + final TOutLck=TOutChiWatLck, + final dTOutLck=dTOutLck, + final dtReq=dtReqDis, + final dtRun=dtRunEna, + final have_inpSch=have_inpSch, + final nReqIgn=nReqIgnChiWat, + final sch=schCoo) + if have_chiWat + "Cooling mode enable" + annotation (Placement(transformation(extent={{-110,90},{-90,110}}))); + StagingRotation.StageChangeCommand chaStaCoo( + final have_inpPlrSta=false, + final plrSta=plrSta, + final staEqu=staEqu, + final capEqu=capCooHp_nominal, + final dtRun=dtRunSta, + final cp_default=cp_default, + final rho_default=rho_default) + if have_chiWat + "Generate cooling stage transition command" + annotation (Placement(transformation(extent={{-40,50},{-20,74}}))); + Utilities.StageIndex idxStaCoo( + final nSta=nSta, + final dtRun=dtRunSta) + if have_chiWat + "Compute cooling stage index" + annotation (Placement(transformation(extent={{-10,90},{10,110}}))); + StagingRotation.EquipmentEnable enaEquCoo( + final staEqu=staEqu) + if have_chiWat + "Compute enable command for equipment in cooling mode" + annotation (Placement(transformation(extent={{40,90},{60,110}}))); + StagingRotation.EquipmentAvailability avaEquHeaCoo[nHp]( + each final have_heaWat=have_heaWat, + each final have_chiWat=have_chiWat, + each final dtOff=dtOff) + "Evaluate equipment availability in heating or cooling mode" + annotation (Placement(transformation(extent={{-152,210},{-132,230}}))); + Buildings.Controls.OBC.CDL.Logical.Pre y1HeaPre[nHp] + if have_heaWat and have_chiWat + "Left-limit of command signal to break algebraic loop" + annotation (Placement(transformation(extent={{230,350},{210,370}}))); + StagingRotation.SortRuntime sorRunTimCoo( + final idxEquAlt=idxEquAlt, + nin=nHp) + if have_chiWat + "Sort lead/lag alternate equipment by staging runtime – Cooling mode" + annotation (Placement(transformation(extent={{-40,20},{-20,40}}))); + Pumps.Generic.StagingHeadered staPumHeaWatPri( + final is_pri=true, + final have_valInlIso=have_valHpInlIso, + final have_valOutIso=have_valHpOutIso, + final nEqu=nHp, + final nPum=nPumHeaWatPri, + final is_hdr=have_pumPriHdr, + final is_ctlDp=have_pumPriCtlDp, + final dtRun=dtRunPumSta, + final dVOffUp=dVOffUpPumSta, + final dVOffDow=dVOffDowPumSta) if have_pumHeaWatPri + "Primary HW pump staging" + annotation (Placement(transformation(extent={{140,190},{160,210}}))); + Pumps.Generic.StagingHeadered staPumChiWatPri( + final is_pri=true, + final have_valInlIso=have_valHpInlIso, + final have_valOutIso=have_valHpOutIso, + final nEqu=nHp, + final nPum=nPumChiWatPri, + final is_hdr=have_pumPriHdr, + final is_ctlDp=have_pumPriCtlDp, + final dtRun=dtRunPumSta, + final dVOffUp=dVOffUpPumSta, + final dVOffDow=dVOffDowPumSta) if have_pumChiWatPri and have_chiWat + "Primary CHW pump staging" + annotation (Placement(transformation(extent={{190,170},{210,190}}))); + Pumps.Generic.StagingHeadered staPumChiWatSec( + final is_pri=false, + final nEqu=nHp, + final nPum=nPumChiWatSec, + final is_hdr=have_pumSecHdr, + final is_ctlDp=have_pumSecCtlDp, + final V_flow_nominal=VChiWatSec_flow_nominal, + final dtRun=dtRunPumSta, + final dVOffUp=dVOffUpPumSta, + final dVOffDow=dVOffDowPumSta) if have_pumChiWatSec and have_chiWat + "Secondary CHW pump staging" + annotation (Placement(transformation(extent={{190,130},{210,150}}))); + Pumps.Generic.StagingHeadered staPumHeaWatSec( + final is_pri=false, + final nEqu=nHp, + final nPum=nPumHeaWatSec, + final is_hdr=have_pumSecHdr, + final is_ctlDp=have_pumSecCtlDp, + final V_flow_nominal=VHeaWatSec_flow_nominal, + final dtRun=dtRunPumSta, + final dVOffUp=dVOffUpPumSta, + final dVOffDow=dVOffDowPumSta) if have_pumHeaWatSec + "Secondary HW pump staging" + annotation (Placement(transformation(extent={{140,150},{160,170}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatSecRet( + final unit="K", + displayUnit="degC") if have_heaWat and have_senTHeaWatSecRet + "Secondary HW return temperature" + annotation (Placement(transformation(extent={{-300,-100},{-260,-60}}), + iconTransformation(extent={{-240,-140},{-200,-100}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput VHeaWatSec_flow( + final unit="m3/s") if have_heaWat and have_senVHeaWatSec + "Secondary HW volume flow rate" + annotation (Placement(transformation(extent={{-300,-120},{-260,-80}}), + iconTransformation(extent={{-240,-160},{-200,-120}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSecRet( + final unit="K", + displayUnit="degC") if have_chiWat and have_senTChiWatSecRet + "Secondary CHW return temperature" + annotation (Placement(transformation(extent={{-300,-160},{-260,-120}}), + iconTransformation(extent={{-240,-200},{-200,-160}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput VChiWatSec_flow( + final unit="m3/s") if have_chiWat and have_senVChiWatSec + "Secondary CHW volume flow rate" + annotation (Placement(transformation(extent={{-300,-180},{-260,-140}}), + iconTransformation(extent={{-240,-220},{-200,-180}}))); + Utilities.PlaceholderReal THeaWatRet(have_inp=have_heaWat and + have_senTHeaWatPriRet, + have_inpPh=true) if have_heaWat "Select HW return temperature sensor" + annotation (Placement(transformation(extent={{-230,30},{-210,50}}))); + Utilities.PlaceholderReal VHeaWat_flow(have_inp=have_heaWat and + have_senVHeaWatPri, + have_inpPh=true) if have_heaWat "Select HW flow sensor" + annotation (Placement(transformation(extent={{-200,10},{-180,30}}))); + Utilities.PlaceholderReal TChiWatRet(have_inp=have_chiWat and + have_senTChiWatPriRet, + have_inpPh=true) if have_chiWat "Select CHW return temperature sensor" + annotation (Placement(transformation(extent={{-230,-30},{-210,-10}}))); + Utilities.PlaceholderReal VChiWat_flow(have_inp=have_chiWat and + have_senVChiWatPri, + have_inpPh=true) if have_chiWat "Select CHW flow sensor" + annotation (Placement(transformation(extent={{-200,-50},{-180,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Pre y1HpPre[nHp] + "Left-limit of command signal to break algebraic loop" + annotation (Placement(transformation(extent={{200,370},{180,390}}))); + StagingRotation.StageCompletion comStaCoo( + nin=nHp) + if have_chiWat + "Check successful completion of cooling stage change" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + StagingRotation.StageCompletion comStaHea( + nin=nHp) + if have_heaWat + "Check successful completion of heating stage change" + annotation (Placement(transformation(extent={{-40,250},{-20,270}}))); + Setpoints.PlantReset resHeaWat( + final TSup_nominal=THeaWatSup_nominal, + final TSupSetLim=THeaWatSupSet_min, + final dpSet_max=dpHeaWatRemSet_max, + final dpSet_min=dpHeaWatRemSet_min, + final dtDel=dtDel, + final dtHol=dtHol, + final dtRes=dtResHeaWat, + final nReqResIgn=nReqResIgnHeaWat, + final nSenDpRem=nSenDpHeaWatRem, + final resDp_max=resDpHeaWat_max, + final resTSup_min=resTHeaWatSup_min, + final res_init=res_init, + final res_max=res_max, + final res_min=res_min, + final rsp=rspHeaWat, + final rsp_max=rspHeaWat_max, + final tri=triHeaWat) if have_heaWat "HW plant reset" + annotation (Placement(transformation(extent={{90,230},{110,250}}))); + Setpoints.PlantReset resChiWat( + final TSup_nominal=TChiWatSup_nominal, + final TSupSetLim=TChiWatSupSet_max, + final dpSet_max=dpChiWatRemSet_max, + final dpSet_min=dpChiWatRemSet_min, + final dtDel=dtDel, + final dtHol=dtHol, + final dtRes=dtResChiWat, + final nReqResIgn=nReqResIgnChiWat, + final nSenDpRem=nSenDpChiWatRem, + final resDp_max=resDpChiWat_max, + final resTSup_min=resTChiWatSup_min, + final res_init=res_init, + final res_max=res_max, + final res_min=res_min, + final rsp=rspChiWat, + final rsp_max=rspChiWat_max, + final tri=triChiWat) if have_chiWat "CHW plant reset" + annotation (Placement(transformation(extent={{90,-50},{110,-30}}))); + Pumps.Primary.VariableSpeedNoDpControl ctlPumPri( + final have_heaWat=have_heaWat, + final have_chiWat=have_chiWat, + final have_pumChiWatPriDed=have_pumChiWatPriDed, + final have_pumPriHdr=have_pumPriHdr, + final nEqu=nHp, + final nPumHeaWatPri=nPumHeaWatPri, + final nPumChiWatPri=nPumChiWatPri, + final yPumHeaWatPriSet=yPumHeaWatPriSet, + final yPumChiWatPriSet=yPumChiWatPriSet) + "Primary pump speed control" + annotation (Placement(transformation(extent={{190,70},{210,90}}))); + Pumps.Generic.ControlDifferentialPressure ctlPumHeaWatSec( + final have_senDpRemWir=have_senDpHeaWatRemWir, + nPum=nPumHeaWatSec, + final nSenDpRem=nSenDpHeaWatRem, + final y_min=yPumHeaWatSec_min, + final k=kPumHeaWatSec, + final Ti=TiPumHeaWatSec) + if have_pumHeaWatSec + "Secondary HW pump speed control" + annotation (Placement(transformation(extent={{140,-10},{160,10}}))); + Pumps.Generic.ControlDifferentialPressure ctlPumChiWatSec( + final have_senDpRemWir=have_senDpChiWatRemWir, + final nPum=nPumChiWatSec, + final nSenDpRem=nSenDpChiWatRem, + final y_min=yPumChiWatSec_min, + final k=kPumChiWatSec, + final Ti=TiPumChiWatSec) if have_chiWat and have_pumChiWatSec + "Secondary CHW pump speed control" + annotation (Placement(transformation(extent={{190,-30},{210,-10}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput TSupSet[nHp]( + each final unit="K", + each final quantity="ThermodynamicTemperature", + each displayUnit="degC") + "Active HP supply temperature setpoint" + annotation (Placement(transformation(extent={{260,-140},{300,-100}}), + iconTransformation(extent={{200,-240},{240,-200}}))); + Buildings.Controls.OBC.CDL.Reals.Switch swiTSupSet[nHp] + if have_heaWat and have_chiWat + "Select supply temperature setpoint based on operating mode" + annotation (Placement(transformation(extent={{190,-130},{210,-110}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator repTChiWatSupSet(final + nout=nHp) if have_chiWat "Replicate CHWST setpoint" + annotation (Placement(transformation(extent={{150,-150},{170,-130}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator repTHeaWatSupSet(final + nout=nHp) if have_heaWat "Replicate HWST setpoint" + annotation (Placement(transformation(extent={{150,-110},{170,-90}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatPriSup(final unit="K", + displayUnit="degC") if have_heaWat "Primary HW supply temperature" + annotation (Placement(transformation(extent={{-300,40},{-260,80}}), + iconTransformation(extent={{-240,0},{-200,40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatPriSup(final unit="K", + displayUnit="degC") if have_chiWat "Primary CHW return temperature" + annotation (Placement(transformation(extent={{-300,-20},{-260,20}}), + iconTransformation(extent={{-240,-60},{-200,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput THeaWatSecSup(final unit="K", + displayUnit="degC") if have_chiWat and have_senTHeaWatSecSup + "Secondary HW supply temperature" annotation (Placement(transformation( + extent={{-300,-80},{-260,-40}}), iconTransformation(extent={{-240,-120}, + {-200,-80}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TChiWatSecSup(final unit="K", + displayUnit="degC") if have_chiWat and have_senTChiWatSecSup + "Secondary CHW return temperature" annotation (Placement(transformation( + extent={{-300,-140},{-260,-100}}), iconTransformation(extent={{-240,-180}, + {-200,-140}}))); + Buildings.Controls.OBC.CDL.Routing.RealExtractSignal pasTHeaWatSupSet(final nin + =nHp, final + nout=nHp) if have_heaWat and not have_chiWat + "Direct pass through for HWST setpoint" + annotation (Placement(transformation(extent={{220,-110},{240,-90}}))); + Buildings.Controls.OBC.CDL.Routing.RealExtractSignal pasTChiWatSupSet(final nin + =nHp, final nout=nHp) if have_chiWat and not have_heaWat + "Direct pass through for CHWST setpoint" + annotation (Placement(transformation(extent={{220,-150},{240,-130}}))); +equation + connect(u1SchHea, enaHea.u1Sch) + annotation (Line(points={{-280,380},{-180,380},{-180,364},{-112,364}},color={255,0,255})); + connect(nReqPlaHeaWat, enaHea.nReqPla) annotation (Line(points={{-280,340},{-178, + 340},{-178,360},{-112,360}}, color={255,127,0})); + connect(TOut, enaHea.TOut) + annotation (Line(points={{-280,80},{-170,80},{-170,356},{-112,356}},color={0,0,127})); + connect(enaHea.y1, idxStaHea.u1Lea) + annotation (Line(points={{-88,360},{-56,360},{-56,366},{-12,366}},color={255,0,255})); + connect(avaStaHea.y1, idxStaHea.u1AvaSta) + annotation (Line(points={{-88,330},{-56,330},{-56,354},{-12,354}},color={255,0,255})); + connect(idxStaHea.y, enaEquHea.uSta) + annotation (Line(points={{12,360},{38,360}},color={255,127,0})); + connect(seqEve.y1, y1Hp) annotation (Line(points={{162,310},{238,310},{238, + 380},{280,380}}, color={255,0,255})); + connect(seqEve.y1Hea, y1HeaHp) annotation (Line(points={{162,308},{240,308},{ + 240,360},{280,360}}, color={255,0,255})); + connect(seqEve.y1ValHeaWatOutIso, y1ValHeaWatHpOutIso) annotation (Line( + points={{162,298},{240,298},{240,300},{280,300}}, color={255,0,255})); + connect(seqEve.y1ValHeaWatInlIso, y1ValHeaWatHpInlIso) annotation (Line( + points={{162,300},{242,300},{242,320},{280,320}}, color={255,0,255})); + connect(seqEve.y1ValChiWatInlIso, y1ValChiWatHpInlIso) annotation (Line( + points={{162,296},{238,296},{238,280},{280,280}}, color={255,0,255})); + connect(seqEve.y1ValChiWatOutIso, y1ValChiWatHpOutIso) annotation (Line( + points={{162,294},{236,294},{236,260},{280,260}}, color={255,0,255})); + connect(idxStaHea.y, chaStaHea.uSta) + annotation (Line(points={{12,360},{20,360},{20,340},{-50,340},{-50,330},{-42,330}}, + color={255,127,0})); + connect(chaStaHea.y1Dow, idxStaHea.u1Dow) + annotation (Line(points={{-18,316},{-14,316},{-14,358},{-12,358}},color={255,0,255})); + connect(chaStaHea.y1Up, idxStaHea.u1Up) + annotation (Line(points={{-18,324},{-16,324},{-16,362},{-12,362}},color={255,0,255})); + connect(avaStaHea.y1, chaStaHea.u1AvaSta) + annotation (Line(points={{-88,330},{-56,330},{-56,326},{-42,326}},color={255,0,255})); + connect(sorRunTimHea.yIdx, enaEquHea.uIdxAltSor) + annotation (Line(points={{-18,284},{32,284},{32,366},{38,366}},color={255,127,0})); + connect(nReqPlaChiWat, enaCoo.nReqPla) annotation (Line(points={{-280,320},{-182, + 320},{-182,100},{-112,100}}, color={255,127,0})); + connect(TOut, enaCoo.TOut) + annotation (Line(points={{-280,80},{-170,80},{-170,96},{-112,96}},color={0,0,127})); + connect(u1SchCoo, enaCoo.u1Sch) + annotation (Line(points={{-280,360},{-180,360},{-180,104},{-112,104}},color={255,0,255})); + connect(avaStaCoo.y1, chaStaCoo.u1AvaSta) + annotation (Line(points={{-88,70},{-56,70},{-56,68},{-42,68}},color={255,0,255})); + connect(enaCoo.y1, idxStaCoo.u1Lea) + annotation (Line(points={{-88,100},{-56,100},{-56,106},{-12,106}},color={255,0,255})); + connect(chaStaCoo.y1Up, idxStaCoo.u1Up) + annotation (Line(points={{-18,66},{-16,66},{-16,102},{-12,102}},color={255,0,255})); + connect(chaStaCoo.y1Dow, idxStaCoo.u1Dow) + annotation (Line(points={{-18,58},{-14,58},{-14,98},{-12,98}},color={255,0,255})); + connect(idxStaCoo.y, enaEquCoo.uSta) + annotation (Line(points={{12,100},{38,100}},color={255,127,0})); + connect(enaEquHea.y1, seqEve.u1Hea) annotation (Line(points={{62,360},{80,360}, + {80,310},{138,310}}, color={255,0,255})); + connect(enaEquCoo.y1, seqEve.u1Coo) annotation (Line(points={{62,100},{80,100}, + {80,306},{138,306}}, color={255,0,255})); + connect(y1HeaHp, y1HeaPre.u) + annotation (Line(points={{280,360},{232,360}},color={255,0,255})); + connect(y1HeaPre.y, avaEquHeaCoo.u1Hea) + annotation (Line(points={{208,360},{160,360},{160,378},{-156,378},{-156,214},{-154,214}}, + color={255,0,255})); + connect(avaEquHeaCoo.y1Hea, avaStaHea.u1Ava) + annotation (Line(points={{-130,226},{-120,226},{-120,330},{-112,330}},color={255,0,255})); + connect(avaEquHeaCoo.y1Coo, avaStaCoo.u1Ava) + annotation (Line(points={{-130,214},{-120,214},{-120,70},{-112,70}},color={255,0,255})); + connect(avaStaCoo.y1, idxStaCoo.u1AvaSta) + annotation (Line(points={{-88,70},{-56,70},{-56,94},{-12,94}},color={255,0,255})); + connect(avaEquHeaCoo.y1Hea, enaEquHea.u1Ava) + annotation (Line(points={{-130,226},{36,226},{36,354},{38,354}},color={255,0,255})); + connect(avaEquHeaCoo.y1Coo, enaEquCoo.u1Ava) + annotation (Line(points={{-130,214},{36,214},{36,94},{38,94}},color={255,0,255})); + connect(sorRunTimCoo.yIdx, enaEquCoo.uIdxAltSor) + annotation (Line(points={{-18,24},{32,24},{32,106},{38,106}},color={255,127,0})); + connect(idxStaCoo.y, chaStaCoo.uSta) + annotation (Line(points={{12,100},{20,100},{20,80},{-48,80},{-48,72},{-42,72}}, + color={255,127,0})); + connect(avaEquHeaCoo.y1Hea, sorRunTimHea.u1Ava) + annotation (Line(points={{-130,226},{-120,226},{-120,284},{-42,284}},color={255,0,255})); + connect(avaEquHeaCoo.y1Coo, sorRunTimCoo.u1Ava) + annotation (Line(points={{-130,214},{-120,214},{-120,24},{-42,24}},color={255,0,255})); + connect(staPumChiWatPri.y1, y1PumChiWatPri) + annotation (Line(points={{212,180},{280,180}},color={255,0,255})); + connect(staPumChiWatPri.y1_actual, seqEve.u1PumChiWatPri_actual) annotation ( + Line(points={{212,186},{220,186},{220,262},{122,262},{122,296},{138,296}}, + color={255,0,255})); + connect(seqEve.y1PumChiWatPri, staPumChiWatPri.u1Pum) annotation (Line(points + ={{162,288},{178,288},{178,178},{188,178}}, color={255,0,255})); + connect(u1PumChiWatPri_actual, staPumChiWatPri.u1Pum_actual) + annotation (Line(points={{-280,180},{170,180},{170,176},{188,176}},color={255,0,255})); + connect(u1PumHeaWatPri_actual, staPumHeaWatPri.u1Pum_actual) + annotation (Line(points={{-280,200},{128,200},{128,196},{138,196}},color={255,0,255})); + connect(staPumHeaWatPri.y1_actual, seqEve.u1PumHeaWatPri_actual) annotation ( + Line(points={{162,206},{164,206},{164,260},{120,260},{120,298},{138,298}}, + color={255,0,255})); + connect(staPumHeaWatSec.y1, y1PumHeaWatSec) + annotation (Line(points={{162,160},{280,160}},color={255,0,255})); + connect(staPumChiWatSec.y1, y1PumChiWatSec) + annotation (Line(points={{212,140},{280,140}},color={255,0,255})); + connect(u1PumHeaWatSec_actual, staPumHeaWatSec.u1Pum_actual) + annotation (Line(points={{-280,160},{120,160},{120,156},{138,156}},color={255,0,255})); + connect(u1PumChiWatSec_actual, staPumChiWatSec.u1Pum_actual) + annotation (Line(points={{-280,140},{180,140},{180,136},{188,136}},color={255,0,255})); + connect(staPumHeaWatPri.y1, y1PumHeaWatPri) + annotation (Line(points={{162,200},{216,200},{216,200},{280,200}},color={255,0,255})); + connect(staPumChiWatSec.y1_actual, seqEve.u1PumChiWatSec_actual) annotation ( + Line(points={{212,146},{222,146},{222,266},{126,266},{126,290},{138,290}}, + color={255,0,255})); + connect(seqEve.y1PumHeaWatPri, staPumHeaWatPri.u1Pum) annotation (Line(points + ={{162,290},{162,220},{130,220},{130,198},{138,198}}, color={255,0,255})); + connect(staPumHeaWatSec.y1_actual, seqEve.u1PumHeaWatSec_actual) annotation ( + Line(points={{162,166},{166,166},{166,264},{124,264},{124,292},{138,292}}, + color={255,0,255})); + connect(VHeaWatSec_flow, staPumHeaWatSec.V_flow) + annotation (Line(points={{-280,-100},{-156,-100},{-156,152},{138,152}},color={0,0,127})); + connect(VChiWatSec_flow, staPumChiWatSec.V_flow) + annotation (Line(points={{-280,-160},{-154,-160},{-154,132},{188,132}},color={0,0,127})); + connect(THeaWatPriRet, THeaWatRet.u) + annotation (Line(points={{-280,40},{-232,40}},color={0,0,127})); + connect(THeaWatRet.y, chaStaHea.TRet) + annotation (Line(points={{-208,40},{-168,40},{-168,306},{-50,306},{-50,314},{-42,314}}, + color={0,0,127})); + connect(THeaWatSecRet, THeaWatRet.uPh) annotation (Line(points={{-280,-80},{-240, + -80},{-240,34},{-232,34}}, color={0,0,127})); + connect(VHeaWatPri_flow, VHeaWat_flow.u) + annotation (Line(points={{-280,20},{-202,20}},color={0,0,127})); + connect(VHeaWat_flow.y, chaStaHea.V_flow) + annotation (Line(points={{-178,20},{-166,20},{-166,304},{-48,304},{-48,312},{-42,312}}, + color={0,0,127})); + connect(VHeaWatSec_flow, VHeaWat_flow.uPh) annotation (Line(points={{-280,-100}, + {-206,-100},{-206,14},{-202,14}}, color={0,0,127})); + connect(TChiWatPriRet, TChiWatRet.u) + annotation (Line(points={{-280,-20},{-232,-20}},color={0,0,127})); + connect(TChiWatRet.y, chaStaCoo.TRet) + annotation (Line(points={{-208,-20},{-164,-20},{-164,48},{-50,48},{-50,56},{-42,56}}, + color={0,0,127})); + connect(TChiWatSecRet, TChiWatRet.uPh) annotation (Line(points={{-280,-140},{-238, + -140},{-238,-26},{-232,-26}}, color={0,0,127})); + connect(VChiWatPri_flow, VChiWat_flow.u) + annotation (Line(points={{-280,-40},{-202,-40}},color={0,0,127})); + connect(VChiWat_flow.y, chaStaCoo.V_flow) + annotation (Line(points={{-178,-40},{-162,-40},{-162,38},{-48,38},{-48,54},{-42,54}}, + color={0,0,127})); + connect(VChiWatSec_flow, VChiWat_flow.uPh) annotation (Line(points={{-280,-160}, + {-204,-160},{-204,-46},{-202,-46}}, color={0,0,127})); + connect(enaHea.y1, staPumHeaWatSec.u1Pla) + annotation (Line(points={{-88,360},{-80,360},{-80,162},{128,162},{128,168}, + {138,168}}, + color={255,0,255})); + connect(enaCoo.y1, staPumChiWatSec.u1Pla) + annotation (Line(points={{-88,100},{-80,100},{-80,138},{186,138},{186,148}, + {188,148}}, + color={255,0,255})); + connect(seqEve.y1ValHeaWatInlIso, staPumHeaWatPri.u1ValInlIso) annotation ( + Line(points={{162,300},{170,300},{170,216},{134,216},{134,204},{138,204}}, + color={255,0,255})); + connect(seqEve.y1ValHeaWatOutIso, staPumHeaWatPri.u1ValOutIso) annotation ( + Line(points={{162,298},{168,298},{168,218},{132,218},{132,202},{138,202}}, + color={255,0,255})); + connect(seqEve.y1ValChiWatInlIso, staPumChiWatPri.u1ValInlIso) annotation ( + Line(points={{162,296},{182,296},{182,184},{188,184}}, color={255,0,255})); + connect(seqEve.y1ValChiWatOutIso, staPumChiWatPri.u1ValOutIso) annotation ( + Line(points={{162,294},{180,294},{180,182},{188,182}}, color={255,0,255})); + connect(u1Hp_actual, sorRunTimHea.u1Run) + annotation (Line(points={{-280,300},{-60,300},{-60,296},{-42,296}},color={255,0,255})); + connect(u1Hp_actual, sorRunTimCoo.u1Run) + annotation (Line(points={{-280,300},{-60,300},{-60,36},{-42,36}},color={255,0,255})); + connect(y1Hp, y1HpPre.u) + annotation (Line(points={{280,380},{202,380}},color={255,0,255})); + connect(y1HpPre.y, avaEquHeaCoo.u1) + annotation (Line(points={{178,380},{-158,380},{-158,226},{-154,226}},color={255,0,255})); + connect(idxStaCoo.y, comStaCoo.uSta) + annotation (Line(points={{12,100},{20,100},{20,-12},{-46,-12},{-46,4},{-42,4}}, + color={255,127,0})); + connect(comStaCoo.y1, chaStaCoo.u1StaPro) + annotation (Line(points={{-18,-6},{-10,-6},{-10,48},{-46,48},{-46,64},{-42,64}}, + color={255,0,255})); + connect(u1Hp_actual, comStaCoo.u1_actual) + annotation (Line(points={{-280,300},{-60,300},{-60,-4},{-42,-4}},color={255,0,255})); + connect(y1HpPre.y, comStaCoo.u1) + annotation (Line(points={{178,380},{-158,380},{-158,0},{-42,0}},color={255,0,255})); + connect(idxStaHea.y, comStaHea.uSta) + annotation (Line(points={{12,360},{20,360},{20,248},{-44,248},{-44,264},{-42,264}}, + color={255,127,0})); + connect(u1Hp_actual, comStaHea.u1_actual) + annotation (Line(points={{-280,300},{-60,300},{-60,256},{-42,256}},color={255,0,255})); + connect(y1HpPre.y, comStaHea.u1) + annotation (Line(points={{178,380},{-60,380},{-60,260},{-42,260}},color={255,0,255})); + connect(comStaHea.y1, chaStaHea.u1StaPro) + annotation (Line(points={{-18,254},{-10,254},{-10,306},{-44,306},{-44,322},{-42,322}}, + color={255,0,255})); + connect(resHeaWat.dpSet, dpHeaWatRemSet) + annotation (Line(points={{112,246},{242,246},{242,-60},{280,-60}},color={0,0,127})); + connect(resChiWat.dpSet, dpChiWatRemSet) + annotation (Line(points={{112,-34},{238,-34},{238,-80},{280,-80}},color={0,0,127})); + connect(nReqResHeaWat,resHeaWat.nReqRes) + annotation (Line(points={{-280,-340},{76,-340},{76,246},{88,246}},color={255,127,0})); + connect(nReqResChiWat,resChiWat.nReqRes) + annotation (Line(points={{-280,-360},{80,-360},{80,-34},{88,-34}},color={255,127,0})); + connect(enaCoo.y1, resChiWat.u1Ena) + annotation (Line(points={{-88,100},{-80,100},{-80,-40},{88,-40}},color={255,0,255})); + connect(enaHea.y1, resHeaWat.u1Ena) + annotation (Line(points={{-88,360},{-80,360},{-80,240},{88,240}},color={255,0,255})); + connect(comStaHea.y1, resHeaWat.u1StaPro) + annotation (Line(points={{-18,254},{-10,254},{-10,234},{88,234}},color={255,0,255})); + connect(comStaCoo.y1, resChiWat.u1StaPro) + annotation (Line(points={{-18,-6},{-10,-6},{-10,-46},{88,-46}},color={255,0,255})); + connect(resChiWat.TSupSet, chaStaCoo.TSupSet) + annotation (Line(points={{112,-46},{116,-46},{116,-20},{-52,-20},{-52,58},{-42, + 58}}, + color={0,0,127})); + connect(resHeaWat.TSupSet, chaStaHea.TSupSet) + annotation (Line(points={{112,234},{118,234},{118,220},{-52,220},{-52,316},{ + -42,316}}, + color={0,0,127})); + connect(ctlPumPri.yPumHeaWatPriHdr, yPumHeaWatPriHdr) + annotation (Line(points={{212,86},{222,86},{222,100},{280,100}},color={0,0,127})); + connect(ctlPumPri.yPumChiWatPriHdr, yPumChiWatPriHdr) + annotation (Line(points={{212,82},{220,82},{220,80},{280,80}},color={0,0,127})); + connect(ctlPumPri.yPumHeaWatPriDed, yPumHeaWatPriDed) + annotation (Line(points={{212,78},{220,78},{220,60},{280,60},{280,60}},color={0,0,127})); + connect(ctlPumPri.yPumChiWatPriDed, yPumChiWatPriDed) + annotation (Line(points={{212,74},{216,74},{216,40},{280,40}},color={0,0,127})); + connect(staPumHeaWatPri.y1, ctlPumPri.u1PumHeaWatPri) + annotation (Line(points={{162,200},{172,200},{172,86},{188,86}},color={255,0,255})); + connect(staPumChiWatPri.y1, ctlPumPri.u1PumChiWatPri) + annotation (Line(points={{212,180},{220,180},{220,100},{184,100},{184,80},{188, + 80}}, + color={255,0,255})); + connect(seqEve.y1Hea, ctlPumPri.u1Hea) annotation (Line(points={{162,308},{ + 174,308},{174,74},{188,74}}, color={255,0,255})); + connect(ctlPumHeaWatSec.y, yPumHeaWatSec) + annotation (Line(points={{161.8,0},{280,0}}, color={0,0,127})); + connect(ctlPumChiWatSec.y, yPumChiWatSec) + annotation (Line(points={{211.8,-20},{280,-20}}, color={0,0,127})); + connect(u1PumHeaWatSec_actual, ctlPumHeaWatSec.y1_actual) + annotation (Line(points={{-280,160},{120,160},{120,8},{138,8}}, color={255,0,255})); + connect(u1PumChiWatSec_actual, ctlPumChiWatSec.y1_actual) + annotation (Line(points={{-280,140},{180,140},{180,-12},{188,-12}}, + color={255,0,255})); + connect(resChiWat.dpSet, ctlPumChiWatSec.dpRemSet) + annotation (Line(points={{112,-34},{178,-34},{178,-16},{188,-16}}, + color={0,0,127})); + connect(dpHeaWatRem, ctlPumHeaWatSec.dpRem) + annotation (Line(points={{-280,-200},{130,-200},{130,0},{138,0}}, color={0,0,127})); + connect(resHeaWat.dpSet, ctlPumHeaWatSec.dpRemSet) + annotation (Line(points={{112,246},{122,246},{122,4},{138,4}}, color={0,0,127})); + connect(dpHeaWatLoc, ctlPumHeaWatSec.dpLoc) + annotation (Line(points={{-280,-240},{134,-240},{134,-8},{138,-8}},color={0,0,127})); + connect(dpHeaWatLocSet, ctlPumHeaWatSec.dpLocSet) + annotation (Line(points={{-280,-220},{132,-220},{132,-4},{138,-4}},color={0,0,127})); + connect(dpChiWatRem, ctlPumChiWatSec.dpRem) + annotation (Line(points={{-280,-260},{180,-260},{180,-20},{188,-20}}, + color={0,0,127})); + connect(dpChiWatLocSet, ctlPumChiWatSec.dpLocSet) + annotation (Line(points={{-280,-280},{182,-280},{182,-24},{188,-24}}, + color={0,0,127})); + connect(dpChiWatLoc, ctlPumChiWatSec.dpLoc) + annotation (Line(points={{-280,-300},{184,-300},{184,-28},{188,-28}}, + color={0,0,127})); + connect(u1AvaHp.y, avaEquHeaCoo.u1Ava) annotation (Line(points={{-228,260},{ + -200,260},{-200,220},{-154,220}}, color={255,0,255})); + connect(repTChiWatSupSet.y, swiTSupSet.u3) annotation (Line(points={{172,-140}, + {178,-140},{178,-128},{188,-128}}, color={0,0,127})); + connect(repTHeaWatSupSet.y, swiTSupSet.u1) annotation (Line(points={{172,-100}, + {178,-100},{178,-112},{188,-112}}, color={0,0,127})); + connect(resChiWat.TSupSet, repTChiWatSupSet.u) annotation (Line(points={{112,-46}, + {116,-46},{116,-140},{148,-140}}, color={0,0,127})); + connect(resHeaWat.TSupSet, repTHeaWatSupSet.u) annotation (Line(points={{112,234}, + {118,234},{118,-100},{148,-100}}, color={0,0,127})); + connect(seqEve.y1Hea, swiTSupSet.u2) annotation (Line(points={{162,308},{176, + 308},{176,-120},{188,-120}}, color={255,0,255})); + connect(swiTSupSet.y, TSupSet) annotation (Line(points={{212,-120},{242,-120}, + {242,-120},{280,-120}}, color={0,0,127})); + connect(pasTChiWatSupSet.y, TSupSet) annotation (Line(points={{242,-140},{250, + -140},{250,-120},{280,-120}}, color={0,0,127})); + connect(pasTHeaWatSupSet.y, TSupSet) annotation (Line(points={{242,-100},{250, + -100},{250,-120},{280,-120}}, color={0,0,127})); + connect(repTChiWatSupSet.y, pasTChiWatSupSet.u) + annotation (Line(points={{172,-140},{218,-140}}, color={0,0,127})); + connect(repTHeaWatSupSet.y, pasTHeaWatSupSet.u) + annotation (Line(points={{172,-100},{218,-100}}, color={0,0,127})); + connect(resChiWat.TSupSet, TChiWatSupSet) annotation (Line(points={{112,-46}, + {116,-46},{116,-180},{280,-180}}, color={0,0,127})); + connect(resHeaWat.TSupSet, THeaWatSupSet) annotation (Line(points={{112,234}, + {118,234},{118,-160},{280,-160}}, color={0,0,127})); + annotation ( + defaultComponentName="ctl", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-200,-340},{200,340}}), + graphics={ + Rectangle( + extent={{-200,340},{200,-340}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,390},{150,350}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-260,-400},{260,400}})), + Documentation( + info=" +

+This block implements the sequence of operation for plants with +air-to-water heat pumps. +Most parts of the sequence of operation are similar to that +described in ASHRAE, 2021 for chiller plants. +

+

+The supported plant configurations are enumerated in the table below.
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Configuration parameterOptionsNotes
Function +Heating and cooling
+Heating-only
+Cooling-only +
+
Type of distribution +Constant primary-variable secondary centralized + +\"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.
+Options are limited to constant primary distributions because most +AWHPs on the market use a reverse cycle for defrosting. +This requires maximum primary flow during defrost cycles and hinders +variable primary distributions.
+An option for constant primary-only distributions with ∆p-controlled +variable speed pumps will be added in a next release. +
Type of primary pump arrangement +Dedicated
+Headered +
It is assumed that the HW and the CHW loops have the +same type of primary pump arrangement, as specified by this parameter. +
Separate dedicated primary CHW pumps +False
+True +
This option is only available for heating and cooling plants +with dedicated primary pumps. +If this option is not selected, each AWHP uses +a common dedicated primary pump for HW and CHW. +Otherwise, each AWHP relies on a separate dedicated HW pump +and a separate dedicated CHW pump. +
Type of primary HW pumps +Variable speed
+Constant speed +
+For constant primary-variable secondary distributions, the variable +speed primary pumps are commanded at fixed speeds, determined during the +Testing, Adjusting and Balancing phase to provide design AWHP flow in +heating and cooling modes. +The same intent is achieved with constant speed primary pumps through the +use of balancing valves. +
Type of primary CHW pumps +Variable speed
+Constant speed +
See the note above on primary HW pumps.
+

Details

+

+A staging matrix staEqu is required as a parameter. +See the documentation of + +Buildings.Templates.Plants.Controls.StagingRotation.EquipmentEnable +for the associated definition and requirements. +

+

+Depending on the plant configuration, the term \"primary HW pumps\" +(and the corresponding variables containing *pumHeaWatPri*) +refers either to primary HW pumps for plants with separate primary +HW and CHW pumps (either headered or dedicated) +or to dedicated primary pumps for plants with common primary pumps +serving both the HW and CHW loops. +

+

+At its current stage of development, this controller contains no +logic for handling faulted equipment. +It is therefore assumed that any equipment is available at all times. +

+

References

+
    +
  • +ASHRAE, 2021. Guideline 36-2021, High-Performance Sequences of Operation +for HVAC Systems. Atlanta, GA. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end AirToWater; diff --git a/Buildings/Templates/Plants/Controls/HeatPumps/Validation/AirToWater.mo b/Buildings/Templates/Plants/Controls/HeatPumps/Validation/AirToWater.mo new file mode 100644 index 00000000000..075e68506d6 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/HeatPumps/Validation/AirToWater.mo @@ -0,0 +1,381 @@ +within Buildings.Templates.Plants.Controls.HeatPumps.Validation; +model AirToWater + final parameter Real capHea_nominal( + final unit="W")=sum(ctl.capHeaHp_nominal) + "Installed heating capacity" + annotation (Dialog(group="Nominal condition")); + parameter Real THeaWatSup_nominal( + unit="K", + displayUnit="degC")=323.15 + "Design HW supply temperature" + annotation (Dialog(group="Nominal condition")); + parameter Real THeaWatRet_nominal( + unit="K", + displayUnit="degC")=315.15 + "Design HW return temperature" + annotation (Dialog(group="Nominal condition")); + parameter Real VHeaWat_flow_nominal(unit="m3/s")=capHea_nominal/abs( + THeaWatSup_nominal - THeaWatRet_nominal)/ctl.cp_default/ctl.rho_default + "Design HW volume flow rate" + annotation (Dialog(group="Nominal condition")); + final parameter Real capCoo_nominal( + final unit="W")=sum(ctl.capCooHp_nominal) + "Installed cooling capacity" + annotation (Dialog(group="Nominal condition")); + parameter Real TChiWatSup_nominal( + unit="K", + displayUnit="degC")=280.15 + "Design CHW supply temperature" + annotation (Dialog(group="Nominal condition")); + parameter Real TChiWatRet_nominal( + unit="K", + displayUnit="degC")=285.15 + "Design CHW return temperature" + annotation (Dialog(group="Nominal condition")); + parameter Real VChiWat_flow_nominal(unit="m3/s")=capHea_nominal/abs( + TChiWatSup_nominal - TChiWatRet_nominal)/ctl.cp_default/ctl.rho_default + "Design CHW volume flow rate" + annotation (Dialog(group="Nominal condition")); + Buildings.Templates.Plants.Controls.HeatPumps.AirToWater ctl( + have_heaWat=true, + have_chiWat=true, + have_valHpInlIso=true, + have_valHpOutIso=true, + have_pumChiWatPriDed_select=true, + have_pumHeaWatSec_select=true, + have_pumPriHdr=false, + have_pumChiWatSec_select=true, + have_senVHeaWatPri_select=false, + have_senVChiWatPri_select=false, + have_senTHeaWatPriRet_select=false, + have_senTChiWatPriRet_select=false, + have_senTHeaWatSecRet=true, + have_senTChiWatSecRet=false, + nHp=3, + have_senDpHeaWatRemWir=false, + nSenDpHeaWatRem=1, + have_senDpChiWatRemWir=false, + nSenDpChiWatRem=1, + final THeaWatSup_nominal=THeaWatSup_nominal, + THeaWatSupSet_min=298.15, + final VHeaWatSec_flow_nominal=VHeaWat_flow_nominal, + capHeaHp_nominal=fill(350, ctl.nHp), + dpHeaWatRemSet_max={5E4}, + final TChiWatSup_nominal=TChiWatSup_nominal, + TChiWatSupSet_max=288.15, + final VChiWatSec_flow_nominal=VChiWat_flow_nominal, + capCooHp_nominal=fill(350, ctl.nHp), + yPumHeaWatPriSet=0.8, + yPumChiWatPriSet=0.7, + dpChiWatRemSet_max={5E4}, + staEqu=[1/3,1/3,1/3; 2/3,2/3,2/3; 1,1,1], + idxEquAlt={1,2,3}) "Plant controller" + annotation (Placement(transformation(extent={{0,0},{40,68}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratV_flow( + table=[ + 0, 0, 0; + 5, 0, 0; + 6, 1, 0; + 12, 0.2, 0.2; + 15, 0, 1; + 22, 0.1, 0.1; + 24, 0, 0], + timeScale=3600) + "Source signal for volume flow rate ratio – Index 1 for HW, 2 for CHW" + annotation (Placement(transformation(extent={{-160,-30},{-140,-10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatRet( + final k=THeaWatRet_nominal) "HWRT" + annotation (Placement(transformation(extent={{-150,50},{-130,70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatRet( + final k=TChiWatRet_nominal) "CHWRT" + annotation (Placement(transformation(extent={{-150,10},{-130,30}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter VHeaWat_flow( + final k=VHeaWat_flow_nominal) + "Scale by design flow" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter VChiWat_flow( + final k=VChiWat_flow_nominal) + "Scale by design flow" + annotation (Placement(transformation(extent={{-80,-30},{-60,-10}}))); + Components.Controls.StatusEmulator y1Hp_actual[ctl.nHp] + "HP status" + annotation (Placement(transformation(extent={{70,70},{90,90}}))); + Components.Controls.StatusEmulator y1PumHeaWatPri_actual1[ctl.nPumHeaWatPri] + if ctl.have_heaWat and ctl.have_pumHeaWatPri + "Primary HW pump status" + annotation (Placement(transformation(extent={{100,50},{120,70}}))); + Components.Controls.StatusEmulator y1PumChiWatPri_actual[ctl.nPumChiWatPri] + if ctl.have_chiWat and ctl.have_pumChiWatPri + "Primary CHW pump status" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Components.Controls.StatusEmulator y1PumHeaWatSec_actual[ctl.nPumHeaWatSec] + if ctl.have_heaWat and ctl.have_pumHeaWatSec + "Secondary HW pump status" + annotation (Placement(transformation(extent={{100,10},{120,30}}))); + Components.Controls.StatusEmulator y1PumChiWatSec_actual[ctl.nPumChiWatSec] + if ctl.have_chiWat and ctl.have_pumChiWatSec + "Secondary CHW pump status" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin TOut( + amplitude=10, + freqHz=0.5 / 24 / 3600, + phase=- 0.43633231299858, + offset=10 + 273.15) + "OAT" + annotation (Placement(transformation(extent={{-160,110},{-140,130}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isDemHea( + t=1E-2, + h=0.5E-2) + "Return true if heating demand" + annotation (Placement(transformation(extent={{-110,170},{-90,190}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isDemCoo( + t=1E-2, + h=0.5E-2) + "Return true if cooling demand" + annotation (Placement(transformation(extent={{-110,130},{-90,150}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger reqPlaHeaWat + "Generate HW plant request" + annotation (Placement(transformation(extent={{-80,170},{-60,190}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger reqPlaChiWat + "Generate CHW plant request" + annotation (Placement(transformation(extent={{-80,130},{-60,150}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter gai[2]( + each k=5) + "Use fraction of flow rate as a proxy for plant reset request" + annotation (Placement(transformation(extent={{-108,90},{-88,110}}))); + Buildings.Controls.OBC.CDL.Conversions.RealToInteger reqResHeaWat + "Generate HW reset request" + annotation (Placement(transformation(extent={{-80,90},{-60,110}}))); + Buildings.Controls.OBC.CDL.Conversions.RealToInteger reqResChiWat + "Generate CHW reset request" + annotation (Placement(transformation(extent={{-80,60},{-60,80}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin[1]( + amplitude=0.1 * ctl.dpHeaWatRemSet_max, + freqHz={4 / 8000}, + each phase=3.1415926535898) + if ctl.have_heaWat + "Source signal used to generate measurement values" + annotation (Placement(transformation(extent={{-160,-76},{-140,-56}}))); + Buildings.Controls.OBC.CDL.Reals.Add dpHeaWatRem[1] + if ctl.have_heaWat + "Differential pressure at remote location" + annotation (Placement(transformation(extent={{-80,-70},{-60,-50}}))); + Buildings.Controls.OBC.CDL.Reals.Add dpChiWatRem[1] + if ctl.have_chiWat + "Differential pressure at remote location" + annotation (Placement(transformation(extent={{-80,-110},{-60,-90}}))); + Pumps.Generic.ResetLocalDifferentialPressure resDpHeaWatLoc[1](each + dpLocSet_max=20E4) + if ctl.have_heaWat + "Local HW DP reset" + annotation (Placement(transformation(extent={{-40,-130},{-20,-110}}))); + Pumps.Generic.ResetLocalDifferentialPressure resDpChiWatLoc[1](each + dpLocSet_max=15E4) + if ctl.have_chiWat + "Local CHW DP reset" + annotation (Placement(transformation(extent={{-40,-170},{-20,-150}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin1[1]( + amplitude=0.1 * ctl.dpChiWatRemSet_max, + freqHz={3 / 8000}, + each phase=3.1415926535898) + "Source signal used to generate measurement values" + annotation (Placement(transformation(extent={{-160,-116},{-140,-96}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter dpHeaWatLoc(final k=4) + if ctl.have_heaWat + "Differential pressure local to the plant" + annotation (Placement(transformation(extent={{-80,-150},{-60,-130}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter dpChiWatLoc(final k=3) + if ctl.have_chiWat + "Differential pressure local to the plant" + annotation (Placement(transformation(extent={{-80,-190},{-60,-170}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSup(final k= + THeaWatSup_nominal) "HWST" + annotation (Placement(transformation(extent={{-180,70},{-160,90}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSup(final k= + TChiWatSup_nominal) "CHWST" + annotation (Placement(transformation(extent={{-180,30},{-160,50}}))); +equation + connect(ratV_flow.y[1], VHeaWat_flow.u) + annotation (Line(points={{-138,-20},{-120,-20},{-120,0},{-112,0}},color={0,0,127})); + connect(ratV_flow.y[2], VChiWat_flow.u) + annotation (Line(points={{-138,-20},{-82,-20}},color={0,0,127})); + connect(ctl.y1Hp, y1Hp_actual.y1) + annotation (Line(points={{42,60},{58,60},{58,80},{68,80}},color={255,0,255})); + connect(y1Hp_actual.y1_actual, ctl.u1Hp_actual) + annotation (Line(points={{92,80},{100,80},{100,100},{-4,100},{-4,60},{-2,60}}, + color={255,0,255})); + connect(ctl.y1PumHeaWatPri, y1PumHeaWatPri_actual1.y1) + annotation (Line(points={{42,44},{60,44},{60,60},{98,60}},color={255,0,255})); + connect(ctl.y1PumChiWatPri, y1PumChiWatPri_actual.y1) + annotation (Line(points={{42,42},{60,42},{60,40},{68,40}},color={255,0,255})); + connect(ctl.y1PumHeaWatSec, y1PumHeaWatSec_actual.y1) + annotation (Line(points={{42,38},{60,38},{60,20},{98,20}},color={255,0,255})); + connect(ctl.y1PumChiWatSec, y1PumChiWatSec_actual.y1) + annotation (Line(points={{42,36},{58,36},{58,0},{68,0}},color={255,0,255})); + connect(y1PumHeaWatPri_actual1.y1_actual, ctl.u1PumHeaWatPri_actual) + annotation (Line(points={{122,60},{134,60},{134,102},{-6,102},{-6,58},{-2, + 58}}, + color={255,0,255})); + connect(y1PumHeaWatSec_actual.y1_actual, ctl.u1PumHeaWatSec_actual) + annotation (Line(points={{122,20},{138,20},{138,106},{-10,106},{-10,54},{-2, + 54}}, + color={255,0,255})); + connect(y1PumChiWatPri_actual.y1_actual, ctl.u1PumChiWatPri_actual) + annotation (Line(points={{92,40},{136,40},{136,104},{-8,104},{-8,56},{-2,56}}, + color={255,0,255})); + connect(y1PumChiWatSec_actual.y1_actual, ctl.u1PumChiWatSec_actual) + annotation (Line(points={{92,0},{140,0},{140,108},{-12,108},{-12,52},{-2,52}}, + color={255,0,255})); + connect(TOut.y, ctl.TOut) + annotation (Line(points={{-138,120},{-122,120},{-122,38},{-2,38}}, color={0,0,127})); + connect(ratV_flow.y[1], isDemHea.u) + annotation (Line(points={{-138,-20},{-120,-20},{-120,180},{-112,180}},color={0,0,127})); + connect(ratV_flow.y[2], isDemCoo.u) + annotation (Line(points={{-138,-20},{-120,-20},{-120,140},{-112,140}},color={0,0,127})); + connect(isDemCoo.y, reqPlaChiWat.u) + annotation (Line(points={{-88,140},{-82,140}},color={255,0,255})); + connect(isDemHea.y, reqPlaHeaWat.u) + annotation (Line(points={{-88,180},{-82,180}},color={255,0,255})); + connect(reqPlaHeaWat.y, ctl.nReqPlaHeaWat) annotation (Line(points={{-58,180}, + {-40,180},{-40,48},{-2,48}}, color={255,127,0})); + connect(reqPlaChiWat.y, ctl.nReqPlaChiWat) annotation (Line(points={{-58,140}, + {-40,140},{-40,46},{-2,46}}, color={255,127,0})); + connect(THeaWatRet.y, ctl.THeaWatSecRet) + annotation (Line(points={{-128,60},{-100,60},{-100,22},{-2,22}}, color={0,0,127})); + connect(THeaWatRet.y, ctl.THeaWatPriRet) + annotation (Line(points={{-128,60},{-100,60},{-100,34},{-2,34}}, color={0,0,127})); + connect(TChiWatRet.y, ctl.TChiWatSecRet) + annotation (Line(points={{-128,20},{-28,20},{-28,16},{-2,16}},color={0,0,127})); + connect(TChiWatRet.y, ctl.TChiWatPriRet) + annotation (Line(points={{-128,20},{-28,20},{-28,28},{-2,28}}, color={0,0,127})); + connect(VHeaWat_flow.y, ctl.VHeaWatPri_flow) + annotation (Line(points={{-88,0},{-26,0},{-26,32},{-2,32}}, color={0,0,127})); + connect(VHeaWat_flow.y, ctl.VHeaWatSec_flow) + annotation (Line(points={{-88,0},{-26,0},{-26,20},{-2,20}},color={0,0,127})); + connect(VChiWat_flow.y, ctl.VChiWatPri_flow) + annotation (Line(points={{-58,-20},{-24,-20},{-24,26},{-2,26}}, color={0,0,127})); + connect(VChiWat_flow.y, ctl.VChiWatSec_flow) + annotation (Line(points={{-58,-20},{-22,-20},{-22,14},{-2,14}},color={0,0,127})); + connect(ratV_flow.y, gai.u) + annotation (Line(points={{-138,-20},{-120,-20},{-120,100},{-110,100}}, + color={0,0,127})); + connect(gai[1].y, reqResHeaWat.u) + annotation (Line(points={{-86,100},{-82,100}}, + color={0,0,127})); + connect(gai[2].y, reqResChiWat.u) + annotation (Line(points={{-86,100},{-84,100},{-84,70},{-82,70}}, + color={0,0,127})); + connect(reqResHeaWat.y,ctl.nReqResHeaWat) + annotation (Line(points={{-58,100},{-38,100},{-38,44},{-2,44}}, + color={255,127,0})); + connect(reqResChiWat.y,ctl.nReqResChiWat) + annotation (Line(points={{-58,70},{-36,70},{-36,42},{-2,42}},color={255,127,0})); + connect(sin.y, dpHeaWatRem.u2) + annotation (Line(points={{-138,-66},{-82,-66}},color={0,0,127})); + connect(dpChiWatRem.y, ctl.dpChiWatRem) + annotation (Line(points={{-58,-100},{-18,-100},{-18,6},{-2,6}},color={0,0,127})); + connect(dpHeaWatRem.y, ctl.dpHeaWatRem) + annotation (Line(points={{-58,-60},{-20,-60},{-20,12},{-2,12}},color={0,0,127})); + connect(ctl.dpHeaWatRemSet, dpHeaWatRem.u1) + annotation (Line(points={{42,18},{50,18},{50,-40},{-100,-40},{-100,-54},{ + -82,-54}}, + color={0,0,127})); + connect(ctl.dpChiWatRemSet, dpChiWatRem.u1) + annotation (Line(points={{42,16},{48,16},{48,-80},{-90,-80},{-90,-94},{-82, + -94}}, + color={0,0,127})); + connect(sin1.y, dpChiWatRem.u2) + annotation (Line(points={{-138,-106},{-82,-106}},color={0,0,127})); + connect(dpHeaWatRem[1].y, dpHeaWatLoc.u) + annotation (Line(points={{-58,-60},{-52,-60},{-52,-120},{-86,-120},{-86,-140},{-82,-140}}, + color={0,0,127})); + connect(ctl.dpHeaWatRemSet, resDpHeaWatLoc.dpRemSet) + annotation (Line(points={{42,18},{50,18},{50,-40},{-100,-40},{-100,-114},{ + -42,-114}}, + color={0,0,127})); + connect(dpChiWatRem[1].y, dpChiWatLoc.u) + annotation (Line(points={{-58,-100},{-54,-100},{-54,-160},{-90,-160},{-90,-180},{-82,-180}}, + color={0,0,127})); + connect(ctl.dpChiWatRemSet, resDpChiWatLoc.dpRemSet) + annotation (Line(points={{42,16},{47.9167,16},{47.9167,-80},{-90,-80},{-90, + -154},{-42,-154}}, + color={0,0,127})); + connect(dpHeaWatRem.y, resDpHeaWatLoc.dpRem) + annotation (Line(points={{-58,-60},{-52,-60},{-52,-126},{-42,-126}},color={0,0,127})); + connect(dpChiWatRem.y, resDpChiWatLoc.dpRem) + annotation (Line(points={{-58,-100},{-54,-100},{-54,-166},{-42,-166}},color={0,0,127})); + connect(resDpChiWatLoc.dpLocSet, ctl.dpChiWatLocSet) + annotation (Line(points={{-18.2,-160},{-14,-160},{-14,4},{-2,4}},color={0,0,127})); + connect(dpChiWatLoc.y, ctl.dpChiWatLoc) + annotation (Line(points={{-58,-180},{-12,-180},{-12,2},{-2,2}},color={0,0,127})); + connect(dpHeaWatLoc.y, ctl.dpHeaWatLoc) + annotation (Line(points={{-58,-140},{-16,-140},{-16,8},{-2,8}},color={0,0,127})); + connect(resDpHeaWatLoc.dpLocSet, ctl.dpHeaWatLocSet) + annotation (Line(points={{-18.2,-120},{-10,-120},{-10,10},{-2,10}},color={0,0,127})); + connect(TChiWatSup.y, ctl.TChiWatPriSup) annotation (Line(points={{-158,40},{ + -102,40},{-102,30},{-2,30}}, color={0,0,127})); + connect(THeaWatSup.y, ctl.THeaWatPriSup) annotation (Line(points={{-158,80},{ + -98,80},{-98,36},{-2,36}}, color={0,0,127})); + connect(TChiWatSup.y, ctl.TChiWatSecSup) annotation (Line(points={{-158,40},{ + -102,40},{-102,18},{-2,18}}, color={0,0,127})); + connect(THeaWatSup.y, ctl.THeaWatSecSup) annotation (Line(points={{-158,80},{ + -98,80},{-98,24},{-2,24}}, color={0,0,127})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/HeatPumps/Validation/AirToWater.mos" + "Simulate and plot"), + experiment( + StopTime=86400.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + extent={{-200,-240},{200,240}})), + Documentation(revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+", info=" +

+This model validates + +Buildings.Templates.Plants.Controls.HeatPumps.AirToWater +in a configuration with three equally sized lead/lag alternate +heat pumps. +

+

+Simulating this model shows how the controller responds to a varying load by +

+
    +
  • +staging or unstaging the AWHPs and associated primary pumps, +
  • +
  • +rotating lead/lag alternate equipment to ensure even wear, +
  • +
  • +resetting the supply temperature and remote differential pressure +in both the CHW and HW loops based on the valve position, +
  • +
  • +staging the secondary pumps. +
  • +
+")); +end AirToWater; diff --git a/Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.mo b/Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.mo new file mode 100644 index 00000000000..d1394bc2049 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.mo @@ -0,0 +1,27 @@ +within Buildings.Templates.Plants.Controls.HeatPumps; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), Documentation(info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.order b/Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.order new file mode 100644 index 00000000000..971b641363f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/HeatPumps/Validation/package.order @@ -0,0 +1 @@ +AirToWater diff --git a/Buildings/Templates/Plants/Controls/HeatPumps/package.mo b/Buildings/Templates/Plants/Controls/HeatPumps/package.mo new file mode 100644 index 00000000000..af3c9fb29f4 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/HeatPumps/package.mo @@ -0,0 +1,8 @@ +within Buildings.Templates.Plants.Controls; +package HeatPumps + annotation (Documentation(info=" +

+This package contains control sequences for heat pump plants. +

+")); +end HeatPumps; diff --git a/Buildings/Templates/Plants/Controls/HeatPumps/package.order b/Buildings/Templates/Plants/Controls/HeatPumps/package.order new file mode 100644 index 00000000000..8df76113296 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/HeatPumps/package.order @@ -0,0 +1,2 @@ +AirToWater +Validation diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/ControlDifferentialPressure.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/ControlDifferentialPressure.mo new file mode 100644 index 00000000000..f731cf30b09 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/ControlDifferentialPressure.mo @@ -0,0 +1,233 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic; +block ControlDifferentialPressure + "Differential pressure control for variable speed pumps" + parameter Boolean have_senDpRemWir + "Set to true for remote differential pressure sensor(s) hardwired to controller" + annotation (Evaluate=true); + parameter Integer nPum( + min=1) + "Number of pumps that operate at design conditions" + annotation (Evaluate=true); + parameter Integer nSenDpRem( + min=1) + "Number of remote loop differential pressure sensors used for pump speed control" + annotation (Evaluate=true); + parameter Real y_min( + max=1, + min=0, + unit="1")=0.1 + "Minimum pump speed"; + final parameter Real y_max( + final unit="1", + final min=0, + final max=1)=1 + "Maximum pump speed"; + parameter Real k( + min=100 * Buildings.Controls.OBC.CDL.Constants.eps)=1 + "Gain of controller" + annotation (Dialog(group="Control gains")); + parameter Real Ti( + min=100 * Buildings.Controls.OBC.CDL.Constants.eps, + unit="s")=60 + "Time constant of integrator block" + annotation (Dialog(group="Control gains")); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput y1_actual[nPum] + "Pump status" + annotation (Placement(transformation(extent={{-140,60},{-100,100}}), + iconTransformation(extent={{-140,60},{-100,100}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpRemSet[nSenDpRem]( + each final unit="Pa") + if have_senDpRemWir + "Remote differential pressure setpoint" + annotation (Placement(transformation(extent={{-140,20},{-100,60}}), + iconTransformation(extent={{-140,20},{-100,60}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpLoc( + final unit="Pa") + if not have_senDpRemWir + "Loop differential pressure local to the plant" + annotation (Placement(transformation(extent={{-140,-100},{-100,-60}}), + iconTransformation(extent={{-140,-100},{-100,-60}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpRem[nSenDpRem]( + each final unit="Pa") + if have_senDpRemWir + "Remote loop differential pressure" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpLocSet[nSenDpRem]( + each final unit="Pa") + if not have_senDpRemWir + "Local differential pressure setpoint" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-60},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput y( + final unit="1") + "Pump speed command" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{98,-20},{138,20}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyOn( + final nin=nPum) + "Return true when any pump is proven on" + annotation (Placement(transformation(extent={{-90,70},{-70,90}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator repEna( + final nout=nSenDpRem) + "Replicate" + annotation (Placement(transformation(extent={{-50,70},{-30,90}}))); + Buildings.Controls.OBC.CDL.Reals.MultiMax maxSet( + nin=nSenDpRem) + if not have_senDpRemWir + "Maximum DP setpoint" + annotation (Placement(transformation(extent={{-90,-50},{-70,-30}}))); + Utilities.PIDWithEnable ctlDpRem[nSenDpRem]( + each final k=k, + each final Ti=Ti, + each r=dpSca, + each final yMin=y_min, + each final yMax=y_max, + each final y_reset=y_min, + each final y_neutral=0) + if have_senDpRemWir + "Remote differential pressure control" + annotation (Placement(transformation(extent={{-10,30},{10,50}}))); + Utilities.PIDWithEnable ctlDpLoc( + final k=k, + final Ti=Ti, + final r=dpSca, + final yMin=y_min, + final yMax=y_max, + final y_reset=y_min, + final y_neutral=0) + if not have_senDpRemWir + "Local differential pressure control" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); + Buildings.Controls.OBC.CDL.Reals.MultiMax maxY( + nin=nSenDpRem) + if have_senDpRemWir + "Maximum control loop output" + annotation (Placement(transformation(extent={{40,30},{60,50}}))); +protected + parameter Real dpSca( + final unit="Pa", + final min=0)=1E4 + "Differential pressure used as a scaling factor for PI control"; +equation + connect(y1_actual, anyOn.u) + annotation (Line(points={{-120,80},{-92,80}},color={255,0,255})); + connect(anyOn.y, repEna.u) + annotation (Line(points={{-68,80},{-52,80}},color={255,0,255})); + connect(dpLocSet, maxSet.u) + annotation (Line(points={{-120,-40},{-92,-40}},color={0,0,127})); + connect(dpRemSet, ctlDpRem.u_s) + annotation (Line(points={{-120,40},{-12,40}},color={0,0,127})); + connect(maxSet.y, ctlDpLoc.u_s) + annotation (Line(points={{-68,-40},{-12,-40}},color={0,0,127})); + connect(dpRem, ctlDpRem.u_m) + annotation (Line(points={{-120,0},{0,0},{0,28}},color={0,0,127})); + connect(repEna.y, ctlDpRem.uEna) + annotation (Line(points={{-28,80},{-20,80},{-20,20},{-4,20},{-4,28}},color={255,0,255})); + connect(dpLoc, ctlDpLoc.u_m) + annotation (Line(points={{-120,-80},{0,-80},{0,-52}},color={0,0,127})); + connect(anyOn.y, ctlDpLoc.uEna) + annotation (Line(points={{-68,80},{-60,80},{-60,-60},{-4,-60},{-4,-52}}, + color={255,0,255})); + connect(ctlDpRem.y, maxY.u) + annotation (Line(points={{12,40},{38,40}},color={0,0,127})); + connect(ctlDpLoc.y, y) + annotation (Line(points={{12,-40},{80,-40},{80,0},{120,0}},color={0,0,127})); + connect(maxY.y, y) + annotation (Line(points={{62,40},{80,40},{80,0},{120,0}},color={0,0,127})); + annotation ( + defaultComponentName="ctlDp", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation( + info=" +

+For plants where a remote DP sensor(s) is hardwired to the pump controller +(have_senDpRemHar=true): +

+
    +
  • +When any pump is proven on, the pump speed is controlled by a reverse acting PI loop +maintaining the differential pressure signal at setpoint. +All pumps receive the same speed signal. +
  • +
  • +Where multiple DP sensors exist, a PI loop runs for each sensor. +The pumps are controlled to the highest signal output of all DP sensor loops. +
  • +
+

+For plants where the remote DP sensor(s) is not hardwired to the plant controller, but +a local DP sensor is hardwired to the plant controller +(have_senDpRemHar=false): +

+
    +
  • +When any pump is proven on, the pump speed is controlled by a reverse acting PI +loop maintaining the local DP signal at the DP setpoint output from the +remote sensor control loop (see + +Buildings.Templates.Plants.Controls.Pumps.Generic.ResetLocalDifferentialPressure). +All pumps receive the same speed signal. +
  • +
  • +Where multiple remote DP sensors exist, a PI loop shall run for each sensor. +The DP setpoint for the local DP sensor is the highest DP setpoint output +from each of the remote loops. +
  • +
+

Details

+

This logic is prescribed in ASHRAE, 2021 for: +

+
    +
  • +variable speed primary pumps in primary-only chiller and boiler plants +where the remote DP sensor(s) is hardwired to the plant controller, +
  • +
  • +variable speed primary pumps in primary-only chiller and boiler plants +where the remote DP sensor(s) is not hardwired to the plant controller, but +a local DP sensor is hardwired to the plant controller, +
  • +
  • +variable speed secondary pumps in primary-secondary chiller and boiler +plants where a remote DP sensor(s) is hardwired to the secondary pump controller, +
  • +
  • +variable speed secondary pumps in primary-secondary chiller and boiler plants +where a remote DP sensor is not hardwired to the secondary pump controller, +but a local DP sensor is hardwired to the secondary pump controller. +
  • +
+

References

+
    +
  • +ASHRAE, 2021. Guideline 36-2021, High-Performance Sequences of Operation +for HVAC Systems. Atlanta, GA. +
  • +
+ +", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Diagram( + coordinateSystem( + extent={{-100,-100},{100,100}}))); +end ControlDifferentialPressure; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/ResetLocalDifferentialPressure.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/ResetLocalDifferentialPressure.mo new file mode 100644 index 00000000000..ef5defaf7d5 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/ResetLocalDifferentialPressure.mo @@ -0,0 +1,153 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic; +block ResetLocalDifferentialPressure + "Local differential pressure reset" + parameter Real dpLocSet_min( + start=0, + final unit="Pa", + final min=0)=5 * 6895 + "Minimum loop differential pressure setpoint local to the plant"; + parameter Real dpLocSet_max( + start=1E5, + final unit="Pa", + final min=0) + "Maximum loop differential pressure setpoint local to the plant"; + parameter Real k( + final min=100 * Buildings.Controls.OBC.CDL.Constants.eps)=1 + "Gain of controller" + annotation (Dialog(group="Control gains")); + parameter Real Ti( + final unit="s", + final min=100 * Buildings.Controls.OBC.CDL.Constants.eps)=60 + "Time constant of integrator block" + annotation (Dialog(group="Control gains")); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpRemSet( + final unit="Pa") + "Remote loop differential pressure setpoint" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput dpRem( + final unit="Pa") + "Remote loop differential pressure" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput dpLocSet( + final unit="Pa") + "Local differential pressure setpoint " + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{98,-20},{138,20}}))); + Buildings.Controls.OBC.CDL.Reals.PID ctlDpRem( + final k=k, + final Ti=Ti, + final r=dpLocSet_max) + "Remote loop differential pressure controller" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + Buildings.Controls.OBC.CDL.Reals.Line dpLocRes + "Local loop differential pressure reset" + annotation (Placement(transformation(extent={{40,-10},{60,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer( + final k=0) + "Constant" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant one( + final k=1) + "Constant" + annotation (Placement(transformation(extent={{0,-30},{20,-10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpLocSetMin( + final k=dpLocSet_min) + "Constant" + annotation (Placement(transformation(extent={{60,24},{40,44}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpLocSetMax( + final k=dpLocSet_max) + "Constant" + annotation (Placement(transformation(extent={{60,-40},{40,-20}}))); +equation + connect(dpRem, ctlDpRem.u_m) + annotation (Line(points={{-120,-40},{-60,-40},{-60,-12}},color={0,0,127})); + connect(zer.y, dpLocRes.x1) + annotation (Line(points={{22,40},{30,40},{30,8},{38,8}},color={0,0,127})); + connect(dpLocSetMin.y, dpLocRes.f1) + annotation (Line(points={{38,34},{34,34},{34,4},{38,4}},color={0,0,127})); + connect(one.y, dpLocRes.x2) + annotation (Line(points={{22,-20},{30,-20},{30,-4},{38,-4}},color={0,0,127})); + connect(dpLocSetMax.y, dpLocRes.f2) + annotation (Line(points={{38,-30},{34,-30},{34,-8},{38,-8}},color={0,0,127})); + connect(dpRemSet, ctlDpRem.u_s) + annotation (Line(points={{-120,0},{-72,0}},color={0,0,127})); + connect(ctlDpRem.y, dpLocRes.u) + annotation (Line(points={{-48,0},{38,0}},color={0,0,127})); + connect(dpLocRes.y, dpLocSet) + annotation (Line(points={{62,0},{120,0}},color={0,0,127})); + annotation ( + defaultComponentName="resDpLoc", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation( + info=" +

+For plants where the remote DP sensor(s) is not hardwired to the plant controller, but +a local DP sensor is hardwired to the plant controller, +remote DP is maintained at setpoint by a reverse acting PI loop running in the controller +to which the remote sensor is wired. +

+

+The loop output is a DP setpoint for the local primary loop DP sensor hardwired to the +plant controller. +

+

+The local DP setpoint is reset from dpLocSet_min at 0 % loop output +to dpLocSet_max at 100 % loop output. +

+

+The minimum local differential pressure setpoint dpLocSet_min is +dictated by minimum flow control in primary-only plants but has no lower +limit in primary-secondary plants. +In primary-only plants, the minimum setpoint needs to be high enough to drive design +minimum flow for the largest equipment through the minimum flow bypass valve. +

+

Details

+

This logic is prescribed in ASHRAE, 2021 for: +

+
    +
  • +variable speed primary pumps in primary-only chiller and boiler plants +where the remote DP sensor(s) is not hardwired to the plant controller, but +a local DP sensor is hardwired to the plant controller, +
  • +
  • +variable speed secondary pumps in primary-secondary chiller and boiler plants +where a remote DP sensor is not hardwired to the secondary pump controller, +but a local DP sensor is hardwired to the secondary pump controller. +
  • +
+

References

+
    +
  • +ASHRAE, 2021. Guideline 36-2021, High-Performance Sequences of Operation +for HVAC Systems. Atlanta, GA. +
  • +
+ +", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Diagram( + coordinateSystem( + extent={{-100,-100},{100,100}}))); +end ResetLocalDifferentialPressure; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeadered.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeadered.mo new file mode 100644 index 00000000000..add1f3d443d --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeadered.mo @@ -0,0 +1,352 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic; +block StagingHeadered "Generic staging logic for headered pumps" + parameter Boolean is_pri(start=true) + "Set to true for primary pumps, false for secondary pumps" + annotation (Evaluate=true, + Dialog(enable=nPum > 0)); + parameter Boolean is_hdr(start=false) + "Set to true for headered pumps, false for dedicated pumps" + annotation (Evaluate=true, + Dialog(enable=nPum > 0)); + parameter Boolean is_ctlDp(start=false) + "Set to true for headered variable speed pumps using ∆p pump speed control" + annotation (Evaluate=true, + Dialog(enable=is_hdr)); + parameter Boolean have_valInlIso(start=false) + "Set to true if the system as inlet isolation valves" + annotation (Evaluate=true, + Dialog(enable=is_pri)); + parameter Boolean have_valOutIso(start=false) + "Set to true if the system as outlet isolation valves" + annotation (Evaluate=true, + Dialog(enable=is_pri)); + parameter Integer nEqu + "Number of equipment" + annotation (Evaluate=true); + parameter Integer nPum + "Number of pumps" + annotation (Evaluate=true); + parameter Real V_flow_nominal( + min=1E-6, + start=1E-6, + unit="m3/s") + "Design flow rate" + annotation (Dialog(enable=is_hdr and is_ctlDp)); + parameter Real dtRun( + min=0, + start=600, + unit="s")=600 + "Runtime before triggering stage command" + annotation (Dialog(enable=is_hdr and is_ctlDp)); + parameter Real dVOffUp( + max=1, + min=0, + start=0.03, + unit="1")=0.03 + "Stage up flow point offset" + annotation (Dialog(enable=is_hdr and is_ctlDp)); + parameter Real dVOffDow( + max=1, + min=0, + start=0.03, + unit="1")=dVOffUp + "Stage down flow point offset" + annotation (Dialog(enable=is_hdr and is_ctlDp)); + final parameter Real staPum[nPum, nPum]( + each unit="1", + each min=0, + each max=1)={fill(i / nPum, nPum) for i in 1:nPum} + "Pump staging matrix" + annotation(Evaluate=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Pum[nEqu] + if is_pri and (not is_hdr or is_hdr and not is_ctlDp) + "Pump command from equipment enable logic" + annotation (Placement(transformation(extent={{-200,80},{-160,120}}), + iconTransformation(extent={{-140,-40},{-100,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Pum_actual[nPum] + "Pump status – Hardware point" + annotation (Placement(transformation(extent={{-200,0},{-160,40}}), + iconTransformation(extent={{-140,-60},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1[nPum] + "Pump command – Hardware point" + annotation (Placement(transformation(extent={{160,-80},{200,-40}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1_actual[nEqu] + "Pump status to equipment enable logic" + annotation (Placement(transformation(extent={{160,40},{200,80}}), + iconTransformation(extent={{100,40},{140,80}}))); + Utilities.StageIndex nPumHdrDp( + final have_inpAva=false, + final nSta=nPum, + final dtRun=dtRun) + if is_hdr and is_ctlDp + "Compute number of pumps to be staged on – Headered pumps using ∆p control" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); + Generic.StagingHeaderedDeltaP staHdrDp( + final nPum=nPum, + final V_flow_nominal=V_flow_nominal, + final dtRun=dtRun, + final dVOffUp=dVOffUp, + final dVOffDow=dVOffDow) + if is_hdr and is_ctlDp + "Stage headered variable speed pumps using ∆p control" + annotation (Placement(transformation(extent={{-130,-30},{-110,-10}}))); + StagingRotation.SortRuntime sorRunTimHdr( + nin=nPum) + if is_hdr + "Sort by increasing staging runtime" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nEqu]( + each final integerTrue=1, + each final integerFalse=0) + if is_pri and is_hdr and not is_ctlDp + "Convert to integer" + annotation (Placement(transformation(extent={{-140,90},{-120,110}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum nPumHdrPriNotDp0( + nin=nEqu) + if is_pri and is_hdr and not is_ctlDp + "Compute number of pumps to be staged on – Headered primary pumps not using ∆p control" + annotation (Placement(transformation(extent={{-100,90},{-80,110}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1Ava[nPum]( + each final k=true) + if is_hdr + "Pump available signal – Block does not handle faulted equipment yet" + annotation (Placement(transformation(extent={{-10,-110},{10,-90}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput V_flow( + final unit="m3/s") + if is_hdr and is_ctlDp + "Flow rate" + annotation (Placement(transformation(extent={{-200,-40},{-160,0}}), + iconTransformation(extent={{-140,-100},{-100,-60}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanExtractSignal sigPumPriDed(final nin + =nEqu, final nout=nPum) + if is_pri and not is_hdr + "Extract dedicated primary pump command signal assuming nEqu=nPum" + annotation (Placement(transformation(extent={{-10,-150},{10,-130}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanExtractSignal y1Ded_actual( + nin=nPum, + nout=nEqu) + if not is_hdr + "Extract dedicated pump status assuming nEqu=nPum" + annotation (Placement(transformation(extent={{70,70},{90,90}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanExtractor y1LeaHdr_actual( + final nin=nPum) + if is_hdr + "Lead headered pump status" + annotation (Placement(transformation(extent={{30,30},{50,50}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator booScaRep( + final nout=nEqu) + if is_hdr + "Replicate signal" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1ValInlIso[nEqu] + if is_pri and is_hdr and have_valInlIso + "Equipment inlet isolation valve command" + annotation (Placement(transformation(extent={{-200,-100},{-160,-60}}), + iconTransformation(extent={{-140,20},{-100,60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1ValOutIso[nEqu] + if is_pri and is_hdr and have_valOutIso + "Equipment outlet isolation valve command" + annotation (Placement(transformation(extent={{-200,-140},{-160,-100}}), + iconTransformation(extent={{-140,0},{-100,40}}))); + Primary.EnableLeadHeadered enaLeaHdrPri( + final typCon=Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel, + final typValIso=Buildings.Templates.Plants.Controls.Types.Actuator.TwoPosition, + final nValIso=2 * nEqu) + if is_pri and is_hdr + "Enable/disable lead primary headered pump" + annotation (Placement(transformation(extent={{-70,-110},{-50,-90}}))); + Utilities.PlaceholderLogical phValInlIso[nEqu](each final have_inp= + have_valInlIso, each final have_inpPh=true) if is_pri and is_hdr + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{-130,-90},{-110,-70}}))); + Utilities.PlaceholderLogical phValOutIso[nEqu](each final have_inp= + have_valOutIso, each final have_inpPh=true) if is_pri and is_hdr + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{-130,-130},{-110,-110}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Pla + if not is_pri and is_hdr + "Plant enable signal" + annotation (Placement(transformation(extent={{-200,120},{-160,160}}), + iconTransformation(extent={{-140,60},{-100,100}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt1( + final integerTrue=1, + final integerFalse=0) + if is_pri and is_hdr and not is_ctlDp + "Convert lead pump enable signal to integer" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-40,-50}))); + Buildings.Controls.OBC.CDL.Integers.Multiply nPumHdrPriNotDp + if is_pri and is_hdr and not is_ctlDp + "Reset number of enabled pumps to zero if lead pump disabled" + annotation (Placement(transformation(extent={{-10,90},{10,110}}))); + StagingRotation.EquipmentEnable enaHdr( + final staEqu=staPum) + if is_hdr + "Enable headered pumps" + annotation (Placement(transformation(extent={{50,-30},{70,-10}}))); +equation + connect(u1Pum_actual, staHdrDp.u1_actual) + annotation (Line(points={{-180,20},{-152,20},{-152,-14},{-132,-14}}, + color={255,0,255})); + connect(staHdrDp.y1Up, nPumHdrDp.u1Up) + annotation (Line(points={{-108,-14},{-100,-14},{-100,-18},{-12,-18}}, + color={255,0,255})); + connect(staHdrDp.y1Dow, nPumHdrDp.u1Dow) + annotation (Line(points={{-108,-26},{-100,-26},{-100,-22},{-12,-22}}, + color={255,0,255})); + connect(u1Pum, booToInt.u) + annotation (Line(points={{-180,100},{-142,100}},color={255,0,255})); + connect(booToInt.y, nPumHdrPriNotDp0.u) + annotation (Line(points={{-118,100},{-102,100}},color={255,127,0})); + connect(u1Ava.y, sorRunTimHdr.u1Ava) + annotation (Line(points={{12,-100},{20,-100},{20,-60},{-18,-60},{-18,14},{ + -12,14}}, color={255,0,255})); + connect(V_flow, staHdrDp.V_flow) + annotation (Line(points={{-180,-20},{-146,-20},{-146,-26},{-132,-26}}, + color={0,0,127})); + connect(u1Pum, sigPumPriDed.u) + annotation (Line(points={{-180,100},{-156,100},{-156,-140},{-12,-140}}, + color={255,0,255})); + connect(u1Pum_actual, y1Ded_actual.u) + annotation (Line(points={{-180,20},{-152,20},{-152,80},{68,80}},color={255,0,255})); + connect(y1Ded_actual.y, y1_actual) + annotation (Line(points={{92,80},{140,80},{140,60},{180,60}},color={255,0,255})); + connect(u1Pum_actual, y1LeaHdr_actual.u) + annotation (Line(points={{-180,20},{-152,20},{-152,40},{28,40}},color={255,0,255})); + connect(y1LeaHdr_actual.y, booScaRep.u) + annotation (Line(points={{52,40},{68,40}},color={255,0,255})); + connect(booScaRep.y, y1_actual) + annotation (Line(points={{92,40},{140,40},{140,60},{180,60}},color={255,0,255})); + connect(u1ValInlIso, phValInlIso.u) + annotation (Line(points={{-180,-80},{-132,-80}}, color={255,0,255})); + connect(enaLeaHdrPri.y1, nPumHdrDp.u1Lea) + annotation (Line(points={{-48,-100},{-20,-100},{-20,-14},{-12,-14}}, + color={255,0,255})); + connect(phValInlIso.y, enaLeaHdrPri.u1ValIso[1:nEqu]) annotation (Line(points={{-108, + -80},{-80,-80},{-80,-100},{-72,-100}}, color={255,0,255})); + connect(phValOutIso.y, enaLeaHdrPri.u1ValIso[nEqu + 1:2*nEqu]) + annotation (Line(points={{-108,-120},{-80,-120},{-80,-100},{-72,-100}}, + color={255,0,255})); + connect(u1ValOutIso, phValOutIso.u) + annotation (Line(points={{-180,-120},{-132,-120}}, + color={255,0,255})); + connect(u1ValOutIso, phValInlIso.uPh) annotation (Line(points={{-180,-120},{ + -146,-120},{-146,-86},{-132,-86}}, + color={255,0,255})); + connect(u1ValInlIso, phValOutIso.uPh) annotation (Line(points={{-180,-80},{ + -152,-80},{-152,-126},{-132,-126}}, + color={255,0,255})); + connect(u1Pla, nPumHdrDp.u1Lea) + annotation (Line(points={{-180,140},{-20,140},{-20,-14},{-12,-14}},color={255,0,255})); + connect(enaLeaHdrPri.y1, booToInt1.u) + annotation (Line(points={{-48,-100},{-40,-100},{-40,-62}}, + color={255,0,255})); + connect(nPumHdrPriNotDp0.y, nPumHdrPriNotDp.u1) + annotation (Line(points={{-78,100},{-60,100},{-60,106},{-12,106}},color={255,127,0})); + connect(booToInt1.y, nPumHdrPriNotDp.u2) + annotation (Line(points={{-40,-38},{-40,94},{-12,94}}, color={255,127,0})); + connect(sorRunTimHdr.yIdx[1], y1LeaHdr_actual.index) + annotation (Line(points={{12,14},{40,14},{40,28}},color={255,127,0})); + connect(u1Pum_actual, sorRunTimHdr.u1Run) + annotation (Line(points={{-180,20},{-16,20},{-16,26},{-12,26}},color={255,0,255})); + connect(enaHdr.y1, y1) + annotation (Line(points={{72,-20},{140,-20},{140,-60},{180,-60}},color={255,0,255})); + connect(nPumHdrDp.y, enaHdr.uSta) + annotation (Line(points={{12,-20},{48,-20}},color={255,127,0})); + connect(nPumHdrPriNotDp.y, enaHdr.uSta) + annotation (Line(points={{12,100},{20,100},{20,-20},{48,-20}},color={255,127,0})); + connect(u1Ava.y, enaHdr.u1Ava) + annotation (Line(points={{12,-100},{20,-100},{20,-26},{48,-26}}, + color={255,0,255})); + connect(sorRunTimHdr.yIdx, enaHdr.uIdxAltSor) + annotation (Line(points={{12,14},{40,14},{40,-14},{48,-14}},color={255,127,0})); + connect(sigPumPriDed.y, y1) annotation (Line(points={{12,-140},{140,-140},{ + 140,-60},{180,-60}}, color={255,0,255})); + annotation ( + defaultComponentName="staPum", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-160,-160},{160,160}})), + Documentation( + info=" +
Plants with headered primary pumps that are not controlled to maintain differential pressure or flow setpoint
+

+Primary pumps are lead/lag alternated as described in + +Buildings.Templates.Plants.Controls.StagingRotation.SortRuntime. +

+

+The lead primary pump is enabled as described in + +Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered. +

+

+The number of operating primary pumps matches the number of operating +equipment. +

+
Plants with headered primary pumps that are controlled to maintain differential pressure or flow setpoint
+

+Primary pumps are lead/lag alternated as described in + +Buildings.Templates.Plants.Controls.StagingRotation.SortRuntime. +

+

+The lead primary pump is enabled as described in + +Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered. +

+Primary pumps are staged as described in + +Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeaderedDeltaP. +

+
Plants with headered secondary pumps
+

+Secondary pumps are lead/lag alternated as described in + +Buildings.Templates.Plants.Controls.StagingRotation.SortRuntime. +

+

+The lead secondary pump is enabled when the plant is enabled. +Otherwise, the lead secondary pump is disabled. +

+Secondary pumps are staged as described in + +Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeaderedDeltaP. +

+

Details

+

+At its current stage of development, this block contains no +logic for handling faulted equipment. +It is therefore assumed that all pumps are available at all times. +

+

+To simplify integration into the plant controller this block also +serves as a pass-through for the dedicated primary pump command signal +that is generated in + +Buildings.Templates.Plants.Controls.StagingRotation.EventSequencing. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end StagingHeadered; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeaderedDeltaP.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeaderedDeltaP.mo new file mode 100644 index 00000000000..3775466401a --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/StagingHeaderedDeltaP.mo @@ -0,0 +1,230 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic; +block StagingHeaderedDeltaP + "Staging logic for headered variable speed pumps using ∆p pump speed control" + parameter Integer nPum( + final min=1) + "Number of pumps that operate at design conditions" + annotation (Evaluate=true); + parameter Real V_flow_nominal( + final min=1E-6, + final unit="m3/s") + "Design flow rate"; + parameter Real dtRun( + final min=0, + final unit="s")=10 * 60 + "Runtime before triggering stage command"; + parameter Real dVOffUp( + final min=0, + final max=1, + final unit="1")=0.03 + "Stage up flow point offset"; + parameter Real dVOffDow( + final min=0, + final max=1, + final unit="1")=dVOffUp + "Stage down flow point offset"; + Buildings.Controls.OBC.CDL.Interfaces.RealInput V_flow( + final unit="m3/s") + "Flow rate" + annotation (Placement(transformation(extent={{-160,-20},{-120,20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Up + "Stage up command" + annotation (Placement(transformation(extent={{120,20},{160,60}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Dow + "Stage down command" + annotation (Placement(transformation(extent={{120,-60},{160,-20}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1_actual[nPum] + "Pump status" + annotation (Placement(transformation(extent={{-160,80},{-120,120}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter norV( + final k=1 / V_flow_nominal) + "Normalize to design value" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter norN( + final k=1 / nPum) + "Normalize to design value" + annotation (Placement(transformation(extent={{-60,30},{-40,50}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[nPum] + "Convert to real value" + annotation (Placement(transformation(extent={{-90,90},{-70,110}}))); + Buildings.Controls.OBC.CDL.Reals.Greater gre + "Compare to stage up flow point" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + Buildings.Controls.OBC.CDL.Reals.Less les + "Compare to stage down flow point" + annotation (Placement(transformation(extent={{30,-50},{50,-30}}))); + Buildings.Controls.OBC.CDL.Reals.AddParameter poiDow( + p=- 1 / nPum - dVOffDow) + "Calculate stage down flow point" + annotation (Placement(transformation(extent={{-20,10},{0,30}}))); + Buildings.Controls.OBC.CDL.Reals.AddParameter poiUp( + p=- dVOffUp) + "Calculate stage up flow point" + annotation (Placement(transformation(extent={{-20,50},{0,70}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset runUp( + final t=dtRun) + "Return true if stage up condition is true for specified duration" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset runDow( + final t=dtRun) + "Return true if stage down condition is true for specified duration" + annotation (Placement(transformation(extent={{70,-50},{90,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Change cha[nPum] + "Return true when pump status changes" + annotation (Placement(transformation(extent={{-90,-70},{-70,-50}}))); + Buildings.Controls.OBC.CDL.Reals.MultiSum nOpe( + nin=nPum) + "Return number of operating pumps" + annotation (Placement(transformation(extent={{-60,90},{-40,110}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyCha( + nin=nPum) + "Return true when any pump status changes" + annotation (Placement(transformation(extent={{-50,-70},{-30,-50}}))); +equation + connect(norN.y, poiDow.u) + annotation (Line(points={{-38,40},{-30,40},{-30,20},{-22,20}},color={0,0,127})); + connect(norN.y, poiUp.u) + annotation (Line(points={{-38,40},{-30,40},{-30,60},{-22,60}},color={0,0,127})); + connect(norV.y, gre.u1) + annotation (Line(points={{-38,0},{28,0}},color={0,0,127})); + connect(poiUp.y, gre.u2) + annotation (Line(points={{2,60},{20,60},{20,-8},{28,-8}},color={0,0,127})); + connect(poiDow.y, les.u2) + annotation (Line(points={{2,20},{10,20},{10,-48},{28,-48}},color={0,0,127})); + connect(norV.y, les.u1) + annotation (Line(points={{-38,0},{0,0},{0,-40},{28,-40}},color={0,0,127})); + connect(les.y, runDow.u) + annotation (Line(points={{52,-40},{68,-40}},color={255,0,255})); + connect(V_flow, norV.u) + annotation (Line(points={{-140,0},{-62,0}},color={0,0,127})); + connect(gre.y, runUp.u) + annotation (Line(points={{52,0},{68,0}},color={255,0,255})); + connect(runUp.passed, y1Up) + annotation (Line(points={{92,-8},{100,-8},{100,40},{140,40}},color={255,0,255})); + connect(runDow.passed, y1Dow) + annotation (Line(points={{92,-48},{100,-48},{100,-40},{140,-40}},color={255,0,255})); + connect(booToRea.y, nOpe.u) + annotation (Line(points={{-68,100},{-62,100}},color={0,0,127})); + connect(u1_actual, booToRea.u) + annotation (Line(points={{-140,100},{-92,100}},color={255,0,255})); + connect(u1_actual, cha.u) + annotation (Line(points={{-140,100},{-100,100},{-100,-60},{-92,-60}},color={255,0,255})); + connect(nOpe.y, norN.u) + annotation (Line(points={{-38,100},{-30,100},{-30,70},{-70,70},{-70,40},{-62,40}}, + color={0,0,127})); + connect(cha.y, anyCha.u) + annotation (Line(points={{-68,-60},{-52,-60}},color={255,0,255})); + connect(anyCha.y, runUp.reset) + annotation (Line(points={{-28,-60},{60,-60},{60,-8},{68,-8}},color={255,0,255})); + connect(anyCha.y, runDow.reset) + annotation (Line(points={{-28,-60},{60,-60},{60,-48},{68,-48}},color={255,0,255})); + annotation ( + defaultComponentName="staPum", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation( + info=" +

+Pumps are staged as a function of the ratio ratV_flow +of current volume flow rate V_flow to design volume +flow rate V_flow_nominal, +the number of operating pumps nPum_actual +and the number of pumps that operate at design conditions +nPum. +Pumps are assumed to be equally sized. +

+FR = V_flow / V_flow_nominal +

+

+The next lag pump is enabled whenever the following is true for +dtRun: +

+

+FR > nPum_actual / nPum − dVOffUp +

+

+The last lag pump is disabled whenever the following is true for +dtRun: +

+

+FR < (nPum_actual - 1) / nPum − dVOffDow +

+

+If desired, the stage down flow point dVOffDow can be +offset slightly below the stage up point dVOffUp to +prevent cycling between pump stages in applications with highly variable loads. +

+

+The timers are reset to zero when the status of a pump changes. +This is necessary to ensure the minimum pump runtime with rapidly changing loads. +

+

Details

+

This logic is prescribed in ASHRAE, 2021 for:

+
    +
  • +headered variable speed primary pumps in primary-only chiller +and boiler plants using differential pressure pump speed control, +
  • +
  • +variable speed secondary pumps in primary-secondary chiller plants +with one or more sets of secondary loop pumps serving downstream +control valves, +
  • +
  • +variable speed secondary pumps in primary-secondary boiler +plants with serving a secondary loop with a flow meter. +
  • +
+

+For other plant configurations, the pumps are staged with the equipment, +i.e., the number of pumps matches the number of chillers or boilers. +The actual logic for generating the pump enable commands is part of the +staging event sequencing. +

+

+A \"if\" condition is used to generate the stage up and down command as opposed +to a \"when\" condition. This means that the command remains true as long as the +condition is verified. This is necessary, for example, if no higher stage is +available when a stage up command is triggered. Using a \"when\" condition – +which is only valid at the point in time at which the condition becomes true – +would prevent the plant from staging when a higher stage becomes available again. +To avoid multiple consecutive stage changes, the block that receives the stage up +and down command and computes the stage index must enforce a minimum stage runtime +of dtRun. +

+

References

+
    +
  • +ASHRAE, 2021. Guideline 36-2021, High-Performance Sequences of Operation +for HVAC Systems. Atlanta, GA. +
  • +
+ +", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Diagram( + coordinateSystem( + extent={{-120,-120},{120,120}}))); +end StagingHeaderedDeltaP; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ControlDifferentialPressure.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ControlDifferentialPressure.mo new file mode 100644 index 00000000000..e1a3f325eac --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ControlDifferentialPressure.mo @@ -0,0 +1,152 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic.Validation; +model ControlDifferentialPressure + "Validation model for the differential pressure control of variable speed pumps" + parameter Integer nPum=4 + "Number of primary pumps that operate at design conditions"; + parameter Real VPri_flow_nominal=0.1 + "Design primary flow rate"; + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratDp( + table=[ + 0, 0.1, 0.5; + 1, 1, 0.5; + 1.5, 1, 0.2; + 2, 0.1, 0.1], + timeScale=3600) + "Differential pressure ratio to design value" + annotation (Placement(transformation(extent={{-90,10},{-70,30}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Pum( + table=[ + 0, 0, 0; + 2000, 1, 0; + 6000, 0, 1; + 8000, 0, 0], + period=8400) + "Pump status" + annotation (Placement(transformation(extent={{-90,50},{-70,70}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter dpRemSet[2]( + k={3E4, 2E4}) + "Differential pressure setpoint" + annotation (Placement(transformation(extent={{-48,10},{-28,30}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.ControlDifferentialPressure ctlDpRem( + have_senDpRemWir=true, + nPum=2, + nSenDpRem=2) + "Differential pressure control with remote sensors hardwired to the plant controller" + annotation (Placement(transformation(extent={{70,10},{90,30}}))); + Buildings.Controls.OBC.CDL.Reals.MultiMax mulMax( + nin=2) + "Maximum value" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter dpLoc( + final k=5) + "Differential pressure local to the plant" + annotation (Placement(transformation(extent={{30,-90},{50,-70}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.ControlDifferentialPressure ctlDpLoc( + have_senDpRemWir=false, + nPum=2, + nSenDpRem=2) + "Differential pressure control without remote sensors hardwired to the plant controller" + annotation (Placement(transformation(extent={{70,-50},{90,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin[2]( + amplitude=0.1 * dpRemSet.k, + freqHz={2 / 8000, 4 / 8000}, + each phase=3.1415926535898) + "Source signal used to generate measurement values" + annotation (Placement(transformation(extent={{-88,-50},{-68,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Add dpRem[2] + "Differential pressure at remote location" + annotation (Placement(transformation(extent={{-48,-30},{-28,-10}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter dpLocSet[2]( + each final k=5) + "Local differential pressure setpoint" + annotation (Placement(transformation(extent={{30,-50},{50,-30}}))); +equation + connect(y1Pum.y, ctlDpRem.y1_actual) + annotation (Line(points={{-68,60},{60,60},{60,28},{68,28}},color={255,0,255})); + connect(mulMax.y, dpLoc.u) + annotation (Line(points={{12,-80},{28,-80}},color={0,0,127})); + connect(y1Pum.y, ctlDpLoc.y1_actual) + annotation (Line(points={{-68,60},{60,60},{60,-32},{68,-32}},color={255,0,255})); + connect(dpLoc.y, ctlDpLoc.dpLoc) + annotation (Line(points={{52,-80},{60,-80},{60,-48},{68,-48}},color={0,0,127})); + connect(ratDp.y, dpRemSet.u) + annotation (Line(points={{-68,20},{-50,20}},color={0,0,127})); + connect(sin.y, dpRem.u2) + annotation (Line(points={{-66,-40},{-60,-40},{-60,-26},{-50,-26}},color={0,0,127})); + connect(dpRemSet.y, dpRem.u1) + annotation (Line(points={{-26,20},{-20,20},{-20,0},{-60,0},{-60,-14},{-50,-14}}, + color={0,0,127})); + connect(dpRemSet.y, ctlDpRem.dpRemSet) + annotation (Line(points={{-26,20},{40,20},{40,24},{68,24}},color={0,0,127})); + connect(dpRem.y, ctlDpRem.dpRem) + annotation (Line(points={{-26,-20},{50,-20},{50,20},{68,20}},color={0,0,127})); + connect(dpRem.y, mulMax.u) + annotation (Line(points={{-26,-20},{-20,-20},{-20,-80},{-12,-80}},color={0,0,127})); + connect(dpRemSet.y, dpLocSet.u) + annotation (Line(points={{-26,20},{20,20},{20,-40},{28,-40}},color={0,0,127})); + connect(dpLocSet.y, ctlDpLoc.dpLocSet) + annotation (Line(points={{52,-40},{60,-40},{60,-44},{68,-44}},color={0,0,127})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/ControlDifferentialPressure.mos" + "Simulate and plot"), + experiment( + StopTime=8400.0, + Tolerance=1e-06), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Pumps.Generic.ControlDifferentialPressure +in a configuration with two pumps and two remote DP sensors that either are +hardwired to the controller (component ctlDpRem) +or are not hardwired to the controller, which uses a local DP sensor instead +(component ctlDpLoc). +

+

+The simulation of this model shows that when any pump is proven on, +the controller is enabled and its output is +initially set to the minimum pump speed y_min. +The minimum pump speed sets the lower limit of the controller output +for the entire time that the controller is enabled. +The output of the controller ctlDpRem is driven by the most +demanding remote DP control loop, e.g., +the controller output only drops when both loop input measurements are +above setpoints. +Without remote sensors hardwired to the controller, the pump speed is +driven by the highest local DP setpoint. +

+

+When no pump is proven on, the controller is disabled and its output +is set to 0 %. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + graphics={ + Polygon( + points={{214,66},{214,66}}, + lineColor={28,108,200})})); +end ControlDifferentialPressure; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ResetLocalDifferentialPressure.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ResetLocalDifferentialPressure.mo new file mode 100644 index 00000000000..756bdd1a10f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/ResetLocalDifferentialPressure.mo @@ -0,0 +1,97 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic.Validation; +model ResetLocalDifferentialPressure + "Validation model for the local differential pressure reset" + parameter Integer nPum=4 + "Number of primary pumps that operate at design conditions"; + parameter Real VPri_flow_nominal=0.1 + "Design primary flow rate"; + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratDp( + table=[ + 0, 0.1; + 1, 1; + 1.5, 1; + 2, 0.1], + timeScale=3600) + "Differential pressure ratio to design value" + annotation (Placement(transformation(extent={{-90,10},{-70,30}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter dpRemSet( + k=3E4) + "Differential pressure setpoint" + annotation (Placement(transformation(extent={{-48,10},{-28,30}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.ResetLocalDifferentialPressure resDpLoc( + dpLocSet_max=1E5, + Ti=10) + "Local differential pressure reset" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin( + amplitude=0.1 * dpRemSet.k, + freqHz=4 / 8000, + phase=3.1415926535898) + "Source signal used to generate measurement values" + annotation (Placement(transformation(extent={{-88,-50},{-68,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Add dpRem + "Differential pressure at remote location" + annotation (Placement(transformation(extent={{20,-30},{40,-10}}))); +equation + connect(sin.y, dpRem.u2) + annotation (Line(points={{-66,-40},{0,-40},{0,-26},{18,-26}},color={0,0,127})); + connect(dpRemSet.y, resDpLoc.dpRemSet) + annotation (Line(points={{-26,20},{60,20},{60,6},{68,6}},color={0,0,127})); + connect(dpRem.y, resDpLoc.dpRem) + annotation (Line(points={{42,-20},{60,-20},{60,-6},{68,-6}}, + color={0,0,127})); + connect(dpRemSet.y, dpRem.u1) + annotation (Line(points={{-26,20},{0,20},{0,-14},{18,-14}},color={0,0,127})); + connect(ratDp.y[1], dpRemSet.u) + annotation (Line(points={{-68,20},{-50,20}},color={0,0,127})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/ResetLocalDifferentialPressure.mos" + "Simulate and plot"), + experiment( + StopTime=8400.0, + Tolerance=1e-06), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Pumps.Generic.ResetLocalDifferentialPressure. +

+

+The simulation of this model shows how the local DP +setpoint is reset by the controller resDpLoc +based on the variation of the remote differential pressure +around its setpoint. +The local DP setpoint remains bounded by +resDpLoc.dpLocSet_min and resDpLoc.dpLocSet_max. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + graphics={ + Polygon( + points={{214,66},{214,66}}, + lineColor={28,108,200})})); +end ResetLocalDifferentialPressure; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeadered.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeadered.mo new file mode 100644 index 00000000000..177119415fb --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeadered.mo @@ -0,0 +1,181 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic.Validation; +model StagingHeadered + "Validation model for staging of headered pumps" + parameter Integer nEqu=3 + "Number of plant equipment"; + parameter Integer nPum=nEqu + "Number of pumps that operate at design conditions"; + parameter Real V_flow_nominal=0.1 + "Design flow rate"; + Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered staPumPriDp( + is_pri=true, + is_hdr=true, + is_ctlDp=true, + have_valInlIso=true, + have_valOutIso=true, + final nEqu=nEqu, + final nPum=nPum, + final V_flow_nominal=V_flow_nominal) + "Pump staging – Headered primary pumps with ∆p control" + annotation (Placement(transformation(extent={{0,-50},{20,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratFlo(table=[0,0; 1,1; 1.5, + 1; 2,0], timeScale=3600) "Flow ratio to design value" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter VPri_flow(final k= + V_flow_nominal) + "Flow rate" + annotation (Placement(transformation(extent={{-68,-10},{-48,10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[nPum] + "Convert command signal to real value" + annotation (Placement(transformation(extent={{80,70},{60,90}}))); + Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold zerOrdHol[nPum](each + samplePeriod=1) + "Hold signal value" + annotation (Placement(transformation(extent={{50,70},{30,90}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr[nPum] + "Compare to zero to compute equipment status" + annotation (Placement(transformation(extent={{20,70},{0,90}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1( + table=[0,0,0,0; 0.1,1,0,0; 0.5,1,1,0; 1,1,1,1; 1.5,1,1,1; 2,0,1,1; 2.5,0,0,1; + 3,0,0,0], + timeScale=3600, + period=10800) + "Command signal – Plant, equipment or isolation valve depending on tested configuration" + annotation (Placement(transformation(extent={{-110,30},{-90,50}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered staPumSecDp( + is_pri=false, + is_hdr=true, + is_ctlDp=true, + have_valInlIso=true, + have_valOutIso=true, + final nEqu=nEqu, + final nPum=nPum, + final V_flow_nominal=V_flow_nominal) + "Pump staging – Headered primary pumps with ∆p control" + annotation (Placement(transformation(extent={{0,-90},{20,-70}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered staPumPriNoDp( + is_pri=true, + is_hdr=true, + is_ctlDp=false, + have_valInlIso=true, + have_valOutIso=false, + final nEqu=nEqu, + final nPum=nPum, + final V_flow_nominal=V_flow_nominal) + "Pump staging – Headered primary pumps without ∆p control" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered staPumPriDed( + is_pri=true, + is_hdr=false, + is_ctlDp=false, + have_valInlIso=true, + have_valOutIso=false, + final nEqu=nEqu, + final nPum=nPum, + final V_flow_nominal=V_flow_nominal) + "Pump staging – Dedicated primary pumps" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); +equation + connect(ratFlo.y[1],VPri_flow. u) + annotation (Line(points={{-88,0},{-70,0}},color={0,0,127})); + connect(VPri_flow.y, staPumPriDp.V_flow) annotation (Line(points={{-46,0},{-40, + 0},{-40,-48},{-2,-48}}, color={0,0,127})); + connect(booToRea.y,zerOrdHol. u) + annotation (Line(points={{58,80},{52,80}}, + color={0,0,127})); + connect(zerOrdHol.y,greThr. u) + annotation (Line(points={{28,80},{22,80}}, color={0,0,127})); + connect(staPumPriDp.y1, booToRea.u) annotation (Line(points={{22,-40},{100,-40}, + {100,80},{82,80}}, color={255,0,255})); + connect(greThr.y, staPumPriDp.u1Pum_actual) annotation (Line(points={{-2,80},{ + -20,80},{-20,-44},{-2,-44}}, color={255,0,255})); + connect(u1.y, staPumPriDp.u1ValInlIso) annotation (Line(points={{-88,40},{-30, + 40},{-30,-36},{-2,-36}}, color={255,0,255})); + connect(u1.y, staPumPriDp.u1ValOutIso) annotation (Line(points={{-88,40},{-30, + 40},{-30,-38},{-2,-38}}, color={255,0,255})); + connect(u1.y[1], staPumSecDp.u1Pla) annotation (Line(points={{-88,40},{-30,40}, + {-30,-72},{-2,-72}}, color={255,0,255})); + connect(greThr.y, staPumSecDp.u1Pum_actual) annotation (Line(points={{-2,80},{ + -20,80},{-20,-84},{-2,-84}}, color={255,0,255})); + connect(VPri_flow.y, staPumSecDp.V_flow) annotation (Line(points={{-46,0},{-40, + 0},{-40,-88},{-2,-88}}, color={0,0,127})); + connect(u1.y, staPumPriNoDp.u1ValInlIso) annotation (Line(points={{-88,40},{-30, + 40},{-30,4},{-2,4}}, color={255,0,255})); + connect(u1.y, staPumPriNoDp.u1Pum) annotation (Line(points={{-88,40},{-30,40}, + {-30,-2},{-2,-2}}, color={255,0,255})); + connect(greThr.y, staPumPriNoDp.u1Pum_actual) annotation (Line(points={{-2,80}, + {-20,80},{-20,-4},{-2,-4}}, color={255,0,255})); + connect(u1.y, staPumPriDed.u1Pum) annotation (Line(points={{-88,40},{-30,40},{ + -30,38},{-2,38}}, color={255,0,255})); + connect(greThr.y, staPumPriDed.u1Pum_actual) annotation (Line(points={{-2,80}, + {-20,80},{-20,36},{-2,36}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeadered.mos" + "Simulate and plot"), + experiment( + StopTime=10800.0, + Tolerance=1e-06), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered +with three plant equipment and three pumps and for the following configurations. +

+
    +
  • +Dedicated primary pumps (component staPumPriDed): +the number of pumps commanded on matches the number of operating +equipment with a one-to-one relationship. +
  • +
  • +Headered primary pumps without ∆p control (component staPumPriNoDp): +the number of pumps commanded on matches the number of operating +equipment without a one-to-one relationship. +
  • +
  • +Headered primary pumps with ∆p control (component staPumPriDp): +the number of pumps commanded on does not match the number of operating +equipment but is rather related to the fractional flow rate. +The simulation also exhibits the lead/lag rotation of the primary pumps. +
  • +
  • +Headered secondary pumps with ∆p control (component staPumSecDp): +the number of pumps commanded on does not match the number of operating +equipment but is rather related to the fractional flow rate. +All pumps are disabled when the plant is disabled. +
  • +
+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + extent={{-120,-100},{120,100}}), + graphics={ + Polygon( + points={{214,66},{214,66}}, + lineColor={28,108,200})})); +end StagingHeadered; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeaderedDeltaP.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeaderedDeltaP.mo new file mode 100644 index 00000000000..2811f125c7a --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeaderedDeltaP.mo @@ -0,0 +1,138 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic.Validation; +model StagingHeaderedDeltaP + "Validation model for staging of headered variable speed pumps using ∆p pump speed control" + parameter Integer nPum=4 + "Number of pumps that operate at design conditions"; + parameter Real V_flow_nominal=0.1 + "Design flow rate"; + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratFlo( + table=[ + 0, 0; + 1, 1; + 1.5, 1; + 2, 0], + timeScale=3600) + "Flow ratio to design value" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable enaLea( + table=[ + 0, 1; + 8000, 0], + period=8400) + "Lead pump enable signal" + annotation (Placement(transformation(extent={{-110,30},{-90,50}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter VPri_flow( + final k=V_flow_nominal) + "Flow rate" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeaderedDeltaP staPum( + final nPum=nPum, + final V_flow_nominal=V_flow_nominal) + "Pump staging" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Utilities.StageIndex idxSta( + have_inpAva=false, + final nSta=nPum, + final dtRun=staPum.dtRun) + "Calculate stage index = number of enabled pumps" + annotation (Placement(transformation(extent={{50,-10},{70,10}}))); + Buildings.Controls.OBC.CDL.Integers.GreaterEqualThreshold y1[nPum]( + final t={i for i in 1:nPum}) + "Pump command" + annotation (Placement(transformation(extent={{62,50},{42,70}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator rep( + nout=nPum) + "Replicate signal" + annotation (Placement(transformation(extent={{92,50},{72,70}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[nPum] + "Convert command signal to real value" + annotation (Placement(transformation(extent={{32,50},{12,70}}))); + Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold zerOrdHol[nPum]( + each samplePeriod=1) + "Hold signal value" + annotation (Placement(transformation(extent={{2,50},{-18,70}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr[nPum] + "Compare to zero to compute equipment status" + annotation (Placement(transformation(extent={{-28,50},{-48,70}}))); +equation + connect(ratFlo.y[1], VPri_flow.u) + annotation (Line(points={{-88,0},{-42,0}},color={0,0,127})); + connect(VPri_flow.y, staPum.V_flow) + annotation (Line(points={{-18,0},{-10,0},{-10,-6},{-2,-6}},color={0,0,127})); + connect(staPum.y1Up, idxSta.u1Up) + annotation (Line(points={{22,6},{40,6},{40,2},{48,2}},color={255,0,255})); + connect(staPum.y1Dow, idxSta.u1Dow) + annotation (Line(points={{22,-6},{40,-6},{40,-2},{48,-2}},color={255,0,255})); + connect(rep.y, y1.u) + annotation (Line(points={{70,60},{64,60}},color={255,127,0})); + connect(enaLea.y[1], idxSta.u1Lea) + annotation (Line(points={{-88,40},{40,40},{40,6},{48,6}},color={255,0,255})); + connect(idxSta.y, rep.u) + annotation (Line(points={{72,0},{100,0},{100,60},{94,60}},color={255,127,0})); + connect(y1.y, booToRea.u) + annotation (Line(points={{40,60},{34,60}},color={255,0,255})); + connect(booToRea.y, zerOrdHol.u) + annotation (Line(points={{10,60},{4,60}},color={0,0,127})); + connect(zerOrdHol.y, greThr.u) + annotation (Line(points={{-20,60},{-26,60}},color={0,0,127})); + connect(greThr.y, staPum.u1_actual) + annotation (Line(points={{-50,60},{-60,60},{-60,20},{-10,20},{-10,6},{-2,6}}, + color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Generic/Validation/StagingHeaderedDeltaP.mos" + "Simulate and plot"), + experiment( + StopTime=8400.0, + Tolerance=1e-06), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeaderedDeltaP +in a configuration with four pumps. +

+

+The simulation of this model shows that when the lead pump is enabled, +the output of the staging controller is greater than or equal to one. +The number of enabled pumps increases and decreases with the varying +flow rate and under the condition of a minimum runtime of 10 min. +It remains greater than or equal to one as long as the lead pump remains +enabled. +

+

+When the lead pump is disabled, the number of enabled pumps is set +to 0. This transition is not subject to the minimum runtime. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + extent={{-120,-100},{120,100}}), + graphics={ + Polygon( + points={{214,66},{214,66}}, + lineColor={28,108,200})})); +end StagingHeaderedDeltaP; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.mo new file mode 100644 index 00000000000..7651e5bcdb1 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.mo @@ -0,0 +1,29 @@ +within Buildings.Templates.Plants.Controls.Pumps.Generic; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), + Documentation( + info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.order b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.order new file mode 100644 index 00000000000..6071ceab043 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/Validation/package.order @@ -0,0 +1,4 @@ +ControlDifferentialPressure +ResetLocalDifferentialPressure +StagingHeadered +StagingHeaderedDeltaP diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/package.mo b/Buildings/Templates/Plants/Controls/Pumps/Generic/package.mo new file mode 100644 index 00000000000..6d707adf50c --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/package.mo @@ -0,0 +1,8 @@ +within Buildings.Templates.Plants.Controls.Pumps; +package Generic + annotation (Documentation(info=" +

+This package contains control sequences for primary or secondary pumps. +

+")); +end Generic; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Generic/package.order b/Buildings/Templates/Plants/Controls/Pumps/Generic/package.order new file mode 100644 index 00000000000..530b96ee682 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Generic/package.order @@ -0,0 +1,5 @@ +ControlDifferentialPressure +ResetLocalDifferentialPressure +StagingHeadered +StagingHeaderedDeltaP +Validation diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/EnableLeadHeadered.mo b/Buildings/Templates/Plants/Controls/Pumps/Primary/EnableLeadHeadered.mo new file mode 100644 index 00000000000..ed16681af43 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/EnableLeadHeadered.mo @@ -0,0 +1,199 @@ +within Buildings.Templates.Plants.Controls.Pumps.Primary; +block EnableLeadHeadered + "Lead primary pump enable/disable for plants with headered primary pumps" + parameter Buildings.Templates.Plants.Controls.Types.EquipmentConnection typCon + "Type of connection between equipment and primary loop" + annotation (Evaluate=true); + parameter Buildings.Templates.Plants.Controls.Types.Actuator typValIso= + Buildings.Templates.Plants.Controls.Types.Actuator.TwoPosition + "Type of isolation valve" + annotation (Evaluate=true); + parameter Integer nValIso( + final min=1) + "Number of isolation valves" + annotation (Evaluate=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1ValIso[nValIso] + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.TwoPosition + "Isolation valve command" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput uValIso[nValIso] + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.Modulating + "Isolation valve command" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1 + "Lead pump enable signal" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyOpePar( + nin=nValIso) + if typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel + "Return true if any valve is commanded open - Parallel piped equipment" + annotation (Placement(transformation(extent={{10,-10},{30,10}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd allCloPar( + nin=nValIso) + if typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel + "Return true if all valves are commanded closed - Parallel piped equipment" + annotation (Placement(transformation(extent={{10,-50},{30,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Not cloParMod[nValIso] + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.Modulating + and typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel + "Return true if valve is commanded closed" + annotation (Placement(transformation(extent={{-30,-50},{-10,-30}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold opeParMod[nValIso]( + each final t=0) + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.Modulating + and typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel + "Return true if valve commanded > 0 % open" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Latch lat + "Clear enable signal if disable conditions are met" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyCloSer( + nin=nValIso) + if typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Series + "Return true if any valve is commanded closed - Series piped equipment" + annotation (Placement(transformation(extent={{10,70},{30,90}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd allOpeSer( + nin=nValIso) + if typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Series + "Return true if all valves are commanded open - Series piped equipment" + annotation (Placement(transformation(extent={{10,30},{30,50}}))); + Buildings.Controls.OBC.CDL.Reals.LessThreshold cloSerMod[nValIso]( + each final t=0.99) + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.Modulating + and typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Series + "Return true if valve commanded < 99 % open" + annotation (Placement(transformation(extent={{-80,-90},{-60,-70}}))); + Buildings.Controls.OBC.CDL.Logical.Not opeSerMod[nValIso] + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.Modulating + and typCon == Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Series + "Return true if valve is commanded open" + annotation (Placement(transformation(extent={{-30,-90},{-10,-70}}))); + Buildings.Controls.OBC.CDL.Logical.Not cloTwo[nValIso] + if typValIso == Buildings.Templates.Plants.Controls.Types.Actuator.TwoPosition + "Return true if valve is commanded closed" + annotation (Placement(transformation(extent={{-30,10},{-10,30}}))); +equation + connect(uValIso, opeParMod.u) + annotation (Line(points={{-120,-40},{-82,-40}},color={0,0,127})); + connect(opeParMod.y, cloParMod.u) + annotation (Line(points={{-58,-40},{-32,-40}},color={255,0,255})); + connect(lat.y, y1) + annotation (Line(points={{92,0},{120,0}},color={255,0,255})); + connect(anyOpePar.y, lat.u) + annotation (Line(points={{32,0},{68,0}},color={255,0,255})); + connect(allCloPar.y, lat.clr) + annotation (Line(points={{32,-40},{50,-40},{50,-6},{68,-6}},color={255,0,255})); + connect(allOpeSer.y, lat.clr) + annotation (Line(points={{32,40},{50,40},{50,-6},{68,-6}},color={255,0,255})); + connect(anyCloSer.y, lat.u) + annotation (Line(points={{32,80},{60,80},{60,0},{68,0}},color={255,0,255})); + connect(uValIso, cloSerMod.u) + annotation (Line(points={{-120,-40},{-90,-40},{-90,-80},{-82,-80}},color={0,0,127})); + connect(cloSerMod.y, opeSerMod.u) + annotation (Line(points={{-58,-80},{-32,-80}},color={255,0,255})); + connect(u1ValIso, cloTwo.u) + annotation (Line(points={{-120,0},{-60,0},{-60,20},{-32,20}},color={255,0,255})); + connect(cloTwo.y, anyCloSer.u) + annotation (Line(points={{-8,20},{0,20},{0,80},{8,80}},color={255,0,255})); + connect(u1ValIso, anyOpePar.u) + annotation (Line(points={{-120,0},{8,0}},color={255,0,255})); + connect(cloTwo.y, allCloPar.u) + annotation (Line(points={{-8,20},{0,20},{0,-40},{8,-40}},color={255,0,255})); + connect(u1ValIso, allOpeSer.u) + annotation (Line(points={{-120,0},{0,0},{0,40},{8,40}},color={255,0,255})); + connect(cloParMod.y, allCloPar.u) + annotation (Line(points={{-8,-40},{0,-40},{0,-40},{8,-40}},color={255,0,255})); + connect(cloSerMod.y, anyCloSer.u) + annotation (Line(points={{-58,-80},{-40,-80},{-40,80},{8,80}},color={255,0,255})); + connect(opeSerMod.y, allOpeSer.u) + annotation (Line(points={{-8,-80},{0,-80},{0,40},{8,40}},color={255,0,255})); + connect(opeParMod.y, anyOpePar.u) + annotation (Line(points={{-58,-40},{-40,-40},{-40,0},{8,0}},color={255,0,255})); + annotation ( + defaultComponentName="enaLea", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation( + info=" +
+Plants with parallel piped equipment +
+

+The lead primary pump is enabled when any equipment isolation valve is commanded open. +

+

+The lead primary pump is disabled when all equipment isolation valves are commanded closed. +

+

+For modulating valves, the \"valve commanded open\" +condition is evaluated based on a command signal > 0 %. +The \"valve commanded closed\" condition is evaluated as the negation of the previous condition. +

+
+Plants with series piped equipment +
+

+The lead primary pump is enabled when any equipment isolation valve is commanded closed. +

+

+The lead primary pump is disabled when all equipment isolation valves are commanded open. +

+

+For modulating valves, the \"valve commanded closed\" +condition is evaluated based on a command signal < 100 %. +The \"valve commanded open\" condition is evaluated as the negation of the previous condition. +

+

Details

+

This logic is prescribed in ASHRAE, 2021 for: +

+
    +
  • +headered primary pumps in chiller plants with parallel chillers +and without a waterside economizer, +
  • +
  • +primary pumps in chiller plants with series chillers +and without a waterside economizer, +
  • +
  • +headered primary pumps in boiler plants. +
  • +
+

+The valve command is used in contrast to the feedback of the +valve position or the end switch status, as prescribed by Guideline 36. +This is for the sake of simplicity, as there is no harm in deadheading the pump +for a couple seconds and it simplifies the programming. +

+

+For modulating valves, the \"valve commanded open/closed\" condition is +evaluated without hysteresis because the +valve command signal is generated by the +enabling or staging logic and both use minimum runtime conditions. +Therefore, the valve command signal is not subject to any oscillatory +behavior. +

+

References

+
    +
  • +ASHRAE, 2021. Guideline 36-2021, High-Performance Sequences of Operation +for HVAC Systems. Atlanta, GA. +
  • +
+")); +end EnableLeadHeadered; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/EnableLeadHeadered.mo b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/EnableLeadHeadered.mo new file mode 100644 index 00000000000..72d39cf6bca --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/EnableLeadHeadered.mo @@ -0,0 +1,96 @@ +within Buildings.Templates.Plants.Controls.Pumps.Primary.Validation; +model EnableLeadHeadered + "Validation model for the enabling logic of headered primary pumps" + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse u1ValIso[2]( + period=60 * {20, 30}) + "Isolation valve command" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered enaSerTwo( + typCon=Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Series, + typValIso=Buildings.Templates.Plants.Controls.Types.Actuator.TwoPosition, + nValIso=2) + "Enable lead pump - Series piped equipment with two-position isolation valves" + annotation (Placement(transformation(extent={{50,-30},{70,-10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[2] + "Convert to real" + annotation (Placement(transformation(extent={{-40,-50},{-20,-30}}))); + Buildings.Controls.OBC.CDL.Reals.LimitSlewRate uValIso[2]( + each raisingSlewRate=1 / 200) + "Compute valve command" + annotation (Placement(transformation(extent={{0,-50},{20,-30}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered enaSerMod( + typCon=Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Series, + typValIso=Buildings.Templates.Plants.Controls.Types.Actuator.Modulating, + nValIso=2) + "Enable lead pump - Series piped equipment with modulating isolation valves" + annotation (Placement(transformation(extent={{50,-70},{70,-50}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered enaParTwo( + typCon=Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel, + typValIso=Buildings.Templates.Plants.Controls.Types.Actuator.TwoPosition, + nValIso=2) + "Enable lead pump - Parallel piped equipment with two-position isolation valves" + annotation (Placement(transformation(extent={{52,50},{72,70}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered enaParMod( + typCon=Buildings.Templates.Plants.Controls.Types.EquipmentConnection.Parallel, + typValIso=Buildings.Templates.Plants.Controls.Types.Actuator.Modulating, + nValIso=2) + "Enable lead pump - Parallel piped equipment with modulating isolation valves" + annotation (Placement(transformation(extent={{52,10},{72,30}}))); +equation + connect(u1ValIso.y, booToRea.u) + annotation (Line(points={{-58,0},{-50,0},{-50,-40},{-42,-40}},color={255,0,255})); + connect(booToRea.y, uValIso.u) + annotation (Line(points={{-18,-40},{-2,-40}},color={0,0,127})); + connect(u1ValIso.y, enaSerTwo.u1ValIso) + annotation (Line(points={{-58,0},{40,0},{40,-20},{48,-20}},color={255,0,255})); + connect(uValIso.y, enaSerMod.uValIso) + annotation (Line(points={{22,-40},{40,-40},{40,-66},{48,-66}},color={0,0,127})); + connect(u1ValIso.y, enaParTwo.u1ValIso) + annotation (Line(points={{-58,0},{40,0},{40,60},{50,60}},color={255,0,255})); + connect(uValIso.y, enaParMod.uValIso) + annotation (Line(points={{22,-40},{30,-40},{30,14},{50,14}},color={0,0,127})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Primary/Validation/EnableLeadHeadered.mos" + "Simulate and plot"), + experiment( + StopTime=3000.0, + Tolerance=1e-06), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Pumps.Primary.EnableLeadHeadered +in a configuration with two production units, either parallel piped +or series piped, with either two-position or modulating isolation valves. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + graphics={ + Polygon( + points={{214,66},{214,66}}, + lineColor={28,108,200})})); +end EnableLeadHeadered; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/VariableSpeedNoDpControl.mo b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/VariableSpeedNoDpControl.mo new file mode 100644 index 00000000000..397ff499750 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/VariableSpeedNoDpControl.mo @@ -0,0 +1,129 @@ +within Buildings.Templates.Plants.Controls.Pumps.Primary.Validation; +model VariableSpeedNoDpControl + "Validation model for the control logic of variable speed primary pumps without ∆p control" + Buildings.Templates.Plants.Controls.Pumps.Primary.VariableSpeedNoDpControl + ctlPumPriHdrHea( + have_heaWat=true, + have_chiWat=false, + have_pumPriHdr=true, + nPumHeaWatPri=2, + yPumHeaWatPriSet=0.8) "Headered primary pumps – Heating-only plant" + annotation (Placement(transformation(extent={{20,50},{40,70}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1( + table=[0,0,0; 0.1,1,0; 0.5,1,1; 1,1,1; 1.5,1,1; 2,0,1; 2.5,0,0; 3,0,0], + timeScale=300, + period=900) + "Command signal – Plant, equipment or isolation valve depending on tested configuration" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.VariableSpeedNoDpControl ctlPumPriHdr( + have_heaWat=true, + have_chiWat=true, + have_pumPriHdr=true, + nEqu=2, + nPumHeaWatPri=2, + nPumChiWatPri=2, + yPumHeaWatPriSet=0.8, + yPumChiWatPriSet=0.9) + "Headered primary pumps – Heating and cooling plant" + annotation (Placement(transformation(extent={{20,10},{40,30}}))); + Buildings.Controls.OBC.CDL.Logical.Not u1Coo[2] + "Opposite signal to generate cooling system commands" + annotation (Placement(transformation(extent={{-30,-10},{-10,10}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.VariableSpeedNoDpControl ctlPumPriDedCom( + have_heaWat=true, + have_chiWat=true, + have_pumChiWatPriDed=false, + have_pumPriHdr=false, + nEqu=2, + nPumHeaWatPri=2, + yPumHeaWatPriSet=0.8, + yPumChiWatPriSet=0.9) + "Common dedicated primary pumps – Heating and cooling plant" + annotation (Placement(transformation(extent={{20,-30},{40,-10}}))); + Buildings.Templates.Plants.Controls.Pumps.Primary.VariableSpeedNoDpControl ctlPumPriDedSep( + have_heaWat=true, + have_chiWat=true, + have_pumChiWatPriDed=true, + have_pumPriHdr=false, + nEqu=2, + nPumHeaWatPri=2, + nPumChiWatPri=2, + yPumHeaWatPriSet=0.8, + yPumChiWatPriSet=0.9) + "Separate dedicated primary pumps – Heating and cooling plant" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); +equation + connect(u1.y,ctlPumPriHdrHea. u1PumHeaWatPri) annotation (Line(points={{-58,0}, + {-40,0},{-40,66},{18,66}}, color={255,0,255})); + connect(u1.y, u1Coo.u) + annotation (Line(points={{-58,0},{-32,0}}, color={255,0,255})); + connect(u1Coo.y, ctlPumPriHdr.u1PumChiWatPri) + annotation (Line(points={{-8,0},{0,0},{0,20},{18,20}}, color={255,0,255})); + connect(u1.y, ctlPumPriHdr.u1PumHeaWatPri) annotation (Line(points={{-58,0},{-40, + 0},{-40,26},{18,26}}, color={255,0,255})); + connect(u1.y, ctlPumPriDedCom.u1PumHeaWatPri) annotation (Line(points={{-58,0}, + {-40,0},{-40,-14},{18,-14}}, color={255,0,255})); + connect(u1Coo.y, ctlPumPriDedCom.u1Hea) annotation (Line(points={{-8,0},{0,0}, + {0,-26},{18,-26}}, color={255,0,255})); + connect(u1.y, ctlPumPriDedSep.u1PumHeaWatPri) annotation (Line(points={{-58,0}, + {-40,0},{-40,-54},{18,-54}}, color={255,0,255})); + connect(u1Coo.y, ctlPumPriDedSep.u1PumChiWatPri) annotation (Line(points={{-8, + 0},{0,0},{0,-60},{18,-60}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Pumps/Primary/Validation/VariableSpeedNoDpControl.mos" + "Simulate and plot"), + experiment( + StopTime=900.0, + Tolerance=1e-06), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Pumps.Primary.VariableSpeedNoDpControl +with two plant equipment and two primary pumps and for the following configurations. +

+
    +
  • +Heating-only plant with headered primary pumps (component ctlPumPriHdrHea) +
  • +
  • +Heating and cooling plant with headered primary pumps (component ctlPumPriHdr) +
  • +
  • +Heating and cooling plant with common dedicated primary pumps (component ctlPumPriDedCom) +
  • +
  • +Heating and cooling plant with separate dedicated primary pumps (component ctlPumPriDedSep) +
  • +
+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + graphics={ + Polygon( + points={{214,66},{214,66}}, + lineColor={28,108,200})})); +end VariableSpeedNoDpControl; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.mo b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.mo new file mode 100644 index 00000000000..c10f41cb32a --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.mo @@ -0,0 +1,29 @@ +within Buildings.Templates.Plants.Controls.Pumps.Primary; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), + Documentation( + info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.order b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.order new file mode 100644 index 00000000000..7de919ee9d0 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/Validation/package.order @@ -0,0 +1,2 @@ +EnableLeadHeadered +VariableSpeedNoDpControl diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/VariableSpeedNoDpControl.mo b/Buildings/Templates/Plants/Controls/Pumps/Primary/VariableSpeedNoDpControl.mo new file mode 100644 index 00000000000..6001958af8c --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/VariableSpeedNoDpControl.mo @@ -0,0 +1,281 @@ +within Buildings.Templates.Plants.Controls.Pumps.Primary; +block VariableSpeedNoDpControl + "Variable speed primary pumps without differential pressure control" + parameter Boolean have_heaWat + "Set to true for plants that provide HW" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Boolean have_chiWat + "Set to true for plants that provide CHW" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + final parameter Boolean have_pumHeaWatPri=have_heaWat + "Set to true for plants with primary HW pumps" + annotation (Evaluate=true); + parameter Boolean have_pumChiWatPriDed(start=false) + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_chiWat and not have_pumPriHdr)); + final parameter Boolean have_pumChiWatPri= + have_chiWat and (have_pumPriHdr or have_pumChiWatPriDed) + "Set to true for plants with separate primary CHW pumps" + annotation (Evaluate=true); + parameter Boolean have_pumPriHdr + "Set to true for headered primary pumps, false for dedicated pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Integer nEqu(start=0) + "Number of equipment" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_heaWat and have_chiWat)); + parameter Integer nPumHeaWatPri + "Number of primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration")); + parameter Integer nPumChiWatPri(start=if have_chiWat and have_pumChiWatPri + then nEqu else 0) + "Number of primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Plant configuration", + enable=have_pumChiWatPri)); + parameter Real yPumHeaWatPriSet( + max=1, + min=0, + start=1, + unit="1") + "Primary pump speed providing design heat pump flow in heating mode" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=have_heaWat)); + parameter Real yPumChiWatPriSet( + max=1, + min=0, + start=1, + unit="1") + "Primary pump speed providing design heat pump flow in cooling mode" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=have_chiWat)); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumHeaWatPri[nPumHeaWatPri] + if have_heaWat and have_pumHeaWatPri + "Primary HW pump start command" + annotation (Placement(transformation(extent={{-180,40},{-140,80}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumHeaWatPriHdr + if have_heaWat and have_pumHeaWatPri and have_pumPriHdr + "Headered primary HW pump speed command" + annotation (Placement(transformation(extent={{140,80},{180,120}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumChiWatPri[nPumChiWatPri] + if have_chiWat and have_pumChiWatPri + "Primary CHW pump start command" + annotation (Placement(transformation(extent={{-180,-20},{-140,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumChiWatPriHdr + if have_chiWat and have_pumChiWatPri and have_pumPriHdr + "Headered primary CHW pump speed command" + annotation (Placement(transformation(extent={{140,40},{180,80}}), + iconTransformation(extent={{100,0},{140,40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumHeaWatPriDed[nPumHeaWatPri] + if have_heaWat and have_pumHeaWatPri and not have_pumPriHdr + "Dedicated primary HW pump speed command" + annotation (Placement(transformation(extent={{140,-80},{180,-40}}), + iconTransformation(extent={{100,-40},{140,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yPumChiWatPriDed[nPumChiWatPri] + if have_chiWat and have_pumChiWatPri and not have_pumPriHdr + "Dedicated primary CHW pump speed command" + annotation (Placement(transformation(extent={{140,-120},{180,-80}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Hea[nEqu] if have_heaWat + and have_chiWat and not have_pumChiWatPriDed and not have_pumPriHdr + "Heating/cooling mode command" + annotation (Placement(transformation(extent={{-180,-80},{-140,-40}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Reals.Switch setPumChiWatPriDed[nPumChiWatPri] + if have_chiWat and have_pumChiWatPri and not have_pumPriHdr + "Set prescribed speed when pump is enabled" + annotation (Placement(transformation(extent={{110,-110},{130,-90}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer( + final k=0) + "Constant" + annotation (Placement(transformation(extent={{-110,-90},{-90,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant spePumChiWatPri( + final k=yPumChiWatPriSet) + if have_chiWat + "Constant" + annotation (Placement(transformation(extent={{-110,-130},{-90,-110}}))); + Buildings.Controls.OBC.CDL.Reals.Switch setPumHeaWatPriDed[nPumHeaWatPri] + if have_heaWat and have_pumHeaWatPri and not have_pumPriHdr + "Set prescribed speed when pump is enabled" + annotation (Placement(transformation(extent={{110,-70},{130,-50}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep( + nout=nPumHeaWatPri) + if have_heaWat and have_pumHeaWatPri + "Replicate signal" + annotation (Placement(transformation(extent={{-60,-30},{-40,-10}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep1( + nout=nPumChiWatPri) + if have_chiWat and have_pumChiWatPri + "Replicate signal" + annotation (Placement(transformation(extent={{-60,-130},{-40,-110}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep2( + nout=nPumChiWatPri) + if have_chiWat and have_pumChiWatPri + "Replicate signal" + annotation (Placement(transformation(extent={{-60,-90},{-40,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant spePumHeaWatPri( + final k=yPumHeaWatPriSet) + if have_heaWat and have_pumHeaWatPri + "Constant" + annotation (Placement(transformation(extent={{-110,110},{-90,130}}))); + Buildings.Controls.OBC.CDL.Reals.Switch setPumChiWatPriHdr + if have_chiWat and have_pumChiWatPri and have_pumPriHdr + "Set prescribed speed when pump is enabled" + annotation (Placement(transformation(extent={{110,50},{130,70}}))); + Buildings.Controls.OBC.CDL.Reals.Switch setPumHeaWatPriHdr + if have_heaWat and have_pumHeaWatPri and have_pumPriHdr + "Set prescribed speed when pump is enabled" + annotation (Placement(transformation(extent={{110,90},{130,110}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyPumChiWatPri( + nin=nPumChiWatPri) + if have_chiWat and have_pumChiWatPri + "Return true if any pump is enabled" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyPumHeaWatPri( + nin=nPumHeaWatPri) + if have_heaWat and have_pumHeaWatPri + "Return true if any pump is enabled" + annotation (Placement(transformation(extent={{-110,50},{-90,70}}))); + Buildings.Controls.OBC.CDL.Reals.Switch selSpeHea[nPumHeaWatPri] if + have_heaWat and have_chiWat and not have_pumChiWatPri and not + have_pumPriHdr + "Select prescribed pump speed depending on heating/cooling mode – Case with common CHW and HW dedicated pumps" + annotation (Placement(transformation(extent={{40,-50},{60,-30}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep3( + nout=nPumHeaWatPri) + if have_heaWat and have_pumHeaWatPri + "Replicate signal" + annotation (Placement(transformation(extent={{-60,20},{-40,40}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep4( + nout=nPumHeaWatPri) if have_heaWat and have_chiWat and not + have_pumChiWatPri and not have_pumPriHdr + "Replicate signal" + annotation (Placement(transformation(extent={{-30,2},{-10,22}}))); + Utilities.PlaceholderReal ph[nPumHeaWatPri]( + each final have_inp=have_heaWat and have_chiWat and not have_pumChiWatPri + and not have_pumPriHdr, + each final have_inpPh=false, + each final u_internal=yPumHeaWatPriSet) + if have_heaWat and have_pumHeaWatPri and not have_pumPriHdr + "Always use HW pump speed in case of separate dedicated CHW pumps " + annotation (Placement(transformation(extent={{70,-50},{90,-30}}))); +equation + connect(u1PumChiWatPri, setPumChiWatPriDed.u2) + annotation (Line(points={{-160,0},{-126,0},{-126,-100},{108,-100}},color={255,0,255})); + connect(setPumChiWatPriDed.y, yPumChiWatPriDed) + annotation (Line(points={{132,-100},{160,-100}},color={0,0,127})); + connect(setPumHeaWatPriDed.y, yPumHeaWatPriDed) + annotation (Line(points={{132,-60},{160,-60}},color={0,0,127})); + connect(zer.y, rep.u) + annotation (Line(points={{-88,-80},{-70,-80},{-70,-20},{-62,-20}},color={0,0,127})); + connect(spePumChiWatPri.y, rep1.u) + annotation (Line(points={{-88,-120},{-62,-120}},color={0,0,127})); + connect(zer.y, rep2.u) + annotation (Line(points={{-88,-80},{-62,-80}},color={0,0,127})); + connect(setPumHeaWatPriHdr.y, yPumHeaWatPriHdr) + annotation (Line(points={{132,100},{160,100}},color={0,0,127})); + connect(setPumChiWatPriHdr.y, yPumChiWatPriHdr) + annotation (Line(points={{132,60},{160,60}},color={0,0,127})); + connect(rep2.y, setPumChiWatPriDed.u3) + annotation (Line(points={{-38,-80},{-20,-80},{-20,-108},{108,-108}},color={0,0,127})); + connect(rep1.y, setPumChiWatPriDed.u1) + annotation (Line(points={{-38,-120},{80,-120},{80,-92},{108,-92}},color={0,0,127})); + connect(zer.y, setPumChiWatPriHdr.u3) + annotation (Line(points={{-88,-80},{-70,-80},{-70,52},{108,52}},color={0,0,127})); + connect(rep.y, setPumHeaWatPriDed.u3) + annotation (Line(points={{-38,-20},{-20,-20},{-20,-68},{108,-68}},color={0,0,127})); + connect(zer.y, setPumHeaWatPriHdr.u3) + annotation (Line(points={{-88,-80},{-70,-80},{-70,92},{108,92}},color={0,0,127})); + connect(spePumChiWatPri.y, setPumChiWatPriHdr.u1) + annotation (Line(points={{-88,-120},{-80,-120},{-80,68},{108,68}},color={0,0,127})); + connect(u1PumChiWatPri, anyPumChiWatPri.u) + annotation (Line(points={{-160,0},{-112,0}},color={255,0,255})); + connect(u1PumHeaWatPri, anyPumHeaWatPri.u) + annotation (Line(points={{-160,60},{-136,60},{-136,60},{-112,60}},color={255,0,255})); + connect(anyPumHeaWatPri.y, setPumHeaWatPriHdr.u2) + annotation (Line(points={{-88,60},{60,60},{60,100},{108,100}},color={255,0,255})); + connect(spePumHeaWatPri.y, setPumHeaWatPriHdr.u1) + annotation (Line(points={{-88,120},{40,120},{40,108},{108,108}},color={0,0,127})); + connect(anyPumChiWatPri.y, setPumChiWatPriHdr.u2) + annotation (Line(points={{-88,0},{80,0},{80,60},{108,60}},color={255,0,255})); + connect(u1PumHeaWatPri, setPumHeaWatPriDed.u2) + annotation (Line(points={{-160,60},{-120,60},{-120,-60},{108,-60}},color={255,0,255})); + connect(u1Hea, selSpeHea.u2) + annotation (Line(points={{-160,-60},{-132,-60},{-132,-40},{38,-40}},color={255,0,255})); + connect(spePumHeaWatPri.y, rep3.u) + annotation (Line(points={{-88,120},{-84,120},{-84,30},{-62,30}}, + color={0,0,127})); + connect(rep3.y, selSpeHea.u1) + annotation (Line(points={{-38,30},{30,30},{30,-32},{38,-32}},color={0,0,127})); + connect(rep4.y, selSpeHea.u3) + annotation (Line(points={{-8,12},{20,12},{20,-48},{38,-48}},color={0,0,127})); + connect(spePumChiWatPri.y, rep4.u) + annotation (Line(points={{-88,-120},{-80,-120},{-80,12},{-32,12}},color={0,0,127})); + connect(ph.y, setPumHeaWatPriDed.u1) annotation (Line(points={{92,-40},{100,-40}, + {100,-52},{108,-52}}, color={0,0,127})); + connect(selSpeHea.y, ph.u) + annotation (Line(points={{62,-40},{68,-40}}, color={0,0,127})); + annotation ( + defaultComponentName="ctlPumPri", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-140,-140},{140,140}})), + Documentation(info=" +
+Heating-only plants with variable speed primary pumps that are not controlled to maintain differential pressure or flow setpoint +
+

+When commanded on, the primary HW pumps are commanded at a fixed +speed yPumHeaWatPriSet, as determined during the Testing, Adjusting, +and Balancing phase to provide the design heat pump flow. +

+
+Heating and cooling plants with common variable speed primary pumps that are not controlled to maintain differential pressure or flow setpoint +
+

+When commanded on, the primary pumps are commanded at a fixed +speed yPumHeaWatPriSet in heating mode or +yPumChiWatPriSet in cooling mode, as determined during the +Testing, Adjusting, and Balancing phase to provide the design heat pump flow +in heating mode or cooling mode. +

+
+Heating and cooling plants with separate variable speed primary pumps that are not controlled to maintain differential pressure or flow setpoint +
+

+When commanded on, the primary HW pumps are commanded at a fixed +speed yPumHeaWatPriSet. +When commanded on, the primary CHW pumps are commanded at a fixed +speed yPumChiWatPriSet. +The pump speed yPumHeaWatPriSet or yPumChiWatPriSet +is determined during the Testing, Adjusting, and Balancing phase to provide +the design heat pump flow in heating mode or cooling mode. +

+")); +end VariableSpeedNoDpControl; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/package.mo b/Buildings/Templates/Plants/Controls/Pumps/Primary/package.mo new file mode 100644 index 00000000000..bf4fbb8346b --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/package.mo @@ -0,0 +1,8 @@ +within Buildings.Templates.Plants.Controls.Pumps; +package Primary "Sequences for primary pumps" + annotation (Documentation(info=" +

+This package contains control sequences for primary pumps. +

+")); +end Primary; diff --git a/Buildings/Templates/Plants/Controls/Pumps/Primary/package.order b/Buildings/Templates/Plants/Controls/Pumps/Primary/package.order new file mode 100644 index 00000000000..f1ce062b461 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/Primary/package.order @@ -0,0 +1,3 @@ +EnableLeadHeadered +VariableSpeedNoDpControl +Validation diff --git a/Buildings/Templates/Plants/Controls/Pumps/package.mo b/Buildings/Templates/Plants/Controls/Pumps/package.mo new file mode 100644 index 00000000000..c0a653e65ea --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/package.mo @@ -0,0 +1,43 @@ +within Buildings.Templates.Plants.Controls; +package Pumps "Package of sequences for primary and secondary pumps" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Ellipse( + origin={10.0,10.0}, + lineColor={128,128,128}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-80.0,0.0},{-20.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={128,128,128}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,0.0},{60.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,-80.0},{60.0,-20.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={76,76,76}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{-80.0,-80.0},{-20.0,-20.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), Documentation(info=" +

+This package contains control sequences for HW and CHW pumps. +

+")); +end Pumps; diff --git a/Buildings/Templates/Plants/Controls/Pumps/package.order b/Buildings/Templates/Plants/Controls/Pumps/package.order new file mode 100644 index 00000000000..67246907683 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Pumps/package.order @@ -0,0 +1,2 @@ +Generic +Primary diff --git a/Buildings/Templates/Plants/Controls/Setpoints/PlantReset.mo b/Buildings/Templates/Plants/Controls/Setpoints/PlantReset.mo new file mode 100644 index 00000000000..b62059f874e --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Setpoints/PlantReset.mo @@ -0,0 +1,261 @@ +within Buildings.Templates.Plants.Controls.Setpoints; +block PlantReset + "Plant reset logic" + parameter Integer nSenDpRem(final min=1) + "Number of remote loop differential pressure sensors used for pump speed control" + annotation (Evaluate=true); + parameter Real dpSet_max[nSenDpRem]( + each final min=5*6894, + each unit="Pa") + "Maximum differential pressure setpoint"; + parameter Real dpSet_min( + final min=0, + final unit="Pa")=5*6894 + "Minimum value to which the differential pressure can be reset"; + parameter Real TSup_nominal( + final min=273.15, + final unit="K", + displayUnit="degC") + "Design supply temperature"; + parameter Real TSupSetLim( + final min=273.15, + final unit="K", + displayUnit="degC") + "Limit value to which the supply temperature can be reset"; + parameter Real dtHol( + final min=0, + final unit="s")=900 + "Minimum hold time during stage change" + annotation (Dialog(tab="Advanced")); + parameter Real resDp_max( + final max=1, + final min=0, + final unit="1")=0.5 + "Upper limit of plant reset interval for differential pressure reset" + annotation (Dialog(tab="Advanced")); + parameter Real resTSup_min( + final max=1, + final min=0, + final unit="1")=resDp_max + "Lower limit of plant reset interval for supply temperature reset" + annotation (Dialog(tab="Advanced")); + parameter Real res_init( + final max=1, + final min=0, + final unit="1")=1 + "Initial reset value" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real res_min( + final max=1, + final min=0, + final unit="1")=0 + "Minimum reset value" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real res_max( + final max=1, + final min=0, + final unit="1")=1 + "Maximum reset value" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real dtDel( + final min=100*1E-15, + final unit="s")=900 + "Delay time before the reset begins" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real dtRes( + final min=1E-3, + final unit="s")=300 + "Sample period of component" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Integer nReqResIgn(min=0)=2 + "Number of ignored requests" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real tri( + final max=0, + final unit="1")=-0.02 + "Trim amount" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real rsp( + final min=0, + final unit="1")=0.03 + "Respond amount (must have opposite sign of trim amount)" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + parameter Real rsp_max( + final min=0, + final unit="1")=0.07 + "Maximum response per reset period (must have same sign as respond amount)" + annotation (Dialog(tab="Advanced",group="Trim and respond")); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput nReqRes + "Sum of reset requests of all loads served" + annotation (Placement(transformation(extent={{-200,120},{-160,160}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Ena + "Plant enable" + annotation (Placement(transformation(extent={{-200,80},{-160,120}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1StaPro + "Staging process in progress" + annotation (Placement(transformation(extent={{-200,20},{-160,60}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput TSupSet( + final unit="K", + displayUnit="degC") + "Supply temperature setpoint" + annotation (Placement(transformation(extent={{160,-120},{200,-80}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput dpSet[nSenDpRem]( + each final min=0, + each final unit="Pa") + "Differential pressure setpoint" + annotation (Placement(transformation(extent={{160,-40},{200,0}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.ASHRAE.G36.Generic.TrimAndRespond triRes( + final delTim=dtDel, + final iniSet=res_init, + final maxRes=rsp_max, + final maxSet=res_max, + final minSet=res_min, + final numIgnReq=nReqResIgn, + final resAmo=rsp, + final samplePeriod=dtRes, + final triAmo=tri) + "Compute plant reset with trim and respond logic " + annotation (Placement(transformation(extent={{-50,90},{-30,110}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold truHol( + final duration=dtHol) + "Hold true value of input signal for given time" + annotation (Placement(transformation(extent={{-130,30},{-110,50}}))); + Buildings.Controls.OBC.CDL.Discrete.TriggeredSampler triSam + "Fixed value at stage change" + annotation (Placement(transformation(extent={{-10,90},{10,110}}))); + Buildings.Controls.OBC.CDL.Reals.Switch res + "Switch between actual and fixed value to compute actual reset" + annotation (Placement(transformation(extent={{30,50},{50,70}}))); + Buildings.Controls.OBC.CDL.Reals.Line resTSup + "Supply temperature reset" + annotation (Placement(transformation(extent={{120,-110},{140,-90}}))); + Buildings.Controls.OBC.CDL.Reals.Line resDp[nSenDpRem] + "Differential pressure reset" + annotation (Placement(transformation(extent={{120,-30},{140,-10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant zer( + final k=0) + "Constant" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant one( + final k=1) + "Constant" + annotation (Placement(transformation(extent={{-10,-130},{10,-110}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant resDpMax( + final k=resDp_max) + "Constant" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep( + final nout=nSenDpRem) + "Replicate signal" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep1( + final nout=nSenDpRem) + "Replicate signal" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep2( + final nout=nSenDpRem) + "Replicate signal" + annotation (Placement(transformation(extent={{30,-50},{50,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpSetMax[nSenDpRem]( + final k=dpSet_max) + "Constant" + annotation (Placement(transformation(extent={{-90,-70},{-70,-50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant resTSupMin( + final k=resTSup_min) + "Constant" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TSupSetNom( + final k=TSup_nominal) + "Constant" + annotation (Placement(transformation(extent={{-90,-150},{-70,-130}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant dpSetMin( + final k=dpSet_min) + "Constant" + annotation (Placement(transformation(extent={{-90,10},{-70,30}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator rep3( + final nout=nSenDpRem) + "Replicate signal" + annotation (Placement(transformation(extent={{-50,10},{-30,30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TSupSetMinMax(final k= + TSupSetLim) "Constant" + annotation (Placement(transformation(extent={{-90,-110},{-70,-90}}))); +equation + connect(u1StaPro, truHol.u) + annotation (Line(points={{-180,40},{-132,40}},color={255,0,255})); + connect(triRes.y, triSam.u) + annotation (Line(points={{-28,100},{-12,100}},color={0,0,127})); + connect(u1StaPro, triSam.trigger) + annotation (Line(points={{-180,40},{-140,40},{-140,80},{0,80},{0,88}},color={255,0,255})); + connect(truHol.y, res.u2) + annotation (Line(points={{-108,40},{20,40},{20,60},{28,60}},color={255,0,255})); + connect(triSam.y, res.u1) + annotation (Line(points={{12,100},{20,100},{20,68},{28,68}},color={0,0,127})); + connect(triRes.y, res.u3) + annotation (Line(points={{-28,100},{-20,100},{-20,52},{28,52}},color={0,0,127})); + connect(nReqRes, triRes.numOfReq) + annotation (Line(points={{-180,140},{-80,140},{-80,92},{-52,92}},color={255,127,0})); + connect(resTSup.y, TSupSet) + annotation (Line(points={{142,-100},{180,-100}},color={0,0,127})); + connect(resDp.y, dpSet) + annotation (Line(points={{142,-20},{180,-20}},color={0,0,127})); + connect(one.y, resTSup.x2) + annotation (Line(points={{12,-120},{100,-120},{100,-104},{118,-104}},color={0,0,127})); + connect(res.y, resTSup.u) + annotation (Line(points={{52,60},{104,60},{104,-100},{118,-100}},color={0,0,127})); + connect(zer.y, rep.u) + annotation (Line(points={{12,0},{28,0}},color={0,0,127})); + connect(rep.y, resDp.x1) + annotation (Line(points={{52,0},{80,0},{80,-12},{118,-12}},color={0,0,127})); + connect(res.y, rep1.u) + annotation (Line(points={{52,60},{60,60},{60,40},{68,40}},color={0,0,127})); + connect(rep1.y, resDp.u) + annotation (Line(points={{92,40},{100,40},{100,-20},{118,-20}},color={0,0,127})); + connect(rep2.y, resDp.x2) + annotation (Line(points={{52,-40},{80,-40},{80,-24},{118,-24}},color={0,0,127})); + connect(dpSetMax.y, resDp.f2) + annotation (Line(points={{-68,-60},{100,-60},{100,-28},{118,-28}},color={0,0,127})); + connect(TSupSetNom.y, resTSup.f2) + annotation (Line(points={{-68,-140},{104,-140},{104,-108},{118,-108}},color={0,0,127})); + connect(dpSetMin.y, rep3.u) + annotation (Line(points={{-68,20},{-52,20}},color={0,0,127})); + connect(rep3.y, resDp.f1) + annotation (Line(points={{-28,20},{76,20},{76,-16},{118,-16}},color={0,0,127})); + connect(TSupSetMinMax.y, resTSup.f1) + annotation (Line(points={{-68,-100},{80,-100},{80,-96},{118,-96}},color={0,0,127})); + connect(resTSupMin.y, resTSup.x1) + annotation (Line(points={{12,-80},{80,-80},{80,-92},{118,-92}},color={0,0,127})); + connect(resDpMax.y, rep2.u) + annotation (Line(points={{12,-40},{28,-40}},color={0,0,127})); + connect(u1Ena, triRes.uDevSta) annotation (Line(points={{-180,100},{-60,100}, + {-60,108},{-52,108}}, color={255,0,255})); + annotation ( + defaultComponentName="res", + Icon( + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-160,-160},{160,160}})), + Documentation(info=" +", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PlantReset; diff --git a/Buildings/Templates/Plants/Controls/Setpoints/Validation/PlantReset.mo b/Buildings/Templates/Plants/Controls/Setpoints/Validation/PlantReset.mo new file mode 100644 index 00000000000..049ec3b6d6c --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Setpoints/Validation/PlantReset.mo @@ -0,0 +1,97 @@ +within Buildings.Templates.Plants.Controls.Setpoints.Validation; +model PlantReset + Buildings.Templates.Plants.Controls.Setpoints.PlantReset res( + nSenDpRem=2, + dpSet_max={5E4,8E4}, + TSup_nominal=323.15, + TSupSetLim=298.15, + resDp_max=0.75, + resTSup_min=0.25) "Plant reset" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Buildings.Controls.OBC.CDL.Conversions.RealToInteger reaToInt + "Convert real to integer" + annotation (Placement(transformation(extent={{-40,30},{-20,50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable ena( + table=[ + 0, 0; + 2, 1; + 19, 0], + timeScale=1000, + final period=20000) + "Plant enable" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable timTabLin( + final smoothness=Buildings.Controls.OBC.CDL.Types.Smoothness.ConstantSegments, + final table=[ + 0, 0; + 150, 0; + 300, 0; + 450, 0; + 600, 0; + 750, 0; + 900, 0; + 1050, 0; + 1200, 4; + 1350, 3; + 1500, 2; + 1650, 1; + 1800, 0], + timeScale=10) + "Time table with smoothness method of constant segments" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse staPro( + width=0.1, + final period=8000, + shift=2000) + "Staging process in progress" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); +equation + connect(timTabLin.y[1], reaToInt.u) + annotation (Line(points={{-58,40},{-42,40}},color={0,0,127})); + connect(reaToInt.y,res.nReqRes) + annotation (Line(points={{-18,40},{0,40},{0,6},{18,6}},color={255,127,0})); + connect(staPro.y, res.u1StaPro) + annotation (Line(points={{-58,-40},{0,-40},{0,-6},{18,-6}},color={255,0,255})); + connect(ena.y[1], res.u1Ena) + annotation (Line(points={{-58,0},{18,0}},color={255,0,255})); + annotation ( + experiment( + StopTime=20000.0, + Tolerance=1e-06), + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Setpoints/Validation/PlantReset.mos" + "Simulate and plot"), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.Controls.Setpoints.PlantReset. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false))); +end PlantReset; diff --git a/Buildings/Templates/Plants/Controls/Setpoints/Validation/package.mo b/Buildings/Templates/Plants/Controls/Setpoints/Validation/package.mo new file mode 100644 index 00000000000..8ebc63da230 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Setpoints/Validation/package.mo @@ -0,0 +1,29 @@ +within Buildings.Templates.Plants.Controls.Setpoints; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), + Documentation( + info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/Setpoints/Validation/package.order b/Buildings/Templates/Plants/Controls/Setpoints/Validation/package.order new file mode 100644 index 00000000000..f8522085d40 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Setpoints/Validation/package.order @@ -0,0 +1 @@ +PlantReset diff --git a/Buildings/Templates/Plants/Controls/Setpoints/package.mo b/Buildings/Templates/Plants/Controls/Setpoints/package.mo new file mode 100644 index 00000000000..8e7dcd0d270 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Setpoints/package.mo @@ -0,0 +1,27 @@ +within Buildings.Templates.Plants.Controls; +package Setpoints "Plant reset logic" + annotation ( + preferredView="info", + Documentation( + info=" +

+This package contains plant reset sequences. +

+"), + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Text( + extent={{-100,100},{100,-100}}, + textColor={0,0,0}, + textString="S")})); +end Setpoints; diff --git a/Buildings/Templates/Plants/Controls/Setpoints/package.order b/Buildings/Templates/Plants/Controls/Setpoints/package.order new file mode 100644 index 00000000000..e6f148a661f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Setpoints/package.order @@ -0,0 +1,2 @@ +PlantReset +Validation diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/EquipmentAvailability.mo b/Buildings/Templates/Plants/Controls/StagingRotation/EquipmentAvailability.mo new file mode 100644 index 00000000000..c22062208e8 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/EquipmentAvailability.mo @@ -0,0 +1,239 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block EquipmentAvailability + "Equipment availability for heating and cooling applications" + parameter Boolean have_heaWat + "Set to true for plants that provide HW" + annotation (Evaluate=true); + parameter Boolean have_chiWat + "Set to true for plants that provide CHW" + annotation (Evaluate=true); + parameter Real dtOff( + final min=0, + final unit="s")=900 + "Off time required before equipment is deemed available again"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1 + "Equipment enable command" + annotation (Placement(transformation(extent={{-240,-20},{-200,20}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Hea + if have_heaWat + "Equipment available for heating" + annotation (Placement(transformation(extent={{200,-20},{240,20}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Hea + if have_heaWat and have_chiWat + "Equipment operating mode command" + annotation (Placement(transformation(extent={{-240,-140},{-200,-100}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Coo + if have_chiWat + "Equipment available for cooling" + annotation (Placement(transformation(extent={{200,-140},{240,-100}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + Buildings.Controls.OBC.CDL.Logical.And onAndHea + "Return true if equipment on and in heating mode" + annotation (Placement(transformation(extent={{-110,-150},{-90,-130}}))); + Buildings.Controls.OBC.CDL.Logical.And onAndCoo + "Return true if equipment on and in cooling mode" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Buildings.Controls.OBC.CDL.Logical.Not coo + "Return true if equipment in cooling mode" + annotation (Placement(transformation(extent={{-150,-110},{-130,-90}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Ava + "Equipment available signal" + annotation (Placement(transformation(extent={{-240,-80},{-200,-40}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Utilities.PlaceholderLogical phHea(final have_inp=have_heaWat and have_chiWat, + final u_internal=have_heaWat or not have_chiWat) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{-190,-130},{-170,-110}}))); + Buildings.Controls.OBC.CDL.Logical.Not off + "Return true if equipment is off" + annotation (Placement(transformation(extent={{-150,-50},{-130,-30}}))); + inner Modelica.StateGraph.StateGraphRoot stateGraphRoot + annotation (Placement(transformation(extent={{-160,160},{-140,180}}))); + Modelica.StateGraph.StepWithSignal onHea( + nOut=2, + nIn=1) + annotation (Placement(transformation(extent={{10,150},{30,170}}))); + Modelica.StateGraph.InitialStepWithSignal avaMod( + nOut=3, + nIn=2) + "Initial state – Equipment available for all modes" + annotation (Placement(transformation(extent={{-70,150},{-50,170}}))); + Modelica.StateGraph.TransitionWithSignal trnToOff + "Transition to off state" + annotation (Placement(transformation(extent={{50,150},{70,170}}))); + Modelica.StateGraph.StepWithSignal onCoo( + nOut=2, + nIn=1) + annotation (Placement(transformation(extent={{70,110},{90,130}}))); + Modelica.StateGraph.TransitionWithSignal trnToCoo + "Transition to cooling mode" + annotation (Placement(transformation(extent={{-10,110},{10,130}}))); + Modelica.StateGraph.TransitionWithSignal trnToHea + "Transition to heating mode" + annotation (Placement(transformation(extent={{-30,150},{-10,170}}))); + Modelica.StateGraph.TransitionWithSignal trnToOff1 + "Transition to off state" + annotation (Placement(transformation(extent={{110,110},{130,130}}))); + Buildings.Controls.OBC.CDL.Logical.Or avaAllHea + "Return true if equipment available for all modes or in heating mode" + annotation (Placement(transformation(extent={{150,-10},{170,10}}))); + Buildings.Controls.OBC.CDL.Logical.Or avaAllCoo + "Return true if equipment available for all modes or in cooling mode" + annotation (Placement(transformation(extent={{170,-130},{190,-110}}))); + Modelica.StateGraph.Step offSta( + nOut=1, + nIn=2) + "Off state" + annotation (Placement(transformation(extent={{140,130},{160,150}}))); + Modelica.StateGraph.Transition trnToAvaTim( + enableTimer=true, + final waitTime=dtOff) + "Transition back to available state after off time elapsed" + annotation (Placement(transformation(extent={{160,170},{140,190}}))); + Modelica.StateGraph.Step unaSta( + nOut=1, + nIn=3) + "Unavailable state" + annotation (Placement(transformation(extent={{140,90},{160,110}}))); + Modelica.StateGraph.TransitionWithSignal trnToUna + "Transition to unavailable state" + annotation (Placement(transformation(extent={{-36,70},{-16,90}}))); + Buildings.Controls.OBC.CDL.Logical.Not una + "Return true if equipment is unavailable" + annotation (Placement(transformation(extent={{-110,-90},{-90,-70}}))); + Modelica.StateGraph.TransitionWithSignal trnToAva + "Transition back to available state" + annotation (Placement(transformation(extent={{170,90},{190,110}}))); + Modelica.StateGraph.TransitionWithSignal trnToUna2 + "Transition to unavailable state" + annotation (Placement(transformation(extent={{30,90},{50,110}}))); + Modelica.StateGraph.TransitionWithSignal trnToUna3 + "Transition to unavailable state" + annotation (Placement(transformation(extent={{90,70},{110,90}}))); +equation + connect(coo.y, onAndCoo.u2) + annotation (Line(points={{-128,-100},{-116,-100},{-116,-8},{-112,-8}},color={255,0,255})); + connect(u1, onAndHea.u1) + annotation (Line(points={{-220,0},{-120,0},{-120,-140},{-112,-140}},color={255,0,255})); + connect(u1, onAndCoo.u1) + annotation (Line(points={{-220,0},{-112,0}},color={255,0,255})); + connect(u1Hea, phHea.u) + annotation (Line(points={{-220,-120},{-192,-120}}, color={255,0,255})); + connect(phHea.y, onAndHea.u2) annotation (Line(points={{-168,-120},{-140,-120}, + {-140,-148},{-112,-148}}, color={255,0,255})); + connect(phHea.y, coo.u) annotation (Line(points={{-168,-120},{-160,-120},{-160, + -100},{-152,-100}}, color={255,0,255})); + connect(u1, off.u) + annotation (Line(points={{-220,0},{-160,0},{-160,-40},{-152,-40}},color={255,0,255})); + connect(avaMod.outPort[1], trnToCoo.inPort) + annotation (Line(points={{-49.5,159.833},{-40,159.833},{-40,120},{-4,120}}, + color={0,0,0})); + connect(onAndCoo.y, trnToCoo.condition) + annotation (Line(points={{-88,0},{-80,0},{-80,40},{0,40},{0,108}},color={255,0,255})); + connect(onHea.outPort[1], trnToOff.inPort) + annotation (Line(points={{30.5,159.875},{44,159.875},{44,160},{56,160}}, + color={0,0,0})); + connect(off.y, trnToOff.condition) + annotation (Line(points={{-128,-40},{60,-40},{60,148}},color={255,0,255})); + connect(onCoo.outPort[1], trnToOff1.inPort) + annotation (Line(points={{90.5,119.875},{104,119.875},{104,120},{116,120}}, + color={0,0,0})); + connect(trnToCoo.outPort, onCoo.inPort[1]) + annotation (Line(points={{1.5,120},{69,120}},color={0,0,0})); + connect(onAndHea.y, trnToHea.condition) + annotation (Line(points={{-88,-140},{-20,-140},{-20,148}},color={255,0,255})); + connect(avaMod.outPort[2], trnToHea.inPort) + annotation (Line(points={{-49.5,160},{-24,160}},color={0,0,0})); + connect(avaMod.active, avaAllHea.u1) + annotation (Line(points={{-60,149},{-60,0},{148,0}},color={255,0,255})); + connect(onHea.active, avaAllHea.u2) + annotation (Line(points={{20,149},{20,-8},{148,-8}},color={255,0,255})); + connect(avaAllHea.y, y1Hea) + annotation (Line(points={{172,0},{220,0}},color={255,0,255})); + connect(avaAllCoo.y, y1Coo) + annotation (Line(points={{192,-120},{220,-120}},color={255,0,255})); + connect(off.y, trnToOff1.condition) + annotation (Line(points={{-128,-40},{120,-40},{120,108}},color={255,0,255})); + connect(trnToHea.outPort, onHea.inPort[1]) + annotation (Line(points={{-18.5,160},{9,160}},color={0,0,0})); + connect(offSta.outPort[1], trnToAvaTim.inPort) + annotation (Line(points={{160.5,140},{170,140},{170,180},{154,180}},color={0,0,0})); + connect(trnToOff.outPort, offSta.inPort[1]) + annotation (Line(points={{61.5,160},{130,160},{130,139.75},{139,139.75}}, + color={0,0,0})); + connect(trnToOff1.outPort, offSta.inPort[2]) + annotation (Line(points={{121.5,120},{130,120},{130,140},{134,140},{134,140.25},{139,140.25}}, + color={0,0,0})); + connect(trnToAvaTim.outPort, avaMod.inPort[1]) + annotation (Line(points={{148.5,180},{-80,180},{-80,159.75},{-71,159.75}}, + color={0,0,0})); + connect(u1Ava, una.u) + annotation (Line(points={{-220,-60},{-140,-60},{-140,-80},{-112,-80}},color={255,0,255})); + connect(avaMod.outPort[3], trnToUna.inPort) + annotation (Line(points={{-49.5,160.167},{-49.5,160},{-40,160},{-40,80},{ + -30,80}}, + color={0,0,0})); + connect(una.y, trnToUna.condition) + annotation (Line(points={{-88,-80},{-26,-80},{-26,68}},color={255,0,255})); + connect(trnToUna.outPort, unaSta.inPort[1]) + annotation (Line(points={{-24.5,80},{50,80},{50,99.6667},{139,99.6667}}, + color={0,0,0})); + connect(unaSta.outPort[1], trnToAva.inPort) + annotation (Line(points={{160.5,100},{176,100}},color={0,0,0})); + connect(u1Ava, trnToAva.condition) + annotation (Line(points={{-220,-60},{180,-60},{180,88}},color={255,0,255})); + connect(trnToAva.outPort, avaMod.inPort[2]) + annotation (Line(points={{181.5,100},{190,100},{190,190},{-90,190},{-90,160.25},{-71,160.25}}, + color={0,0,0})); + connect(avaMod.active, avaAllCoo.u1) + annotation (Line(points={{-60,149},{-60,-120},{168,-120}},color={255,0,255})); + connect(onCoo.active, avaAllCoo.u2) + annotation (Line(points={{80,109},{80,-128},{168,-128}},color={255,0,255})); + connect(onHea.outPort[2], trnToUna2.inPort) + annotation (Line(points={{30.5,160.125},{32,160.125},{32,100},{36,100}}, + color={0,0,0})); + connect(trnToUna2.outPort, unaSta.inPort[2]) + annotation (Line(points={{41.5,100},{90,100},{90,100},{139,100}},color={0,0,0})); + connect(una.y, trnToUna2.condition) + annotation (Line(points={{-88,-80},{40,-80},{40,88}},color={255,0,255})); + connect(onCoo.outPort[2], trnToUna3.inPort) + annotation (Line(points={{90.5,120.125},{92,120.125},{92,80},{96,80}},color={0,0,0})); + connect(trnToUna3.outPort, unaSta.inPort[3]) + annotation (Line(points={{101.5,80},{130,80},{130,100.333},{139,100.333}}, + color={0,0,0})); + connect(una.y, trnToUna3.condition) + annotation (Line(points={{-88,-80},{100,-80},{100,68}},color={255,0,255})); + annotation ( + __cdl( + extensionBlock=true), + defaultComponentName="avaHeaCoo", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-200,-200},{200,200}})), + Documentation( + info=" +

+If a heat pump is commanded enabled in either heating or cooling mode, +it is removed from the staging order of the opposite mode until it has +been off for dtOff. +

+")); +end EquipmentAvailability; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/EquipmentEnable.mo b/Buildings/Templates/Plants/Controls/StagingRotation/EquipmentEnable.mo new file mode 100644 index 00000000000..474c3017598 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/EquipmentEnable.mo @@ -0,0 +1,312 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block EquipmentEnable + "Return array of equipment to be enabled at given stage" + parameter Real staEqu[:,:]( + each unit="1", + each min=0, + each max=1) + "Staging matrix – Equipment required for each stage" + annotation (Evaluate=true); + final parameter Integer nEquAlt=max({sum({(if staEqu[i, j] > 0 and staEqu[i, j] < 1 + then 1 else 0) for j in 1:nEqu}) for i in 1:nSta}) + "Number of lead/lag alternate equipment" + annotation (Evaluate=true); + final parameter Integer nSta=size(staEqu, 1) + "Number of stages" + annotation (Evaluate=true); + final parameter Integer nEqu=size(staEqu, 2) + "Number of equipment" + annotation (Evaluate=true); + final parameter Real traStaEqu[nEqu, nSta]={{staEqu[i, j] for i in 1:nSta} for j in 1:nEqu} + "Transpose of staging matrix"; + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uIdxAltSor[nEquAlt] + "Indices of lead/lag alternate equipment sorted by increasing runtime" + annotation (Placement(transformation(extent={{-240,80},{-200,120}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uSta + "Stage index" + annotation (Placement(transformation(extent={{-240,-20},{-200,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Ava[nEqu] + "Equipment available signal" + annotation (Placement(transformation(extent={{-240,-100},{-200,-60}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant traMatStaEqu[nEqu, nSta]( + final k=traStaEqu) + "Transpose of staging matrix" + annotation (Placement(transformation(extent={{-190,70},{-170,90}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1[nEqu] + "Equipment enable command" + annotation (Placement(transformation(extent={{200,-20},{240,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Routing.RealExtractor reqEquSta[nEqu]( + each final nin=nSta) + "Extract equipment required at given stage" + annotation (Placement(transformation(extent={{-160,70},{-140,90}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator intScaRep( + final nout=nEqu) + "Replicate signal" + annotation (Placement(transformation(extent={{-130,-10},{-110,10}}))); + Buildings.Controls.OBC.CDL.Reals.MultiSum nEquStaRea( + nin=nEqu) + "Return the number of equipment required" + annotation (Placement(transformation(extent={{-60,70},{-40,90}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isReq[nEqu]( + each final t=0.99) + "Return true if equipment required without lead/lag alternate" + annotation (Placement(transformation(extent={{-60,-50},{-40,-30}}))); + Buildings.Controls.OBC.CDL.Logical.And isReqAva[nEqu] + "Return true if equipment required without lead/lag alternate and available" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isReqPosAlt[nEqu]( + each final t=0) + "Return true if equipment required (with or without lead/lag alternate)" + annotation (Placement(transformation(extent={{-60,30},{-40,50}}))); + Buildings.Controls.OBC.CDL.Reals.LessThreshold isNotReqNoAlt[nEqu]( + each final t=1) + "Return true if equipment not required or required with lead/lag alternate" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd isReqAltAva[nEqu]( + each final nin=3) + "Return true if lead/lag alternate equipment required and available" + annotation (Placement(transformation(extent={{-10,30},{10,50}}))); + Buildings.Controls.OBC.CDL.Logical.Or ena[nEqu] + "Enable equipment required without lead/lag alternate and available or lead/lag alternate equipment to meet stage requirement" + annotation (Placement(transformation(extent={{110,-10},{130,10}}))); + Buildings.Controls.OBC.CDL.Conversions.RealToInteger nEquSta + "Number of equipment required" + annotation (Placement(transformation(extent={{-10,70},{10,90}}))); + Buildings.Controls.OBC.CDL.Integers.Subtract nAltReq + "Number of lead/lag alternate equipment to run to meet stage requirement" + annotation (Placement(transformation(extent={{60,30},{80,50}}))); + Buildings.Controls.OBC.CDL.Logical.And isReqAltAvaNee[nEqu] + "Return true if equipment required with lead/lag alternate and available and needed to meet stage requirement" + annotation (Placement(transformation(extent={{80,-10},{100,10}}))); + Buildings.Controls.OBC.CDL.Integers.Change cha + "Detect stage index change" + annotation (Placement(transformation(extent={{30,-70},{50,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Pre y1Pre[nEqu] + "Left limit of signal in discrete time" + annotation (Placement(transformation(extent={{180,-70},{160,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Switch logSwi[nEqu] + "Switch to newly computed value at stage change" + annotation (Placement(transformation(extent={{160,-10},{180,10}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator booScaRep( + final nout=nEqu) + "Replicate signal" + annotation (Placement(transformation(extent={{110,-70},{130,-50}}))); + Utilities.CountTrue nReq( + nin=nEqu) + "Count the number of required equipment without lead/lag alternate, not necessarily available" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Utilities.CountTrue nEnaAvaPre( + nin=nEqu) + "Count the number of previously enabled equipment that are available" + annotation (Placement(transformation(extent={{100,-110},{80,-90}}))); + Buildings.Controls.OBC.CDL.Integers.Less intLes + "Compare to required number of equipment" + annotation (Placement(transformation(extent={{30,-110},{50,-90}}))); + Buildings.Controls.OBC.CDL.Logical.Or swiEna + "Evaluate condition to switch to newly computed enable signal" + annotation (Placement(transformation(extent={{80,-70},{100,-50}}))); + Buildings.Controls.OBC.CDL.Logical.And isEnaPreAva[nEqu] + "Return true if equipment previously enabled and available" + annotation (Placement(transformation(extent={{130,-110},{110,-90}}))); + Utilities.TrueArrayConditional truArrCon( + final nout=nEqu, + final nin=nEquAlt) + "Generate array of size nEqu with nAltReq true elements at uIdxAltSor indices " + annotation (Placement(transformation(extent={{100,30},{120,50}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant one( + final k=1) + "Constant" + annotation (Placement(transformation(extent={{-190,10},{-170,30}}))); + Buildings.Controls.OBC.CDL.Integers.Max maxInt + "Maximum between stage index and 1" + annotation (Placement(transformation(extent={{-160,-10},{-140,10}}))); + Buildings.Controls.OBC.CDL.Integers.GreaterThreshold greZer( + final t=0) + "Check if stage index is greater than zero" + annotation (Placement(transformation(extent={{-170,-50},{-150,-30}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea( + final realTrue=1, + final realFalse=0) + "Cast to real" + annotation (Placement(transformation(extent={{-140,-50},{-120,-30}}))); + Buildings.Controls.OBC.CDL.Routing.RealScalarReplicator reaScaRep( + final nout=nEqu) + "Replicate signal" + annotation (Placement(transformation(extent={{-110,-50},{-90,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply voiStaZer[nEqu] + "Void if stage is equal to zero" + annotation (Placement(transformation(extent={{-100,70},{-80,90}}))); +equation + // HACK(AntoineGautier): Explicit `for` loops needed for OCT that cannot flatten the model otherwise. + for i in 1:nEqu loop + for j in 1:i loop end for; + end for; + connect(intScaRep.y, reqEquSta.index) + annotation (Line(points={{-108,0},{-100,0},{-100,60},{-150,60},{-150,68}}, + color={255,127,0})); + connect(traMatStaEqu.y, reqEquSta.u) + annotation (Line(points={{-168,80},{-162,80}},color={0,0,127})); + connect(isReq.y, isReqAva.u1) + annotation (Line(points={{-38,-40},{-12,-40}},color={255,0,255})); + connect(u1Ava, isReqAva.u2) + annotation (Line(points={{-220,-80},{-30,-80},{-30,-48},{-12,-48}},color={255,0,255})); + connect(isReqPosAlt.y, isReqAltAva.u[1]) + annotation (Line(points={{-38,40},{-30,40},{-30,37.6667},{-12,37.6667}}, + color={255,0,255})); + connect(isNotReqNoAlt.y, isReqAltAva.u[2]) + annotation (Line(points={{-38,0},{-32,0},{-32,40},{-12,40}},color={255,0,255})); + connect(u1Ava, isReqAltAva.u[3]) + annotation (Line(points={{-220,-80},{-30,-80},{-30,42.3333},{-12,42.3333}}, + color={255,0,255})); + connect(isReqAva.y, ena.u2) + annotation (Line(points={{12,-40},{104,-40},{104,-8},{108,-8}},color={255,0,255})); + connect(nEquStaRea.y, nEquSta.u) + annotation (Line(points={{-38,80},{-12,80}},color={0,0,127})); + connect(nEquSta.y, nAltReq.u1) + annotation (Line(points={{12,80},{50,80},{50,46},{58,46}},color={255,127,0})); + connect(isReqAltAva.y, isReqAltAvaNee.u2) + annotation (Line(points={{12,40},{30,40},{30,-8},{78,-8}},color={255,0,255})); + connect(isReqAltAvaNee.y, ena.u1) + annotation (Line(points={{102,0},{108,0}},color={255,0,255})); + connect(uSta, cha.u) + annotation (Line(points={{-220,0},{-190,0},{-190,-60},{28,-60}},color={255,127,0})); + connect(logSwi.y, y1) + annotation (Line(points={{182,0},{220,0}},color={255,0,255})); + connect(y1, y1Pre.u) + annotation (Line(points={{220,0},{190,0},{190,-60},{182,-60}},color={255,0,255})); + connect(y1Pre.y, logSwi.u3) + annotation (Line(points={{158,-60},{150,-60},{150,-8},{158,-8}},color={255,0,255})); + connect(ena.y, logSwi.u1) + annotation (Line(points={{132,0},{138,0},{138,8},{158,8}},color={255,0,255})); + connect(booScaRep.y, logSwi.u2) + annotation (Line(points={{132,-60},{144,-60},{144,0},{158,0}},color={255,0,255})); + connect(nReq.y, nAltReq.u2) + annotation (Line(points={{12,0},{50,0},{50,34},{58,34}},color={255,127,0})); + connect(isReq.y, nReq.u1) + annotation (Line(points={{-38,-40},{-20,-40},{-20,0},{-12,0}},color={255,0,255})); + connect(nEnaAvaPre.y, intLes.u1) + annotation (Line(points={{78,-100},{70,-100},{70,-84},{24,-84},{24,-100},{28,-100}}, + color={255,127,0})); + connect(nEquSta.y, intLes.u2) + annotation (Line(points={{12,80},{20,80},{20,-108},{28,-108}},color={255,127,0})); + connect(swiEna.y, booScaRep.u) + annotation (Line(points={{102,-60},{108,-60}},color={255,0,255})); + connect(cha.y, swiEna.u1) + annotation (Line(points={{52,-60},{78,-60}},color={255,0,255})); + connect(intLes.y, swiEna.u2) + annotation (Line(points={{52,-100},{60,-100},{60,-68},{78,-68}},color={255,0,255})); + connect(isEnaPreAva.y, nEnaAvaPre.u1) + annotation (Line(points={{108,-100},{102,-100}},color={255,0,255})); + connect(y1Pre.y, isEnaPreAva.u2) + annotation (Line(points={{158,-60},{150,-60},{150,-108},{132,-108}},color={255,0,255})); + connect(u1Ava, isEnaPreAva.u1) + annotation (Line(points={{-220,-80},{140,-80},{140,-100},{132,-100}},color={255,0,255})); + connect(nAltReq.y, truArrCon.u) + annotation (Line(points={{82,40},{98,40}},color={255,127,0})); + connect(uIdxAltSor, truArrCon.uIdx) + annotation (Line(points={{-220,100},{90,100},{90,34},{98,34}},color={255,127,0})); + connect(truArrCon.y1, isReqAltAvaNee.u1) + annotation (Line(points={{122,40},{130,40},{130,20},{70,20},{70,0},{78,0}}, + color={255,0,255})); + connect(one.y, maxInt.u1) + annotation (Line(points={{-168,20},{-166,20},{-166,6},{-162,6}},color={255,127,0})); + connect(uSta, maxInt.u2) + annotation (Line(points={{-220,0},{-166,0},{-166,-6},{-162,-6}},color={255,127,0})); + connect(maxInt.y, intScaRep.u) + annotation (Line(points={{-138,0},{-132,0}},color={255,127,0})); + connect(uSta, greZer.u) + annotation (Line(points={{-220,0},{-190,0},{-190,-40},{-172,-40}},color={255,127,0})); + connect(greZer.y, booToRea.u) + annotation (Line(points={{-148,-40},{-142,-40}},color={255,0,255})); + connect(booToRea.y, reaScaRep.u) + annotation (Line(points={{-118,-40},{-112,-40}},color={0,0,127})); + connect(reqEquSta.y, voiStaZer.u1) + annotation (Line(points={{-138,80},{-120,80},{-120,86},{-102,86}},color={0,0,127})); + connect(reaScaRep.y, voiStaZer.u2) + annotation (Line(points={{-88,-40},{-80,-40},{-80,64},{-110,64},{-110,74},{-102,74}}, + color={0,0,127})); + connect(voiStaZer.y, nEquStaRea.u) + annotation (Line(points={{-78,80},{-62,80}},color={0,0,127})); + connect(voiStaZer.y, isReqPosAlt.u) + annotation (Line(points={{-78,80},{-70,80},{-70,40},{-62,40}},color={0,0,127})); + connect(voiStaZer.y, isNotReqNoAlt.u) + annotation (Line(points={{-78,80},{-70,80},{-70,0},{-62,0}},color={0,0,127})); + connect(voiStaZer.y, isReq.u) + annotation (Line(points={{-78,80},{-70,80},{-70,-40},{-62,-40}},color={0,0,127})); + annotation ( + defaultComponentName="enaEqu", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-200,-120},{200,120}})), + Documentation( + info=" +

+This block generates the equipment enable commands based on the +active stage index uSta, the equipment available +signal u1Ava and the indices of lead/lag alternate +equipment, sorted by increasing staging runtime. +

+

+A staging matrix staEqu is required as a parameter. +

+
    +
  • Each row of this matrix corresponds to a given stage.
  • +
  • Each column of this matrix corresponds to a given equipment.
  • +
  • A coefficient staEqu[i, j] equal to 0 +means that equipment j shall not be enabled at +stage i.
  • +
  • A coefficient staEqu[i, j] equal to 1 +means that equipment j is required at stage i. +If equipment j is unavailable, stage i is +deemed unavailable. +
  • +
  • A coefficient staEqu[i, j] strictly lower than 1 +and strictly greater than 0 means that equipment j +may be enabled at stage i as a lead/lag alternate equipment. +If equipment j is unavailable but another lead/lag alternate +equipment is available, then the latter equipment is enabled. +Stage i is only deemed unavailable if all +lead/lag alternate equipment specified for stage i +are unavailable. +
  • +
  • +The sum of the coefficients in a given row ∑_j staEqu[i, j] +gives the number of equipment required at stage i. +If this number cannot be achieved with the available equipment, +stage i is deemed unavailable. +
  • +
  • +The condition ∑_j staEqu[i+1, j] ≥ ∑_j staEqu[i, j] +is required for all i < size(staEqu, 1). +
  • +
+

+The state of the enable signals is only updated at stage change, or +if the number of previously enabled equipment that is available is +strictly less than the number of equipment required to run. +This avoids hot swapping equipment, e.g., an equipment would not be started +and another stopped during operation just to fulfill the priority order. +However, when a lead/lag alternate equipment becomes unavailable and another +lead/lag alternate equipment can be enabled to meet the number of required +equipment, then the state of the enable signals is updated. +

+")); +end EquipmentEnable; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/EventSequencing.mo b/Buildings/Templates/Plants/Controls/StagingRotation/EventSequencing.mo new file mode 100644 index 00000000000..33aeb99a775 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/EventSequencing.mo @@ -0,0 +1,405 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block EventSequencing "Staging event sequencing" + parameter Boolean have_heaWat + "Set to true for plants that provide HW" + annotation (Evaluate=true); + parameter Boolean have_chiWat + "Set to true for plants that provide CHW" + annotation (Evaluate=true); + parameter Boolean have_valInlIso + "Set to true if the system as inlet isolation valves" + annotation (Evaluate=true); + parameter Boolean have_valOutIso + "Set to true if the system as outlet isolation valves" + annotation (Evaluate=true); + parameter Boolean have_pumHeaWatPri(start=false) + "Set to true for plants with primary HW pumps" + annotation (Evaluate=true, + Dialog(enable=have_heaWat)); + parameter Boolean have_pumChiWatPri( + start=false) + "Set to true for plants with separate primary CHW pumps" + annotation (Evaluate=true, + Dialog(enable=have_chiWat)); + parameter Boolean have_pumHeaWatSec(start=false) + "Set to true for plants with secondary HW pumps" + annotation (Evaluate=true, + Dialog(enable=have_heaWat)); + parameter Boolean have_pumChiWatSec(start=false) + "Set to true for plants with secondary CHW pumps" + annotation (Evaluate=true, + Dialog(enable=have_chiWat)); + parameter Real dtVal( + min=0, + start=90, + unit="s")=90 + "Nominal valve timing" + annotation (Dialog(enable=have_valInlIso or have_valOutIso)); + parameter Real dtOff( + min=0, + unit="s") = 180 + "Heat pump internal shutdown cycle timing"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Hea + if have_heaWat + "Enable command from heating mode sequence" + annotation (Placement(transformation(extent={{-200,120},{-160,160}}), + iconTransformation(extent={{-140,100},{-100,140}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumHeaWatPri_actual + if have_heaWat and have_pumHeaWatPri + "Primary HW pump status (dedicated or lead headered pump)" + annotation (Placement(transformation(extent={{-200,-30},{-160,10}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumChiWatPri_actual + if have_chiWat and have_pumChiWatPri + "Primary CHW pump status – Dedicated or lead headered pump" + annotation (Placement(transformation(extent={{-200,-70},{-160,-30}}), + iconTransformation(extent={{-140,-40},{-100,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumHeaWatSec_actual + if have_heaWat and have_pumHeaWatSec + "Lead headered secondary HW pump status" + annotation (Placement(transformation(extent={{-200,-110},{-160,-70}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1PumChiWatSec_actual + if have_chiWat and have_pumChiWatSec + "Lead headered secondary CHW pump status" + annotation (Placement(transformation(extent={{-200,-150},{-160,-110}}), + iconTransformation(extent={{-140,-100},{-100,-60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValHeaWatInlIso + if have_heaWat and have_valInlIso + "Inlet HW inlet isolation valve command" + annotation (Placement(transformation(extent={{160,20},{200,60}}), + iconTransformation(extent={{100,0},{140,40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValHeaWatOutIso + if have_heaWat and have_valOutIso + "Outlet HW isolation valve command" + annotation (Placement(transformation(extent={{160,0},{200,40}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValChiWatInlIso + if have_chiWat and have_valInlIso + "Inlet CHW isolation valve command" + annotation (Placement(transformation(extent={{160,-20},{200,20}}), + iconTransformation(extent={{100,-40},{140,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1ValChiWatOutIso + if have_chiWat and have_valOutIso + "Outlet CHW isolation valve command" + annotation (Placement(transformation(extent={{160,-40},{200,0}}), + iconTransformation(extent={{100,-60},{140,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumHeaWatPri + if have_heaWat and have_pumHeaWatPri + "Primary HW pump start command – Dedicated or lead headered pump" + annotation (Placement(transformation(extent={{160,-80},{200,-40}}), + iconTransformation(extent={{100,-100},{140,-60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1PumChiWatPri + if have_chiWat and have_pumChiWatPri + "Primary CHW pump start command – Dedicated or lead headered pump" + annotation (Placement(transformation(extent={{160,-120},{200,-80}}), + iconTransformation(extent={{100,-120},{140,-80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1 + "Equipment enable command" + annotation (Placement(transformation(extent={{160,120},{200,160}}), + iconTransformation(extent={{100,100},{140,140}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Hea + if have_heaWat and have_chiWat + "Heating/cooling mode command: true=heating, false=cooling" + annotation (Placement(transformation(extent={{160,100},{200,140}}), + iconTransformation(extent={{100,80},{140,120}}))); + Buildings.Controls.OBC.CDL.Logical.Timer timVal( + final t=dtVal) + "Return true when nominal valve timing elapsed" + annotation (Placement(transformation(extent={{-50,90},{-30,110}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd heaValPum( + nin=3) + "Return true if heating AND valve timing elapsed AND lead HW pumps on" + annotation (Placement(transformation(extent={{60,110},{80,130}}))); + Buildings.Controls.OBC.CDL.Logical.Or ena + "Return true if enabled" + annotation (Placement(transformation(extent={{90,90},{110,110}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd cooValPum( + nin=4) + "Return true if cooling AND valve timing elapsed AND lead CHW pumps on" + annotation (Placement(transformation(extent={{60,70},{80,90}}))); + Utilities.PlaceholderLogical u1PumChiWatSec_internal( + final have_inp=have_chiWat and have_pumChiWatSec, + final have_inpPh=false, + final u_internal=true) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-150,-140},{-130,-120}}))); + Utilities.PlaceholderLogical timVal_internal( + final have_inp=have_valInlIso or have_valOutIso, + final have_inpPh=true, + final u_internal=true) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-10,90},{10,110}}))); + Utilities.PlaceholderLogical u1PumHeaWatSec_internal( + final have_inp=have_heaWat and have_pumHeaWatSec, + final have_inpPh=false, + final u_internal=true) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-150,-100},{-130,-80}}))); + Utilities.PlaceholderLogical u1PumChiWatPri_internal( + final have_inp=have_chiWat and have_pumChiWatPri, + final have_inpPh=false, + final u_internal=true) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-150,-60},{-130,-40}}))); + Utilities.PlaceholderLogical u1PumHeaWatPri_internal( + final have_inp=have_heaWat and have_pumHeaWatPri, + final have_inpPh=false, + final u_internal=true) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-150,-20},{-130,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Coo + if have_chiWat + "Enable command from cooling mode sequence" + annotation (Placement(transformation(extent={{-200,60},{-160,100}}), + iconTransformation(extent={{-140,60},{-100,100}}))); + Utilities.PlaceholderLogical u1Coo_internal( + final have_inp=have_chiWat, + final have_inpPh=false, + final u_internal=false) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-150,70},{-130,90}}))); + Buildings.Controls.OBC.CDL.Logical.Or u1HeaOrCoo + "Return true if enabled from heating or cooling mode sequence" + annotation (Placement(transformation(extent={{-90,110},{-70,130}}))); + Utilities.PlaceholderLogical u1Hea_internal( + final have_inp=have_heaWat, + final have_inpPh=false, + final u_internal=false) + "Replace with placeholder value if input signal is not available" + annotation (Placement(transformation(extent={{-150,130},{-130,150}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1AndHea + if have_heaWat + "Equipment commanded on in heating mode" + annotation (Placement(transformation(extent={{160,80},{200,120}}), + iconTransformation(extent={{100,60},{140,100}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1AndCoo + if have_chiWat + "Equipment commanded on in cooling mode" + annotation (Placement(transformation(extent={{160,60},{200,100}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.CDL.Logical.And enaAndHea + "Return true if enabled in heating mode" + annotation (Placement(transformation(extent={{130,90},{150,110}}))); + Buildings.Controls.OBC.CDL.Logical.And enaAndCoo + "Return true if enabled in cooling mode" + annotation (Placement(transformation(extent={{130,60},{150,80}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rou( + final nout=1) + if have_pumChiWatPri + "Signal routing for plants with dedicated primary CHW pumps" + annotation (Placement(transformation(extent={{60,-76},{80,-56}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rou1( + final nout=1) + if not have_pumChiWatPri + "Signal routing for plants without dedicated primary CHW pumps" + annotation (Placement(transformation(extent={{60,-50},{80,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Nor off + "Return true if disabled from heating and cooling mode sequence" + annotation (Placement(transformation(extent={{-52,10},{-32,30}}))); + Buildings.Controls.OBC.CDL.Logical.Timer timHp(final t=dtOff) + "Return true when heat pump internal shutdown cycle times out" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + Buildings.Controls.OBC.CDL.Logical.Latch latValHeaWatIso + if have_heaWat + "Keep valve open until heat pump internal shutdown cycle times out" + annotation (Placement(transformation(extent={{100,30},{120,50}}))); + Buildings.Controls.OBC.CDL.Logical.Latch latValChiWatIso + if have_chiWat + "Keep valve open until heat pump internal shutdown cycle times out" + annotation (Placement(transformation(extent={{100,-10},{120,10}}))); + Buildings.Controls.OBC.CDL.Logical.Latch latPumHeaWatPri + if have_heaWat + "Keep pump running until heat pump internal shutdown cycle times out" + annotation (Placement(transformation(extent={{110,-70},{130,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Latch latPumChiWatPri + if have_chiWat and have_pumChiWatPri + "Keep pump running until heat pump internal shutdown cycle times out" + annotation (Placement(transformation(extent={{110,-110},{130,-90}}))); +equation + connect(heaValPum.y, ena.u1) + annotation (Line(points={{82,120},{84,120},{84,100},{88,100}},color={255,0,255})); + connect(cooValPum.y, ena.u2) + annotation (Line(points={{82,80},{84,80},{84,92},{88,92}},color={255,0,255})); + connect(timVal.passed, timVal_internal.u) + annotation (Line(points={{-28,92},{-16,92},{-16,100},{-12,100}},color={255,0,255})); + connect(timVal_internal.y, heaValPum.u[1]) + annotation (Line(points={{12,100},{52,100},{52,117.667},{58,117.667}},color={255,0,255})); + connect(u1PumChiWatSec_actual, u1PumChiWatSec_internal.u) + annotation (Line(points={{-180,-130},{-152,-130}},color={255,0,255})); + connect(u1PumHeaWatPri_actual, u1PumHeaWatPri_internal.u) + annotation (Line(points={{-180,-10},{-152,-10}},color={255,0,255})); + connect(u1PumChiWatPri_actual, u1PumChiWatPri_internal.u) + annotation (Line(points={{-180,-50},{-152,-50}},color={255,0,255})); + connect(u1PumHeaWatSec_actual, u1PumHeaWatSec_internal.u) + annotation (Line(points={{-180,-90},{-152,-90}},color={255,0,255})); + connect(u1PumHeaWatPri_internal.y, heaValPum.u[2]) + annotation (Line(points={{-128,-10},{46,-10},{46,120},{58,120}},color={255,0,255})); + connect(u1PumHeaWatSec_internal.y, heaValPum.u[3]) + annotation (Line(points={{-128,-90},{50,-90},{50,122},{56,122},{56,122.333}, + {58,122.333}}, + color={255,0,255})); + connect(timVal_internal.y, cooValPum.u[1]) + annotation (Line(points={{12,100},{48,100},{48,77.375},{58,77.375}},color={255,0,255})); + connect(u1PumChiWatPri_internal.y, cooValPum.u[2]) + annotation (Line(points={{-128,-50},{48,-50},{48,79.125},{58,79.125}},color={255,0,255})); + connect(u1PumChiWatSec_internal.y, cooValPum.u[3]) + annotation (Line(points={{-128,-130},{52,-130},{52,80.875},{58,80.875}}, + color={255,0,255})); + connect(ena.y, y1) + annotation (Line(points={{112,100},{124,100},{124,140},{180,140}},color={255,0,255})); + connect(u1Hea, u1Hea_internal.u) + annotation (Line(points={{-180,140},{-152,140}},color={255,0,255})); + connect(u1Coo_internal.y, u1HeaOrCoo.u2) + annotation (Line(points={{-128,80},{-100,80},{-100,112},{-92,112}},color={255,0,255})); + connect(u1Hea_internal.y, u1HeaOrCoo.u1) + annotation (Line(points={{-128,140},{-120,140},{-120,120},{-92,120}},color={255,0,255})); + connect(u1HeaOrCoo.y, timVal.u) + annotation (Line(points={{-68,120},{-60,120},{-60,100},{-52,100}},color={255,0,255})); + connect(u1HeaOrCoo.y, timVal_internal.uPh) annotation (Line(points={{-68,120}, + {-20,120},{-20,94},{-12,94}}, color={255,0,255})); + connect(u1Coo, u1Coo_internal.u) + annotation (Line(points={{-180,80},{-152,80}},color={255,0,255})); + connect(u1Coo_internal.y, cooValPum.u[4]) + annotation (Line(points={{-128,80},{58,80},{58,82.625}},color={255,0,255})); + connect(u1Hea_internal.y, y1Hea) + annotation (Line(points={{-128,140},{120,140},{120,120},{180,120}},color={255,0,255})); + connect(ena.y, enaAndHea.u1) + annotation (Line(points={{112,100},{128,100}},color={255,0,255})); + connect(u1Hea_internal.y, enaAndHea.u2) + annotation (Line(points={{-128,140},{120,140},{120,92},{128,92}},color={255,0,255})); + connect(enaAndHea.y, y1AndHea) + annotation (Line(points={{152,100},{180,100}},color={255,0,255})); + connect(ena.y, enaAndCoo.u1) + annotation (Line(points={{112,100},{124,100},{124,70},{128,70}},color={255,0,255})); + connect(u1Coo_internal.y, enaAndCoo.u2) + annotation (Line(points={{-128,80},{-100,80},{-100,48},{60,48},{60,62},{128,62}}, + color={255,0,255})); + connect(enaAndCoo.y, y1AndCoo) + annotation (Line(points={{152,70},{156,70},{156,80},{180,80}},color={255,0,255})); + connect(u1Hea_internal.y, rou.u) + annotation (Line(points={{-128,140},{-120,140},{-120,-66},{58,-66}},color={255,0,255})); + connect(u1HeaOrCoo.y, rou1.u) + annotation (Line(points={{-68,120},{44,120},{44,-40},{58,-40}}, color={255,0,255})); + connect(u1Hea_internal.y, off.u1) + annotation (Line(points={{-128,140},{-120,140},{-120,20},{-54,20}},color={255,0,255})); + connect(u1Coo_internal.y, off.u2) + annotation (Line(points={{-128,80},{-100,80},{-100,12},{-54,12}},color={255,0,255})); + connect(off.y, timHp.u) + annotation (Line(points={{-30,20},{-12,20}},color={255,0,255})); + connect(timHp.passed, latValHeaWatIso.clr) + annotation (Line(points={{12,12},{40,12},{40,34},{98,34}}, color={255,0,255})); + connect(latValHeaWatIso.y, y1ValHeaWatInlIso) + annotation (Line(points={{122,40},{180,40}},color={255,0,255})); + connect(u1Hea_internal.y, latValHeaWatIso.u) + annotation (Line(points={{-128,140},{-120,140},{-120,40},{98,40}},color={255,0,255})); + connect(latValChiWatIso.y, y1ValChiWatInlIso) + annotation (Line(points={{122,0},{180,0}},color={255,0,255})); + connect(timHp.passed, latValChiWatIso.clr) + annotation (Line(points={{12,12},{40,12},{40,-6},{98,-6}}, color={255,0,255})); + connect(latValHeaWatIso.y, y1ValHeaWatOutIso) + annotation (Line(points={{122,40},{140,40},{140,20},{180,20}},color={255,0,255})); + connect(latValChiWatIso.y, y1ValChiWatOutIso) + annotation (Line(points={{122,0},{140,0},{140,-20},{180,-20}},color={255,0,255})); + connect(rou1.y[1], latPumHeaWatPri.u) + annotation (Line(points={{82,-40},{90,-40},{90,-60},{108,-60}}, + color={255,0,255})); + connect(rou.y[1], latPumHeaWatPri.u) + annotation (Line(points={{82,-66},{90,-66},{90,-60},{108,-60}}, + color={255,0,255})); + connect(timHp.passed, latPumHeaWatPri.clr) + annotation (Line(points={{12,12},{40,12},{40,-20},{100,-20},{100,-66},{108, + -66}}, + color={255,0,255})); + connect(latPumHeaWatPri.y, y1PumHeaWatPri) + annotation (Line(points={{132,-60},{180,-60}}, color={255,0,255})); + connect(latPumChiWatPri.y, y1PumChiWatPri) + annotation (Line(points={{132,-100},{180,-100}}, + color={255,0,255})); + connect(timHp.passed, latPumChiWatPri.clr) + annotation (Line(points={{12,12},{40,12},{40,-106},{108,-106}}, + color={255,0,255})); + connect(u1Coo_internal.y, latPumChiWatPri.u) + annotation (Line(points={{-128,80},{-100,80},{-100,-100},{108,-100}}, + color={255,0,255})); + connect(u1Coo_internal.y, latValChiWatIso.u) + annotation (Line(points={{-128,80},{-100,80},{-100,0},{98,0}},color={255,0,255})); + annotation ( + defaultComponentName="seqEve", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-140},{100,140}}), + graphics={ + Rectangle( + extent={{-100,140},{100,-142}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,190},{150,150}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-160,-160},{160,160}})), + Documentation( + info=" +

+If a heat pump is commanded on in a desired heating or cooling mode: +

+
    +
  • +The isolation valves for desired heating or cooling mode are commanded +open. +
  • +
  • +Plants with dedicated primary pumps: +The dedicated primary pumps are commanded on when the +associated isolation valves are commanded open. +
  • +
  • +Plants with headered primary pumps: +The headered primary pumps are commanded on as described in + +Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered. +
  • +
  • +Once the isolation valves are fully open (based on nominal valve timing dtVal) +and the lead pumps are proven on, the heat pump is enabled in heating or cooling +mode. +
  • +
+

+If a heat pump is commanded off: +

+
    +
  • +The heat pump is disabled. +
  • +
  • +After the time required for the internal shutdown cycle to time out +(dtOff to be determined empirically, defaulting to 3 min), +all isolation valves are commanded closed. +
  • +
  • +Plants with dedicated primary pumps: +The dedicated primary pumps are commanded off when the associated +isolation valves are commanded closed. +
  • +
  • +Plants with headered primary pumps: +The headered primary pumps are commanded off as described in + +Buildings.Templates.Plants.Controls.Pumps.Generic.StagingHeadered. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end EventSequencing; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/SortRuntime.mo b/Buildings/Templates/Plants/Controls/StagingRotation/SortRuntime.mo new file mode 100644 index 00000000000..10da1a82e72 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/SortRuntime.mo @@ -0,0 +1,315 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block SortRuntime + "Sort equipment by increasing staging runtime" + parameter Integer nin=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + parameter Integer idxEquAlt[:]={i for i in 1:nin} + "Indices of lead/lag alternate equipment" + annotation (Evaluate=true); + final parameter Integer nEquAlt=size(idxEquAlt, 1) + "Number of lead/lag alternate equipment" + annotation (Evaluate=true); + parameter Real runTim_start[nEquAlt]={60 + i for i in 1:nEquAlt} + "Staging runtime initial values"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Run[nin] + "Boolean signal used to assess equipment runtime" + annotation (Placement(transformation(extent={{-240,20},{-200,60}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Ava[nin] + "Equipment available signal" + annotation (Placement(transformation(extent={{-240,-60},{-200,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yRunTimLif[nEquAlt] + "Lifetime runtime" + annotation (Placement(transformation(extent={{200,60},{240,100}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput yRunTimSta[nEquAlt] + "Staging runtime" + annotation (Placement(transformation(extent={{200,20},{240,60}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yIdx[nEquAlt]( + start={i for i in 1:nEquAlt}) + "Indices of equipment sorted by increasing staging runtime" + annotation (Placement(transformation(extent={{200,-20},{240,20}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + Buildings.Controls.OBC.CDL.Logical.TimerAccumulating timRun[nEquAlt] + "Compute staging runtime" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}))); + Buildings.Controls.OBC.CDL.Logical.Not off[nEquAlt] + "Return true if equipment off" + annotation (Placement(transformation(extent={{-130,30},{-110,50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1Res[nEquAlt]( + each k=false) "Signal for staging runtime reset" + annotation (Placement(transformation(extent={{-180,-110},{-160,-90}}))); + Utilities.SortWithIndices sor( + final ascending=true, + nin=nEquAlt) + "Sort equipment by increasing weighted runtime" + annotation (Placement(transformation(extent={{110,-10},{130,10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal weiOffAva[nEquAlt]( + each final realTrue=1E10, + each final realFalse=1) + "Weight to be applied to runtime of equipment off and available" + annotation (Placement(transformation(extent={{-50,30},{-30,50}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply appWeiOffAva[nEquAlt] + "Apply weights to runtime of equipment off and available" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply voiRunUna[nEquAlt] + "Void runtime of unavailable equipment" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + Buildings.Controls.OBC.CDL.Logical.And offAva[nEquAlt] + "Return true if equipment off and available" + annotation (Placement(transformation(extent={{-90,30},{-70,50}}))); + Buildings.Controls.OBC.CDL.Logical.Not una[nEquAlt] + "Return true if equipment unavailable" + annotation (Placement(transformation(extent={{-90,-50},{-70,-30}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal zerUna[nEquAlt]( + each final realTrue=0, + each final realFalse=1) + "Assign zero to unavailable equipment" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Timer timUna[nEquAlt] + "Compute time elapsed since equipment is unavailable" + annotation (Placement(transformation(extent={{-50,-90},{-30,-70}}))); + Buildings.Controls.OBC.CDL.Reals.AddParameter addWei[nEquAlt]( + each final p=1E20) + "Add weight" + annotation (Placement(transformation(extent={{10,-90},{30,-70}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter opp[nEquAlt]( + each final k=- 1) + "Take opposite value" + annotation (Placement(transformation(extent={{-20,-90},{0,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Add addWeiUna[nEquAlt] + "Add weight to unavailable equipment" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply voiWeiAva[nEquAlt] + "Void weight of available equipment" + annotation (Placement(transformation(extent={{48,-90},{68,-70}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal zerAva[nEquAlt]( + each final realTrue=0, + each final realFalse=1) + "Assign zero to available equipment" + annotation (Placement(transformation(extent={{-50,-130},{-30,-110}}))); + Buildings.Controls.OBC.CDL.Logical.TimerAccumulating timRunLif[nEquAlt] + "Compute lifetime runtime" + annotation (Placement(transformation(extent={{-50,70},{-30,90}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant fal[nEquAlt]( + each final k=false) + "Constant" + annotation (Placement(transformation(extent={{-180,90},{-160,110}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanExtractSignal u1RunEquAlt( + final nin=nin, + final nout=nEquAlt, + final extract=idxEquAlt) + "Extract signal for lead/lag alternate equipment only" + annotation (Placement(transformation(extent={{-180,30},{-160,50}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanExtractSignal u1AvaEquAlt( + final nin=nin, + final nout=nEquAlt, + final extract=idxEquAlt) + "Extract signal for lead/lag alternate equipment only" + annotation (Placement(transformation(extent={{-180,-50},{-160,-30}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerExtractor resIdxInp[nEquAlt]( + each final nin=nEquAlt) + "Restore indices consistent with input vectors" + annotation (Placement(transformation(extent={{170,-10},{190,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant idxEquAltMat[nEquAlt, nEquAlt]( + final k={idxEquAlt for i in 1:nEquAlt}) + "Indices of lead/lag alternate equipment repeated nEquAlt times" + annotation (Placement(transformation(extent={{110,-50},{130,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant runTimSta[nEquAlt]( + final k=runTim_start) + "Staging runtime initial values" + annotation (Placement(transformation(extent={{-100,110},{-80,130}}))); + Buildings.Controls.OBC.CDL.Reals.Max iniRunTim[nEquAlt] + "Fix runtime until it exceeds the initial value" + annotation (Placement(transformation(extent={{-50,-10},{-30,10}}))); +equation + connect(u1Res.y, timRun.reset) + annotation (Line(points={{-158,-100},{-120,-100},{-120,-8},{-92,-8}},color={255,0,255})); + connect(weiOffAva.y, appWeiOffAva.u1) + annotation (Line(points={{-28,40},{-20,40},{-20,6},{-12,6}},color={0,0,127})); + connect(off.y, offAva.u1) + annotation (Line(points={{-108,40},{-92,40}},color={255,0,255})); + connect(offAva.y, weiOffAva.u) + annotation (Line(points={{-68,40},{-52,40}},color={255,0,255})); + connect(appWeiOffAva.y, voiRunUna.u1) + annotation (Line(points={{12,0},{20,0},{20,6},{28,6}},color={0,0,127})); + connect(zerUna.y, voiRunUna.u2) + annotation (Line(points={{-28,-40},{20,-40},{20,-6},{28,-6}},color={0,0,127})); + connect(una.y, timUna.u) + annotation (Line(points={{-68,-40},{-60,-40},{-60,-80},{-52,-80}},color={255,0,255})); + connect(una.y, zerUna.u) + annotation (Line(points={{-68,-40},{-52,-40}},color={255,0,255})); + connect(timUna.y, opp.u) + annotation (Line(points={{-28,-80},{-22,-80}},color={0,0,127})); + connect(opp.y, addWei.u) + annotation (Line(points={{2,-80},{8,-80}},color={0,0,127})); + connect(addWeiUna.y, sor.u) + annotation (Line(points={{92,0},{108,0}},color={0,0,127})); + connect(voiRunUna.y, addWeiUna.u1) + annotation (Line(points={{52,0},{54,0},{54,6},{68,6}},color={0,0,127})); + connect(voiWeiAva.y, addWeiUna.u2) + annotation (Line(points={{70,-80},{80,-80},{80,-20},{60,-20},{60,-6},{68,-6}}, + color={0,0,127})); + connect(addWei.y, voiWeiAva.u1) + annotation (Line(points={{32,-80},{40,-80},{40,-74},{46,-74}},color={0,0,127})); + connect(zerAva.y, voiWeiAva.u2) + annotation (Line(points={{-28,-120},{40,-120},{40,-86},{46,-86}},color={0,0,127})); + connect(timRunLif.y, yRunTimLif) + annotation (Line(points={{-28,80},{220,80}},color={0,0,127})); + connect(fal.y, timRunLif.reset) + annotation (Line(points={{-158,100},{-60,100},{-60,72},{-52,72}},color={255,0,255})); + connect(u1Run, u1RunEquAlt.u) + annotation (Line(points={{-220,40},{-182,40}},color={255,0,255})); + connect(u1RunEquAlt.y, off.u) + annotation (Line(points={{-158,40},{-132,40}},color={255,0,255})); + connect(u1RunEquAlt.y, timRunLif.u) + annotation (Line(points={{-158,40},{-140,40},{-140,80},{-52,80}},color={255,0,255})); + connect(u1RunEquAlt.y, timRun.u) + annotation (Line(points={{-158,40},{-140,40},{-140,0},{-92,0}},color={255,0,255})); + connect(u1Ava, u1AvaEquAlt.u) + annotation (Line(points={{-220,-40},{-182,-40}},color={255,0,255})); + connect(u1AvaEquAlt.y, una.u) + annotation (Line(points={{-158,-40},{-92,-40}},color={255,0,255})); + connect(u1AvaEquAlt.y, zerAva.u) + annotation (Line(points={{-158,-40},{-100,-40},{-100,-120},{-52,-120}},color={255,0,255})); + connect(u1AvaEquAlt.y, offAva.u2) + annotation (Line(points={{-158,-40},{-100,-40},{-100,32},{-92,32}},color={255,0,255})); + connect(idxEquAltMat.y, resIdxInp.u) + annotation (Line(points={{132,-40},{160,-40},{160,0},{168,0}},color={255,127,0})); + connect(sor.yIdx, resIdxInp.index) + annotation (Line(points={{132,-6},{164,-6},{164,-16},{180,-16},{180,-12}}, + color={255,127,0})); + connect(resIdxInp.y, yIdx) + annotation (Line(points={{192,0},{220,0}},color={255,127,0})); + connect(runTimSta.y, iniRunTim.u1) + annotation (Line(points={{-78,120},{-66,120},{-66,6},{-52,6}},color={0,0,127})); + connect(timRun.y, iniRunTim.u2) + annotation (Line(points={{-68,0},{-60,0},{-60,-6},{-52,-6}},color={0,0,127})); + connect(iniRunTim.y, appWeiOffAva.u2) + annotation (Line(points={{-28,0},{-20,0},{-20,-6},{-12,-6}},color={0,0,127})); + connect(timRun.y, yRunTimSta) + annotation (Line(points={{-68,0},{-60,0},{-60,20},{180,20},{180,40},{220,40}}, + color={0,0,127})); + annotation ( + defaultComponentName="sorRunTim", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-200,-160},{200,160}})), + Documentation( + info=" +

+This block implements the rotation logic for identical parallel +staged equipment that are lead/lag alternated. +

+

+Two runtime points are defined for each equipment. +The Lifetime Runtime is the cumulative runtime of the equipment +since equipment start-up. This point is not readily resettable by operators. +Lifetime Runtime should be stored to a software point on the control +system server so the recorded value is not lost due to controller reset, +loss of power, programming file update, etc. +The Staging Runtime is an operator resettable runtime point that stores +cumulative runtime since the last operator reset. +

+

+In the case of available equipment, +when more than one equipment is off or more than one is on, +the equipment with the most operating hours as determined by +Staging Runtime is made the last stage equipment and the one +with the least number of hours is made the lead stage equipment. +

+

+In the case of unavailable equipment, +the equipment that alarmed most recently is sent to the last position. +The equipment in alarm automatically moves up in the staging order +only if another equipment goes into alarm. +

+

Staging runtime initialization

+

+When the controller is initialized, the choice of the first equipment to run +is random since all runtimes are equal to zero. +So, before this first equipment reports status, all equipment will be +considered off and only this first equipment will increase runtime and be +queued in the staging order. +At next stage change, another equipment will then be staged on instead, +resulting in the first running equipment being \"hot swapped\". +To avoid this behavior, the vector parameter runTim_start is used +to initialize the staging runtime, which will be fixed at this parameter +value until it becomes higher. +The parameter runTim_start should be set to a vector of +strictly increasing values, where the minimum value is greater than +the time needed for the equipment to report status. +

+

Details

+

+The sorting logic is implemented using the following method. +

+
    +
  • +If a unit is on and available, its staging runtime is used as is. +
  • +
  • +If a unit is off and available, its staging runtime is increased +by a constant of 1E10 s. +
  • +
  • +If a unit is unavailable, its staging runtime is replaced by +the time that has elapsed since the unit became unavailable. +This time is then increased by a constant of 1E20 s. +
  • +
  • +A unique instance of the sorting block is then used to order +the different units. +
  • +
+

+This is effectively the same as sorting the units within +the three following subsets: units that are on and available, +units that are off and available, units that are unavailable. +In particular, the order index of a given unit remains unchanged +if it is the only element of a given subset. +Note that the staging runtime and the time elapsed since an equipment became unavailable +are both computed from Boolean signals (u1Run and u1Ava). +These are discrete-time, piecewise constant variables, +which is why the caveat in the documentation of + +Buildings.Templates.Plants.Controls.Utilities.SortWithIndices +for purely continuous time-varying variables does not apply here. +Therefore, no sampling is performed before sorting the equipment runtimes. +

+

+To facilitate integration into the plant controller, the input vectors +cover the full set of equipment, including equipment that may not be +lead/lag alternate. +The output vectors cover only the subset of lead/lag alternate equipment, +and the vector of sorted equipment provides indices with respect +to the input vectors (full set of equipment). +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end SortRuntime; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/StageAvailability.mo b/Buildings/Templates/Plants/Controls/StagingRotation/StageAvailability.mo new file mode 100644 index 00000000000..398f600f4ab --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/StageAvailability.mo @@ -0,0 +1,158 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block StageAvailability + "Compute stage availability" + parameter Real staEqu[:,:]( + each unit="1", + each min=0, + each max=1) + "Staging matrix – Equipment required for each stage"; + final parameter Integer nSta=size(staEqu, 1) + "Number of stages" + annotation (Evaluate=true); + final parameter Integer nEqu=size(staEqu, 2) + "Number of equipment" + annotation (Evaluate=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Ava[nEqu] + "Equipment available signal" + annotation (Placement(transformation(extent={{-180,-80},{-140,-40}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1[nSta] + "Stage available signal" + annotation (Placement(transformation(extent={{140,-20},{180,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant matStaEqu[nSta, nEqu]( + final k=staEqu) + "Staging matrix" + annotation (Placement(transformation(extent={{-130,-10},{-110,10}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isReq[nSta, nEqu]( + each final t=0.99) + "Return true if equipment required without lead/lag alternate" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold isReqPosAlt[nSta, nEqu]( + each final t=0) + "Return true if equipment required (with or without lead/lag alternate)" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Buildings.Controls.OBC.CDL.Reals.LessThreshold isNotReqNoAlt[nSta, nEqu]( + each final t=1) + "Return true if equipment not required or required with lead/lag alternate" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator booVecRep( + final nin=nEqu, + final nout=nSta) + "Replicate equipment available signal" + annotation (Placement(transformation(extent={{-130,-70},{-110,-50}}))); + Buildings.Controls.OBC.CDL.Logical.And isReqAva[nSta, nEqu] + "Return true if equipment required without lead/lag alternate and available" + annotation (Placement(transformation(extent={{-40,-50},{-20,-30}}))); + Buildings.Controls.OBC.CDL.Logical.And isReqAltAva[nSta, nEqu] + "Return true if equipment required (with or without lead/lag alternate) and available" + annotation (Placement(transformation(extent={{-40,30},{-20,50}}))); + Buildings.Controls.OBC.CDL.Logical.Or isReqAvaOrNotReq[nSta, nEqu] + "Return true if equipment required without lead/lag alternate and available, or if not required" + annotation (Placement(transformation(extent={{0,-30},{20,-10}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd all[nSta]( + each final nin=nEqu) + "Return true if previous block condition valid for all elements" + annotation (Placement(transformation(extent={{30,-30},{50,-10}}))); + Buildings.Controls.OBC.CDL.Logical.And isAva[nSta] + "Return true if stage available" + annotation (Placement(transformation(extent={{110,-10},{130,10}}))); + Buildings.Controls.OBC.CDL.Reals.MultiSum nEquSta[nSta]( + each final nin=nEqu) + "Return the number of equipment required at each stage" + annotation (Placement(transformation(extent={{-80,70},{-60,90}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nSta, nEqu] + "Convert to integer" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); + Buildings.Controls.OBC.CDL.Integers.GreaterEqual isReqAltAvaGreReq[nSta] + "Return true if number of required available equipment higher than number of required equipment" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum nReqAltAva[nSta]( + each final nin=nEqu) + "Number of equipment required (with or without lead/lag alternate) and available" + annotation (Placement(transformation(extent={{30,30},{50,50}}))); + Buildings.Controls.OBC.CDL.Conversions.RealToInteger nEquStaInt[nSta] + "Integer cast of number of equipment required at each stage" + annotation (Placement(transformation(extent={{-40,70},{-20,90}}))); +equation + connect(matStaEqu.y, isReq.u) + annotation (Line(points={{-108,0},{-90,0},{-90,-40},{-82,-40}},color={0,0,127})); + connect(matStaEqu.y, isReqPosAlt.u) + annotation (Line(points={{-108,0},{-90,0},{-90,40},{-82,40}},color={0,0,127})); + connect(matStaEqu.y, isNotReqNoAlt.u) + annotation (Line(points={{-108,0},{-82,0}},color={0,0,127})); + connect(isReq.y, isReqAva.u1) + annotation (Line(points={{-58,-40},{-42,-40}},color={255,0,255})); + connect(booVecRep.y, isReqAva.u2) + annotation (Line(points={{-108,-60},{-50,-60},{-50,-48},{-42,-48}},color={255,0,255})); + connect(booVecRep.y, isReqAltAva.u2) + annotation (Line(points={{-108,-60},{-50,-60},{-50,32},{-42,32}},color={255,0,255})); + connect(isReqAva.y, isReqAvaOrNotReq.u2) + annotation (Line(points={{-18,-40},{-10,-40},{-10,-28},{-2,-28}},color={255,0,255})); + connect(isNotReqNoAlt.y, isReqAvaOrNotReq.u1) + annotation (Line(points={{-58,0},{-10,0},{-10,-20},{-2,-20}},color={255,0,255})); + connect(isAva.y, y1) + annotation (Line(points={{132,0},{160,0}},color={255,0,255})); + connect(isReqAvaOrNotReq.y, all.u) + annotation (Line(points={{22,-20},{28,-20}},color={255,0,255})); + connect(matStaEqu.y, nEquSta.u) + annotation (Line(points={{-108,0},{-90,0},{-90,80},{-82,80}},color={0,0,127})); + connect(nReqAltAva.y, isReqAltAvaGreReq.u1) + annotation (Line(points={{52,40},{68,40}},color={255,127,0})); + connect(nReqAltAva.u, booToInt.y) + annotation (Line(points={{28,40},{22,40}},color={255,127,0})); + connect(nEquSta.y, nEquStaInt.u) + annotation (Line(points={{-58,80},{-42,80}},color={0,0,127})); + connect(nEquStaInt.y, isReqAltAvaGreReq.u2) + annotation (Line(points={{-18,80},{60,80},{60,32},{68,32}},color={255,127,0})); + connect(u1Ava, booVecRep.u) + annotation (Line(points={{-160,-60},{-132,-60}},color={255,0,255})); + connect(isReqPosAlt.y, isReqAltAva.u1) + annotation (Line(points={{-58,40},{-42,40}},color={255,0,255})); + connect(isReqAltAva.y, booToInt.u) + annotation (Line(points={{-18,40},{-2,40}},color={255,0,255})); + connect(isReqAltAvaGreReq.y, isAva.u1) + annotation (Line(points={{92,40},{100,40},{100,0},{108,0}},color={255,0,255})); + connect(all.y, isAva.u2) + annotation (Line(points={{52,-20},{100,-20},{100,-8},{108,-8}},color={255,0,255})); + annotation ( + defaultComponentName="avaSta", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + extent={{-140,-100},{140,100}})), + Documentation( + info=" +

+A stage is deemed available if both the following are true: +

+
    +
  • +Each equipment required to run at that stage without +lead/lag alternate is available. +
  • +
  • +The number of equipment required to run at that stage – +with or without lead/lag alternate – and available +is greater or equal to the number of equipment required to run +at that stage. +
  • +
+

+Otherwise, the stage is deemed unavailable. +

+")); +end StageAvailability; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/StageChangeCommand.mo b/Buildings/Templates/Plants/Controls/StagingRotation/StageChangeCommand.mo new file mode 100644 index 00000000000..3eef5577daf --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/StageChangeCommand.mo @@ -0,0 +1,458 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block StageChangeCommand + "Generate stage change command" + parameter Boolean have_inpPlrSta=false + "Set to true to use an input signal for SPLR, false to use a parameter" + annotation (Evaluate=true); + parameter Real plrSta( + final max=1, + final min=0, + start=0.9, + final unit="1")=0.9 + "Staging part load ratio" + annotation (Dialog(enable=not have_inpPlrSta)); + final parameter Real traStaEqu[nEqu, nSta]={{staEqu[i, j] for i in 1:nSta} for j in 1:nEqu} + "Transpose of staging matrix"; + parameter Real staEqu[:,:]( + each final max=1, + each final min=0, + each final unit="1") + "Staging matrix – Equipment required for each stage"; + final parameter Integer nSta=size(staEqu, 1) + "Number of stages" + annotation (Evaluate=true); + final parameter Integer nEqu=size(staEqu, 2) + "Number of equipment" + annotation (Evaluate=true); + parameter Real capEqu[nEqu]( + each final min=0, + each final unit="W") + "Design capacity of each equipment"; + parameter Real dtRun( + final min=0, + final unit="s")=900 + "Runtime with exceeded staging part load ratio before staging event is triggered"; + parameter Real dtMea( + final min=0, + final unit="s")=300 + "Duration used to compute the moving average of required capacity"; + parameter Real cp_default( + final min=0, + final unit="J/(kg.K)") + "Default specific heat capacity used to compute required capacity"; + parameter Real rho_default( + final min=0, + final unit="kg/m3") + "Default density used to compute required capacity"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1AvaSta[nSta] + "Stage available signal" + annotation (Placement(transformation(extent={{-240,60},{-200,100}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1StaPro + "Staging process in progress" + annotation (Placement(transformation(extent={{-240,-40},{-200,0}}), + iconTransformation(extent={{-140,0},{-100,40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput uPlrSta( + final unit="1", + final min=0, + final max=1) + if have_inpPlrSta + "Input signal for staging part load ratio" + annotation (Placement(transformation(extent={{-240,-200},{-200,-160}}), + iconTransformation(extent={{-140,-120},{-100,-80}}))); + // We allow the stage index to be zero, e.g., when the plant is disabled. + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uSta( + final min=0, + final max=nSta) + "Stage index" + annotation (Placement(transformation(extent={{-240,160},{-200,200}}), + iconTransformation(extent={{-140,80},{-100,120}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TRet( + final unit="K", + displayUnit="degC") + "Return temperature used to compute required capacity" + annotation (Placement(transformation(extent={{-240,-120},{-200,-80}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput TSupSet( + final unit="K", + displayUnit="degC") + "Active supply temperature setpoint used to compute required capacity" + annotation (Placement(transformation(extent={{-240,-80},{-200,-40}}), + iconTransformation(extent={{-140,-60},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput V_flow( + final unit="m3/s") + "Volume flow rate used to compute required capacity" + annotation (Placement(transformation(extent={{-240,-160},{-200,-120}}), + iconTransformation(extent={{-140,-100},{-100,-60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Up + "Stage up command" + annotation (Placement(transformation(extent={{200,60},{240,100}}), + iconTransformation(extent={{100,20},{140,60}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1Dow + "Stage down command" + annotation (Placement(transformation(extent={{200,-100},{240,-60}}), + iconTransformation(extent={{100,-60},{140,-20}}))); + Buildings.Controls.OBC.CDL.Reals.Subtract delT( + y(final unit="K")) + "Compute ∆T" + annotation (Placement(transformation(extent={{-170,-90},{-150,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Abs absDelT( + y(final unit="K")) + "Compute absolute value of ∆T" + annotation (Placement(transformation(extent={{-130,-90},{-110,-70}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter capFlo( + y(final unit="W/K"), + final k=rho_default * cp_default) + "Compute capacity flow rate" + annotation (Placement(transformation(extent={{-130,-150},{-110,-130}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply capReq + "Compute required capacity" + annotation (Placement(transformation(extent={{-90,-90},{-70,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant traMatStaEqu[nEqu, nSta]( + final k=traStaEqu) + "Transpose of staging matrix" + annotation (Placement(transformation(extent={{-70,210},{-50,230}}))); + Buildings.Controls.OBC.CDL.Routing.RealExtractor reqEquSta[nEqu]( + each final nin=nSta) + "Extract equipment required at given stage" + annotation (Placement(transformation(extent={{-10,210},{10,230}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator intScaRep( + final nout=nEqu) + "Replicate signal" + annotation (Placement(transformation(extent={{-104,190},{-84,210}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply capEquSta[nEqu] + "Capacity of each equipment required at given stage" + annotation (Placement(transformation(extent={{30,210},{50,230}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant capEquPar[nEqu]( + final k=capEqu) + "Capacity of each equipment" + annotation (Placement(transformation(extent={{-70,150},{-50,170}}))); + Buildings.Controls.OBC.CDL.Reals.MultiSum capSta( + nin=nEqu) + "Compute nominal capacity of active stage" + annotation (Placement(transformation(extent={{70,210},{90,230}}))); + Buildings.Controls.OBC.CDL.Reals.Greater gre(h=1E-4*min(capEqu)) + "Compare OPLR to SPLR (hysteresis is to avoid chattering with some simulators)" + annotation (Placement(transformation(extent={{60,-70},{80,-50}}))); + Buildings.Controls.OBC.CDL.Reals.MovingAverage movAve( + delta=dtMea) + "Compute moving average" + annotation (Placement(transformation(extent={{-50,-90},{-30,-70}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset timUp( + final t=dtRun) + "Timer" + annotation (Placement(transformation(extent={{110,-70},{130,-50}}))); + Buildings.Controls.OBC.CDL.Reals.Less les(h=1E-4*min(capEqu)) + "Compare OPLR to SPLR (hysteresis is to avoid chattering with some simulators)" + annotation (Placement(transformation(extent={{60,-130},{80,-110}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset timDow( + final t=dtRun) + "Timer" + annotation (Placement(transformation(extent={{110,-130},{130,-110}}))); + Utilities.HoldReal hol(final dtHol=dtRun) + "Hold value of required capacity at stage change" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); + Buildings.Controls.OBC.CDL.Integers.Max maxInt + "Maximum between stage index and 1" + annotation (Placement(transformation(extent={{-140,190},{-120,210}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant one( + final k=1) + "Constant" + annotation (Placement(transformation(extent={{-180,170},{-160,190}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant idxSta[nSta]( + final k={i for i in 1:nSta}) + "Stage index" + annotation (Placement(transformation(extent={{-180,130},{-160,150}}))); + Buildings.Controls.OBC.CDL.Integers.Less idxStaLesAct[nSta] + "Return true if stage index lower than active stage index" + annotation (Placement(transformation(extent={{-150,90},{-130,110}}))); + Buildings.Controls.OBC.CDL.Logical.And idxStaLesActAva[nSta] + annotation (Placement(transformation(extent={{-110,70},{-90,90}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator intScaRep1( + final nout=nSta) + "Replicate signal" + annotation (Placement(transformation(extent={{-180,90},{-160,110}}))); + Utilities.LastTrueIndex idxLasTru( + nin=nSta) + "Index of next available lower stage" + annotation (Placement(transformation(extent={{-70,70},{-50,90}}))); + Buildings.Controls.OBC.CDL.Integers.Max maxInt1 + "Maximum between stage index and 1" + annotation (Placement(transformation(extent={{-30,110},{-10,130}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator intScaRep2( + final nout=nEqu) + "Replicate signal" + annotation (Placement(transformation(extent={{10,110},{30,130}}))); + Buildings.Controls.OBC.CDL.Routing.RealExtractor reqEquStaLow[nEqu]( + each final nin=nSta) + "Extract equipment required at next available lower stage" + annotation (Placement(transformation(extent={{-10,170},{10,190}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply capEquStaLow[nEqu] + "Capacity of each equipment required at next available lower stage" + annotation (Placement(transformation(extent={{30,170},{50,190}}))); + Buildings.Controls.OBC.CDL.Reals.MultiSum capStaLow( + nin=nEqu) + "Compute nominal capacity of next available lower stage" + annotation (Placement(transformation(extent={{70,170},{90,190}}))); + Buildings.Controls.OBC.CDL.Integers.Min minInt + "Minimum between stage index and 1" + annotation (Placement(transformation(extent={{-30,70},{-10,90}}))); + Buildings.Controls.OBC.CDL.Conversions.IntegerToReal intToRea + "Convert to real value" + annotation (Placement(transformation(extent={{10,70},{30,90}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply setZer + "Set nominal capacity to zero if no lower available stage" + annotation (Placement(transformation(extent={{110,170},{130,190}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply splTimCapSta + "SPLR times capacity of active stage" + annotation (Placement(transformation(extent={{20,-130},{40,-110}}))); + Buildings.Controls.OBC.CDL.Reals.Multiply splTimCapStaLow + "SPLR times capacity of next available lower stage" + annotation (Placement(transformation(extent={{20,-170},{40,-150}}))); + Utilities.PlaceholderReal parPlrSta( + final have_inp=have_inpPlrSta, + final have_inpPh=false, + final u_internal=plrSta) "Parameter value for SPLR" + annotation (Placement(transformation(extent={{-180,-190},{-160,-170}}))); + Buildings.Controls.OBC.CDL.Logical.FallingEdge endStaPro + "True when staging process terminates" + annotation (Placement(transformation(extent={{20,-30},{40,-10}}))); +equation + connect(delT.y, absDelT.u) + annotation (Line(points={{-148,-80},{-132,-80}},color={0,0,127})); + connect(absDelT.y, capReq.u1) + annotation (Line(points={{-108,-80},{-100,-80},{-100,-74},{-92,-74}}, color={0,0,127})); + connect(capFlo.y, capReq.u2) + annotation (Line(points={{-108,-140},{-100,-140},{-100,-86},{-92,-86}}, + color={0,0,127})); + connect(intScaRep.y, reqEquSta.index) + annotation (Line(points={{-82,200},{0,200},{0,208}},color={255,127,0})); + connect(traMatStaEqu.y, reqEquSta.u) + annotation (Line(points={{-48,220},{-12,220}},color={0,0,127})); + connect(reqEquSta.y, capEquSta.u1) + annotation (Line(points={{12,220},{20,220},{20,226},{28,226}},color={0,0,127})); + connect(capEquPar.y, capEquSta.u2) + annotation (Line(points={{-48,160},{20,160},{20,214},{28,214}},color={0,0,127})); + connect(capEquSta.y, capSta.u) + annotation (Line(points={{52,220},{68,220}},color={0,0,127})); + connect(movAve.y, hol.u) + annotation (Line(points={{-28,-80},{-10,-80},{-10,-66},{18,-66}}, color={0,0,127})); + connect(intScaRep.u, maxInt.y) + annotation (Line(points={{-106,200},{-118,200}},color={255,127,0})); + connect(idxSta.y, idxStaLesAct.u1) + annotation (Line(points={{-158,140},{-154,140},{-154,100},{-152,100}},color={255,127,0})); + connect(uSta, intScaRep1.u) + annotation (Line(points={{-220,180},{-190,180},{-190,100},{-182,100}},color={255,127,0})); + connect(intScaRep1.y, idxStaLesAct.u2) + annotation (Line(points={{-158,100},{-156,100},{-156,92},{-152,92}},color={255,127,0})); + connect(idxStaLesAct.y, idxStaLesActAva.u1) + annotation (Line(points={{-128,100},{-120,100},{-120,80},{-112,80}},color={255,0,255})); + connect(u1AvaSta, idxStaLesActAva.u2) + annotation (Line(points={{-220,80},{-126,80},{-126,72},{-112,72}},color={255,0,255})); + connect(idxStaLesActAva.y, idxLasTru.u1) + annotation (Line(points={{-88,80},{-72,80}},color={255,0,255})); + connect(idxLasTru.y, maxInt1.u2) + annotation (Line(points={{-48,80},{-44,80},{-44,114},{-32,114}},color={255,127,0})); + connect(one.y, maxInt1.u1) + annotation (Line(points={{-158,180},{-40,180},{-40,126},{-32,126}},color={255,127,0})); + connect(maxInt1.y, intScaRep2.u) + annotation (Line(points={{-8,120},{8,120}},color={255,127,0})); + connect(uSta, maxInt.u1) + annotation (Line(points={{-220,180},{-190,180},{-190,206},{-142,206}},color={255,127,0})); + connect(one.y, maxInt.u2) + annotation (Line(points={{-158,180},{-150,180},{-150,194},{-142,194}},color={255,127,0})); + connect(intScaRep2.y, reqEquStaLow.index) + annotation (Line(points={{32,120},{40,120},{40,140},{0,140},{0,168}},color={255,127,0})); + connect(traMatStaEqu.y, reqEquStaLow.u) + annotation (Line(points={{-48,220},{-20,220},{-20,180},{-12,180}},color={0,0,127})); + connect(reqEquStaLow.y, capEquStaLow.u2) + annotation (Line(points={{12,180},{16,180},{16,174},{28,174}},color={0,0,127})); + connect(capEquPar.y, capEquStaLow.u1) + annotation (Line(points={{-48,160},{20,160},{20,186},{28,186}},color={0,0,127})); + connect(capEquStaLow.y, capStaLow.u) + annotation (Line(points={{52,180},{68,180}},color={0,0,127})); + connect(idxLasTru.y, minInt.u2) + annotation (Line(points={{-48,80},{-44,80},{-44,74},{-32,74}},color={255,127,0})); + connect(one.y, minInt.u1) + annotation (Line(points={{-158,180},{-40,180},{-40,86},{-32,86}},color={255,127,0})); + connect(minInt.y, intToRea.u) + annotation (Line(points={{-8,80},{8,80}},color={255,127,0})); + connect(capStaLow.y, setZer.u1) + annotation (Line(points={{92,180},{100,180},{100,186},{108,186}},color={0,0,127})); + connect(intToRea.y, setZer.u2) + annotation (Line(points={{32,80},{100,80},{100,174},{108,174}},color={0,0,127})); + connect(hol.y, gre.u1) + annotation (Line(points={{42,-60},{58,-60}},color={0,0,127})); + connect(splTimCapSta.y, gre.u2) + annotation (Line(points={{42,-120},{44,-120},{44,-68},{58,-68}},color={0,0,127})); + connect(capSta.y, splTimCapSta.u2) + annotation (Line(points={{92,220},{184,220},{184,-140},{10,-140},{10,-126}, + {18,-126}}, + color={0,0,127})); + connect(setZer.y, splTimCapStaLow.u2) + annotation (Line(points={{132,180},{180,180},{180,-180},{10,-180},{10,-166}, + {18,-166}}, + color={0,0,127})); + connect(splTimCapStaLow.y, les.u2) + annotation (Line(points={{42,-160},{50,-160},{50,-128},{58,-128}},color={0,0,127})); + connect(hol.y, les.u1) + annotation (Line(points={{42,-60},{50,-60},{50,-120},{58,-120}},color={0,0,127})); + connect(gre.y, timUp.u) + annotation (Line(points={{82,-60},{108,-60}}, + color={255,0,255})); + connect(les.y, timDow.u) + annotation (Line(points={{82,-120},{108,-120}}, + color={255,0,255})); + connect(uPlrSta, parPlrSta.u) + annotation (Line(points={{-220,-180},{-182,-180}}, color={0,0,127})); + connect(parPlrSta.y, splTimCapSta.u1) annotation (Line(points={{-158,-180},{ + -40,-180},{-40,-114},{18,-114}}, + color={0,0,127})); + connect(parPlrSta.y, splTimCapStaLow.u1) annotation (Line(points={{-158,-180}, + {-40,-180},{-40,-154},{18,-154}}, color={0,0,127})); + connect(u1StaPro, hol.u1) + annotation (Line(points={{-220,-20},{-10,-20},{-10,-60},{18,-60}}, color={255,0,255})); + connect(u1StaPro, endStaPro.u) + annotation (Line(points={{-220,-20},{18,-20}}, color={255,0,255})); + connect(endStaPro.y, timUp.reset) + annotation (Line(points={{42,-20},{90,-20},{90,-68},{108,-68}}, + color={255,0,255})); + connect(endStaPro.y, timDow.reset) + annotation (Line(points={{42,-20},{90,-20},{90,-128},{108,-128}}, + color={255,0,255})); + connect(timUp.passed, y1Up) annotation (Line(points={{132,-68},{140,-68},{140, + 80},{220,80}}, color={255,0,255})); + connect(timDow.passed, y1Dow) annotation (Line(points={{132,-128},{140,-128}, + {140,-80},{220,-80}},color={255,0,255})); + connect(TSupSet, delT.u1) annotation (Line(points={{-220,-60},{-180,-60},{ + -180,-74},{-172,-74}}, color={0,0,127})); + connect(TRet, delT.u2) annotation (Line(points={{-220,-100},{-180,-100},{-180, + -86},{-172,-86}}, color={0,0,127})); + connect(V_flow, capFlo.u) annotation (Line(points={{-220,-140},{-132,-140}}, + color={0,0,127})); + connect(capReq.y, movAve.u) + annotation (Line(points={{-68,-80},{-52,-80}}, color={0,0,127})); + annotation ( + defaultComponentName="chaSta", + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-100,-120},{100,120}}), + graphics={ + Rectangle( + extent={{-100,120},{100,-120}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,170},{150,130}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-200,-240},{200,240}})), + Documentation( + info=" +

+The plant equipment is staged in part based on required capacity, Qrequired, +relative to nominal capacity of a given stage, Qstage. +This ratio is the operative part load ratio, OPLR. +

+

+OPLR = Qrequired / Qstage +

+

+If both primary and secondary hot water temperatures and flow rates are available, +the sensors in the primary loop are used for calculating Qrequired. +If a heat recovery chiller is piped into the secondary return, the sensors in the +primary loop are used. +(These conditions are implemented in + +Buildings.Templates.Plants.Controls.HeatPumps.AirToWater.) +

+

+The required capacity is calculated based on return temperature, +active supply temperature setpoint and measured flow through the +associated circuit flow meter. +

+

+The required capacity used in logic is a rolling average over a period +of dtMea +of instantaneous values sampled at minimum once every 30 s. +

+

+When a stage up or stage down transition is initiated, +Qrequired is held fixed at its last value until the longer of +the successful completion of the stage change +and the duration dtRun. +

+

+The nominal capacity of a given stage, Qstage, is calculated +as the sum of the design capacities of all units enabled in a given stage. +

+

+Staging is executed per the conditions below subject to the following requirements. +

+
    +
  • +Each stage has a minimum runtime of dtRun. +(This condition is implemented in + +Buildings.Templates.Plants.Controls.Utilities.StageIndex.) +
  • +
  • +Timers are reset to zero at the completion of every stage change. +
  • +
  • +Any unavailable stage is skipped during staging events, +but staging conditionals in the current stage are evaluated as per usual. +
  • +
+

+A stage up command is triggered if any of the following is true: +

+
    +
  • +Availability Condition: The equipment necessary to operate the +current stage is unavailable. +The availability condition is not subject to the minimum stage runtime requirement. +(This condition is implemented in + +Buildings.Templates.Plants.Controls.Utilities.StageIndex.) +
  • +
  • +Efficiency Condition: Current stage OPLR > plrSta for a duration of dtRun. +
  • +
+

+A stage down command is triggered if the following is true: +

+
    +
  • +Next available lower stage OPLR < plrSta for a duration of dtRun. +
  • +
+

+Details +

+

+A staging matrix staEqu is required as a parameter. +See the documentation of + +Buildings.Templates.Plants.Controls.StagingRotation.EquipmentEnable +for the associated definition and requirements. +

+

+An \"if\" condition is used to generate the stage up and down command as opposed +to a \"when\" condition. This means that the command remains true as long as the +condition is verified. This is necessary, for example, if no higher stage is +available when a stage up command is triggered. Using a \"when\" condition – +which is only valid at the point in time at which the condition becomes true – +would prevent the plant from staging when a higher stage becomes available again. +To avoid multiple consecutive stage changes, the block that receives the stage up +and down command and computes the stage index must enforce a minimum stage runtime +of dtRun. +

+")); +end StageChangeCommand; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/StageCompletion.mo b/Buildings/Templates/Plants/Controls/StagingRotation/StageCompletion.mo new file mode 100644 index 00000000000..502f90bad01 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/StageCompletion.mo @@ -0,0 +1,158 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +block StageCompletion + "Checks successful completion of stage change" + parameter Integer nin=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1[nin] + "Equipment enable command" + annotation (Placement(transformation(extent={{-200,-20},{-160,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1_actual[nin] + "Equipment status" + annotation (Placement(transformation(extent={{-200,-80},{-160,-40}}), + iconTransformation(extent={{-140,-60},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1End + "Successful completion of stage change" + annotation (Placement(transformation(extent={{160,80},{200,120}}), + iconTransformation(extent={{100,40},{140,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1 + "Stage change in progress" + annotation (Placement(transformation(extent={{160,-80},{200,-40}}), + iconTransformation(extent={{100,-80},{140,-40}}))); + Buildings.Controls.OBC.CDL.Logical.And enaAndOn[nin] + "True if equipment enabled and on status returned" + annotation (Placement(transformation(extent={{-50,-10},{-30,10}}))); + Buildings.Controls.OBC.CDL.Logical.Nor disAndOff[nin] + "True if equipment disabled and off status returned" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd allTru( + nin=nin) + "True if all inputs true" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); + Buildings.Controls.OBC.CDL.Logical.Or onOrOff[nin] + "True if on or off condition met" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Logical.FallingEdge endStaPro + "True when staging process terminates" + annotation (Placement(transformation(extent={{120,90},{140,110}}))); + Buildings.Controls.OBC.CDL.Logical.Latch lckChaSta + "Lock stage change signal until conditions on equipment command and status met" + annotation (Placement(transformation(extent={{30,90},{50,110}}))); + Buildings.Controls.OBC.CDL.Logical.Change cha[nin] + "True if enable signal changes" + annotation (Placement(transformation(extent={{-130,50},{-110,70}}))); + Buildings.Controls.OBC.CDL.Logical.Latch lckAnyCha + "Lock equipment command change signal until next stage change" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + Buildings.Controls.OBC.CDL.Logical.MultiOr anyCha( + nin=nin) + "True if any enable signal changes" + annotation (Placement(transformation(extent={{-90,50},{-70,70}}))); + Buildings.Controls.OBC.CDL.Logical.And chaAndMat + "True if enable command changed and equipment status matches command" + annotation (Placement(transformation(extent={{30,50},{50,70}}))); + Buildings.Controls.OBC.CDL.Logical.TrueFalseHold holAnyCha( + trueHoldDuration=1, + falseHoldDuration=0) + "Hold signal to guard against concomitant stage change and command change" + annotation (Placement(transformation(extent={{-50,50},{-30,70}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uSta + "Stage index" + annotation (Placement(transformation(extent={{-200,80},{-160,120}}), + iconTransformation(extent={{-140,20},{-100,60}}))); + Buildings.Controls.OBC.CDL.Integers.Change chaSta + "Return true when stage change is initiated" + annotation (Placement(transformation(extent={{-130,90},{-110,110}}))); +equation + connect(u1_actual, disAndOff.u2) + annotation (Line(points={{-180,-60},{-60,-60},{-60,-48},{-52,-48}},color={255,0,255})); + connect(u1_actual, enaAndOn.u2) + annotation (Line(points={{-180,-60},{-60,-60},{-60,-8},{-52,-8}},color={255,0,255})); + connect(endStaPro.y, y1End) + annotation (Line(points={{142,100},{180,100}},color={255,0,255})); + connect(lckChaSta.y, y1) + annotation (Line(points={{52,100},{100,100},{100,-60},{180,-60}},color={255,0,255})); + connect(cha.y, anyCha.u) + annotation (Line(points={{-108,60},{-92,60}},color={255,0,255})); + connect(u1, cha.u) + annotation (Line(points={{-180,0},{-140,0},{-140,60},{-132,60}},color={255,0,255})); + connect(u1, enaAndOn.u1) + annotation (Line(points={{-180,0},{-52,0}},color={255,0,255})); + connect(lckAnyCha.y, chaAndMat.u1) + annotation (Line(points={{12,60},{28,60}},color={255,0,255})); + connect(chaAndMat.y, lckChaSta.clr) + annotation (Line(points={{52,60},{60,60},{60,80},{20,80},{20,94},{28,94}}, + color={255,0,255})); + connect(lckChaSta.y, endStaPro.u) + annotation (Line(points={{52,100},{118,100}},color={255,0,255})); + connect(u1, disAndOff.u1) + annotation (Line(points={{-180,0},{-140,0},{-140,-40},{-52,-40}},color={255,0,255})); + connect(enaAndOn.y, onOrOff.u1) + annotation (Line(points={{-28,0},{-12,0}},color={255,0,255})); + connect(disAndOff.y, onOrOff.u2) + annotation (Line(points={{-28,-40},{-20,-40},{-20,-8},{-12,-8}},color={255,0,255})); + connect(onOrOff.y, allTru.u) + annotation (Line(points={{12,0},{28,0}},color={255,0,255})); + connect(allTru.y, chaAndMat.u2) + annotation (Line(points={{52,0},{60,0},{60,40},{20,40},{20,52},{28,52}}, + color={255,0,255})); + connect(anyCha.y, holAnyCha.u) + annotation (Line(points={{-68,60},{-52,60}},color={255,0,255})); + connect(holAnyCha.y, lckAnyCha.u) + annotation (Line(points={{-28,60},{-12,60}},color={255,0,255})); + connect(chaSta.y, lckChaSta.u) + annotation (Line(points={{-108,100},{28,100}},color={255,0,255})); + connect(chaSta.y, lckAnyCha.clr) + annotation (Line(points={{-108,100},{-20,100},{-20,54},{-12,54}},color={255,0,255})); + connect(uSta, chaSta.u) + annotation (Line(points={{-180,100},{-132,100}},color={255,127,0})); + annotation ( + defaultComponentName="comSta", + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,170},{150,130}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-160,-140},{160,140}})), + Documentation( + info=" +

+Block that detects a stage change and evaluates whether the stage +transition is completed. +

+

+The completion of a stage change is considered successful when +both of the following conditions have been verified. +

+
    +
  • +Following a stage transition event, or exactly at the same time, +there is a change in the enable command of at least one equipment. +
  • +
  • +The equipment status matches the enable command for all units, +after any change in the enable command has been detected. +
  • +
+

+The output signal y1End is true exactly at the time when +the successful completion of the stage change is confirmed. +The output signal y1 is true during the entire time in which +the stage change is in progress. +

+")); +end StageCompletion; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentAvailability.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentAvailability.mo new file mode 100644 index 00000000000..0efd4813da9 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentAvailability.mo @@ -0,0 +1,94 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model EquipmentAvailability "Validation model for the evaluation of equipment availability" + Buildings.Templates.Plants.Controls.StagingRotation.EquipmentAvailability + avaHeaCoo(have_heaWat=true, have_chiWat=true) + "Evaluate equipment availability – Heating and cooling" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1Ava( + table=[ + 0, 1; + 8, 0; + 9, 1], + timeScale=1000, + period=10000) + "Equipment available signal" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1_actual( + table=[ + 0, 1; + 1, 0; + 2.5, 1; + 4.2, 0; + 5, 1; + 7, 1; + 8, 0; + 9, 1], + timeScale=1000, + period=10000) + "Equipment status" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1Hea_actual( + table=[ + 0, 1; + 1, 1; + 2, 1; + 5, 0; + 8.5, 1; + 9.7, 0], + timeScale=1000, + period=10000) + "Equipment operating mode" + annotation (Placement(transformation(extent={{-80,-48},{-60,-28}}))); + Buildings.Templates.Plants.Controls.StagingRotation.EquipmentAvailability + avaHea(have_heaWat=true, have_chiWat=false) + "Evaluate equipment availability – Heating only" + annotation (Placement(transformation(extent={{0,-70},{20,-50}}))); +equation + connect(u1Hea_actual.y[1], avaHeaCoo.u1Hea) + annotation (Line(points={{-58,-38},{-30,-38},{-30,-6},{-2,-6}},color={255,0,255})); + connect(u1_actual.y[1], avaHeaCoo.u1) + annotation (Line(points={{-58,40},{-20,40},{-20,6},{-2,6}},color={255,0,255})); + connect(u1_actual.y[1], avaHea.u1) + annotation (Line(points={{-58,40},{-20,40},{-20,-54},{-2,-54}},color={255,0,255})); + connect(u1Ava.y[1], avaHeaCoo.u1Ava) + annotation (Line(points={{-58,0},{-2,0}},color={255,0,255})); + connect(u1Ava.y[1], avaHea.u1Ava) + annotation (Line(points={{-58,0},{-40,0},{-40,-60},{-2,-60}},color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/EquipmentAvailability.mos" + "Simulate and plot"), + experiment( + StopTime=10000.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Documentation(info=" +

+This model validates + +Buildings.Templates.Plants.Controls.StagingRotation.EquipmentAvailability +for heating-only applications (component avaHeaCoo) and heating and cooling +applications (component avaHea). +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end EquipmentAvailability; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentEnable.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentEnable.mo new file mode 100644 index 00000000000..bf527d4ed7d --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EquipmentEnable.mo @@ -0,0 +1,134 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model EquipmentEnable "Validation model for equipment enable logic" + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1AvaEqu( + table=[ + 0, 1, 1, 1; + 6, 0, 0, 1; + 8, 0, 1, 1; + 10, 1, 0, 1; + 15, 1, 1, 0; + 18, 0, 1, 1; + 22, 1, 1, 1], + timeScale=1, + period=25) + "Equipment available signal" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); + Buildings.Templates.Plants.Controls.StagingRotation.EquipmentEnable equEnaOneTwo( + staEqu=[ + 1, 0, 0; + 0, 1 / 2, 1 / 2; + 1, 1 / 2, 1 / 2; + 0, 1, 1; + 1, 1, 1]) + "Compute array of enabled equipment – One small equipment, two large equally sized equipment" + annotation (Placement(transformation(extent={{70,-50},{90,-30}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.TimeTable uSta( + table=[ + 0, 1; + 5, 2; + 10, 3; + 15, 4; + 20, 5], + timeScale=1, + period=25) + "Stage index" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.StagingRotation.EquipmentEnable equEnaEqu( + staEqu=[ + 1 / 3, 1 / 3, 1 / 3; + 2 / 3, 2 / 3, 2 / 3; + 1, 1, 1]) + "Compute array of enabled equipment – Equally sized units" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.TimeTable uSta1( + table=[ + 0, 1; + 10, 2; + 20, 3], + timeScale=1, + period=25) + "Stage index" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[3] + "Cast to real" + annotation (Placement(transformation(extent={{-28,50},{-8,70}}))); + Utilities.SortWithIndices sort( + ascending=false, + nin=3) + "Sort lead/lag alternate equipment with available equipment first" + annotation (Placement(transformation(extent={{0,50},{20,70}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea1[2] + "Cast to real" + annotation (Placement(transformation(extent={{-28,-90},{-8,-70}}))); + Utilities.SortWithIndices sort1( + ascending=false, + nin=2) + "Sort lead/lag alternate equipment with available equipment first" + annotation (Placement(transformation(extent={{0,-90},{20,-70}}))); + Buildings.Controls.OBC.CDL.Integers.AddParameter addPar[2]( + each final p=1) + "Restore indices with respect to original vector u1AvaEqu" + annotation (Placement(transformation(extent={{30,-90},{50,-70}}))); +equation + connect(u1AvaEqu.y, equEnaOneTwo.u1Ava) + annotation (Line(points={{-58,-40},{-40,-40},{-40,-46},{68,-46}},color={255,0,255})); + connect(uSta.y[1], equEnaOneTwo.uSta) + annotation (Line(points={{-58,0},{40,0},{40,-40},{68,-40}},color={255,127,0})); + connect(uSta1.y[1], equEnaEqu.uSta) + annotation (Line(points={{-58,40},{30,40},{30,40},{68,40}},color={255,127,0})); + connect(u1AvaEqu.y, equEnaEqu.u1Ava) + annotation (Line(points={{-58,-40},{-40,-40},{-40,34},{68,34}},color={255,0,255})); + connect(u1AvaEqu.y, booToRea.u) + annotation (Line(points={{-58,-40},{-40,-40},{-40,60},{-30,60}},color={255,0,255})); + connect(booToRea.y, sort.u) + annotation (Line(points={{-6,60},{-2,60}},color={0,0,127})); + connect(sort.yIdx, equEnaEqu.uIdxAltSor) + annotation (Line(points={{22,54},{60,54},{60,46},{68,46}},color={255,127,0})); + connect(u1AvaEqu.y[2:3], booToRea1.u) + annotation (Line(points={{-58,-40},{-40,-40},{-40,-80},{-30,-80}},color={255,0,255})); + connect(booToRea1.y, sort1.u) + annotation (Line(points={{-6,-80},{-2,-80}},color={0,0,127})); + connect(sort1.yIdx, addPar.u) + annotation (Line(points={{22,-86},{26,-86},{26,-80},{28,-80}},color={255,127,0})); + connect(addPar.y, equEnaOneTwo.uIdxAltSor) + annotation (Line(points={{52,-80},{60,-80},{60,-34},{68,-34}},color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/EquipmentEnable.mos" + "Simulate and plot"), + experiment( + StopTime=25.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Documentation(info=" +

+This model validates + +Buildings.Templates.Plants.Controls.StagingRotation.EquipmentEnable +in a configuration with three equally sized units (component equEnaEqu) +and in a configuration with one small unit and two large equally sized +units (component equEnaOneTwo). +Only the units of the same size are lead/lag alternated. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end EquipmentEnable; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EventSequencing.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EventSequencing.mo new file mode 100644 index 00000000000..b65464224cf --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/EventSequencing.mo @@ -0,0 +1,117 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model EventSequencing "Validation model for event sequencing logic" + Buildings.Templates.Plants.Controls.StagingRotation.EventSequencing seqEveHea( + have_heaWat=true, + have_chiWat=false, + have_valInlIso=true, + have_valOutIso=false, + have_pumHeaWatPri=true, + have_pumHeaWatSec=true) + "Event sequencing – Heating-only system with primary-secondary distribution" + annotation (Placement(transformation(extent={{20,6},{40,34}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1( + table=[0,0,0; 1,1,0; 2,0,0; 3,0,1; 4,0,0; 5,0,0], + timeScale=900, + period=4500) + "Command signal – Index 1 for heating command, 2 for cooling command" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea + "Convert command signal to real value" + annotation (Placement(transformation(extent={{50,50},{30,70}}))); + Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold zerOrdHol(samplePeriod=1) + "Hold signal value" + annotation (Placement(transformation(extent={{20,50},{0,70}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr + "Compare to zero to compute equipment status" + annotation (Placement(transformation(extent={{-10,50},{-30,70}}))); + Buildings.Templates.Plants.Controls.StagingRotation.EventSequencing seqEveHeaCoo( + have_heaWat=true, + have_chiWat=true, + have_valInlIso=true, + have_valOutIso=true, + have_pumHeaWatPri=true, + have_pumChiWatPri=false, + have_pumHeaWatSec=false, + have_pumChiWatSec=false) + "Event sequencing – Heating and cooling system with primary-only distribution" + annotation (Placement(transformation(extent={{20,-34},{40,-6}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea1 + "Convert command signal to real value" + annotation (Placement(transformation(extent={{50,-70},{30,-50}}))); + Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold zerOrdHol1(samplePeriod=1) + "Hold signal value" + annotation (Placement(transformation(extent={{20,-70},{0,-50}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr1 + "Compare to zero to compute equipment status" + annotation (Placement(transformation(extent={{-10,-70},{-30,-50}}))); +equation + connect(u1.y[1], seqEveHea.u1Hea) annotation (Line(points={{-58,0},{0,0},{0, + 32},{18,32}}, color={255,0,255})); + connect(u1.y[1], seqEveHea.u1PumHeaWatSec_actual) annotation (Line(points={{-58,0}, + {0,0},{0,14},{18,14}}, color={255,0,255})); + connect(booToRea.y,zerOrdHol. u) + annotation (Line(points={{28,60},{22,60}}, + color={0,0,127})); + connect(zerOrdHol.y,greThr. u) + annotation (Line(points={{-2,60},{-8,60}}, color={0,0,127})); + connect(seqEveHea.y1PumHeaWatPri, booToRea.u) annotation (Line(points={{42,12}, + {60,12},{60,60},{52,60}}, color={255,0,255})); + connect(greThr.y, seqEveHea.u1PumHeaWatPri_actual) annotation (Line(points={{-32,60}, + {-40,60},{-40,20},{18,20}}, color={255,0,255})); + connect(u1.y[1], seqEveHeaCoo.u1Hea) annotation (Line(points={{-58,0},{0,0},{ + 0,-8},{18,-8}}, color={255,0,255})); + connect(booToRea1.y, zerOrdHol1.u) + annotation (Line(points={{28,-60},{22,-60}}, color={0,0,127})); + connect(zerOrdHol1.y, greThr1.u) + annotation (Line(points={{-2,-60},{-8,-60}}, color={0,0,127})); + connect(seqEveHeaCoo.y1PumHeaWatPri, booToRea1.u) annotation (Line(points={{ + 42,-28},{60,-28},{60,-60},{52,-60}}, color={255,0,255})); + connect(greThr1.y, seqEveHeaCoo.u1PumHeaWatPri_actual) annotation (Line( + points={{-32,-60},{-40,-60},{-40,-20},{18,-20}}, color={255,0,255})); + connect(u1.y[2], seqEveHeaCoo.u1Coo) annotation (Line(points={{-58,0},{0,0},{ + 0,-12},{18,-12}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/EventSequencing.mos" + "Simulate and plot"), + experiment( + StopTime=4500.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Documentation(info=" +

+This model validates + +Buildings.Templates.Plants.Controls.StagingRotation.EventSequencing +for the following configurations. +

+
    +
  • +Heating-only plant with primary-secondary distribution (component seqEveHea) +
  • +
  • +Heating and cooling plant with primary-only distribution (component seqEveHeaCoo) +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end EventSequencing; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/SortRuntime.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/SortRuntime.mo new file mode 100644 index 00000000000..88174ac9745 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/SortRuntime.mo @@ -0,0 +1,148 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model SortRuntime "Validation model for equipment runtime sorting logic" + Buildings.Templates.Plants.Controls.StagingRotation.SortRuntime sorRunTim( + nin=3) + "Sort runtime" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + Utilities.TrueArrayConditional u1Ena( + nin=3) + "Equipment enable signal" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal booToRea[3] + "Convert command signal to real value" + annotation (Placement(transformation(extent={{60,-10},{80,10}}))); + Buildings.Controls.OBC.CDL.Discrete.ZeroOrderHold zerOrdHol[3]( + each samplePeriod=1) + "Hold signal value" + annotation (Placement(transformation(extent={{90,-10},{110,10}}))); + Buildings.Controls.OBC.CDL.Reals.GreaterThreshold greThr[3] + "Compare to zero to compute equipment status" + annotation (Placement(transformation(extent={{120,-10},{140,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1AvaEqu( + table=[ + 0, 1, 1, 1; + 2000, 0, 1, 1; + 2500, 0, 1, 0; + 3000, 1, 1, 1], + timeScale=1, + period=3000) + "Equipment available signal" + annotation (Placement(transformation(extent={{-130,-110},{-110,-90}}))); + Utilities.StageIndex idxSta( + nSta=3, + dtRun=60) + annotation (Placement(transformation(extent={{-40,30},{-20,50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1Lea( + k=true) + "Lead equipment enable signal" + annotation (Placement(transformation(extent={{-130,90},{-110,110}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.SampleTrigger upPul( + period=60) + "Stage up command pulse" + annotation (Placement(transformation(extent={{-130,-30},{-110,-10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.SampleTrigger dowPul( + period=60) + "Stage down command pulse" + annotation (Placement(transformation(extent={{-130,-70},{-110,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable booTimTab( + table=[ + 0, 0, 0; + 60, 1, 0; + 300, 0, 1], + period=500) + "Signal to inhibit up and down commands" + annotation (Placement(transformation(extent={{-130,10},{-110,30}}))); + Buildings.Controls.OBC.CDL.Logical.And up + "Stage up command" + annotation (Placement(transformation(extent={{-80,-30},{-60,-10}}))); + Buildings.Controls.OBC.CDL.Logical.And dow + "Stage up command" + annotation (Placement(transformation(extent={{-80,-70},{-60,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1AvaSta[3]( + each k=true) + "Stage available signal" + annotation (Placement(transformation(extent={{-130,50},{-110,70}}))); + Buildings.Controls.OBC.CDL.Logical.And run[3] + "Returns true if equipment is enabled and available" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); +equation + connect(sorRunTim.yIdx, u1Ena.uIdx) + annotation (Line(points={{-18,-6},{-12,-6},{-12,-6},{-2,-6}},color={255,127,0})); + connect(booToRea.y, zerOrdHol.u) + annotation (Line(points={{82,0},{88,0}},color={0,0,127})); + connect(zerOrdHol.y, greThr.u) + annotation (Line(points={{112,0},{118,0}},color={0,0,127})); + connect(greThr.y, sorRunTim.u1Run) + annotation (Line(points={{142,0},{150,0},{150,20},{-46,20},{-46,6},{-42,6}}, + color={255,0,255})); + connect(u1AvaEqu.y[1:3], sorRunTim.u1Ava[1:3]) + annotation (Line(points={{-108,-100},{-46,-100},{-46,-6},{-42,-6},{-42,-5.33333}}, + color={255,0,255})); + connect(u1Lea.y, idxSta.u1Lea) + annotation (Line(points={{-108,100},{-50,100},{-50,46},{-42,46}},color={255,0,255})); + connect(upPul.y, up.u2) + annotation (Line(points={{-108,-20},{-100,-20},{-100,-28},{-82,-28}},color={255,0,255})); + connect(booTimTab.y[2], dow.u1) + annotation (Line(points={{-108,20},{-90,20},{-90,-60},{-82,-60}},color={255,0,255})); + connect(booTimTab.y[1], up.u1) + annotation (Line(points={{-108,20},{-90,20},{-90,-20},{-82,-20}},color={255,0,255})); + connect(dowPul.y, dow.u2) + annotation (Line(points={{-108,-60},{-100,-60},{-100,-68},{-82,-68}},color={255,0,255})); + connect(up.y, idxSta.u1Up) + annotation (Line(points={{-58,-20},{-50,-20},{-50,42},{-42,42}},color={255,0,255})); + connect(dow.y, idxSta.u1Dow) + annotation (Line(points={{-58,-60},{-48,-60},{-48,38},{-42,38}},color={255,0,255})); + connect(u1AvaSta.y, idxSta.u1AvaSta) + annotation (Line(points={{-108,60},{-52,60},{-52,34},{-42,34}},color={255,0,255})); + connect(idxSta.y, u1Ena.u) + annotation (Line(points={{-18,40},{-10,40},{-10,0},{-2,0}},color={255,127,0})); + connect(u1Ena.y1, run.u1) + annotation (Line(points={{22,0},{28,0}},color={255,0,255})); + connect(u1AvaEqu.y[1:3], run.u2) + annotation (Line(points={{-108,-100},{24,-100},{24,-8},{28,-8}},color={255,0,255})); + connect(run.y, booToRea.u) + annotation (Line(points={{52,0},{58,0}},color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/SortRuntime.mos" + "Simulate and plot"), + experiment( + StopTime=5000.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + extent={{-160,-120},{160,120}})), + Documentation( + info=" +

+The simulation shows that even wear is achieved among available equipment. +When it becomes unavailable, equipment #1 is sent to last position, +and automatically moves up in the staging order only if another +equipment (#3) becomes unavailable. +

+

+We can verify that no equipment gets \"hot swapped\". +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end SortRuntime; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageAvailability.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageAvailability.mo new file mode 100644 index 00000000000..a0b2c512e60 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageAvailability.mo @@ -0,0 +1,77 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model StageAvailability "Validation model for the evaluation of stage availability" + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable u1AvaEqu( + table=[ + 0, 0, 0, 0; + 1, 1, 0, 0; + 2, 0, 1, 0; + 3, 0, 0, 1; + 4, 1, 1, 0; + 5, 0, 1, 1; + 6, 1, 1, 1; + 7, 0, 0, 0], + timeScale=1, + period=7) + "Equipment available signal" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.StagingRotation.StageAvailability avaStaEqu( + staEqu=[ + 1 / 3, 1 / 3, 1 / 3; + 2 / 3, 2 / 3, 2 / 3; + 1, 1, 1]) + "Compute stage availability – Equally sized units" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + Buildings.Templates.Plants.Controls.StagingRotation.StageAvailability avaStaOneTwo( + staEqu=[ + 1, 0, 0; + 0, 1 / 2, 1 / 2; + 1, 1 / 2, 1 / 2; + 0, 1, 1; + 1, 1, 1]) + "Compute stage availability – One small equipment, two large equally sized equipment" + annotation (Placement(transformation(extent={{-10,-30},{10,-10}}))); +equation + connect(u1AvaEqu.y, avaStaEqu.u1Ava) + annotation (Line(points={{-58,0},{-20,0},{-20,20},{-12,20}},color={255,0,255})); + connect(u1AvaEqu.y, avaStaOneTwo.u1Ava) + annotation (Line(points={{-58,0},{-20,0},{-20,-20},{-12,-20}},color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/StageAvailability.mos" + "Simulate and plot"), + experiment( + StopTime=7.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Documentation(info=" +

+This model validates + +Buildings.Templates.Plants.Controls.StagingRotation.StageAvailability +in a configuration with three equally sized units (component avaStaEqu) +and in a configuration with one small unit and two large equally sized +units (component avaStaOneTwo). +Only the units of the same size are lead/lag alternated. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end StageAvailability; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageChangeCommand.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageChangeCommand.mo new file mode 100644 index 00000000000..00122f80dd9 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageChangeCommand.mo @@ -0,0 +1,200 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model StageChangeCommand "Validation model for stage change logic" + parameter Real cp_default( + final unit="J/(kg.K)")=4184 + "Default specific heat capacity" + annotation (Dialog(group="Configuration", + enable=false)); + parameter Real rho_default( + final unit="kg/m3")=996 + "Default specific heat capacity" + annotation (Dialog(group="Configuration", + enable=false)); + final parameter Real capHea_nominal( + final unit="W")=sum(chaSta.capEqu) + "Installed heating capacity" + annotation (Dialog(group="Nominal condition")); + parameter Real THeaWatSup_nominal( + final unit="K", + displayUnit="degC")=50 + 273.15 + "Design HW supply temperature" + annotation (Dialog(group="Nominal condition")); + final parameter Real THeaWatRet_nominal( + final unit="K", + displayUnit="degC")=42 + 273.15 + "Design HW return temperature" + annotation (Dialog(group="Nominal condition")); + parameter Real VHeaWat_flow_nominal( + final unit="m3/s")=capHea_nominal /(THeaWatSup_nominal - THeaWatRet_nominal) / + cp_default / rho_default + "Design primary HW volume flow rate" + annotation (Dialog(group="Nominal condition")); + final parameter Integer nSta=size(chaSta.staEqu, 1) + "Number of stages" + annotation (Evaluate=true); + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratV_flow( + table=[ + 0, 0; + 1, 0; + 5, 0.2; + 6, 0.01; + 11, 1; + 12, 1; + 18, 0], + timeScale=1000) + "Source signal for volume flow rate ratio" + annotation (Placement(transformation(extent={{-130,-50},{-110,-30}}))); + Buildings.Templates.Plants.Controls.StagingRotation.StageChangeCommand chaSta( + plrSta=0.9, + staEqu=[ + 1, 0, 0; + 0, 1 / 2, 1 / 2; + 1, 1 / 2, 1 / 2; + 0, 1, 1; + 1, 1, 1], + capEqu=1E3 * {100, 450, 450}, + cp_default=cp_default, + rho_default=rho_default) + "Generate stage change command" + annotation (Placement(transformation(extent={{-50,-12},{-30,12}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TSupSet( + final k=THeaWatSup_nominal) + "HWST setpoint" + annotation (Placement(transformation(extent={{-130,30},{-110,50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TRet( + final k=THeaWatRet_nominal) + "HWRT" + annotation (Placement(transformation(extent={{-130,-10},{-110,10}}))); + Utilities.StageIndex idxSta( + final nSta=nSta, dtRun=900) + "Compute stage index" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1Lea( + k=true) + "Lead equipment enable signal" + annotation (Placement(transformation(extent={{-130,70},{-110,90}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1AvaSta[nSta]( + each k=true) + "Stage available signal" + annotation (Placement(transformation(extent={{-130,-90},{-110,-70}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold y1UpHol(duration=1) + "Hold stage up command for plotting" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold y1DowHol(duration=1) + "Hold stage down command for plotting" + annotation (Placement(transformation(extent={{0,-50},{20,-30}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter V_flow( + final k=VHeaWat_flow_nominal) + "Scale by design flow" + annotation (Placement(transformation(extent={{-100,-50},{-80,-30}}))); + Buildings.Templates.Plants.Controls.StagingRotation.EquipmentEnable enaEqu( + final staEqu=chaSta.staEqu) + "Enable equipment" + annotation (Placement(transformation(extent={{60,-10},{80,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant idxEquLeaLag[2]( + final k={2, 3}) + "Indices of lead/lag equipment" + annotation (Placement(transformation(extent={{-100,90},{-80,110}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1AvaEqu[3]( + each final k=true) + "Equipment available signal" + annotation (Placement(transformation(extent={{-100,-110},{-80,-90}}))); + Components.Controls.StatusEmulator staEqu[3]( + each riseTime=60) + "Evaluate equipment status" + annotation (Placement(transformation(extent={{100,-10},{120,10}}))); + Buildings.Templates.Plants.Controls.StagingRotation.StageCompletion comSta( + nin=3) + "Check completion of stage change" + annotation (Placement(transformation(extent={{-30,50},{-50,70}}))); +equation + connect(TRet.y, chaSta.TRet) + annotation (Line(points={{-108,0},{-100,0},{-100,-6},{-52,-6}},color={0,0,127})); + connect(TSupSet.y, chaSta.TSupSet) + annotation (Line(points={{-108,40},{-100,40},{-100,-4},{-52,-4}},color={0,0,127})); + connect(chaSta.y1Up, idxSta.u1Up) + annotation (Line(points={{-28,4},{-20,4},{-20,2},{-2,2}},color={255,0,255})); + connect(chaSta.y1Dow, idxSta.u1Dow) + annotation (Line(points={{-28,-4},{-20,-4},{-20,-2},{-2,-2}},color={255,0,255})); + connect(u1Lea.y, idxSta.u1Lea) + annotation (Line(points={{-108,80},{-10,80},{-10,6},{-2,6}},color={255,0,255})); + connect(u1AvaSta.y, idxSta.u1AvaSta) + annotation (Line(points={{-108,-80},{-10,-80},{-10,-6},{-2,-6}},color={255,0,255})); + connect(idxSta.y, chaSta.uSta) + annotation (Line(points={{22,0},{40,0},{40,20},{-56,20},{-56,10},{-52,10}}, + color={255,127,0})); + connect(chaSta.y1Up, y1UpHol.u) + annotation (Line(points={{-28,4},{-20,4},{-20,40},{-2,40}},color={255,0,255})); + connect(chaSta.y1Dow, y1DowHol.u) + annotation (Line(points={{-28,-4},{-20,-4},{-20,-40},{-2,-40}},color={255,0,255})); + connect(u1AvaSta.y, chaSta.u1AvaSta) + annotation (Line(points={{-108,-80},{-60,-80},{-60,6},{-52,6}},color={255,0,255})); + connect(ratV_flow.y[1], V_flow.u) + annotation (Line(points={{-108,-40},{-102,-40}},color={0,0,127})); + connect(V_flow.y, chaSta.V_flow) + annotation (Line(points={{-78,-40},{-56,-40},{-56,-8},{-52,-8}},color={0,0,127})); + connect(idxSta.y, enaEqu.uSta) + annotation (Line(points={{22,0},{58,0}},color={255,127,0})); + connect(idxEquLeaLag.y, enaEqu.uIdxAltSor) + annotation (Line(points={{-78,100},{54,100},{54,6},{58,6}},color={255,127,0})); + connect(u1AvaEqu.y, enaEqu.u1Ava) + annotation (Line(points={{-78,-100},{54,-100},{54,-6},{58,-6}},color={255,0,255})); + connect(enaEqu.y1, staEqu.y1) + annotation (Line(points={{82,0},{98,0}},color={255,0,255})); + connect(comSta.y1, chaSta.u1StaPro) + annotation (Line(points={{-52,54},{-58,54},{-58,2},{-52,2}},color={255,0,255})); + connect(enaEqu.y1, comSta.u1) + annotation (Line(points={{82,0},{90,0},{90,60},{-28,60},{-28,60}},color={255,0,255})); + connect(staEqu.y1_actual, comSta.u1_actual) + annotation (Line(points={{122,0},{130,0},{130,56},{-28,56}},color={255,0,255})); + connect(idxSta.y, comSta.uSta) + annotation (Line(points={{22,0},{40,0},{40,64},{-28,64}},color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/StageChangeCommand.mos" + "Simulate and plot"), + experiment( + StopTime=20000.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + extent={{-140,-120},{140,120}})), + Documentation(info=" +

+This model validates + +Buildings.Templates.Plants.Controls.StagingRotation.StageChangeCommand +in a configuration with one small unit and two large equally sized +units (component avaStaOneTwo). +In response to a varying flow rate, the variation of the +required capacity chaSta.capReq.y triggers stage change +events. +The block + +Buildings.Templates.Plants.Controls.Utilities.StageIndex +is used to illustrate how these events translate into +a varying plant stage index idxSta.y. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end StageChangeCommand; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageCompletion.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageCompletion.mo new file mode 100644 index 00000000000..9ac6eee1833 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/StageCompletion.mo @@ -0,0 +1,86 @@ +within Buildings.Templates.Plants.Controls.StagingRotation.Validation; +model StageCompletion "Validation model for the evaluation of stage completion" + Buildings.Templates.Plants.Controls.StagingRotation.StageCompletion comSta( + nin=2) + "Check successful completion of stage change" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable booTimTab( + table=[ + 0, 0, 0, 0, 0; + 1, 0, 0, 0, 0; + 3, 1, 0, 0, 0; + 6, 1, 0, 1, 0; + 21, 1, 0, 1, 0; + 22, 0, 0, 1, 0; + 24, 0, 0, 0, 0], + timeScale=60, + period=1800) + "Source for Boolean signals" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold y1ComSta(duration=1) + "Hold stage completion signal for plotting" + annotation (Placement(transformation(extent={{60,-10},{80,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.TimeTable idxSta( + table=[ + 0, 0; + 1, 1; + 21, 0], + timeScale=60, + period=1800) + "Stage index" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); +equation + connect(comSta.y1End, y1ComSta.u) + annotation (Line(points={{42,6},{50,6},{50,0},{58,0}},color={255,0,255})); + connect(booTimTab.y[1:2], comSta.u1[1:2]) + annotation (Line(points={{-58,0},{18,0},{18,0.5}},color={255,0,255})); + connect(booTimTab.y[3:4], comSta.u1_actual[1:2]) + annotation (Line(points={{-58,0},{0,0},{0,-4},{18,-4},{18,-3.5}},color={255,0,255})); + connect(idxSta.y[1], comSta.uSta) + annotation (Line(points={{-58,40},{0,40},{0,4},{18,4}},color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/StagingRotation/Validation/StageCompletion.mos" + "Simulate and plot"), + experiment( + StopTime=1800.0, + Tolerance=1e-06), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Documentation(info=" +

+This model validates + +Buildings.Templates.Plants.Controls.StagingRotation.StageCompletion +in a configuration with one small unit and two large equally sized +units (component avaStaOneTwo). +In response to a varying flow rate, the variation of the +required capacity chaSta.capReq.y triggers stage change +events. +The block + +Buildings.Templates.Plants.Controls.Utilities.StageIndex +is used to illustrate how these events translate into +a varying plant stage index idxSta.y. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end StageCompletion; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.mo b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.mo new file mode 100644 index 00000000000..704ea747169 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.mo @@ -0,0 +1,29 @@ +within Buildings.Templates.Plants.Controls.StagingRotation; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), + Documentation( + info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.order b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.order new file mode 100644 index 00000000000..fb6e2c8e0f6 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/Validation/package.order @@ -0,0 +1,7 @@ +EquipmentAvailability +EquipmentEnable +EventSequencing +SortRuntime +StageAvailability +StageChangeCommand +StageCompletion diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/package.mo b/Buildings/Templates/Plants/Controls/StagingRotation/package.mo new file mode 100644 index 00000000000..34a7cfdbcf1 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/package.mo @@ -0,0 +1,43 @@ +within Buildings.Templates.Plants.Controls; +package StagingRotation "Package of sequences for equipment staging and rotation" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Ellipse( + origin={10.0,10.0}, + lineColor={128,128,128}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-80.0,0.0},{-20.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={128,128,128}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,0.0},{60.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,-80.0},{60.0,-20.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={76,76,76}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{-80.0,-80.0},{-20.0,-20.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), Documentation(info=" +

+This package contains equipment staging and rotation sequences. +

+")); +end StagingRotation; diff --git a/Buildings/Templates/Plants/Controls/StagingRotation/package.order b/Buildings/Templates/Plants/Controls/StagingRotation/package.order new file mode 100644 index 00000000000..b55032749c8 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/StagingRotation/package.order @@ -0,0 +1,8 @@ +EquipmentAvailability +EquipmentEnable +EventSequencing +SortRuntime +StageAvailability +StageChangeCommand +StageCompletion +Validation diff --git a/Buildings/Templates/Plants/Controls/Types.mo b/Buildings/Templates/Plants/Controls/Types.mo new file mode 100644 index 00000000000..fd911f43f50 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Types.mo @@ -0,0 +1,28 @@ +within Buildings.Templates.Plants.Controls; +package Types + "Package with type definitions" + extends Modelica.Icons.TypesPackage; + type Application = enumeration( + Cooling + "Cooling system", + Heating + "Heating system") + "Enumeration to specify the type of application"; + type Actuator = enumeration( + Modulating + "Modulating", + TwoPosition + "Two-position") + "Enumeration to specify the type of actuator"; + type EquipmentConnection = enumeration( + Parallel + "Parallel piped", + Series + "Series piped") + "Enumeration to specify the type of connection between equipment and primary loop"; + annotation (Documentation(info=" +

+This package provides type definitions. +

+")); +end Types; diff --git a/Buildings/Templates/Plants/Controls/Utilities/CountTrue.mo b/Buildings/Templates/Plants/Controls/Utilities/CountTrue.mo new file mode 100644 index 00000000000..8290098d308 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/CountTrue.mo @@ -0,0 +1,62 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block CountTrue + "Output the number of true elements in a Boolean array" + parameter Integer nin( + min=0)=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1[nin] + "Array of Boolean signals" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Index of first element being true" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nin]( + each final integerTrue=1, + each final integerFalse=0) + "Cast to integer" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum sumMul( + final nin=nin) + "Sum over array elements" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); +equation + connect(u1, booToInt.u) + annotation (Line(points={{-120,0},{-42,0}},color={255,0,255})); + connect(sumMul.y, y) + annotation (Line(points={{42,0},{120,0}},color={255,127,0})); + connect(booToInt.y, sumMul.u) + annotation (Line(points={{-18,0},{18,0}},color={255,127,0})); + annotation ( + defaultComponentName="couTru", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation(info=" +

+Counts the number of true elements in the Boolean +input vector. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end CountTrue; diff --git a/Buildings/Templates/Plants/Controls/Utilities/FirstTrueIndex.mo b/Buildings/Templates/Plants/Controls/Utilities/FirstTrueIndex.mo new file mode 100644 index 00000000000..fd16855a651 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/FirstTrueIndex.mo @@ -0,0 +1,81 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block FirstTrueIndex + parameter Integer nin( + min=0)=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1[nin] + "Array of Boolean signals" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Index of first element being true" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nin]( + final integerTrue={i for i in 1:nin}, + each final integerFalse=nin + 1) + "Return index if element is true, 0 otherwise" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + MultiMinInteger mulMin(nin=nin) "Return minimum index" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Integers.Equal intEqu + annotation (Placement(transformation(extent={{34,-50},{54,-30}}))); + Buildings.Controls.OBC.CDL.Integers.Switch intSwi + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant conInt( + k=nin + 1) + annotation (Placement(transformation(extent={{-10,-70},{10,-50}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant zer( + k=0) + annotation (Placement(transformation(extent={{-12,50},{8,70}}))); +equation + connect(booToInt.y, mulMin.u) + annotation (Line(points={{-38,0},{-12,0}},color={255,127,0})); + connect(u1, booToInt.u) + annotation (Line(points={{-120,0},{-62,0}},color={255,0,255})); + connect(conInt.y, intEqu.u2) + annotation (Line(points={{12,-60},{20,-60},{20,-48},{32,-48}},color={255,127,0})); + connect(mulMin.y, intSwi.u3) + annotation (Line(points={{12,0},{40,0},{40,-8},{68,-8}},color={255,127,0})); + connect(intEqu.y, intSwi.u2) + annotation (Line(points={{56,-40},{60,-40},{60,0},{68,0}},color={255,0,255})); + connect(zer.y, intSwi.u1) + annotation (Line(points={{10,60},{60,60},{60,8},{68,8}},color={255,127,0})); + connect(mulMin.y, intEqu.u1) + annotation (Line(points={{12,0},{20,0},{20,-40},{32,-40}},color={255,127,0})); + connect(intSwi.y, y) + annotation (Line(points={{92,0},{120,0}},color={255,127,0})); + annotation ( + defaultComponentName="idxFirTru", + Documentation( + info=" +

+Returns the index of the first true element of the Boolean +input vector. +If no element is true, the block returns 0. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})})); +end FirstTrueIndex; diff --git a/Buildings/Templates/Plants/Controls/Utilities/HoldReal.mo b/Buildings/Templates/Plants/Controls/Utilities/HoldReal.mo new file mode 100644 index 00000000000..db9edb53a0f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/HoldReal.mo @@ -0,0 +1,81 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block HoldReal "Hold value of real signal based on timer and Boolean signal" + parameter Real dtHol( + final unit="s")=0 + "Hold time"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1 + "Boolean signal that triggers fixed output value" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput u + "Input signal" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput y + "Output signal" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Discrete.TriggeredSampler triSam + "Sample signal when the Boolean input switches to true" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + Buildings.Controls.OBC.CDL.Reals.Switch swi + "Switch between actual and fixed value" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold truHol( + final duration=dtHol) if dtHol > 0 + "Hold true value of input signal for given time" + annotation (Placement(transformation(extent={{-10,10},{10,30}}))); + PlaceholderLogical ph(have_inp=dtHol > 0, final have_inpPh=true) + "Placeholder signal in case of zero minimum hold time" + annotation (Placement(transformation(extent={{30,-10},{50,10}}))); +equation + connect(u, triSam.u) + annotation (Line(points={{-120,-40},{-60,-40},{-60,60},{-12,60}},color={0,0,127})); + connect(swi.y, y) + annotation (Line(points={{92,0},{120,0}},color={0,0,127})); + connect(u1, triSam.trigger) + annotation (Line(points={{-120,0},{-40,0},{-40,40},{0,40},{0,48}},color={255,0,255})); + connect(u1, truHol.u) + annotation (Line(points={{-120,0},{-40,0},{-40,20},{-12,20}}, + color={255,0,255})); + connect(triSam.y, swi.u1) + annotation (Line(points={{12,60},{60,60},{60,8},{68,8}},color={0,0,127})); + connect(u, swi.u3) + annotation (Line(points={{-120,-40},{60,-40},{60,-8},{68,-8}},color={0,0,127})); + connect(truHol.y, ph.u) annotation (Line(points={{12,20},{20,20},{20,0},{28,0}}, + color={255,0,255})); + connect(u1, ph.uPh) annotation (Line(points={{-120,0},{-40,0},{-40,-6},{28,-6}}, + color={255,0,255})); + connect(ph.y, swi.u2) + annotation (Line(points={{52,0},{68,0}}, color={255,0,255})); + annotation ( + defaultComponentName="hol", + Icon( + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false)), + Documentation( + info=" +

+Holds input value fixed at its last value while the Boolean signal +u1 is true, and for at least the hold time dtHol. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end HoldReal; diff --git a/Buildings/Templates/Plants/Controls/Utilities/LastTrueIndex.mo b/Buildings/Templates/Plants/Controls/Utilities/LastTrueIndex.mo new file mode 100644 index 00000000000..b0893c1cb14 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/LastTrueIndex.mo @@ -0,0 +1,62 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block LastTrueIndex + parameter Integer nin( + min=0)=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1[nin] + "Array of Boolean signals" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Index of first element being true" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt[nin]( + final integerTrue={i for i in 1:nin}, + each final integerFalse=0) + "Return index if element is true, 0 otherwise" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Templates.Plants.Controls.Utilities.MultiMaxInteger mulMax(nin=nin) + "Return minimum index" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); +equation + connect(booToInt.y, mulMax.u) + annotation (Line(points={{-38,0},{-12,0}},color={255,127,0})); + connect(u1, booToInt.u) + annotation (Line(points={{-120,0},{-62,0}},color={255,0,255})); + connect(mulMax.y, y) + annotation (Line(points={{12,0},{120,0}},color={255,127,0})); + annotation ( + defaultComponentName="idxLasTru", + Documentation( + info=" +

+Returns the index of the last true element of the Boolean +input vector. +If no element is true, the block returns 0. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})})); +end LastTrueIndex; diff --git a/Buildings/Templates/Plants/Controls/Utilities/MultiMaxInteger.mo b/Buildings/Templates/Plants/Controls/Utilities/MultiMaxInteger.mo new file mode 100644 index 00000000000..d0e4d1d0a85 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/MultiMaxInteger.mo @@ -0,0 +1,57 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block MultiMaxInteger "Output the maximum element of the input vector" + parameter Integer nin( + min=0)=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u[nin] + "Integer input signal" + annotation (Placement(transformation(extent={{-140,20},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Integer output signal" + annotation (Placement(transformation(extent={{100,-20},{140,20}}))); +equation + y=max(u); + annotation ( + __cdl( + extensionBlock=true), + defaultComponentName="mulMax", + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,-100},{100,100}}, + lineColor={255,127,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255}), + Text( + extent={{-90,36},{90,-36}}, + textColor={160,160,164}, + textString="max()"), + Text( + extent={{226,60},{106,10}}, + textColor={0,0,0}, + textString=DynamicSelect("",String(y, + leftJustified=false, + significantDigits=3)))}), + Documentation( + info=" +

+Outputs the maximum element of the input vector. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end MultiMaxInteger; diff --git a/Buildings/Templates/Plants/Controls/Utilities/MultiMinInteger.mo b/Buildings/Templates/Plants/Controls/Utilities/MultiMinInteger.mo new file mode 100644 index 00000000000..484e0434487 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/MultiMinInteger.mo @@ -0,0 +1,57 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block MultiMinInteger "Output the minimum element of the input vector" + parameter Integer nin( + min=0)=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u[nin] + "Integer input signal" + annotation (Placement(transformation(extent={{-140,20},{-100,-20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Integer output signal" + annotation (Placement(transformation(extent={{100,-20},{140,20}}))); +equation + y=min(u); + annotation ( + __cdl( + extensionBlock=true), + defaultComponentName="mulMin", + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,-100},{100,100}}, + lineColor={255,127,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255}), + Text( + extent={{-90,36},{90,-36}}, + textColor={160,160,164}, + textString="min()"), + Text( + extent={{226,60},{106,10}}, + textColor={0,0,0}, + textString=DynamicSelect("",String(y, + leftJustified=false, + significantDigits=3)))}), + Documentation( + info=" +

+Outputs the minimum element of the input vector. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end MultiMinInteger; diff --git a/Buildings/Templates/Plants/Controls/Utilities/PIDWithEnable.mo b/Buildings/Templates/Plants/Controls/Utilities/PIDWithEnable.mo new file mode 100644 index 00000000000..4e0fa4dba99 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/PIDWithEnable.mo @@ -0,0 +1,205 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block PIDWithEnable + "PID controller with enable signal" + extends Modelica.Blocks.Icons.Block; + parameter Buildings.Controls.OBC.CDL.Types.SimpleController controllerType= + Buildings.Controls.OBC.CDL.Types.SimpleController.PI + "Type of controller"; + parameter Real k( + min=0)=1 + "Gain of controller"; + parameter Modelica.Units.SI.Time Ti( + min=Buildings.Controls.OBC.CDL.Constants.small)=0.5 + "Time constant of integrator block" + annotation (Dialog(enable=controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PI + or controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PID)); + parameter Modelica.Units.SI.Time Td( + min=0)=0.1 + "Time constant of derivative block" + annotation (Dialog(enable=controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PD + or controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PID)); + parameter Real r( + min=100 * Modelica.Constants.eps)=1 + "Typical range of control error, used for scaling the control error"; + parameter Real yMin=0 + "Lower limit of output"; + parameter Real yMax=1 + "Upper limit of output"; + parameter Boolean reverseActing=true + "Set to true for reverse acting, or false for direct acting control action"; + parameter Real y_reset=yMin + "Value to which the controller output is reset if the boolean trigger has a rising edge"; + parameter Real y_neutral=y_reset + "Value to which the controller output is reset when the controller is disabled"; + Buildings.Controls.OBC.CDL.Interfaces.RealInput u_s + "Connector of setpoint input signal" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput u_m + "Connector of measurement input signal" + annotation (Placement(transformation(origin={0,-120},extent={{20,-20},{-20,20}}, + rotation=270), + iconTransformation(extent={{20,-20},{-20,20}},rotation=270,origin={0,-120}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput y + "Connector of actuator output signal" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uEna + "Enable signal" + annotation (Placement(transformation(extent={{-20,-20},{20,20}},rotation=90, + origin={-60,-120}), + iconTransformation(extent={{-20,-20},{20,20}},rotation=90,origin={-40,-120}))); + Buildings.Controls.OBC.CDL.Reals.PIDWithReset conPID( + final k=k, + final Ti=Ti, + final Td=Td, + final r=r, + final controllerType=controllerType, + final yMin=yMin, + final yMax=yMax, + final reverseActing=reverseActing, + final y_reset=y_reset) + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Reals.Switch swi + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + Buildings.Controls.OBC.CDL.Reals.Switch swi1 + annotation (Placement(transformation(extent={{72,-10},{92,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant valDis( + final k=y_neutral) + "Value when disabled" + annotation (Placement(transformation(extent={{30,-50},{50,-30}}))); +equation + connect(conPID.u_s, swi.y) + annotation (Line(points={{-12,0},{-18,0}},color={0,0,127})); + connect(uEna, swi.u2) + annotation (Line(points={{-60,-120},{-60,-21.5625},{-60,0},{-42,0}},color={255,0,255})); + connect(u_s, swi.u1) + annotation (Line(points={{-120,0},{-80,0},{-80,8},{-42,8}},color={0,0,127})); + connect(u_m, swi.u3) + annotation (Line(points={{0,-120},{0,-80},{-50,-80},{-50,-8},{-42,-8}},color={0,0,127})); + connect(uEna, conPID.trigger) + annotation (Line(points={{-60,-120},{-60,-20},{-6,-20},{-6,-12}},color={255,0,255})); + connect(u_m, conPID.u_m) + annotation (Line(points={{0,-120},{0,-12}},color={0,0,127})); + connect(conPID.y, swi1.u1) + annotation (Line(points={{12,0},{40,0},{40,8},{70,8}},color={0,0,127})); + connect(swi1.y, y) + annotation (Line(points={{94,0},{120,0}},color={0,0,127})); + connect(uEna, swi1.u2) + annotation (Line(points={{-60,-120},{-60,-20},{60,-20},{60,0},{70,0}},color={255,0,255})); + connect(valDis.y, swi1.u3) + annotation (Line(points={{52,-40},{64,-40},{64,-8},{70,-8}},color={0,0,127})); + annotation ( + defaultComponentName="conPID", + defaultComponentName="conPID", + Icon( + coordinateSystem( + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,-100},{100,100}}, + lineColor={0,0,127}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Rectangle( + extent={{-6,-20},{66,-66}}, + lineColor={255,255,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + visible=(controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.P), + extent={{-32,-22},{68,-62}}, + textColor={0,0,0}, + textString="P", + fillPattern=FillPattern.Solid, + fillColor={175,175,175}), + Text( + visible=(controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PI), + extent={{-26,-22},{74,-62}}, + textColor={0,0,0}, + textString="PI", + fillPattern=FillPattern.Solid, + fillColor={175,175,175}), + Text( + visible=(controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PD), + extent={{-16,-22},{88,-62}}, + textColor={0,0,0}, + fillPattern=FillPattern.Solid, + fillColor={175,175,175}, + textString="P D"), + Text( + visible=(controllerType==Buildings.Controls.OBC.CDL.Types.SimpleController.PID), + extent={{-14,-22},{86,-62}}, + textColor={0,0,0}, + textString="PID", + fillPattern=FillPattern.Solid, + fillColor={175,175,175}), + Polygon( + points={{-80,82},{-88,60},{-72,60},{-80,82}}, + lineColor={192,192,192}, + fillColor={192,192,192}, + fillPattern=FillPattern.Solid), + Line( + points={{-80,68},{-80,-100}}, + color={192,192,192}), + Line( + points={{-90,-80},{70,-80}}, + color={192,192,192}), + Polygon( + points={{74,-80},{52,-72},{52,-88},{74,-80}}, + lineColor={192,192,192}, + fillColor={192,192,192}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255}), + Line( + points={{-80,-80},{-80,-22}}, + color={0,0,0}), + Line( + points={{-80,-22},{6,56}}, + color={0,0,0}), + Line( + points={{6,56},{68,56}}, + color={0,0,0}), + Rectangle( + extent=DynamicSelect({{100,-100},{84,-100}},{{100,-100},{84,-100+(y-yMin)/(yMax-yMin)*200}}), + fillColor={175,175,175}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + lineColor={0,0,0})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false)), + Documentation( + info=" +

+This is an update of + +Buildings.Controls.OBC.CDL.Reals.PIDWithReset +with an additional enable signal provided as a Boolean input. +

+
    +
  • +When enabled, the output of the controller is identical to + +Buildings.Controls.OBC.CDL.Reals.PIDWithReset, +and the integral term is reset to y_reset at +enable time. +
  • +
  • +When disabled, the output of the controller is set to y_neutral +and the setpoint is overridden by the measurement signal in order to avoid +time integration of the control error. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PIDWithEnable; diff --git a/Buildings/Templates/Plants/Controls/Utilities/PlaceholderInteger.mo b/Buildings/Templates/Plants/Controls/Utilities/PlaceholderInteger.mo new file mode 100644 index 00000000000..01b5c66b80a --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/PlaceholderInteger.mo @@ -0,0 +1,82 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block PlaceholderInteger "Output a placeholder signal" + parameter Boolean have_inp=true + "Set to true if input signal is available" + annotation (Evaluate=true); + parameter Boolean have_inpPh=false + "Set to true if placeholder value is provided with input signal" + annotation (Evaluate=true); + parameter Integer u_internal( + start=0) + "Placeholder value if input signal is not available" + annotation (Dialog(enable=not have_inpPh)); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u + if have_inp + "Input" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uPh + if not have_inp and have_inpPh "Input" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Output" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant ph(final k=u_internal) + if not have_inp and not have_inpPh + "Placeholder signal if input signal is not available" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); +equation + connect(u, y) annotation (Line(points={{-120,0},{-6,0},{-6,0},{120,0}}, color + ={255,127,0})); + connect(uPh, y) annotation (Line(points={{-120,-40},{60,-40},{60,0},{120,0}}, + color={255,127,0})); + connect(ph.y, y) annotation (Line(points={{12,-80},{80,-80},{80,0},{120,0}}, + color={255,127,0})); + annotation ( + defaultComponentName="ph", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation(info=" +

+This block enables replacing a variable that is conditionally +removed with either a parameter or another input variable. +

+
    +
  • +If the parameter have_inp is true, the output variable +y is equal to the input variable u. +
  • +
  • +If the parameter have_inp is false and the +parameter have_inpPh is true, the output variable +y is equal to the input variable uPh. +
  • +
  • +If the parameter have_inp is false and the +parameter have_inpPh is false, the output variable +y is equal to the parameter u_internal. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PlaceholderInteger; diff --git a/Buildings/Templates/Plants/Controls/Utilities/PlaceholderLogical.mo b/Buildings/Templates/Plants/Controls/Utilities/PlaceholderLogical.mo new file mode 100644 index 00000000000..723a5f8b908 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/PlaceholderLogical.mo @@ -0,0 +1,95 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block PlaceholderLogical "Output a placeholder signal" + parameter Boolean have_inp=true + "Set to true if input signal is available" + annotation (Evaluate=true); + parameter Boolean have_inpPh=false + "Set to true if placeholder value is provided with input signal" + annotation (Evaluate=true); + parameter Boolean u_internal(start=true) + "Placeholder value if input signal is not available" + annotation (Dialog(enable=not have_inpPh)); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u + if have_inp + "Input" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput uPh + if not have_inp and have_inpPh "Input" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y + "Output" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant ph(final k=u_internal) + if not have_inp and not have_inpPh + "Placeholder signal if input signal is not available" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); +equation + connect(u, y) + annotation (Line(points={{-120,0},{-6,0},{-6,0},{120,0}},color={255,0,255})); + connect(ph.y, y) annotation (Line(points={{12,-80},{80,-80},{80,0},{120,0}}, + color={255,0,255})); + connect(uPh, y) annotation (Line(points={{-120,-40},{60,-40},{60,0},{120,0}}, + color={255,0,255})); + annotation ( + defaultComponentName="ph", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + lineThickness=5.0, + fillColor={215,215,215}, + fillPattern=FillPattern.Solid, + borderPattern=BorderPattern.Raised), + Ellipse( + extent={{71,7},{85,-7}}, + lineColor=DynamicSelect({235,235,235},if y then + {0,255,0} else + {235,235,235}), + fillColor=DynamicSelect({235,235,235},if y then + {0,255,0} else + {235,235,235}), + fillPattern=FillPattern.Solid), + Polygon( + points={{-120,140},{-120,140}}, + lineColor={28,108,200}), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation(info=" +

+This block enables replacing a variable that is conditionally +removed with either a parameter or another input variable. +

+
    +
  • +If the parameter have_inp is true, the output variable +y is equal to the input variable u. +
  • +
  • +If the parameter have_inp is false and the +parameter have_inpPh is true, the output variable +y is equal to the input variable uPh. +
  • +
  • +If the parameter have_inp is false and the +parameter have_inpPh is false, the output variable +y is equal to the parameter u_internal. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PlaceholderLogical; diff --git a/Buildings/Templates/Plants/Controls/Utilities/PlaceholderReal.mo b/Buildings/Templates/Plants/Controls/Utilities/PlaceholderReal.mo new file mode 100644 index 00000000000..a8b853ed0cb --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/PlaceholderReal.mo @@ -0,0 +1,82 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block PlaceholderReal "Output a placeholder signal" + parameter Boolean have_inp=true + "Set to true if input signal is available" + annotation (Evaluate=true); + parameter Boolean have_inpPh=false + "Set to true if placeholder value is provided with input signal" + annotation (Evaluate=true); + parameter Real u_internal( + start=0) + "Placeholder value if input signal is not available" + annotation (Dialog(enable=not have_inpPh)); + Buildings.Controls.OBC.CDL.Interfaces.RealInput u + if have_inp + "Input" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealInput uPh + if not have_inp and have_inpPh "Input" + annotation (Placement(transformation(extent={{-140,-60},{-100,-20}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput y + "Output" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant ph(final k=u_internal) + if not have_inp and not have_inpPh + "Placeholder signal if input signal is not available" + annotation (Placement(transformation(extent={{-10,-90},{10,-70}}))); +equation + connect(u, y) + annotation (Line(points={{-120,0},{120,0}},color={0,0,127})); + connect(ph.y, y) annotation (Line(points={{12,-80},{80,-80},{80,0},{120,0}}, + color={0,0,127})); + connect(uPh, y) annotation (Line(points={{-120,-40},{60,-40},{60,0},{120,0}}, + color={0,0,127})); + annotation ( + defaultComponentName="ph", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Documentation(info=" +

+This block enables replacing a variable that is conditionally +removed with either a parameter or another input variable. +

+
    +
  • +If the parameter have_inp is true, the output variable +y is equal to the input variable u. +
  • +
  • +If the parameter have_inp is false and the +parameter have_inpPh is true, the output variable +y is equal to the input variable uPh. +
  • +
  • +If the parameter have_inp is false and the +parameter have_inpPh is false, the output variable +y is equal to the parameter u_internal. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PlaceholderReal; diff --git a/Buildings/Templates/Plants/Controls/Utilities/SortWithIndices.mo b/Buildings/Templates/Plants/Controls/Utilities/SortWithIndices.mo new file mode 100644 index 00000000000..56b868566c7 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/SortWithIndices.mo @@ -0,0 +1,104 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block SortWithIndices + "Sort elements of input vector in ascending or descending order" + parameter Integer nin( + final min=0)=0 + "Number of input connections" + annotation (Dialog(connectorSizing=true),HideResult=true); + parameter Boolean ascending=true + "Set to true if ascending order, otherwise order is descending"; + Buildings.Controls.OBC.CDL.Interfaces.RealInput u[nin] + "Connector of Real input signals" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput y[nin] + "Sorted vector" + annotation (Placement(transformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput yIdx[nin] + "Indices of the sorted vector with respect to the original vector" + annotation (Placement(transformation(extent={{100,-80},{140,-40}}), + iconTransformation(extent={{100,-80},{140,-40}}))); +equation + (y, yIdx)=Modelica.Math.Vectors.sort(u, + ascending=ascending); + annotation ( + __cdl( + extensionBlock=true), + defaultComponentName="sort", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,-100},{100,100}}, + lineColor={0,0,127}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255}), + Text( + extent={{-58,70},{54,-60}}, + textColor={0,0,89}, + textString="sort")}), + Documentation( + info=" +

+Block that sorts the elements of the input signal u. +If the parameter ascending = true, then the output signal y satisfies +yi <= yi+1 for all i ∈ {1, ..., n-1}. +Otherwise, it satisfies +yi >= yi+1 for all i ∈ {1, ..., n-1}. +The output signal yIdx contains the indices of the sorted elements, +with respect to the input vector u. +

+

Usage

+

+Note that this block shall only be used for input signals u that are +time sampled.
+Otherwise, in simulation, numerical noise from a nonlinear solver or from an +implicit time integration algorithm may cause the simulation to stall. +Numerical noise can be present if an input depends +on a state variable or a quantity that requires an iterative solution, +such as a temperature or a mass flow rate of an HVAC system.
+In real controllers, measurement noise may cause the output to change frequently. +

+

+This block may for example be used in a variable air volume flow +controller to access the position of the dampers that are most open. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +Added an output variable with the indices of the sorted elements. +
  • +
  • +March 2, 2020, by Michael Wetter:
    +Changed icon to display dynamically the output value. +
  • +
  • +September 22, 2017, by Michael Wetter:
    +Reimplemented function to make it work with OpenModelica. +
  • +
  • +September 14, 2017, by Jianjun Hu:
    +Changed model name. +
  • +
  • +January 10, 2017, by Milica Grahovac:
    +Initial CDL implementation. +
  • +
  • +November 21, 2011, by Michael Wetter:
    +Removed assert statement. +
  • +
  • +November 25, 2008, by Michael Wetter:
    +First implementation. +
  • +
+")); +end SortWithIndices; diff --git a/Buildings/Templates/Plants/Controls/Utilities/StageIndex.mo b/Buildings/Templates/Plants/Controls/Utilities/StageIndex.mo new file mode 100644 index 00000000000..0cfa41c297a --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/StageIndex.mo @@ -0,0 +1,480 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block StageIndex + "Evaluation of stage index from staging signals" + parameter Boolean have_inpAva=true + "Set to true if stage availability is provided with input signal, false for stages always available" + annotation (Evaluate=true); + parameter Integer nSta( + start=1, + final min=1) + "Number of stages" + annotation (Evaluate=true); + parameter Real dtRun( + final unit="s", + final min=0, + displayUnit="min")=0 + "Minimum runtime of each stage" + annotation (Evaluate=true); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Lea + "Lead unit enable signal" + annotation (Placement(transformation(extent={{-280,100},{-240,140}}), + iconTransformation(extent={{-140,40},{-100,80}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Up + "Stage up command" + annotation (Placement(transformation(extent={{-280,-20},{-240,20}}), + iconTransformation(extent={{-140,0},{-100,40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1Dow + "Stage down command" + annotation (Placement(transformation(extent={{-280,-60},{-240,-20}}), + iconTransformation(extent={{-140,-40},{-100,0}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u1AvaSta[nSta] + if have_inpAva + "Stage available signal" + annotation (Placement(transformation(extent={{-280,-180},{-240,-140}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerOutput y + "Stage index" + annotation (Placement(transformation(extent={{240,80},{280,120}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Modelica.StateGraph.InitialStepWithSignal sta0( + final nOut=nSta, + final nIn=nSta) + "Stage 0 – All units disabled" + annotation (Placement(transformation(extent={{-110,130},{-90,150}}))); + Modelica.StateGraph.StepWithSignal sta[nSta]( + each final nIn=nSta + 1, + each final nOut=nSta + 1) + "Stage i>0" + annotation (Placement(transformation(extent={{-10,130},{10,150}}))); + Modelica.StateGraph.TransitionWithSignal sta0ToSta[nSta]( + each final enableTimer=false) + "Transition from stage 0 to stage i>0" + annotation (Placement(transformation(extent={{-70,130},{-50,150}}))); + inner Modelica.StateGraph.StateGraphRoot stateGraphRoot + "State graph root" + annotation (Placement(transformation(extent={{-10,210},{10,230}}))); + Modelica.StateGraph.TransitionWithSignal staToSta[nSta, nSta]( + each final enableTimer=false) + "Transition to higher or lower stage" + annotation (Placement(transformation(extent={{130,130},{150,150}}))); + Buildings.Controls.OBC.CDL.Logical.And runAndTrn[nSta] + "Runtime condition met AND stage transition command" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rep( + final nout=nSta) + "Replicate" + annotation (Placement(transformation(extent={{-40,-10},{-20,10}}))); + Modelica.StateGraph.TransitionWithSignal staToSta0[nSta]( + each final enableTimer=false) + "Transition from stage i>0 to stage 0" + annotation (Placement(transformation(extent={{50,150},{70,170}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rep2( + final nout=nSta) + "Replicate" + annotation (Placement(transformation(extent={{-40,30},{-20,50}}))); + Buildings.Controls.OBC.CDL.Logical.Not notLea + "True if lead unit is disabled" + annotation (Placement(transformation(extent={{-190,30},{-170,50}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd upAndEna( + nin=3) + "Stage up and lead unit enabled and higher stage available" + annotation (Placement(transformation(extent={{-110,-10},{-90,10}}))); + Utilities.FirstTrueIndex idxFirAct( + nin=nSta) + "Return index of first active stage" + annotation (Placement(transformation(extent={{180,90},{200,110}}))); + Buildings.Controls.OBC.CDL.Logical.Not una[nSta] + "True if stage is not available" + annotation (Placement(transformation(extent={{-190,-170},{-170,-150}}))); + Buildings.Controls.OBC.CDL.Logical.And runAndEna[nSta] + "Runtime condition met AND lead enable signal false" + annotation (Placement(transformation(extent={{0,30},{20,50}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanExtractor staUna( + final nin=nSta) + "Return true if current stage is unavailable" + annotation (Placement(transformation(extent={{-150,-170},{-130,-150}}))); + Buildings.Controls.OBC.CDL.Integers.Max maxInt + "Maximum between current stage index and 1" + annotation (Placement(transformation(extent={{-190,-210},{-170,-190}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant one( + final k=1) + "Constant" + annotation (Placement(transformation(extent={{-230,-210},{-210,-190}}))); + PlaceholderLogical pas[nSta](each final have_inp=dtRun > 0, each final + have_inpPh=true) "Direct pass-through when no minimum runtime" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={-30,80}))); + FirstTrueIndex idxFirAva( + nin=nSta) + "Return index of first available stage" + annotation (Placement(transformation(extent={{-190,-130},{-170,-110}}))); + LastTrueIndex idxLasAva( + nin=nSta) + "Return index of last available stage" + annotation (Placement(transformation(extent={{-190,-90},{-170,-70}}))); + Buildings.Controls.OBC.CDL.Integers.Greater higAva + "Return true if there is any higher stage available" + annotation (Placement(transformation(extent={{-150,-90},{-130,-70}}))); + Buildings.Controls.OBC.CDL.Integers.Less lowAva + "Return true if there is any lower stage available" + annotation (Placement(transformation(extent={{-150,-130},{-130,-110}}))); + Buildings.Controls.OBC.CDL.Logical.Timer tim[nSta]( + passed( + each start=false), + each final t=dtRun) + if dtRun > 0 + "Timer for minimum runtime" + annotation (Placement(transformation(extent={{-90,70},{-70,90}}))); + PlaceholderLogical phAvaSta[nSta]( + each final have_inp=have_inpAva, + each final have_inpPh=false, + each final u_internal=true) "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{-230,-170},{-210,-150}}))); + Buildings.Controls.OBC.CDL.Logical.MultiAnd dowAndEna( + nin=3) + "Stage down and lead unit enabled and lower stage available" + annotation (Placement(transformation(extent={{-110,-50},{-90,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Or upOrDow + "Stage up or down" + annotation (Placement(transformation(extent={{-70,-10},{-50,10}}))); + Buildings.Controls.OBC.CDL.Integers.Switch idxNex + "Return index of next stage to be enabled" + annotation (Placement(transformation(extent={{110,-190},{130,-170}}))); + Buildings.Controls.OBC.CDL.Integers.Less intLesEqu[nSta] + "Return true if index less or equal to active stage index minus one" + annotation (Placement(transformation(extent={{-10,-210},{10,-190}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant idxStaAll[nSta]( + final k={i for i in 1:nSta}) + "Stage indices" + annotation (Placement(transformation(extent={{-50,-170},{-30,-150}}))); + Buildings.Controls.OBC.CDL.Routing.IntegerScalarReplicator intScaRep( + nout=nSta) + "Replicate signal" + annotation (Placement(transformation(extent={{-50,-210},{-30,-190}}))); + Buildings.Controls.OBC.CDL.Logical.And andAva[nSta] + "True if previous condition met and stage available" + annotation (Placement(transformation(extent={{30,-210},{50,-190}}))); + LastTrueIndex idxNexLowAva( + final nin=nSta) + "Return index of next lower available stage" + annotation (Placement(transformation(extent={{60,-210},{80,-190}}))); + FirstTrueIndex idxNexHigAva( + final nin=nSta) + "Return index of next higher available stage" + annotation (Placement(transformation(extent={{60,-170},{80,-150}}))); + Buildings.Controls.OBC.CDL.Integers.Greater intGreEqu[nSta] + "Return true if index greater or equal to active stage index plus one" + annotation (Placement(transformation(extent={{-10,-170},{10,-150}}))); + Buildings.Controls.OBC.CDL.Logical.And andAva1[nSta] + "True if previous condition met and stage available" + annotation (Placement(transformation(extent={{30,-170},{50,-150}}))); + Buildings.Controls.OBC.CDL.Logical.Or upOrActUna + "Stage up command or active stage unavailable" + annotation (Placement(transformation(extent={{-10,-130},{10,-110}}))); + TrueArrayConditional truIdxNex( + final nout=nSta, + nin=1) + "Generate array with true value at index of next stage to be enabled" + annotation (Placement(transformation(extent={{150,-190},{170,-170}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanVectorReplicator repVec( + final nin=nSta, + final nout=nSta) + "Replicate vector" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={160,-140}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rep3[nSta]( + each final nout=nSta) + "Replicate signal" + annotation (Placement(transformation(extent={{70,-10},{90,10}}))); + Buildings.Controls.OBC.CDL.Logical.And matTrn[nSta, nSta] + "Generate matrix with a maximum of one true element where transition must fire" + annotation (Placement(transformation(extent={{112,-10},{132,10}}))); + Buildings.Controls.OBC.CDL.Logical.And actUnaHigAva + "Active stage unavailable and higher stage available" + annotation (Placement(transformation(extent={{-50,-50},{-30,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Or upOrDowOrActUna[nSta] + "Stage up or down command or active stage unavailable (not subject to runtime requirement)" + annotation (Placement(transformation(extent={{40,-10},{60,10}}))); + Buildings.Controls.OBC.CDL.Routing.BooleanScalarReplicator rep1( + final nout=nSta) + "Replicate" + annotation (Placement(transformation(extent={{-10,-50},{10,-30}}))); + TrueArrayConditional truNexHigAva( + final nout=nSta, + nin=1) + "Generate array with true element at index of next higher available stage (if any, otherwise all false)" + annotation (Placement(transformation(extent={{-150,110},{-130,130}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToInteger booToInt( + final integerTrue=1, + final integerFalse=0) + "Cast to integer" + annotation (Placement(transformation(extent={{-190,110},{-170,130}}))); +equation + for i in 1:nSta loop + for j in 1:nSta loop + connect(staToSta[i, j].outPort, sta[j].inPort[i]) + annotation (Line(points={{141.5,140},{160,140},{160,180},{-40,180},{-40,140},{-11,140}}, + color={0,0,0})); + connect(sta[i].outPort[j], staToSta[i, j].inPort) + annotation (Line(points={{10.5,140},{136,140}},color={0,0,0})); + end for; + end for; + // Transitio to/from stage 0 – All units disabled. + connect(sta.outPort[nSta + 1], staToSta0.inPort) + annotation (Line(points={{10.5,140},{20,140},{20,160},{56,160}},color={0,0,0})); + connect(sta0ToSta.outPort, sta.inPort[nSta + 1]) + annotation (Line(points={{-58.5,140},{-11,140}},color={0,0,0})); + connect(staToSta0.outPort, sta0.inPort) + annotation (Line(points={{61.5,160},{80,160},{80,200},{-140,200},{-140,140},{-111,140}}, + color={0,0,0})); + connect(sta0.outPort, sta0ToSta.inPort) + annotation (Line(points={{-89.5,140},{-64,140}},color={0,0,0})); + connect(u1Lea, notLea.u) + annotation (Line(points={{-260,120},{-200,120},{-200,40},{-192,40}},color={255,0,255})); + connect(runAndEna.y, staToSta0.condition) + annotation (Line(points={{22,40},{60,40},{60,148}},color={255,0,255})); + connect(sta.active, idxFirAct.u1) + annotation (Line(points={{0,129},{0,100},{178,100}},color={255,0,255})); + connect(maxInt.y, staUna.index) + annotation (Line(points={{-168,-200},{-140,-200},{-140,-172}},color={255,127,0})); + connect(una.y, staUna.u) + annotation (Line(points={{-168,-160},{-152,-160}},color={255,0,255})); + connect(idxFirAct.y, y) + annotation (Line(points={{202,100},{260,100}},color={255,127,0})); + connect(idxLasAva.y, higAva.u1) + annotation (Line(points={{-168,-80},{-152,-80}},color={255,127,0})); + connect(idxFirAva.y, lowAva.u1) + annotation (Line(points={{-168,-120},{-152,-120}},color={255,127,0})); + connect(idxFirAct.y, higAva.u2) + annotation (Line(points={{202,100},{220,100},{220,-220},{-156,-220},{-156,-88},{-152,-88}}, + color={255,127,0})); + connect(idxFirAct.y, lowAva.u2) + annotation (Line(points={{202,100},{220,100},{220,-220},{-156,-220},{-156,-128},{-152,-128}}, + color={255,127,0})); + connect(one.y, maxInt.u1) + annotation (Line(points={{-208,-200},{-200,-200},{-200,-194},{-192,-194}}, + color={255,127,0})); + connect(idxFirAct.y, maxInt.u2) + annotation (Line(points={{202,100},{220,100},{220,-220},{-196,-220},{-196,-206},{-192,-206}}, + color={255,127,0})); + connect(sta.active, tim.u) + annotation (Line(points={{0,129},{0,100},{-100,100},{-100,80},{-92,80}}, + color={255,0,255})); + connect(tim.passed, pas.u) + annotation (Line(points={{-68,72},{-60,72},{-60,80},{-42,80}},color={255,0,255})); + connect(sta.active, pas.uPh) annotation (Line(points={{0,129},{0,100},{-50, + 100},{-50,74},{-42,74}}, color={255,0,255})); + connect(u1AvaSta, phAvaSta.u) + annotation (Line(points={{-260,-160},{-232,-160}}, color={255,0,255})); + connect(phAvaSta.y, una.u) + annotation (Line(points={{-208,-160},{-192,-160}}, color={255,0,255})); + connect(phAvaSta.y, idxLasAva.u1) annotation (Line(points={{-208,-160},{-200, + -160},{-200,-80},{-192,-80}}, color={255,0,255})); + connect(phAvaSta.y, idxFirAva.u1) annotation (Line(points={{-208,-160},{-200, + -160},{-200,-120},{-192,-120}}, color={255,0,255})); + connect(u1Lea, upAndEna.u[1]) + annotation (Line(points={{-260,120},{-200,120},{-200,-2.33333},{-112,-2.33333}}, + color={255,0,255})); + connect(u1Lea, dowAndEna.u[1]) + annotation (Line(points={{-260,120},{-200,120},{-200,-42.3333},{-112, + -42.3333}}, + color={255,0,255})); + connect(u1Up, upAndEna.u[2]) + annotation (Line(points={{-260,0},{-186,0},{-186,0},{-112,0}},color={255,0,255})); + connect(u1Dow, dowAndEna.u[2]) + annotation (Line(points={{-260,-40},{-112,-40}},color={255,0,255})); + connect(higAva.y, upAndEna.u[3]) + annotation (Line(points={{-128,-80},{-120,-80},{-120,2},{-112,2},{-112,2.33333}}, + color={255,0,255})); + connect(lowAva.y, dowAndEna.u[3]) + annotation (Line(points={{-128,-120},{-116,-120},{-116,-37.6667},{-112, + -37.6667}}, + color={255,0,255})); + connect(upOrDow.y, rep.u) + annotation (Line(points={{-48,0},{-42,0}},color={255,0,255})); + connect(pas.y, runAndTrn.u1) + annotation (Line(points={{-18,80},{-12,80},{-12,0},{-2,0}},color={255,0,255})); + connect(rep.y, runAndTrn.u2) + annotation (Line(points={{-18,0},{-14,0},{-14,-8},{-2,-8}},color={255,0,255})); + connect(intScaRep.y, intLesEqu.u2) + annotation (Line(points={{-28,-200},{-24,-200},{-24,-208},{-12,-208}},color={255,127,0})); + connect(idxStaAll.y, intLesEqu.u1) + annotation (Line(points={{-28,-160},{-20,-160},{-20,-200},{-12,-200}},color={255,127,0})); + connect(intLesEqu.y, andAva.u1) + annotation (Line(points={{12,-200},{28,-200}},color={255,0,255})); + connect(phAvaSta.y, andAva.u2) annotation (Line(points={{-208,-160},{-200,-160}, + {-200,-180},{20,-180},{20,-208},{28,-208}}, color={255,0,255})); + connect(andAva.y, idxNexLowAva.u1) + annotation (Line(points={{52,-200},{58,-200}},color={255,0,255})); + connect(idxStaAll.y, intGreEqu.u1) + annotation (Line(points={{-28,-160},{-12,-160}},color={255,127,0})); + connect(intGreEqu.y, andAva1.u1) + annotation (Line(points={{12,-160},{28,-160}},color={255,0,255})); + connect(phAvaSta.y, andAva1.u2) annotation (Line(points={{-208,-160},{-200,-160}, + {-200,-180},{20,-180},{20,-168},{28,-168}}, color={255,0,255})); + connect(andAva1.y, idxNexHigAva.u1) + annotation (Line(points={{52,-160},{58,-160}},color={255,0,255})); + connect(u1Up, upOrActUna.u1) + annotation (Line(points={{-260,0},{-220,0},{-220,-60},{-20,-60},{-20,-120},{-12,-120}}, + color={255,0,255})); + connect(staUna.y, upOrActUna.u2) + annotation (Line(points={{-128,-160},{-60,-160},{-60,-128},{-12,-128}},color={255,0,255})); + connect(upOrActUna.y, idxNex.u2) + annotation (Line(points={{12,-120},{100,-120},{100,-180},{108,-180}},color={255,0,255})); + connect(andAva1.y, idxNexHigAva.u1) + annotation (Line(points={{52,-160},{58,-160}},color={255,0,255})); + connect(idxNexHigAva.y, idxNex.u1) + annotation (Line(points={{82,-160},{90,-160},{90,-172},{108,-172}},color={255,127,0})); + connect(idxNexLowAva.y, idxNex.u3) + annotation (Line(points={{82,-200},{90,-200},{90,-188},{108,-188}},color={255,127,0})); + connect(one.y, truIdxNex.u) + annotation (Line(points={{-208,-200},{-200,-200},{-200,-224},{140,-224},{140,-180},{148,-180}}, + color={255,127,0})); + connect(truIdxNex.y1, repVec.u) + annotation (Line(points={{172,-180},{180,-180},{180,-160},{160,-160},{160,-152}}, + color={255,0,255})); + connect(rep3.y, matTrn.u1) + annotation (Line(points={{92,0},{110,0}},color={255,0,255})); + connect(repVec.y, matTrn.u2) + annotation (Line(points={{160,-128},{160,-20},{106,-20},{106,-8},{110,-8}}, + color={255,0,255})); + connect(matTrn.y, staToSta.condition) + annotation (Line(points={{134,0},{140,0},{140,128}},color={255,0,255})); + connect(dowAndEna.y, upOrDow.u2) + annotation (Line(points={{-88,-40},{-80,-40},{-80,-8},{-72,-8}},color={255,0,255})); + connect(staUna.y, actUnaHigAva.u2) + annotation (Line(points={{-128,-160},{-60,-160},{-60,-48},{-52,-48}},color={255,0,255})); + connect(higAva.y, actUnaHigAva.u1) + annotation (Line(points={{-128,-80},{-74,-80},{-74,-40},{-52,-40}},color={255,0,255})); + connect(actUnaHigAva.y, rep1.u) + annotation (Line(points={{-28,-40},{-12,-40}},color={255,0,255})); + connect(rep1.y, upOrDowOrActUna.u2) + annotation (Line(points={{12,-40},{30,-40},{30,-8},{38,-8}},color={255,0,255})); + connect(idxNex.y, truIdxNex.uIdx[1]) + annotation (Line(points={{132,-180},{134,-180},{134,-186},{148,-186}},color={255,127,0})); + connect(truNexHigAva.y1, sta0ToSta.condition) + annotation (Line(points={{-128,120},{-60,120},{-60,128}},color={255,0,255})); + connect(u1Lea, booToInt.u) + annotation (Line(points={{-260,120},{-192,120}},color={255,0,255})); + connect(booToInt.y, truNexHigAva.u) + annotation (Line(points={{-168,120},{-152,120}},color={255,127,0})); + connect(idxFirAva.y, truNexHigAva.uIdx[1]) + annotation (Line(points={{-168,-120},{-160,-120},{-160,114},{-152,114}}, + color={255,127,0})); + connect(upAndEna.y, upOrDow.u1) + annotation (Line(points={{-88,0},{-72,0}},color={255,0,255})); + connect(notLea.y, rep2.u) + annotation (Line(points={{-168,40},{-42,40}},color={255,0,255})); + connect(runAndTrn.y, upOrDowOrActUna.u1) + annotation (Line(points={{22,0},{38,0}},color={255,0,255})); + connect(upOrDowOrActUna.y, rep3.u) + annotation (Line(points={{62,0},{68,0}},color={255,0,255})); + connect(rep2.y, runAndEna.u1) + annotation (Line(points={{-18,40},{-2,40}},color={255,0,255})); + connect(pas.y, runAndEna.u2) + annotation (Line(points={{-18,80},{-12,80},{-12,32},{-2,32}},color={255,0,255})); + connect(idxFirAct.y, intScaRep.u) + annotation (Line(points={{202,100},{220,100},{220,-220},{-60,-220},{-60,-200},{-52,-200}}, + color={255,127,0})); + connect(intScaRep.y, intGreEqu.u2) + annotation (Line(points={{-28,-200},{-24,-200},{-24,-168},{-12,-168}},color={255,127,0})); + annotation ( + __cdl( + extensionBlock=true), + defaultComponentName="idxSta", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-240,-240},{240,240}})), + Documentation( + info=" +

+This block is used to compute the stage index for a group of +multiple equipment such as CHW pumps or chillers. +

+
    +
  • +At initial time, stage 0 is active – +all units are disabled. +
  • +
  • +From stage 0, the transition to the next higher available +stage is triggered when the lead unit is enabled (u1Lea = true) +and if at least one stage is available. +
  • +
  • +From any stage i (1 ≤ i ≤ nSta), the transition +to the next higher or lower available stage j +(1 ≤ j ≤ nSta, j ≠ i) +is triggered when stage i has been active for the minimum runtime +and there is a stage up command u1Up or stage down command u1Dow, respectively. +
  • +
  • +From any stage i (1 ≤ i ≤ nSta), the transition +to stage 0 is triggered when stage i has been active +for the minimum runtime and the lead unit is disabled (u1Lea = false). +
  • +
+

+Unavailable stages are handled by the following requirements. +

+
    +
  • +Any unavailable stage (u1Ava[i] = false) is skipped during +staging events. +
  • +
  • +If all higher (resp. lower) stages are unavailable, then the transition +to a higher (resp. lower) stage is blocked. +
  • +
  • +If the current stage is unavailable, the transition to the next +higher available stage is triggered. +
  • +
  • +Stage transitions due to availability conditions are +not subject to the minimum stage runtime requirement. +
  • +
+

Caveats

+

+The only way to transition to stage 0 is by disabling the lead unit +(u1Lea = false). +The stage down command u1Dow cannot be used to transition +below stage 1. +

+

+When the current stage becomes unavailable, the transition to the next +higher available stage is triggered. +However, it can happen that equipment that is enabled at the current +stage is no longer available while the current stage is not deemed +unavailable – for example if a lead/lag alternate equipment remains available. +In this case, the equipment rotation logic must stage on the +lead/lag alternate equipment to replace the faulty equipment. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end StageIndex; diff --git a/Buildings/Templates/Plants/Controls/Utilities/TimerWithReset.mo b/Buildings/Templates/Plants/Controls/Utilities/TimerWithReset.mo new file mode 100644 index 00000000000..cf530459b2f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/TimerWithReset.mo @@ -0,0 +1,143 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block TimerWithReset + "Timer measuring the time from the time instant where the Boolean input became true" + parameter Real t( + final quantity="Time", + final unit="s")=0 + "Threshold time for comparison"; + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput u + "Input that switches timer on if true, and off if false" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanInput reset + "Reset signal" + annotation (Placement(transformation(extent={{-140,-100},{-100,-60}}), + iconTransformation(extent={{-140,-100},{-100,-60}}))); + Buildings.Controls.OBC.CDL.Interfaces.RealOutput y( + final quantity="Time", + final unit="s") + "Elapsed time" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput passed + "True if the elapsed time is greater than threshold" + annotation (Placement(transformation(extent={{100,-100},{140,-60}}), + iconTransformation(extent={{100,-100},{140,-60}}))); +protected + discrete Real entryTime( + final quantity="Time", + final unit="s") + "Time instant when u became true"; +initial equation + pre(entryTime)=time; + pre(passed)=t <= 0; +equation + when u and not reset then + entryTime=time; + // When u becomes true, and t=0, we want passed to be true + // at the first step (in superdense time). + passed=t <= 0; + elsewhen reset then + entryTime=time; + passed=false; + elsewhen + (u and time >= t + pre(entryTime)) then + passed=true; + entryTime=pre(entryTime); + elsewhen not u then + // Set passed to false. + // This is the behavior a timer would have if the threshold test is done with a greater block connected to the output of the timer + passed=false; + entryTime=pre(entryTime); + end when; + y=if u then time - entryTime else 0.0; + annotation ( + __cdl( + extensionBlock=true), + defaultComponentName="tim", + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100.0,-100.0},{100.0,100.0}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + fillColor={210,210,210}, + lineThickness=5.0, + fillPattern=FillPattern.Solid, + borderPattern=BorderPattern.Raised), + Line( + points={{-66,-60},{82,-60}}, + color={192,192,192}), + Line( + points={{-58,68},{-58,-80}}, + color={192,192,192}), + Polygon( + lineColor={192,192,192}, + fillColor={192,192,192}, + fillPattern=FillPattern.Solid, + points={{90,-60},{68,-52},{68,-68},{90,-60}}), + Polygon( + lineColor={192,192,192}, + fillColor={192,192,192}, + fillPattern=FillPattern.Solid, + points={{-58,90},{-66,68},{-50,68},{-58,90}}), + Line( + points={{-56,-60},{-38,-60},{-38,-16},{40,-16},{40,-60},{68,-60}}, + color={255,0,255}), + Line( + points={{-58,0},{-40,0},{40,58},{40,0},{68,0}}, + color={0,0,127}), + Text( + extent={{-150,150},{150,110}}, + textColor={0,0,255}, + textString="%name"), + Text( + extent={{-64,62},{62,92}}, + textColor={0,0,0}, + textString="t=%t"), + Ellipse( + extent={{-83,7},{-69,-7}}, + lineColor=DynamicSelect({235,235,235},if u then + {0,255,0} else + {235,235,235}), + fillColor=DynamicSelect({235,235,235},if u then + {0,255,0} else + {235,235,235}), + fillPattern=FillPattern.Solid), + Ellipse( + extent={{71,-73},{85,-87}}, + lineColor=DynamicSelect({235,235,235},if passed then + {0,255,0} else + {235,235,235}), + fillColor=DynamicSelect({235,235,235},if passed then + {0,255,0} else + {235,235,235}), + fillPattern=FillPattern.Solid), + Text( + extent={{226,60},{106,10}}, + textColor={0,0,0}, + textString=DynamicSelect("",String(y, + leftJustified=false, + significantDigits=3)))}), + Diagram( + coordinateSystem( + preserveAspectRatio=false)), + Documentation(revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+", info=" +

+This block is similar to + +Buildings.Controls.OBC.CDL.Logical.Timer, +but introduces an additional Boolean input signal reset, +which resets the timer. +When reset becomes true: +y=0 and passed=false. +

+")); +end TimerWithReset; diff --git a/Buildings/Templates/Plants/Controls/Utilities/TrueArrayConditional.mo b/Buildings/Templates/Plants/Controls/Utilities/TrueArrayConditional.mo new file mode 100644 index 00000000000..800d94a604c --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/TrueArrayConditional.mo @@ -0,0 +1,80 @@ +within Buildings.Templates.Plants.Controls.Utilities; +block TrueArrayConditional + "Output a Boolean array with a given number of true elements and a priority order" + parameter Integer nin( + min=0)=0 + "Size of input array" + annotation (Evaluate=true, + Dialog(connectorSizing=true),HideResult=true); + parameter Integer nout( + min=0)=nin + "Size of output array" + annotation (Evaluate=true); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput u + "Number of true elements" + annotation (Placement(transformation(extent={{-140,-20},{-100,20}}), + iconTransformation(extent={{-140,-20},{-100,20}}))); + Buildings.Controls.OBC.CDL.Interfaces.IntegerInput uIdx[nin] + "Array of indices by order of priority to be true" + annotation (Placement(transformation(extent={{-140,-80},{-100,-40}}), + iconTransformation(extent={{-140,-80},{-100,-40}}))); + Buildings.Controls.OBC.CDL.Interfaces.BooleanOutput y1[nout] + "Output" + annotation (Placement(transformation(extent={{100,-20},{140,20}}), + iconTransformation(extent={{100,-20},{140,20}}))); +protected + Integer iTru + "Iteration variable - Count number of true elements"; + Integer iIdx + "Iteration variable - Count number of indices in input vector"; +initial equation + pre(u)=0; +algorithm + iTru := 0; + iIdx := 1; + y1 := fill(false, nout); + while + (iTru < u) and (iIdx <= nin) loop + if (uIdx[iIdx] >= 1) and (uIdx[iIdx] <= nout) then + y1[uIdx[iIdx]] := true; + iTru := iTru + 1; + end if; + iIdx := iIdx + 1; + end while; + annotation ( + defaultComponentName="truArrCon", + __cdl( + extensionBlock=true), + Icon( + coordinateSystem( + preserveAspectRatio=true, + extent={{-100,-100},{100,100}}), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false)), + Documentation( + info=" +

+Accepts indices of true elements that may not be within the +range of indices of the output vector. +In this, the number of true elements will not be met. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end TrueArrayConditional; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/CountTrue.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/CountTrue.mo new file mode 100644 index 00000000000..1541a792899 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/CountTrue.mo @@ -0,0 +1,56 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model CountTrue "Validation model" + Utilities.FirstTrueIndex couTru(nin=6) "Return number of true elements" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + Utilities.FirstTrueIndex couTruAllFal(nin=6) + "Return number of true elements – All elements of input vector are false" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant conAllFal[6](k=fill(false, + 6)) "Constant array" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant con[6](k={false,true,false, + false,true,false}) "Constant array" + annotation (Placement(transformation(extent={{-60,50},{-40,70}}))); +equation + connect(con.y, couTru.u1) + annotation (Line(points={{-38,60},{-12,60}}, color={255,0,255})); + connect(conAllFal.y, couTruAllFal.u1) + annotation (Line(points={{-38,0},{-12,0}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/CountTrue.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.CountTrue. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end CountTrue; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/FirstTrueIndex.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/FirstTrueIndex.mo new file mode 100644 index 00000000000..4c510e136f6 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/FirstTrueIndex.mo @@ -0,0 +1,59 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model FirstTrueIndex + "Validation model" + Utilities.FirstTrueIndex idxFirTru( + nin=6) + "Return first true index" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + Utilities.FirstTrueIndex idxFirTruAllFal(nin=6) + "Return first true index – All elements of input vector are false" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant conAllFal[6](k=fill(false, + 6)) "Constant array" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant con[6](k={false,true, + false,false,true,false}) "Constant array" + annotation (Placement(transformation(extent={{-60,50},{-40,70}}))); +equation + connect(con.y, idxFirTru.u1) + annotation (Line(points={{-38,60},{-12,60}}, color={255,0,255})); + connect(conAllFal.y, idxFirTruAllFal.u1) + annotation (Line(points={{-38,0},{-12,0}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/FirstTrueIndex.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.FirstTrueIndex. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end FirstTrueIndex; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/HoldReal.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/HoldReal.mo new file mode 100644 index 00000000000..597ae698440 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/HoldReal.mo @@ -0,0 +1,62 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model HoldReal "Validation model" + Buildings.Templates.Plants.Controls.Utilities.HoldReal hol(dtHol=0) + "Hold signal – No minimum hold time" + annotation (Placement(transformation(extent={{20,30},{40,50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul(width=0.2, period=30) + "Source signal for hold trigger" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin sin(freqHz=1/60) + "Source signal for value to hold" + annotation (Placement(transformation(extent={{-80,50},{-60,70}}))); + Buildings.Templates.Plants.Controls.Utilities.HoldReal holTim(dtHol=20) + "Hold signal – With minimum hold time" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); +equation + connect(booPul.y, hol.u1) + annotation (Line(points={{-58,0},{-20,0},{-20,40},{18,40}}, + color={255,0,255})); + connect(sin.y, hol.u) annotation (Line(points={{-58,60},{0,60},{0,34},{18,34}}, + color={0,0,127})); + connect(booPul.y, holTim.u1) + annotation (Line(points={{-58,0},{18,0}}, color={255,0,255})); + connect(sin.y, holTim.u) annotation (Line(points={{-58,60},{0,60},{0,-6},{18, + -6}}, color={0,0,127})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/HoldReal.mos" + "Simulate and plot"), + experiment( + StopTime=60.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.HoldValue. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end HoldReal; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/LastTrueIndex.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/LastTrueIndex.mo new file mode 100644 index 00000000000..ddab53a4ea7 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/LastTrueIndex.mo @@ -0,0 +1,59 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model LastTrueIndex + "Validation model" + Buildings.Templates.Plants.Controls.Utilities.LastTrueIndex idxLasTru( + nin=6) + "Return last true index" + annotation (Placement(transformation(extent={{-10,50},{10,70}}))); + Buildings.Templates.Plants.Controls.Utilities.LastTrueIndex idxLasTruAllFal(nin=6) + "Return last true index – All elements of input vector are false" + annotation (Placement(transformation(extent={{-10,-10},{10,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant conAllFal[6](k=fill(false, + 6)) "Constant array" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant con[6](k={false,true, + false,false,true,false}) "Constant array" + annotation (Placement(transformation(extent={{-60,50},{-40,70}}))); +equation + connect(con.y, idxLasTru.u1) + annotation (Line(points={{-38,60},{-12,60}}, color={255,0,255})); + connect(conAllFal.y, idxLasTruAllFal.u1) + annotation (Line(points={{-38,0},{-12,0}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/LastTrueIndex.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.FirstTrueIndex. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end LastTrueIndex; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMaxInteger.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMaxInteger.mo new file mode 100644 index 00000000000..25b2ef56d04 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMaxInteger.mo @@ -0,0 +1,50 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model MultiMaxInteger + Buildings.Templates.Plants.Controls.Utilities.MultiMaxInteger mulMax(nin=5) + "Block that outputs the maximum element of the input vector" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant con[5]( + k={1, 2, 3, 4, 5}) + "Constant vector" + annotation (Placement(transformation(extent={{-48,-10},{-28,10}}))); +equation + connect(con.y,mulMax. u) + annotation (Line(points={{-26,0},{-2,0}},color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/MultiMaxInteger.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.MultiMaxInteger. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end MultiMaxInteger; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMinInteger.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMinInteger.mo new file mode 100644 index 00000000000..3f6748433c9 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/MultiMinInteger.mo @@ -0,0 +1,50 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model MultiMinInteger + Buildings.Templates.Plants.Controls.Utilities.MultiMinInteger mulMin(nin=5) + "Block that outputs the minimum element of the input vector" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant con[5]( + k={1, 2, 3, 4, 5}) + "Constant vector" + annotation (Placement(transformation(extent={{-48,-10},{-28,10}}))); +equation + connect(con.y, mulMin.u) + annotation (Line(points={{-26,0},{-2,0}},color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/MultiMinInteger.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.MultiMinInteger. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end MultiMinInteger; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderInteger.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderInteger.mo new file mode 100644 index 00000000000..c8a72e83070 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderInteger.mo @@ -0,0 +1,70 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model PlaceholderInteger "Validation model" + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger + phPar( + have_inp=false, + have_inpPh=false, u_internal=1) "Placeholder parameter" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Pulse pul(period=1) + "Source signal for value to replace" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger + phInp(have_inp= + false, + have_inpPh=true) "Placeholder signal" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant con(k=2) "Constant" + annotation (Placement(transformation(extent={{-80,-70},{-60,-50}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger + phNo( + have_inp=true, + have_inpPh=false, + u_internal=3) "No placeholder: use input signal" + annotation (Placement(transformation(extent={{20,50},{40,70}}))); +equation + connect(pul.y, phNo.u) annotation (Line(points={{-58,0},{0,0},{0,60},{18,60}}, + color={255,127,0})); + connect(con.y, phInp.uPh) annotation (Line(points={{-58,-60},{-20,-60},{-20, + -66},{18,-66}}, color={255,127,0})); + connect(pul.y, phPar.u) + annotation (Line(points={{-58,0},{18,0}}, color={255,127,0})); + connect(pul.y, phInp.u) annotation (Line(points={{-58,0},{0,0},{0,-60},{18, + -60}}, color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/PlaceholderInteger.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end PlaceholderInteger; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderLogical.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderLogical.mo new file mode 100644 index 00000000000..02fbeef9d45 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderLogical.mo @@ -0,0 +1,71 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model PlaceholderLogical "Validation model" + Buildings.Templates.Plants.Controls.Utilities.PlaceholderLogical + phPar( + have_inp=false, + have_inpPh=false, + u_internal=false) "Placeholder parameter" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse pul(period=1) + "Source signal for value to replace" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderLogical + phInp(have_inp=false, + have_inpPh=true) "Placeholder signal" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant con(k=true) "Constant" + annotation (Placement(transformation(extent={{-80,-70},{-60,-50}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderLogical + phNo( + have_inp=true, + have_inpPh=false, + u_internal=false) + "No placeholder: use input signal" + annotation (Placement(transformation(extent={{20,50},{40,70}}))); +equation + connect(pul.y, phPar.u) + annotation (Line(points={{-58,0},{18,0}}, color={255,0,255})); + connect(pul.y, phInp.u) annotation (Line(points={{-58,0},{0,0},{0,-60},{18, + -60}}, color={255,0,255})); + connect(pul.y, phNo.u) annotation (Line(points={{-58,0},{0,0},{0,60},{18,60}}, + color={255,0,255})); + connect(con.y, phInp.uPh) annotation (Line(points={{-58,-60},{-20,-60},{-20,-66}, + {18,-66}}, color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/PlaceholderLogical.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.PlaceholderLogical. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end PlaceholderLogical; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderReal.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderReal.mo new file mode 100644 index 00000000000..8d0c99d9ae5 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/PlaceholderReal.mo @@ -0,0 +1,67 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model PlaceholderReal "Validation model" + Buildings.Templates.Plants.Controls.Utilities.PlaceholderReal phPar( + have_inp=false, + have_inpPh=false, u_internal=1) "Placeholder parameter" + annotation (Placement(transformation(extent={{20,-10},{40,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Pulse + pul(period=1) + "Source signal for value to replace" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderReal phInp(have_inp=false, + have_inpPh=true) "Placeholder signal" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant con(k=2) "Constant" + annotation (Placement(transformation(extent={{-80,-70},{-60,-50}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderReal phNo( + have_inp=true, + have_inpPh=false, + u_internal=1) "No placeholder: use input signal" + annotation (Placement(transformation(extent={{20,50},{40,70}}))); +equation + connect(pul.y, phNo.u) + annotation (Line(points={{-58,0},{0,0},{0,60},{18,60}}, color={0,0,127})); + connect(pul.y, phPar.u) + annotation (Line(points={{-58,0},{18,0}}, color={0,0,127})); + connect(pul.y, phInp.u) annotation (Line(points={{-58,0},{0,0},{0,-60},{18,-60}}, + color={0,0,127})); + connect(con.y, phInp.uPh) annotation (Line(points={{-58,-60},{-20,-60},{-20,-66}, + {18,-66}}, color={0,0,127})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/PlaceholderReal.mos" + "Simulate and plot"), + experiment( + StopTime=1.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.PlaceholderReal. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end PlaceholderReal; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/SortWithIndices.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/SortWithIndices.mo new file mode 100644 index 00000000000..cb645e2dcfa --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/SortWithIndices.mo @@ -0,0 +1,113 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model SortWithIndices + "Validation model for the Sort block" + Buildings.Templates.Plants.Controls.Utilities.SortWithIndices sorAsc( + nin=5) + "Block that sorts signals in ascending order" + annotation (Placement(transformation(extent={{0,20},{20,40}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp1( + duration=1, + offset=-2, + height=4) + "Block that generates ramp signal" + annotation (Placement(transformation(extent={{-60,56},{-40,76}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp2( + duration=1, + offset=-1, + height=3) + "Block that generates ramp signal" + annotation (Placement(transformation(extent={{-60,22},{-40,42}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp3( + duration=1, + offset=2, + height=-4) + "Block that generates ramp signal" + annotation (Placement(transformation(extent={{-60,-10},{-40,10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp4( + duration=1, + offset=3, + height=-1) + "Block that generates ramp signal" + annotation (Placement(transformation(extent={{-60,-42},{-40,-22}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Ramp ramp5( + duration=1, + offset=0, + height=4) + "Block that generates ramp signal" + annotation (Placement(transformation(extent={{-60,-74},{-40,-54}}))); + Buildings.Templates.Plants.Controls.Utilities.SortWithIndices sorDes( + nin=5, + ascending=false) + "Block that sorts signals in descending order" + annotation (Placement(transformation(extent={{0,-40},{20,-20}}))); + +equation + connect(ramp1.y,sorAsc.u[1]) + annotation (Line(points={{-38,66},{-22,66},{-22,29.2},{-2,29.2}},color={0,0,127})); + connect(ramp2.y,sorAsc.u[2]) + annotation (Line(points={{-38,32},{-20,32},{-20,29.6},{-2,29.6}},color={0,0,127})); + connect(ramp3.y,sorAsc.u[3]) + annotation (Line(points={{-38,0},{-22,0},{-22,30},{-2,30}},color={0,0,127})); + connect(ramp4.y,sorAsc.u[4]) + annotation (Line(points={{-38,-32},{-22,-32},{-22,30.4},{-2,30.4}},color={0,0,127})); + connect(ramp5.y,sorAsc.u[5]) + annotation (Line(points={{-38,-64},{-20,-64},{-20,30.8},{-2,30.8}},color={0,0,127})); + connect(ramp1.y,sorDes.u[1]) + annotation (Line(points={{-38,66},{-22,66},{-22,-30.8},{-2,-30.8}},color={0,0,127})); + connect(ramp2.y,sorDes.u[2]) + annotation (Line(points={{-38,32},{-20,32},{-20,-30.4},{-2,-30.4}},color={0,0,127})); + connect(ramp3.y,sorDes.u[3]) + annotation (Line(points={{-38,0},{-22,0},{-22,-30},{-2,-30}},color={0,0,127})); + connect(ramp4.y,sorDes.u[4]) + annotation (Line(points={{-38,-32},{-22,-32},{-22,-29.6},{-2,-29.6}},color={0,0,127})); + connect(ramp5.y,sorDes.u[5]) + annotation (Line(points={{-38,-64},{-20,-64},{-20,-29.2},{-2,-29.2}},color={0,0,127})); + annotation ( + experiment( + StopTime=1.0, + Tolerance=1e-06), + __Dymola_Commands( + file="modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/SortWithIndices.mos" "Simulate and plot"), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.SortWithIndices. +

+

+The input u1 varies from -2 to +2, input u2 varies from -1 to +2, +input u3 varies from +2 to -2, input u4 varies from +3 to +2, +input u5 varies from 0 to +4, +

+", + revisions=" +
    +
  • + March 29, 2024, by Antoine Gautier:
    + Updated model with indices of sorted elements. +
  • +
  • +September 14, 2017, by Jianjun Hu:
    +Changed model name. +
  • +
  • +March 22, 2017, by Jianjun Hu:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end SortWithIndices; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/StageIndex.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/StageIndex.mo new file mode 100644 index 00000000000..6330fec213f --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/StageIndex.mo @@ -0,0 +1,145 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model StageIndex + parameter Integer nSta=4 + "Number of stages" + annotation (Evaluate=true); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse ena( + width=0.9, + period=160, + shift=10) + "Enable signal" + annotation (Placement(transformation(extent={{-90,50},{-70,70}}))); + Buildings.Templates.Plants.Controls.Utilities.StageIndex idxSta( + have_inpAva=false, + final nSta=nSta) + "Compute stage index - No minimum runtime, all stages available" + annotation (Placement(transformation(extent={{20,50},{40,70}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.SampleTrigger upPul( + period=20) + "Stage up command pulse" + annotation (Placement(transformation(extent={{-90,10},{-70,30}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.SampleTrigger dowPul( + period=20) + "Stage down command pulse" + annotation (Placement(transformation(extent={{-90,-30},{-70,-10}}))); + Buildings.Templates.Plants.Controls.Utilities.StageIndex idxStaUna( + final nSta=nSta) + "Compute stage index - No minimum runtime, some unavailable stages" + annotation (Placement(transformation(extent={{62,20},{82,40}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant u1AvaSta[nSta]( + k={false, false, true, true}) + "Stage available signal" + annotation (Placement(transformation(extent={{-90,-90},{-70,-70}}))); + Buildings.Templates.Plants.Controls.Utilities.StageIndex idxStaRun( + have_inpAva=false, + final nSta=nSta, + dtRun=25) + "Compute stage index - Minimum runtime, all stages available" + annotation (Placement(transformation(extent={{20,-40},{40,-20}}))); + Buildings.Templates.Plants.Controls.Utilities.StageIndex idxStaRunUna( + final nSta=nSta, + dtRun=25) + "Compute stage index - Minimum runtime, some unavailable stages" + annotation (Placement(transformation(extent={{60,-70},{80,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable booTimTab( + table=[ + 0, 0, 0; + 10, 1, 0; + 70, 0, 1], + period=160) + "Signal to inhibit up and down commands" + annotation (Placement(transformation(extent={{-90,80},{-70,100}}))); + Buildings.Controls.OBC.CDL.Logical.And u1Up + "Stage up command" + annotation (Placement(transformation(extent={{-40,10},{-20,30}}))); + Buildings.Controls.OBC.CDL.Logical.And u1Dow + "Stage down command" + annotation (Placement(transformation(extent={{-40,-30},{-20,-10}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold u1UpHol(duration=0.1) + "Hold stage up command for plotting" + annotation (Placement(transformation(extent={{0,90},{20,110}}))); + Buildings.Controls.OBC.CDL.Logical.TrueHold u1DowHol(duration=0.1) + "Hold stage down command for plotting" + annotation (Placement(transformation(extent={{0,-110},{20,-90}}))); +equation + connect(ena.y, idxSta.u1Lea) + annotation (Line(points={{-68,60},{0,60},{0,66},{18,66}},color={255,0,255})); + connect(ena.y, idxStaUna.u1Lea) + annotation (Line(points={{-68,60},{0,60},{0,36},{60,36}},color={255,0,255})); + connect(ena.y, idxStaRun.u1Lea) + annotation (Line(points={{-68,60},{0,60},{0,-24},{18,-24}},color={255,0,255})); + connect(u1AvaSta.y, idxStaUna.u1AvaSta) + annotation (Line(points={{-68,-80},{50,-80},{50,24},{60,24}},color={255,0,255})); + connect(ena.y, idxStaRunUna.u1Lea) + annotation (Line(points={{-68,60},{0,60},{0,-54},{58,-54}},color={255,0,255})); + connect(u1AvaSta.y, idxStaRunUna.u1AvaSta) + annotation (Line(points={{-68,-80},{50,-80},{50,-66},{58,-66}},color={255,0,255})); + connect(upPul.y, u1Up.u2) + annotation (Line(points={{-68,20},{-60,20},{-60,12},{-42,12}},color={255,0,255})); + connect(dowPul.y, u1Dow.u2) + annotation (Line(points={{-68,-20},{-60,-20},{-60,-28},{-42,-28}},color={255,0,255})); + connect(booTimTab.y[2], u1Dow.u1) + annotation (Line(points={{-68,90},{-50,90},{-50,-20},{-42,-20}},color={255,0,255})); + connect(u1Up.y, idxSta.u1Up) + annotation (Line(points={{-18,20},{-10,20},{-10,62},{18,62}},color={255,0,255})); + connect(u1Dow.y, idxSta.u1Dow) + annotation (Line(points={{-18,-20},{-4,-20},{-4,58},{18,58}},color={255,0,255})); + connect(u1Up.y, idxStaUna.u1Up) + annotation (Line(points={{-18,20},{30,20},{30,32},{60,32}},color={255,0,255})); + connect(u1Dow.y, idxStaUna.u1Dow) + annotation (Line(points={{-18,-20},{-4,-20},{-4,28},{60,28}},color={255,0,255})); + connect(u1Dow.y, idxStaRun.u1Dow) + annotation (Line(points={{-18,-20},{-4,-20},{-4,-32},{18,-32}},color={255,0,255})); + connect(u1Dow.y, idxStaRunUna.u1Dow) + annotation (Line(points={{-18,-20},{-4,-20},{-4,-62},{58,-62}},color={255,0,255})); + connect(u1Up.y, idxStaRun.u1Up) + annotation (Line(points={{-18,20},{-10,20},{-10,-28},{18,-28}},color={255,0,255})); + connect(u1Up.y, idxStaRunUna.u1Up) + annotation (Line(points={{-18,20},{-10,20},{-10,-58},{58,-58}},color={255,0,255})); + connect(booTimTab.y[1], u1Up.u1) + annotation (Line(points={{-68,90},{-50,90},{-50,20},{-42,20}},color={255,0,255})); + connect(u1Up.y, u1UpHol.u) + annotation (Line(points={{-18,20},{-10,20},{-10,100},{-2,100}},color={255,0,255})); + connect(u1Dow.y, u1DowHol.u) + annotation (Line(points={{-18,-20},{-4,-20},{-4,-100},{-2,-100}},color={255,0,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/StageIndex.mos" + "Simulate and plot"), + experiment( + StopTime=160.0, + Tolerance=1e-06), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.StageIndex. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})}), + Diagram( + coordinateSystem( + extent={{-120,-120},{120,120}}))); +end StageIndex; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/TimerWithReset.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/TimerWithReset.mo new file mode 100644 index 00000000000..46bb48ced19 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/TimerWithReset.mo @@ -0,0 +1,120 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model TimerWithReset + "Validation model for the Timer block" + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset noThr + "Timer that do not compare threshold – No Reset" + annotation (Placement(transformation(extent={{20,10},{40,30}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset thrTim( + final t=0.3) "Timer that compares threshold – No Reset" + annotation (Placement(transformation(extent={{20,-30},{40,-10}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset thrTim1( + final t=0.3) "Timer that compares threshold – No Reset" + annotation (Placement(transformation(extent={{20,-70},{40,-50}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul( + final width=0.7, + final period=2) + "Block that outputs cyclic on and off" + annotation (Placement(transformation(extent={{-40,10},{-20,30}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Pulse booPul1( + final width=0.7, + final period=2, + final shift=-1) + "Block that outputs cyclic on and off" + annotation (Placement(transformation(extent={{-40,-70},{-20,-50}}))); + + Buildings.Controls.OBC.CDL.Logical.Sources.Constant + con(k=false) "Constant" + annotation (Placement(transformation(extent={{-40,-38},{-20,-18}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset noThrRes + "Timer that do not compare threshold – With Reset" + annotation (Placement(transformation(extent={{70,30},{90,50}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset thrTimRes(final t= + 0.3) "Timer that compares threshold – With Reset" + annotation (Placement(transformation(extent={{72,-10},{92,10}}))); + Buildings.Templates.Plants.Controls.Utilities.TimerWithReset thrTim1Res(final t= + 0.3) "Timer that compares threshold – With Reset" + annotation (Placement(transformation(extent={{70,-50},{90,-30}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.SampleTrigger + samTri(final period=1.5, + shift=1.2) "Block that generates periodic reset signal" + annotation (Placement(transformation(extent={{-40,50},{-20,70}}))); + Buildings.Controls.OBC.CDL.Logical.TrueFalseHold res(trueHoldDuration=0.01, + falseHoldDuration=0) "Hold signal for plotting" + annotation (Placement(transformation(extent={{70,70},{90,90}}))); +equation + connect(booPul.y,noThr.u) + annotation (Line(points={{-18,20},{18,20}},color={255,0,255})); + connect(booPul.y,thrTim.u) + annotation (Line(points={{-18,20},{0,20},{0,-20},{18,-20}},color={255,0,255})); + connect(booPul1.y,thrTim1.u) + annotation (Line(points={{-18,-60},{18,-60}},color={255,0,255})); + connect(con.y, noThr.reset) annotation (Line(points={{-18,-28},{10,-28},{10, + 12},{18,12}}, + color={255,0,255})); + connect(con.y, thrTim.reset) annotation (Line(points={{-18,-28},{18,-28}}, + color={255,0,255})); + connect(con.y, thrTim1.reset) annotation (Line(points={{-18,-28},{10,-28},{10, + -68},{18,-68}}, + color={255,0,255})); + connect(samTri.y, noThrRes.reset) annotation (Line(points={{-18,60},{60,60},{ + 60,32},{68,32}}, color={255,0,255})); + connect(booPul.y, noThrRes.u) annotation (Line(points={{-18,20},{0,20},{0,40}, + {68,40}}, color={255,0,255})); + connect(booPul.y, thrTimRes.u) annotation (Line(points={{-18,20},{0,20},{0,0}, + {70,0}}, color={255,0,255})); + connect(samTri.y, thrTimRes.reset) annotation (Line(points={{-18,60},{60,60}, + {60,-8},{70,-8}}, color={255,0,255})); + connect(samTri.y, thrTim1Res.reset) annotation (Line(points={{-18,60},{60,60}, + {60,-48},{68,-48}}, color={255,0,255})); + connect(booPul1.y, thrTim1Res.u) annotation (Line(points={{-18,-60},{0,-60},{ + 0,-40},{68,-40}}, color={255,0,255})); + connect(samTri.y, res.u) annotation (Line(points={{-18,60},{60,60},{60,80},{ + 68,80}}, color={255,0,255})); + annotation ( + experiment( + StopTime=5.0, + Tolerance=1e-06), + __Dymola_Commands( + file="modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/TimerWithReset.mos" "Simulate and plot"), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.TimerWithReset. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +Updated implementation to reset timer with boolean input. +
  • +
  • +July 23, 2018, by Jianjun Hu:
    +Updated implementation to reset accumulate timer with boolean input. +
  • +
  • +July 18, 2018, by Jianjun Hu:
    +Updated implementation to include accumulate timer. +
  • +
  • +April 2, 2017, by Jianjun Hu:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end TimerWithReset; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/TrueArrayConditional.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/TrueArrayConditional.mo new file mode 100644 index 00000000000..6524701b2be --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/TrueArrayConditional.mo @@ -0,0 +1,70 @@ +within Buildings.Templates.Plants.Controls.Utilities.Validation; +model TrueArrayConditional + Buildings.Templates.Plants.Controls.Utilities.TrueArrayConditional truArrConSam(nin=2) + "Array with true elements and same size as input vector" + annotation (Placement(transformation(extent={{0,-10},{20,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Pulse uIdx1( + amplitude=1, + period=4, + shift=1.5) "Source signal for index of first true element" + annotation (Placement(transformation(extent={{-80,-10},{-60,10}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Pulse uIdx2( + amplitude=1, + period=2.5, + offset=2) "Source signal for index of second true element" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.TimeTable uTru(table=[0,0; 1,1; 2, + 2], period=4) "Source signal for number of true elements" + annotation (Placement(transformation(extent={{-80,30},{-60,50}}))); + Buildings.Templates.Plants.Controls.Utilities.TrueArrayConditional truArrConGre(nout=4, + nin=2) "Array with true elements and size greater than input vector" + annotation (Placement(transformation(extent={{0,-50},{20,-30}}))); +equation + connect(uTru.y[1], truArrConSam.u) annotation (Line(points={{-58,40},{-20,40}, + {-20,0},{-2,0}}, color={255,127,0})); + connect(uIdx1.y, truArrConSam.uIdx[1]) annotation (Line(points={{-58,0},{-40,0}, + {-40,-6.5},{-2,-6.5}}, color={255,127,0})); + connect(uTru.y[1], truArrConGre.u) annotation (Line(points={{-58,40},{-20,40}, + {-20,-40},{-2,-40}}, color={255,127,0})); + connect(uIdx1.y, truArrConGre.uIdx[1]) annotation (Line(points={{-58,0},{-40,0}, + {-40,-46.5},{-2,-46.5}}, color={255,127,0})); + connect(uIdx2.y, truArrConSam.uIdx[2]) annotation (Line(points={{-58,-40},{-50, + -40},{-50,-7.5},{-2,-7.5},{-2,-5.5}}, color={255,127,0})); + connect(uIdx2.y, truArrConGre.uIdx[2]) annotation (Line(points={{-58,-40},{-50, + -40},{-50,-48},{-2,-48},{-2,-45.5}}, color={255,127,0})); + annotation ( + experiment( + StopTime=5.0, + Tolerance=1e-06), + __Dymola_Commands( + file="modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/Controls/Utilities/Validation/TrueArrayConditional.mos" "Simulate and plot"), + Documentation( + info=" +

+Validation model for the block + +Buildings.Templates.Plants.Controls.Utilities.TrueArrayConditional. +

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Icon( + graphics={ + Ellipse( + lineColor={75,138,73}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-100,-100},{100,100}}), + Polygon( + lineColor={0,0,255}, + fillColor={75,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-36,60},{64,0},{-36,-60},{-36,60}})})); +end TrueArrayConditional; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/package.mo b/Buildings/Templates/Plants/Controls/Utilities/Validation/package.mo new file mode 100644 index 00000000000..e5def715485 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/package.mo @@ -0,0 +1,29 @@ +within Buildings.Templates.Plants.Controls.Utilities; +package Validation "Collection of validation models" + annotation ( + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Polygon( + origin={8.0,14.0}, + lineColor={78,138,73}, + fillColor={78,138,73}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-58.0,46.0},{42.0,-14.0},{-58.0,-74.0},{-58.0,46.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)}), + Documentation( + info=" +

+This package contains validation models. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/Controls/Utilities/Validation/package.order b/Buildings/Templates/Plants/Controls/Utilities/Validation/package.order new file mode 100644 index 00000000000..caa1e43ad37 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/Validation/package.order @@ -0,0 +1,13 @@ +CountTrue +FirstTrueIndex +HoldReal +LastTrueIndex +MultiMaxInteger +MultiMinInteger +PlaceholderInteger +PlaceholderLogical +PlaceholderReal +SortWithIndices +StageIndex +TimerWithReset +TrueArrayConditional diff --git a/Buildings/Templates/Plants/Controls/Utilities/package.mo b/Buildings/Templates/Plants/Controls/Utilities/package.mo new file mode 100644 index 00000000000..bf3ce309a24 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/package.mo @@ -0,0 +1,48 @@ +within Buildings.Templates.Plants.Controls; +package Utilities "Package with utility blocks" + annotation ( + Documentation( + info=" +

+This package contains utility blocks that are used to implement +the control sequences within + +Buildings.Templates.Plants.Controls. +

+"), + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Ellipse( + origin={10.0,10.0}, + lineColor={128,128,128}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-80.0,0.0},{-20.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={128,128,128}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,0.0},{60.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,-80.0},{60.0,-20.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={76,76,76}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{-80.0,-80.0},{-20.0,-20.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)})); +end Utilities; diff --git a/Buildings/Templates/Plants/Controls/Utilities/package.order b/Buildings/Templates/Plants/Controls/Utilities/package.order new file mode 100644 index 00000000000..7e02dab8af1 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/Utilities/package.order @@ -0,0 +1,15 @@ +CountTrue +FirstTrueIndex +HoldReal +LastTrueIndex +MultiMaxInteger +MultiMinInteger +PIDWithEnable +PlaceholderInteger +PlaceholderLogical +PlaceholderReal +SortWithIndices +StageIndex +TimerWithReset +TrueArrayConditional +Validation diff --git a/Buildings/Templates/Plants/Controls/package.mo b/Buildings/Templates/Plants/Controls/package.mo new file mode 100644 index 00000000000..35798c237e9 --- /dev/null +++ b/Buildings/Templates/Plants/Controls/package.mo @@ -0,0 +1,47 @@ +within Buildings.Templates.Plants; +package Controls "Control blocks" + annotation ( + Documentation( + info=" +

+This package contains control blocks that comply with the CDL specification: + +https://obc.lbl.gov/specification/cdl.html. +

+"), + Icon( + graphics={ + Rectangle( + lineColor={200,200,200}, + fillColor={248,248,248}, + fillPattern=FillPattern.HorizontalCylinder, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0), + Ellipse( + origin={10.0,10.0}, + lineColor={128,128,128}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + extent={{-80.0,0.0},{-20.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={128,128,128}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,0.0},{60.0,60.0}}), + Ellipse( + origin={10.0,10.0}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{0.0,-80.0},{60.0,-20.0}}), + Ellipse( + origin={10.0,10.0}, + fillColor={76,76,76}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + extent={{-80.0,-80.0},{-20.0,-20.0}}), + Rectangle( + lineColor={128,128,128}, + extent={{-100.0,-100.0},{100.0,100.0}}, + radius=25.0)})); +end Controls; diff --git a/Buildings/Templates/Plants/Controls/package.order b/Buildings/Templates/Plants/Controls/package.order new file mode 100644 index 00000000000..07c7d33a37e --- /dev/null +++ b/Buildings/Templates/Plants/Controls/package.order @@ -0,0 +1,7 @@ +Enabling +HeatPumps +Pumps +Setpoints +StagingRotation +Utilities +Types diff --git a/Buildings/Templates/Plants/HeatPumps/AirToWater.mo b/Buildings/Templates/Plants/HeatPumps/AirToWater.mo new file mode 100644 index 00000000000..39702ac659d --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/AirToWater.mo @@ -0,0 +1,766 @@ +within Buildings.Templates.Plants.HeatPumps; +model AirToWater + "Air-to-water heat pump plant" + extends Buildings.Templates.Plants.HeatPumps.Interfaces.PartialHeatPumpPlant( + redeclare final package MediumChiWat=MediumHeaWat, + redeclare final package MediumSou=MediumAir, + redeclare Buildings.Templates.Plants.HeatPumps.Components.Controls.AirToWater ctl, + final typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + final is_rev=have_chiWat, + final cfg( + final typMod=hp.typMod)); + // Heat pumps, dedicated primary pumps and isolation valves + Buildings.Templates.Plants.HeatPumps.Components.HeatPumpGroups.AirToWater hp( + redeclare final package MediumHeaWat=MediumHeaWat, + redeclare final package MediumAir=MediumAir, + final nHp=nHp, + final is_rev=is_rev, + final energyDynamics=energyDynamics, + final have_preDroChiHeaWat=false, + final have_preDroSou=false, + final dat=dat.hp, + final allowFlowReversal=allowFlowReversal, + final allowFlowReversalSou=false) + "Heat pump group" + annotation (Placement(transformation(extent={{-540,-210},{-60,-130}}))); + Components.PumpsPrimaryDedicated pumPri( + redeclare final package Medium=MediumHeaWat, + final nHp=nHp, + final typArrPumPri=typArrPumPri, + final have_pumChiWatPriDed=have_pumChiWatPriDed, + final have_pumHeaWatPriVar=have_pumHeaWatPriVar, + final have_pumChiWatPriVar=have_pumChiWatPriVar, + final datPumHeaWat=dat.pumHeaWatPri, + final datPumChiWat=dat.pumChiWatPri, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal) + "Dedicated primary pumps" + annotation (Placement(transformation(extent={{-540,-130},{-60,-50}}))); + Components.ValvesIsolation valIso( + redeclare final package Medium=MediumHeaWat, + final nHp=nHp, + final have_chiWat=have_chiWat, + final have_valHpInlIso=have_valHpInlIso, + final have_valHpOutIso=have_valHpOutIso, + final have_pumChiWatPriDed=have_pumChiWatPriDed, + final mHeaWatHp_flow_nominal=fill(dat.hp.mHeaWatHp_flow_nominal, nHp), + final dpHeaWatHp_nominal=fill(dat.hp.dpHeaWatHp_nominal, nHp), + final mChiWatHp_flow_nominal=fill(dat.hp.mChiWatHp_flow_nominal, nHp), + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal) + "Heat pump isolation valves" + annotation (Placement(transformation(extent={{-540,-50},{-60,90}}))); + // Primary CHW loop + Buildings.Templates.Components.Pumps.Multiple pumChiWatPri( + final energyDynamics=energyDynamics, + redeclare final package Medium=MediumChiWat, + final dat=dat.pumChiWatPri, + final nPum=nPumChiWatPri, + final have_var=have_pumChiWatPriVar, + final have_varCom=true, + final allowFlowReversal=allowFlowReversal) + if have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + "Headered primary CHW pumps" + annotation (Placement(transformation(extent={{-20,70},{0,90}}))); + Buildings.Templates.Components.Routing.SingleToMultiple inlPumChiWatPri( + redeclare final package Medium=MediumChiWat, + final nPorts=nPumChiWatPri, + final m_flow_nominal=mChiWatPri_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) + if have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + "Primary CHW pumps inlet manifold" + annotation (Placement(transformation(extent={{-40,70},{-20,90}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumChiWatPri( + redeclare final package Medium=MediumChiWat, + final nPorts=nPumChiWatPri, + final m_flow_nominal=mChiWatPri_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) + if have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + "Primary CHW pumps outlet manifold" + annotation (Placement(transformation(extent={{0,70},{20,90}}))); + Buildings.Templates.Components.Routing.PassThroughFluid supChiWatPri( + redeclare final package Medium=MediumChiWat, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) if have_chiWat and typArrPumPri + == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Primary CHW supply pipe - Plant with dedicated primary CHW pumps" + annotation (Placement(transformation(extent={{-20,70},{0,90}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VChiWatPri_flow( + redeclare final package Medium=MediumChiWat, + final m_flow_nominal=mChiWatPri_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVChiWatPri, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_chiWat + "Primary CHW volume flow rate" + annotation (Placement(transformation(extent={{20,70},{40,90}}))); + Buildings.Templates.Components.Routing.Junction junChiWatBypSup( + redeclare final package Medium=MediumChiWat, + final tau=tau, + final m_flow_nominal=mChiWatPri_flow_nominal * {1, - 1, - 1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(0, 3), + final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving) if have_chiWat + "Fluid junction" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={100,80}))); + Buildings.Templates.Components.Sensors.Temperature TChiWatPriSup( + redeclare final package Medium=MediumChiWat, + final have_sen=true, + final m_flow_nominal=mChiWatPri_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) if have_chiWat + "Primary CHW supply temperature" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={60,80}))); + Buildings.Templates.Components.Routing.Junction junChiWatBypRet( + redeclare final package Medium=MediumChiWat, + final tau=tau, + final m_flow_nominal=mChiWatPri_flow_nominal * {1, - 1, 1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(0, 3), + final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + icon_pipe1=Buildings.Templates.Components.Types.IconPipe.Return, + icon_pipe3=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_chiWat + "Fluid junction" + annotation (Placement(transformation(extent={{10,10},{-10,-10}},rotation=0, + origin={100,0}))); + Buildings.Templates.Components.Sensors.Temperature TChiWatPriRet( + redeclare final package Medium=MediumChiWat, + final have_sen=ctl.have_senTChiWatPriRet, + final m_flow_nominal=mChiWatPri_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return, + final allowFlowReversal=allowFlowReversal) if have_chiWat + "Primary CHW return temperature" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0, + origin={60,0}))); + // Secondary CHW loop + Buildings.Templates.Components.Pumps.Multiple pumChiWatSec( + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + redeclare final package Medium=MediumChiWat, + final nPum=nPumChiWatSec, + final have_var=true, + final have_varCom=true, + final dat=dat.pumChiWatSec) if have_chiWat and typPumChiWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary CHW pumps" + annotation (Placement(transformation(extent={{170,70},{190,90}}))); + Buildings.Templates.Components.Routing.SingleToMultiple inlPumChiWatSec( + redeclare final package Medium=MediumChiWat, + final nPorts=nPumChiWatSec, + final m_flow_nominal=mChiWat_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) if + have_chiWat and typPumChiWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary CHW pumps inlet manifold" + annotation (Placement(transformation(extent={{150,70},{170,90}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumChiWatSec( + redeclare final package Medium=MediumChiWat, + final nPorts=nPumChiWatSec, + final m_flow_nominal=mChiWat_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) if + have_chiWat and typPumChiWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary CHW pumps outlet manifold" + annotation (Placement(transformation(extent={{190,70},{210,90}}))); + Buildings.Templates.Components.Routing.PassThroughFluid supChiWatSec( + redeclare final package Medium=MediumChiWat, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) if have_chiWat and + typPumChiWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary CHW supply pipe - Plant without secondary CHW pumps" + annotation (Placement(transformation(extent={{170,70},{190,90}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VChiWatSec_flow( + redeclare final package Medium=MediumChiWat, + final m_flow_nominal=mChiWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVChiWatSec, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_chiWat + "Secondary CHW volume flow rate" + annotation (Placement(transformation(extent={{208,70},{228,90}}))); + Buildings.Templates.Components.Sensors.Temperature TChiWatSecSup( + redeclare final package Medium=MediumChiWat, + final have_sen=ctl.have_senTChiWatSecSup, + final m_flow_nominal=mChiWat_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) if have_chiWat + "Secondary CHW supply temperature" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={140,80}))); + Buildings.Templates.Components.Sensors.Temperature TChiWatSecRet( + redeclare final package Medium=MediumChiWat, + final have_sen=ctl.have_senTChiWatSecRet, + final m_flow_nominal=mChiWat_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return, + final allowFlowReversal=allowFlowReversal) if have_chiWat + "Secondary CHW return temperature" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0, + origin={140,0}))); + // Primary HW loop + Buildings.Templates.Components.Routing.SingleToMultiple inlPumHeaWatPri( + redeclare final package Medium=MediumHeaWat, + final nPorts=nPumHeaWatPri, + final m_flow_nominal=mHeaWatPri_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) + if have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + "Primary HW pumps inlet manifold" + annotation (Placement(transformation(extent={{-40,-290},{-20,-270}}))); + Buildings.Templates.Components.Pumps.Multiple pumHeaWatPri( + final energyDynamics=energyDynamics, + redeclare final package Medium=MediumHeaWat, + final dat=dat.pumHeaWatPri, + final nPum=nPumHeaWatPri, + final have_var=have_pumHeaWatPriVar, + final have_varCom=true, + final allowFlowReversal=allowFlowReversal) + if have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + "Headered primary HW pumps" + annotation (Placement(transformation(extent={{-20,-290},{0,-270}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumHeaWatPri( + redeclare final package Medium=MediumHeaWat, + final nPorts=nPumHeaWatPri, + final m_flow_nominal=mHeaWatPri_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) + if have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + "Primary HW pumps outlet manifold" + annotation (Placement(transformation(extent={{0,-290},{20,-270}}))); + Buildings.Templates.Components.Routing.PassThroughFluid supHeaWatPri( + redeclare final package Medium=MediumHeaWat, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) if have_heaWat and typArrPumPri + == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Primary HW supply pipe - Plant with dedicated primary HW pumps" + annotation (Placement(transformation(extent={{-20,-290},{0,-270}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatPri_flow( + redeclare final package Medium=MediumHeaWat, + final m_flow_nominal=mHeaWatPri_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatPri, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + "Primary HW volume flow rate" + annotation (Placement(transformation(extent={{20,-290},{40,-270}}))); + Buildings.Templates.Components.Routing.Junction junHeaWatBypSup( + redeclare final package Medium=MediumHeaWat, + final tau=tau, + final m_flow_nominal=mHeaWatPri_flow_nominal * {1, - 1, - 1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(0, 3), + final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving) if have_heaWat + "Fluid junction" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={100,-280}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatPriSup( + redeclare final package Medium=MediumHeaWat, + final have_sen=true, + final m_flow_nominal=mHeaWatPri_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) + "Primary HW supply temperature" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={60,-280}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatPriRet( + redeclare final package Medium = MediumHeaWat, + final have_sen=ctl.have_senTHeaWatPriRet, + final m_flow_nominal=mHeaWatPri_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return, + final allowFlowReversal=allowFlowReversal) + "Primary HW return temperature" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0, + origin={60,-360}))); + Buildings.Templates.Components.Routing.Junction junHeaWatBypRet( + redeclare final package Medium=MediumHeaWat, + final tau=tau, + final m_flow_nominal=mHeaWatPri_flow_nominal * {1, - 1, 1}, + final energyDynamics=energyDynamics, + dp_nominal=fill(0, 3), + final portFlowDirection_1=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + final portFlowDirection_2=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Leaving, + final portFlowDirection_3=if allowFlowReversal then Modelica.Fluid.Types.PortFlowDirection.Bidirectional + else Modelica.Fluid.Types.PortFlowDirection.Entering, + icon_pipe1=Buildings.Templates.Components.Types.IconPipe.Return, + icon_pipe3=Buildings.Templates.Components.Types.IconPipe.Supply) + if have_heaWat + "Fluid junction" + annotation (Placement(transformation(extent={{10,10},{-10,-10}},rotation=0, + origin={100,-360}))); + Buildings.Fluid.Sources.Boundary_pT bouHeaWat( + redeclare final package Medium=MediumHeaWat, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=1) if have_heaWat + "Pressure boundary condition to mimic expansion tank" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=90, + origin={20,-340}))); + // Secondary HW loop + Buildings.Templates.Components.Pumps.Multiple pumHeaWatSec( + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + redeclare final package Medium=MediumHeaWat, + final nPum=nPumHeaWatSec, + final have_var=true, + final have_varCom=true, + final dat=dat.pumHeaWatSec) + if typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary HW pumps" + annotation (Placement(transformation(extent={{170,-290},{190,-270}}))); + Buildings.Templates.Components.Routing.SingleToMultiple inlPumHeaWatSec( + redeclare final package Medium=MediumHeaWat, + final nPorts=nPumHeaWatSec, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) + if typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary HW pumps inlet manifold" + annotation (Placement(transformation(extent={{150,-290},{170,-270}}))); + Buildings.Templates.Components.Routing.MultipleToSingle outPumHeaWatSec( + redeclare final package Medium=MediumHeaWat, + final nPorts=nPumHeaWatSec, + final m_flow_nominal=mHeaWat_flow_nominal, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final icon_dy=300) + if typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary HW pumps outlet manifold" + annotation (Placement(transformation(extent={{190,-290},{210,-270}}))); + Buildings.Templates.Components.Routing.PassThroughFluid supHeaWatSec( + redeclare final package Medium=MediumHeaWat, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) if have_heaWat and + typPumHeaWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary HW supply pipe - Plant without secondary HW pumps" + annotation (Placement(transformation(extent={{170,-290},{190,-270}}))); + Buildings.Templates.Components.Sensors.VolumeFlowRate VHeaWatSec_flow( + redeclare final package Medium=MediumHeaWat, + final m_flow_nominal=mHeaWat_flow_nominal, + final allowFlowReversal=allowFlowReversal, + final have_sen=ctl.have_senVHeaWatSec, + final text_flip=false, + final typ=Buildings.Templates.Components.Types.SensorVolumeFlowRate.FlowMeter, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply) + "Secondary HW volume flow rate" + annotation (Placement(transformation(extent={{210,-290},{230,-270}}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatSecSup( + redeclare final package Medium=MediumHeaWat, + final have_sen=ctl.have_senTHeaWatSecSup, + final m_flow_nominal=mHeaWat_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Supply, + final allowFlowReversal=allowFlowReversal) + "Secondary HW supply temperature" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={140,-280}))); + Buildings.Templates.Components.Sensors.Temperature THeaWatSecRet( + redeclare final package Medium=MediumHeaWat, + final have_sen=ctl.have_senTHeaWatSecRet, + final m_flow_nominal=mHeaWat_flow_nominal, + final typ=Buildings.Templates.Components.Types.SensorTemperature.InWell, + final icon_pipe=Buildings.Templates.Components.Types.IconPipe.Return, + final allowFlowReversal=allowFlowReversal) + "Secondary HW return temperature" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0, + origin={140,-360}))); +equation + /* Control point connection - start */ + connect(bus, hp.bus); + connect(busWea, hp.busWea); + connect(bus, pumPri.bus); + connect(bus, valIso.bus); + connect(bus.pumChiWatPri, pumChiWatPri.bus); + connect(bus.pumHeaWatPri, pumHeaWatPri.bus); + connect(bus.pumChiWatSec, pumChiWatSec.bus); + connect(bus.pumHeaWatSec, pumHeaWatSec.bus); + connect(VChiWatPri_flow.y, bus.VChiWatPri_flow); + connect(VHeaWatPri_flow.y, bus.VHeaWatPri_flow); + connect(VChiWatSec_flow.y, bus.VChiWatSec_flow); + connect(VHeaWatSec_flow.y, bus.VHeaWatSec_flow); + connect(TChiWatPriSup.y, bus.TChiWatPriSup); + connect(THeaWatPriSup.y, bus.THeaWatPriSup); + connect(TChiWatPriRet.y, bus.TChiWatPriRet); + connect(THeaWatPriRet.y, bus.THeaWatPriRet); + connect(TChiWatSecSup.y, bus.TChiWatSecSup); + connect(THeaWatSecSup.y, bus.THeaWatSecSup); + connect(TChiWatSecRet.y, bus.TChiWatSecRet); + connect(THeaWatSecRet.y, bus.THeaWatSecRet); + /* Control point connection - stop */ + connect(pumChiWatPri.ports_b, outPumChiWatPri.ports_a) + annotation (Line(points={{0,80},{0,80}}, color={0,127,255})); + connect(inlPumChiWatPri.ports_b, pumChiWatPri.ports_a) + annotation (Line(points={{-20,80},{-20,80}}, + color={0,127,255})); + connect(valIso.port_bChiWat, inlPumChiWatPri.port_a) + annotation (Line( + points={{-60,80},{-60,80},{-40,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered)); + connect(hp.ports_bChiHeaWat, pumPri.ports_aChiHeaWatHp) + annotation (Line(points={{-350,-130},{-350,-130}},color={0,127,255})); + connect(pumPri.ports_bChiHeaWat, valIso.ports_aChiHeaWatHp) + annotation (Line(points={{-350,-50},{-350,-50}},color={0,127,255})); + connect(pumPri.ports_bHeaWat, valIso.ports_aHeaWatHp) + annotation (Line(points={{-366,-50},{-366,-50}},color={0,127,255})); + connect(pumPri.ports_bChiWat, valIso.ports_aChiWatHp) + annotation (Line(points={{-334,-50},{-334,-50}}, color={0,127,255})); + connect(outPumChiWatPri.port_b, VChiWatPri_flow.port_a) + annotation (Line(points={{20,80},{20,80}},color={0,127,255})); + connect(VChiWatPri_flow.port_b, TChiWatPriSup.port_a) + annotation (Line( + points={{40,80},{50,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat)); + connect(TChiWatPriSup.port_b, junChiWatBypSup.port_1) + annotation (Line( + points={{70,80},{90,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat)); + connect(pumChiWatSec.ports_b, outPumChiWatSec.ports_a) + annotation (Line(points={{190,80},{190,80}},color={0,127,255})); + connect(inlPumChiWatSec.ports_b, pumChiWatSec.ports_a) + annotation (Line(points={{170,80},{170,80}},color={0,127,255})); + connect(valIso.port_bChiWat, supChiWatPri.port_a) + annotation (Line( + points={{-60,80},{-60,80},{-20,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + connect(supChiWatPri.port_b, VChiWatPri_flow.port_a) + annotation (Line( + points={{0,80},{20,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + connect(valIso.ports_bChiHeaWatHp, pumPri.ports_aChiHeaWat) + annotation (Line(points={{-250,-50},{-250,-50}}, + color={0,127,255})); + connect(pumPri.ports_bChiHeaWatHp, hp.ports_aChiHeaWat) + annotation (Line(points={{-250,-130},{-250,-130}}, + color={0,127,255})); + connect(VChiWatSec_flow.port_b, port_bChiWat) + annotation (Line( + points={{228,80},{600,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat)); + connect(supChiWatSec.port_b, VChiWatSec_flow.port_a) + annotation (Line( + points={{190,80},{208,80}}, + color={0,0,0}, + visible=have_chiWat and typPumChiWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized, + thickness=0.5)); + + connect(pumHeaWatPri.ports_b, outPumHeaWatPri.ports_a) + annotation (Line(points={{0,-280},{0,-280}}, color={0,127,255})); + connect(inlPumHeaWatPri.ports_b, pumHeaWatPri.ports_a) + annotation (Line(points={{-20,-280},{-20,-280}}, + color={0,127,255})); + connect(outPumHeaWatPri.port_b, VHeaWatPri_flow.port_a) + annotation (Line(points={{20,-280},{20,-280}},color={0,127,255})); + connect(VHeaWatPri_flow.port_b, THeaWatPriSup.port_a) + annotation (Line(points={{40,-280},{50,-280}}, color={0,0,0}, + thickness=0.5)); + connect(THeaWatPriSup.port_b, junHeaWatBypSup.port_1) + annotation (Line(points={{70,-280},{90,-280}}, color={0,0,0}, + thickness=0.5)); + connect(pumHeaWatSec.ports_b, outPumHeaWatSec.ports_a) + annotation (Line(points={{190,-280},{190,-280}},color={0,127,255})); + connect(inlPumHeaWatSec.ports_b, pumHeaWatSec.ports_a) + annotation (Line(points={{170,-280},{170,-280}},color={0,127,255})); + connect(supHeaWatPri.port_b, VHeaWatPri_flow.port_a) + annotation (Line( + points={{0,-280},{20,-280}}, + color={0,0,0}, + thickness=0.5, + visible=have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + connect(supHeaWatSec.port_b, VHeaWatSec_flow.port_a) + annotation (Line( + points={{190,-280},{210,-280}}, + color={0,0,0}, + thickness=0.5, + visible=have_heaWat and typPumHeaWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized)); + connect(outPumHeaWatSec.port_b, VHeaWatSec_flow.port_a) + annotation (Line(points={{210,-280},{210,-280}},color={0,0,0}, + thickness=0.5)); + connect(valIso.port_bHeaWat, inlPumHeaWatPri.port_a) + annotation (Line( + points={{-540,20},{-540,-280},{-40,-280}}, + color={0,0,0}, + thickness=0.5, + visible=have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered)); + connect(VHeaWatSec_flow.port_b, port_bHeaWat) + annotation (Line(points={{230,-280},{600,-280}},color={0,0,0}, + thickness=0.5)); + connect(valIso.port_bHeaWat, supHeaWatPri.port_a) + annotation (Line( + points={{-540,20},{-540,-280},{-20,-280}}, + color={0,0,0}, + thickness=0.5, + visible=have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + connect(junHeaWatBypSup.port_3, junHeaWatBypRet.port_3) + annotation (Line(points={{100,-290},{100,-350}}, color={0,0,0}, + thickness=0.5)); + connect(junChiWatBypSup.port_3, junChiWatBypRet.port_3) + annotation (Line( + points={{100,70},{100,10}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat)); + connect(junChiWatBypSup.port_2, TChiWatSecSup.port_a) + annotation (Line( + points={{110,80},{130,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat)); + connect(TChiWatSecSup.port_b, inlPumChiWatSec.port_a) + annotation (Line(points={{150,80},{150,80}}, + color={0,0,0}, + thickness=0.5)); + connect(junChiWatBypRet.port_1, TChiWatSecRet.port_b) + annotation (Line( + points={{110,0},{130,0}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=0.5, + visible=have_chiWat)); + connect(port_aChiWat, TChiWatSecRet.port_a) + annotation (Line( + points={{600,0},{150,0}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=0.5, + visible=have_chiWat)); + connect(junChiWatBypRet.port_2, TChiWatPriRet.port_a) + annotation (Line( + points={{90,0},{70,0}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=0.5, + visible=have_chiWat)); + connect(port_aHeaWat, THeaWatSecRet.port_a) + annotation (Line(points={{600,-360},{150,-360}},color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(junHeaWatBypSup.port_2, THeaWatSecSup.port_a) + annotation (Line(points={{110,-280},{130,-280}}, + color={0,0,0}, + thickness=0.5)); + connect(THeaWatSecSup.port_b, inlPumHeaWatSec.port_a) + annotation (Line(points={{150,-280},{150,-280}}, + color={0,0,0}, + thickness=0.5)); + connect(THeaWatSecSup.port_b, supHeaWatSec.port_a) annotation (Line( + points={{150,-280},{158,-280},{158,-232},{166,-232},{166,-280},{170,-280}}, + color={0,0,0}, + thickness=0.5, + visible=have_heaWat and typPumHeaWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized)); + connect(TChiWatSecSup.port_b, supChiWatSec.port_a) annotation (Line( + points={{150,80},{158,80},{158,60},{166,60},{166,80},{170,80}}, + color={0,0,0}, + thickness=0.5, + visible=have_chiWat and typPumChiWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized)); + connect(bouHeaWat.ports[1], THeaWatPriRet.port_b) + annotation (Line(points={{20,-350},{20,-360},{50,-360}}, + color={0,127,255})); + connect(junHeaWatBypRet.port_1, THeaWatSecRet.port_b) + annotation (Line(points={{110,-360},{130,-360}}, color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(junHeaWatBypRet.port_2, THeaWatPriRet.port_a) annotation (Line( + points={{90,-360},{70,-360}}, + color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(THeaWatPriRet.port_b, valIso.port_aHeaWat) annotation (Line( + points={{50,-360},{-584,-360},{-584,60},{-540,60}}, + color={0,0,0}, + thickness=0.5, + pattern=LinePattern.Dash)); + connect(outPumChiWatSec.port_b, VChiWatSec_flow.port_a) annotation (Line( + points={{210,80},{208,80}}, + color={0,0,0}, + thickness=1)); + connect(TChiWatPriRet.port_b, valIso.port_aChiWat) annotation (Line( + points={{50,0},{0,0},{0,40},{-60,40}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=0.5, + visible=have_chiWat)); + annotation ( + defaultComponentName="pla", + Documentation( + info=" +

Description

+

+This template represents an air-to-water heat pump plant +with closed-loop controls. +

+

+Only identical heat pumps are currently supported. +

+

+The supported plant configurations are enumerated in the table below. +The first option displayed in bold characters corresponds to the default +configuration.
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Configuration parameterOptionsNotes
Function +Heating and cooling
+Heating-only +
+The plant always provides heating hot water.
+Setting the parameter have_chiWat to true (default setting) allows +modeling a plant that provides both heating hot water and chilled water. +
Type of distribution +Constant primary-variable secondary centralized + +It is assumed that the HW and the CHW loops have the +same type of distribution, as specified by this parameter.
+\"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.
+Options are limited to constant primary distributions because most +AWHPs on the market use a reverse cycle for defrosting. +This requires maximum primary flow during defrost cycles and hinders +variable primary distributions.
+An option for constant primary-only distributions with ∆p-controlled +variable speed pumps will be added in a next release. +
Type of primary pump arrangement +Dedicated
+Headered +
It is assumed that the HW and the CHW loops have the +same type of primary pump arrangement, as specified by this parameter. +
Separate dedicated primary CHW pumps +False
+True +
This option is only available for heating and cooling plants +with dedicated primary pumps. +If this option is not selected (default setting), each AWHP uses +a common dedicated primary pump for HW and CHW. +Otherwise, each AWHP relies on a separate dedicated HW pump +and a separate dedicated CHW pump. +
Type of primary HW pumps +Variable speed
+Constant speed +
+For constant primary-variable secondary distributions, the variable +speed primary pumps are commanded at fixed speeds, determined during the +Testing, Adjusting and Balancing phase to provide design AWHP flow in +heating and cooling modes. +The same intent is achieved with constant speed primary pumps through the +use of balancing valves. +
Type of primary CHW pumps +Variable speed
+Constant speed +
See the note above on primary HW pumps.
Controller +Closed-loop controls with supply temperature and differential pressure reset
+
+Most parts of the sequence of operation are similar to that +described in ASHRAE, 2021 for chiller plants.
+See the documentation of +Buildings.Templates.Plants.Controls.HeatPumps.AirToWater +for more details.
+An open loop controller is also available for validation purposes. +
+

Control points

+

+The control sequence implemented in this template requires the +external input points specified in the documentation of the controller + +Buildings.Templates.Plants.HeatPumps.Components.Controls.AirToWater. +

Implementation details

+

+The pressure drops of the heat pump CHW and HW heat exchangers are calculated +within the isolation valve component valIso based on lumped flow +coefficients for the sake of computational efficiency. +

+

References

+
    +
  • +ASHRAE, 2021. Guideline 36-2021, High-Performance Sequences of Operation +for HVAC Systems. Atlanta, GA. +
  • +
+")); +end AirToWater; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Controls/AirToWater.mo b/Buildings/Templates/Plants/HeatPumps/Components/Controls/AirToWater.mo new file mode 100644 index 00000000000..ddb864f12e7 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Controls/AirToWater.mo @@ -0,0 +1,332 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Controls; +model AirToWater + "Controller for AWHP plant" + extends + Buildings.Templates.Plants.HeatPumps.Components.Interfaces.PartialController( + final typ=Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater); + final parameter Real staEqu[:, nHp]( + each final max=1, + each final min=0, + each final unit="1")=dat.staEqu + "Staging matrix – Equipment required for each stage" + annotation (Dialog(group="Equipment staging and rotation")); + final parameter Integer nSta( + final min=1)=size(staEqu, 1) + "Number of stages" + annotation (Evaluate=true); + final parameter Integer nEquAlt( + final min=0)=max({sum({(if staEqu[i, j] > 0 and staEqu[i, j] < 1 then 1 else 0) for j in 1:nHp}) for i in 1:nSta}) + "Number of lead/lag alternate equipment" + annotation (Evaluate=true); + final parameter Integer idxEquAlt[nEquAlt]=Modelica.Math.BooleanVectors.index( + {Modelica.Math.BooleanVectors.anyTrue({staEqu[i,j] > 0 and staEqu[i,j] < 1 for i in 1:nSta}) + for j in 1:nHp}) + "Indices of lead/lag alternate equipment" + annotation (Evaluate=true, + Dialog(group="Equipment staging and rotation")); + Buildings.Templates.Plants.Controls.HeatPumps.AirToWater ctl( + final TChiWatSupSet_max=dat.TChiWatSupSet_max, + final TChiWatSup_nominal=dat.TChiWatSup_nominal, + final THeaWatSupSet_min=dat.THeaWatSupSet_min, + final THeaWatSup_nominal=dat.THeaWatSup_nominal, + final TOutChiWatLck=dat.TOutChiWatLck, + final TOutHeaWatLck=dat.TOutHeaWatLck, + final VChiWatSec_flow_nominal=dat.VChiWatSec_flow_nominal, + final VHeaWatSec_flow_nominal=dat.VHeaWatSec_flow_nominal, + final capCooHp_nominal=fill(dat.capCooHp_nominal, cfg.nHp), + final capHeaHp_nominal=fill(dat.capHeaHp_nominal, cfg.nHp), + final cp_default=if cfg.have_heaWat then cfg.cpHeaWat_default else cfg.cpChiWat_default, + final dpChiWatRemSet_max=dat.dpChiWatRemSet_max, + final dpChiWatRemSet_min=dat.dpChiWatRemSet_min, + final dpHeaWatRemSet_max=dat.dpHeaWatRemSet_max, + final dpHeaWatRemSet_min=dat.dpHeaWatRemSet_min, + final have_chiWat=cfg.have_chiWat, + final have_heaWat=cfg.have_heaWat, + final have_inpSch=have_inpSch, + final have_pumChiWatPriDed_select=cfg.have_pumChiWatPriDed, + final have_pumChiWatSec_select=cfg.typPumChiWatSec==Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized, + final have_pumHeaWatSec_select=cfg.typPumHeaWatSec==Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized, + final have_pumPriHdr=cfg.typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered, + final have_pumHeaWatPriVar=cfg.have_pumHeaWatPriVar, + final have_pumChiWatPriVar=cfg.have_pumChiWatPriVar, + final have_senDpChiWatRemWir=cfg.have_senDpChiWatRemWir, + final have_senDpHeaWatRemWir=cfg.have_senDpHeaWatRemWir, + final have_senTChiWatPriRet_select=have_senTChiWatPriRet_select, + final have_senTChiWatSecRet=have_senTChiWatSecRet, + final have_senTHeaWatPriRet_select=have_senTHeaWatPriRet_select, + final have_senTHeaWatSecRet=have_senTHeaWatSecRet, + final have_senVChiWatPri_select=have_senVChiWatPri_select, + final have_senVHeaWatPri_select=have_senVHeaWatPri_select, + final have_valHpInlIso=cfg.have_valHpInlIso, + final have_valHpOutIso=cfg.have_valHpOutIso, + final idxEquAlt=idxEquAlt, + final nHp=cfg.nHp, + final nPumChiWatPri=cfg.nPumChiWatPri, + final nPumChiWatSec=cfg.nPumChiWatSec, + final nPumHeaWatPri=cfg.nPumHeaWatPri, + final nPumHeaWatSec=cfg.nPumHeaWatSec, + final nSenDpChiWatRem=nSenDpChiWatRem, + final nSenDpHeaWatRem=nSenDpHeaWatRem, + final plrSta=dat.plrSta, + final rho_default=if cfg.have_heaWat then cfg.rhoHeaWat_default else cfg.rhoChiWat_default, + final schCoo=dat.schCoo, + final schHea=dat.schHea, + final staEqu=dat.staEqu, + final yPumChiWatPriSet=dat.yPumChiWatPriSet, + final yPumHeaWatPriSet=dat.yPumHeaWatPriSet) + "Plant controller" + annotation (Placement(transformation(extent={{-20,-20},{20,40}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqPlaHeaWatAirHan( + final nin=nAirHan) if cfg.have_heaWat "Sum of HW plant requests from AHU" + annotation (Placement(transformation(extent={{210,190},{190,210}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqPlaHeaWatEquZon( + final nin=nEquZon) if cfg.have_heaWat + "Sum of HW plant requests from zone equipment" + annotation (Placement(transformation(extent={{210,-90},{190,-70}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqResHeaWatAirHan(nin=1) + if cfg.have_heaWat "Sum of HW reset requests from AHU" + annotation (Placement(transformation(extent={{210,110},{190,130}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqResHeaWatEquZon( + final nin=nEquZon) if cfg.have_heaWat + "Sum of HW reset requests from zone equipment" + annotation (Placement(transformation(extent={{210,-170},{190,-150}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqResChiWatAirHan(final nin= + nAirHan) if cfg.have_chiWat "Sum of CHW reset requests from AHU" + annotation (Placement(transformation(extent={{210,70},{190,90}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqPlaChiWatEquZon(final nin= + nEquZon) if cfg.have_chiWat + "Sum of CHW plant requests from zone equipment" + annotation (Placement(transformation(extent={{210,-130},{190,-110}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqResChiWatEquZon(final nin= + nEquZon) if cfg.have_chiWat + "Sum of CHW reset requests from zone equipment" + annotation (Placement(transformation(extent={{210,-210},{190,-190}}))); + Buildings.Controls.OBC.CDL.Integers.MultiSum reqPlaChiWatAirHan(final nin= + nAirHan) if cfg.have_chiWat "Sum of CHW plant requests from AHU" + annotation (Placement(transformation(extent={{210,150},{190,170}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqPlaHeaWatAirHan( + final have_inp=cfg.have_heaWat, + final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,190},{150,210}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqPlaChiWatAirHan(final + have_inp=cfg.have_chiWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,150},{150,170}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqResHeaWatAirHan(final + have_inp=cfg.have_heaWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,110},{150,130}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqResChiWatAirHan(final + have_inp=cfg.have_chiWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,70},{150,90}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqPlaHeaWatEquZon(final + have_inp=cfg.have_heaWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,-90},{150,-70}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqPlaChiWatEquZon(final + have_inp=cfg.have_chiWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,-130},{150,-110}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqResHeaWatEquZon(final + have_inp=cfg.have_heaWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,-170},{150,-150}}))); + Buildings.Templates.Plants.Controls.Utilities.PlaceholderInteger phReqResChiWatEquZon(final + have_inp=cfg.have_chiWat, final u_internal=0) + "Placeholder value if signal is not available" + annotation (Placement(transformation(extent={{170,-210},{150,-190}}))); + Buildings.Controls.OBC.CDL.Integers.Add reqPlaHeaWat + "Sum of HW plant requests of all loads served" + annotation (Placement(transformation(extent={{110,184},{90,204}}))); + Buildings.Controls.OBC.CDL.Integers.Add reqPlaChiWat + "Sum of CHW plant requests of all loads served" + annotation (Placement(transformation(extent={{110,144},{90,164}}))); + Buildings.Controls.OBC.CDL.Integers.Add reqResHeaWat + "Sum of HW reset requests of all loads served" + annotation (Placement(transformation(extent={{110,104},{90,124}}))); + Buildings.Controls.OBC.CDL.Integers.Add reqResChiWat + "Sum of CHW reset requests of all loads served" + annotation (Placement(transformation(extent={{110,64},{90,84}}))); +equation + /* Control point connection - start */ + // Inputs from plant control bus + connect(bus.TChiWatPriRet, ctl.TChiWatPriRet); + connect(bus.TChiWatPriSup, ctl.TChiWatPriSup); + connect(bus.TChiWatSecRet, ctl.TChiWatSecRet); + connect(bus.TChiWatSecSup, ctl.TChiWatSecSup); + connect(bus.THeaWatPriRet, ctl.THeaWatPriRet); + connect(bus.THeaWatPriSup, ctl.THeaWatPriSup); + connect(bus.THeaWatSecRet, ctl.THeaWatSecRet); + connect(bus.THeaWatSecSup, ctl.THeaWatSecSup); + connect(bus.TOut, ctl.TOut); + connect(bus.VChiWatPri_flow, ctl.VChiWatPri_flow); + connect(bus.VChiWatSec_flow, ctl.VChiWatSec_flow); + connect(bus.VHeaWatPri_flow, ctl.VHeaWatPri_flow); + connect(bus.VHeaWatSec_flow, ctl.VHeaWatSec_flow); + connect(bus.dpChiWatLoc, ctl.dpChiWatLoc); + connect(bus.dpChiWatLocSet, ctl.dpChiWatLocSet); + connect(bus.dpChiWatRem, ctl.dpChiWatRem); + connect(bus.dpHeaWatLoc, ctl.dpHeaWatLoc); + connect(bus.dpHeaWatLocSet, ctl.dpHeaWatLocSet); + connect(bus.dpHeaWatRem, ctl.dpHeaWatRem); + connect(busHp.y1_actual, ctl.u1Hp_actual); + connect(busPumChiWatPri.y1_actual, ctl.u1PumChiWatPri_actual); + connect(busPumChiWatSec.y1_actual, ctl.u1PumChiWatSec_actual); + connect(busPumHeaWatPri.y1_actual, ctl.u1PumHeaWatPri_actual); + connect(busPumHeaWatSec.y1_actual, ctl.u1PumHeaWatSec_actual); + connect(bus.u1SchCoo, ctl.u1SchCoo); + connect(bus.u1SchHea, ctl.u1SchHea); + // Outputs to plant control bus + connect(ctl.TSupSet, busHp.TSet); + connect(ctl.TChiWatSupSet, bus.TChiWatSupSet); + connect(ctl.THeaWatSupSet, bus.THeaWatSupSet); + connect(ctl.dpChiWatRemSet, bus.dpChiWatRemSet); + connect(ctl.dpHeaWatRemSet, bus.dpHeaWatRemSet); + connect(ctl.y1HeaHp, busHp.y1Hea); + connect(ctl.y1Hp, busHp.y1); + connect(ctl.y1PumChiWatPri, busPumChiWatPri.y1); + connect(ctl.y1PumChiWatSec, busPumChiWatSec.y1); + connect(ctl.y1PumHeaWatPri, busPumHeaWatPri.y1); + connect(ctl.y1PumHeaWatSec, busPumHeaWatSec.y1); + connect(ctl.y1ValChiWatHpInlIso, busValChiWatHpInlIso.y1); + connect(ctl.y1ValChiWatHpOutIso, busValChiWatHpOutIso.y1); + connect(ctl.y1ValHeaWatHpInlIso, busValHeaWatHpInlIso.y1); + connect(ctl.y1ValHeaWatHpOutIso, busValHeaWatHpOutIso.y1); + connect(ctl.yPumChiWatPriDed, busPumChiWatPri.y); + connect(ctl.yPumChiWatPriHdr, busPumChiWatPri.y); + connect(ctl.yPumChiWatSec, busPumChiWatSec.y); + connect(ctl.yPumHeaWatPriDed, busPumHeaWatPri.y); + connect(ctl.yPumHeaWatPriHdr, busPumHeaWatPri.y); + connect(ctl.yPumHeaWatSec, busPumHeaWatSec.y); + /* Control point connection - stop */ + connect(busAirHan.reqResChiWat, reqResChiWatAirHan.u) annotation (Line( + points={{260,140},{240,140},{240,80},{212,80}}, + color={255,204,51}, + thickness=0.5)); + connect(busEquZon.reqPlaHeaWat, reqPlaHeaWatEquZon.u) annotation (Line( + points={{260,-140},{240,-140},{240,-80},{212,-80}}, + color={255,204,51}, + thickness=0.5)); + connect(busEquZon.reqResHeaWat, reqResHeaWatEquZon.u) annotation (Line( + points={{260,-140},{240,-140},{240,-160},{212,-160}}, + color={255,204,51}, + thickness=0.5)); + connect(busEquZon.reqPlaChiWat, reqPlaChiWatEquZon.u) annotation (Line( + points={{260,-140},{240,-140},{240,-120},{212,-120}}, + color={255,204,51}, + thickness=0.5)); + connect(busEquZon.reqResChiWat, reqResChiWatEquZon.u) annotation (Line( + points={{260,-140},{240,-140},{240,-200},{212,-200}}, + color={255,204,51}, + thickness=0.5)); + connect(busAirHan.reqPlaChiWat, reqPlaChiWatAirHan.u) annotation (Line( + points={{260,140},{240,140},{240,160},{212,160}}, + color={255,204,51}, + thickness=0.5)); + connect(busAirHan.reqPlaHeaWat, reqPlaHeaWatAirHan.u) annotation (Line( + points={{260,140},{240,140},{240,200},{212,200}}, + color={255,204,51}, + thickness=0.5)); + connect(busAirHan.reqResHeaWat, reqResHeaWatAirHan.u[1:1]) annotation (Line( + points={{260,140},{240,140},{240,120},{212,120}}, + color={255,204,51}, + thickness=0.5)); + connect(reqPlaHeaWatAirHan.y, phReqPlaHeaWatAirHan.u) + annotation (Line(points={{188,200},{172,200}}, color={255,127,0})); + connect(reqPlaChiWatAirHan.y, phReqPlaChiWatAirHan.u) + annotation (Line(points={{188,160},{172,160}}, color={255,127,0})); + connect(reqResHeaWatAirHan.y, phReqResHeaWatAirHan.u) + annotation (Line(points={{188,120},{172,120}}, color={255,127,0})); + connect(reqResChiWatAirHan.y, phReqResChiWatAirHan.u) + annotation (Line(points={{188,80},{172,80}}, color={255,127,0})); + connect(reqPlaHeaWatEquZon.y, phReqPlaHeaWatEquZon.u) annotation (Line(points + ={{188,-80},{180,-80},{180,-80},{172,-80}}, color={255,127,0})); + connect(reqPlaChiWatEquZon.y, phReqPlaChiWatEquZon.u) + annotation (Line(points={{188,-120},{172,-120}}, color={255,127,0})); + connect(reqResChiWatEquZon.y, phReqResChiWatEquZon.u) + annotation (Line(points={{188,-200},{172,-200}}, color={255,127,0})); + connect(reqResHeaWatEquZon.y, phReqResHeaWatEquZon.u) annotation (Line(points + ={{188,-160},{178,-160},{178,-160},{172,-160}}, color={255,127,0})); + connect(phReqPlaHeaWatAirHan.y, reqPlaHeaWat.u1) + annotation (Line(points={{148,200},{112,200}}, color={255,127,0})); + connect(phReqPlaHeaWatEquZon.y, reqPlaHeaWat.u2) annotation (Line(points={{148, + -80},{140,-80},{140,188},{112,188}}, color={255,127,0})); + connect(phReqPlaChiWatAirHan.y, reqPlaChiWat.u1) + annotation (Line(points={{148,160},{112,160}}, color={255,127,0})); + connect(phReqPlaChiWatEquZon.y, reqPlaChiWat.u2) annotation (Line(points={{148, + -120},{138,-120},{138,148},{112,148}}, color={255,127,0})); + connect(phReqResHeaWatAirHan.y, reqResHeaWat.u1) + annotation (Line(points={{148,120},{112,120}}, color={255,127,0})); + connect(phReqResChiWatAirHan.y, reqResChiWat.u1) + annotation (Line(points={{148,80},{112,80}}, color={255,127,0})); + connect(phReqResHeaWatEquZon.y, reqResHeaWat.u2) annotation (Line(points={{148, + -160},{136,-160},{136,108},{112,108}}, color={255,127,0})); + connect(phReqResChiWatEquZon.y, reqResChiWat.u2) annotation (Line(points={{148, + -200},{134,-200},{134,68},{112,68}}, color={255,127,0})); + connect(reqPlaHeaWat.y, ctl.nReqPlaHeaWat) annotation (Line(points={{88,194}, + {-40,194},{-40,22.3529},{-22,22.3529}}, + color={255,127,0})); + connect(reqPlaChiWat.y, ctl.nReqPlaChiWat) annotation (Line(points={{88,154}, + {-38,154},{-38,20.5882},{-22,20.5882}}, + color={255,127,0})); + connect(reqResHeaWat.y,ctl.nReqResHeaWat) annotation (Line(points={{88,114}, + {-36,114},{-36,18.8235},{-22,18.8235}}, + color={255,127,0})); + connect(reqResChiWat.y,ctl.nReqResChiWat) annotation (Line(points={{88,74},{ + -34,74},{-34,17.0588},{-22,17.0588}}, + color={255,127,0})); + annotation ( + defaultComponentName="ctl", Documentation(info=" +

+This class implements the sequence of operation for plants with +air-to-water heat pumps. +It is based on the controller + +Buildings.Templates.Plants.Controls.HeatPumps.AirToWater. +

+

Control points

+

+The control sequence requires the following external input points in +addition to those already included in the HP plant template. +

+
    +
  • Outdoor air temperature TOut: +AI signal with a dimensionality of zero
  • +
  • HW differential pressure from remote sensor(s) dpHeaWatRem: +AI signal with a dimensionality of one, the number of remote +sensors is specified by the parameter nSenDpHeaWatRem.
  • +
  • CHW differential pressure from remote sensor(s) dpChiWatRem – +only for heating and cooling plants: +AI signal with a dimensionality of one, the number of remote +sensors is specified by the parameter nSenDpChiWatRem.
  • +
  • +Inside the sub-bus busAirHan[:] or busEquZon[:], +with a dimensionality of one +
      +
    • HW plant requests yielded by the air handler or zone +equipment controller bus(AirHan|EquZon)[:].reqPlaHeaWat: +AI signal (Integer), with a dimensionality of one +
    • +
    • HW reset requests yielded by the air handler or zone +equipment controller bus(AirHan|EquZon)[:].reqResHeaWat: +AI signal (Integer), with a dimensionality of one +
    • +
    +
  • +
  • +CHW plant requests yielded by the air handler or zone – +only for heating and cooling plants: +equipment controller bus(AirHan|EquZon)[:].reqPlaChiWat: +AI signal (Integer), with a dimensionality of one +
  • +
  • +CHW reset requests yielded by the air handler or zone – +only for heating and cooling plants: +equipment controller bus(AirHan|EquZon)[:].reqResChiWat: +AI signal (Integer), with a dimensionality of one +
  • +
+")); +end AirToWater; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Controls/OpenLoop.mo b/Buildings/Templates/Plants/HeatPumps/Components/Controls/OpenLoop.mo new file mode 100644 index 00000000000..b14e8139bdc --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Controls/OpenLoop.mo @@ -0,0 +1,209 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Controls; +block OpenLoop + "Open-loop controller" + extends + Buildings.Templates.Plants.HeatPumps.Components.Interfaces.PartialController( + final typ=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant THeaWatSupSet[nHp]( + y(each final unit="K", + each displayUnit="degC"), + each k=Buildings.Templates.Data.Defaults.THeaWatSupMed) + "Heat pump HW supply temperature set point" + annotation (Placement(transformation(extent={{-80,330},{-100,350}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TChiWatSupSet[nHp]( + y(each final unit="K", + each displayUnit="degC"), + each k=Buildings.Templates.Data.Defaults.TChiWatSup) + "Heat pump CHW supply temperature set point" + annotation (Placement(transformation(extent={{-80,290},{-100,310}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1ValHeaWatHpInlIso[nHp]( + each table=[ + 0, 0; + 1, 1; + 3, 0; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.have_heaWat and cfg.have_valHpInlIso + "Heat pump inlet HW isolation valve opening signal" + annotation (Placement(transformation(extent={{-180,250},{-200,270}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1ValHeaWatHpOutIso[nHp]( + each table=[ + 0, 0; + 1, 1; + 3, 0; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.have_heaWat and cfg.have_valHpOutIso + "Heat pump outlet HW isolation valve opening signal" + annotation (Placement(transformation(extent={{-180,210},{-200,230}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1ValChiWatHpInlIso[nHp]( + each table=[ + 0, 0; + 3.1, 1; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.have_chiWat and cfg.have_valHpInlIso + "Heat pump inlet CHW isolation valve opening signal" + annotation (Placement(transformation(extent={{-180,-90},{-200,-70}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1ValChiWatHpOutIso[nHp]( + each table=[ + 0, 0; + 3.1, 1; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.have_chiWat and cfg.have_valHpOutIso + "Heat pump outlet CHW isolation valve opening signal" + annotation (Placement(transformation(extent={{-180,-130},{-200,-110}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1Hp[nHp]( + each table=[ + 0, 0; + 1, 0; + 1, 1; + 5, 1], + each timeScale=1000, + each period=5000) + "Heat pump start/stop command" + annotation (Placement(transformation(extent={{-180,330},{-200,350}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1HeaHp[nHp]( + each table=[ + 0, 1; + 3, 0; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.is_rev + "Heat pump heating mode command" + annotation (Placement(transformation(extent={{-180,290},{-200,310}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumHeaWatPri[cfg.nPumHeaWatPri]( + each table=if cfg.have_pumChiWatPriDed or not cfg.have_chiWat then + [ + 0, 0; + 1, 1; + 3, 0; + 5, 0] else + [ + 0, 0; + 1, 1; + 3, 0; + 3.1, 1; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.have_heaWat + "Primary CHW pump start/stop command" + annotation (Placement(transformation(extent={{-180,170},{-200,190}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumChiWatPri[cfg.nPumChiWatPri]( + each table=[ + 0, 0; + 3.1, 1; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.have_pumChiWatPriDed + "Primary CHW pump start/stop command" + annotation (Placement(transformation(extent={{-180,-210},{-200,-190}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumHeaWatSec[cfg.nPumHeaWatSec]( + each table=[ + 0, 0; + 1, 1; + 3, 0; + 5, 0], + each timeScale=1000, + each period=5000) + if cfg.typPumHeaWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Secondary HW pump start/stop command" + annotation (Placement(transformation(extent={{-180,130},{-200,150}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.TimeTable y1PumChiWatSec[cfg.nPumChiWatSec]( + each table=[ + 0, 0; + 3, 1; + 5, 1], + each timeScale=1000, + each period=5000) + if cfg.typPumChiWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Secondary CHW pump start/stop command" + annotation (Placement(transformation(extent={{-180,-250},{-200,-230}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumHeaWatSec( + k=1) + if cfg.typPumHeaWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Secondary HW pump speed signal" + annotation (Placement(transformation(extent={{-140,130},{-160,150}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumChiWatSec( + k=1) + if cfg.typPumChiWatSec <> Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Secondary CHW pump speed signal" + annotation (Placement(transformation(extent={{-140,-250},{-160,-230}}))); + Buildings.Controls.OBC.CDL.Reals.Switch TSet[nHp]( + y(each final unit="K", + each displayUnit="degC")) + "Active supply temperature setpoint" + annotation (Placement(transformation(extent={{-140,310},{-160,330}}))); + Buildings.Controls.OBC.CDL.Logical.Sources.Constant tru[nHp]( + each final k=true) + if not cfg.is_rev + "Constant" + annotation (Placement(transformation(extent={{-80,250},{-100,270}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumHeaWatPriHdr(k=1) + if cfg.have_heaWat and cfg.have_pumHeaWatPriVar and + cfg.typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + "Headered primary HW pump speed signal" + annotation (Placement(transformation(extent={{-140,170},{-160,190}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumChiWatPriHdr(k=1) + if cfg.have_chiWat and cfg.have_pumHeaWatPriVar and + cfg.typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + "Headered primary CHW pump speed signal" + annotation (Placement(transformation(extent={{-140,-210},{-160,-190}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumHeaWatPriDed[cfg.nPumHeaWatPri]( + each k=1) if cfg.have_heaWat and cfg.have_pumHeaWatPriVar and + cfg.typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Dedicated primary HW pump speed signal" + annotation (Placement(transformation(extent={{-100,170},{-120,190}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant yPumChiWatPriDed[cfg.nPumChiWatPri]( + each k=1) if cfg.have_pumChiWatPriDed and cfg.have_pumHeaWatPriVar + "Dedicated primary CHW pump speed signal" + annotation (Placement(transformation(extent={{-100,-210},{-120,-190}}))); +equation + /* Control point connection - start */ + connect(y1PumHeaWatPri.y[1], busPumHeaWatPri.y1); + connect(yPumHeaWatPriHdr.y, busPumHeaWatPri.y); + connect(yPumHeaWatPriDed.y, busPumHeaWatPri.y); + connect(y1PumHeaWatSec.y[1], busPumHeaWatSec.y1); + connect(yPumHeaWatSec.y, busPumHeaWatSec.y); + connect(y1ValHeaWatHpInlIso.y[1], busValHeaWatHpInlIso.y1); + connect(y1ValHeaWatHpOutIso.y[1], busValHeaWatHpOutIso.y1); + connect(yPumChiWatSec.y, busPumChiWatSec.y); + connect(y1ValChiWatHpOutIso.y[1], busValChiWatHpOutIso.y1); + connect(y1PumChiWatPri.y[1], busPumChiWatPri.y1); + connect(yPumChiWatPriHdr.y, busPumChiWatPri.y); + connect(yPumChiWatPriDed.y, busPumChiWatPri.y); + connect(y1ValChiWatHpInlIso.y[1], busValChiWatHpInlIso.y1); + connect(y1PumChiWatSec.y[1], busPumChiWatSec.y1); + connect(y1Hp.y[1], busHp.y1); + connect(y1HeaHp.y[1], busHp.y1Hea); + connect(TSet.y, busHp.TSet); + /* Control point connection - stop */ + connect(TChiWatSupSet.y, TSet.u3) + annotation (Line(points={{-102,300},{-120,300},{-120,312},{-138,312}},color={0,0,127})); + connect(THeaWatSupSet.y, TSet.u1) + annotation (Line(points={{-102,340},{-120,340},{-120,328},{-138,328}},color={0,0,127})); + connect(y1HeaHp.y[1], TSet.u2) + annotation (Line(points={{-202,300},{-210,300},{-210,280},{-130,280},{-130, + 320},{-138,320}}, + color={255,0,255})); + connect(tru.y, TSet.u2) + annotation (Line(points={{-102,260},{-130,260},{-130,320},{-138,320}},color={255,0,255})); + annotation ( + defaultComponentName="ctl", Documentation(info=" +

+This is an open loop controller providing control inputs +for the plant model + +Buildings.Templates.Plants.HeatPumps.AirToWater. +It is only used for testing purposes. +

+")); +end OpenLoop; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Controls/package.mo b/Buildings/Templates/Plants/HeatPumps/Components/Controls/package.mo new file mode 100644 index 00000000000..9e7d14a9162 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Controls/package.mo @@ -0,0 +1,13 @@ +within Buildings.Templates.Plants.HeatPumps.Components; +package Controls "Controllers" + extends Modelica.Icons.VariantsPackage; + annotation ( + Documentation( + info=" +

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

+")); +end Controls; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Controls/package.order b/Buildings/Templates/Plants/HeatPumps/Components/Controls/package.order new file mode 100644 index 00000000000..c1d5525102f --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Controls/package.order @@ -0,0 +1,2 @@ +AirToWater +OpenLoop diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Data/Controller.mo b/Buildings/Templates/Plants/HeatPumps/Components/Data/Controller.mo new file mode 100644 index 00000000000..a577b627f97 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Data/Controller.mo @@ -0,0 +1,229 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Data; +record Controller + "Record for plant controller" + extends Modelica.Icons.Record; + parameter Buildings.Templates.Plants.HeatPumps.Configuration.HeatPumpPlant cfg + "Plant configuration parameters"; + // HW loop + // RFE: Declare array parameters for unequally sized units. + // The current implementation only supports equally sized units. + parameter Modelica.Units.SI.Temperature THeaWatSup_nominal( + displayUnit="degC", + start=Buildings.Templates.Data.Defaults.THeaWatSupMed, + final min=273.15) + "Maximum HW supply temperature setpoint (design HW supply temperature)" + annotation (Dialog(group="Temperature setpoints", + enable=cfg.have_heaWat)); + parameter Real THeaWatSupSet_min( + final min=273.15, + start=25 + 273.15, + final unit="K", + displayUnit="degC") + "Minimum value to which the HW supply temperature can be reset" + annotation (Dialog(group="Temperature setpoints", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.Temperature TOutHeaWatLck( + displayUnit="degC", + final min=273.15)=Buildings.Templates.Data.Defaults.TOutHeaWatLck + "Outdoor air lockout temperature above which the HW loop is prevented from operating" + annotation (Dialog(group="Temperature setpoints", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatHp_flow_nominal( + start=0.1, + displayUnit="L/s", + final min=0) + "Design HW volume flow rate - Each heat pump" + annotation (Evaluate=true, + Dialog(group="Heat pump flow setpoints", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.HeatFlowRate capHeaHp_nominal( + start=1, + final min=0) + "Design heating capacity - Each heat pump" + annotation (Dialog(group="Capacity", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.VolumeFlowRate VHeaWatSec_flow_nominal( + start=0.01, + displayUnit="L/s", + final min=0) + "Design secondary HW volume flow rate" + annotation (Evaluate=true, + Dialog(group="Capacity", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None)); + parameter Modelica.Units.SI.PressureDifference dpHeaWatRemSet_min( + final min=0, + start=5 * 6894)=5 * 6894 + "Minimum value to which the HW differential pressure can be reset - Remote sensor" + annotation (Dialog(group= + "Information provided by designer", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and (cfg.typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + or cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None))); + // HACK(AntoineGautier): + // Using cfg.nSenDpHeaWatRem for size(dpHeaWatRemSet_max, 1) is not supported by Dymola which fails to "evaluate and check the size declaration". + // So the size is kept unassigned. + // This requires explicitely providing a value with OCT, even if enable=false. + parameter Modelica.Units.SI.PressureDifference dpHeaWatRemSet_max[:]( + start=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, cfg.nSenDpHeaWatRem), + final min=fill(0, cfg.nSenDpHeaWatRem)) + "Maximum HW differential pressure setpoint - Remote sensor" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and (cfg.typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + or cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None))); + parameter Real yPumHeaWatPriSet( + final max=1, + final min=0, + start=1, + final unit="1") + "Primary pump speed providing design heat pump flow in heating mode" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater and + cfg.have_heaWat and cfg.have_pumHeaWatPriVar)); + 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=cfg.have_heaWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None)); + // CHW loop + parameter Modelica.Units.SI.Temperature TChiWatSup_nominal( + displayUnit="degC", + start=Buildings.Templates.Data.Defaults.TChiWatSup, + final min=273.15) + "Minimum CHW supply temperature setpoint (design CHW supply temperature)" + annotation (Dialog(group="Temperature setpoints", + enable=cfg.have_chiWat)); + parameter Modelica.Units.SI.Temperature TChiWatSupSet_max( + final min=273.15, + start=15 + 273.15, + displayUnit="degC") + "Maximum value to which the CHW supply temperature can be reset" + annotation (Dialog(group="Temperature setpoints", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.Temperature TOutChiWatLck( + displayUnit="degC", + final min=273.15)=Buildings.Templates.Data.Defaults.TOutChiWatLck + "Outdoor air lockout temperature below which the CHW loop is prevented from operating" + annotation (Dialog(group="Temperature setpoints", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.VolumeFlowRate VChiWatHp_flow_nominal( + start=0.1, + displayUnit="L/s", + final min=0) + "Design CHW volume flow rate - Each heat pump" + annotation (Evaluate=true, + Dialog(group="Heat pump flow setpoints", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.HeatFlowRate capCooHp_nominal( + start=1, + final min=0) + "Design cooling capacity - Each heat pump" + annotation (Dialog(group="Capacity", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + parameter Modelica.Units.SI.VolumeFlowRate VChiWatSec_flow_nominal( + start=0.01, + displayUnit="L/s", + final min=0) + "Design secondary CHW volume flow rate" + annotation (Evaluate=true, + Dialog(group="Capacity", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None)); + parameter Modelica.Units.SI.PressureDifference dpChiWatRemSet_min( + final min=0, + start=5 * 6894)=5 * 6894 + "Minimum value to which the CHW differential pressure can be reset - Remote sensor" + annotation (Dialog(group= + "Information provided by designer", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and (cfg.typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + or cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None))); + // HACK(AntoineGautier): + // Using cfg.nSenDpChiWatRem for size(dpChiWatRemSet_max, 1) is not supported by Dymola which fails to "evaluate and check the size declaration". + // So the size is kept unassigned. + // This requires explicitely providing a value with OCT, even if enable=false. + parameter Modelica.Units.SI.PressureDifference dpChiWatRemSet_max[:]( + start=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, cfg.nSenDpChiWatRem), + final min=fill(0, cfg.nSenDpChiWatRem)) + "Maximum CHW differential pressure setpoint - Remote sensor" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and (cfg.typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + or cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None))); + parameter Real yPumChiWatPriSet( + final max=1, + final min=0, + start=1, + final unit="1") + "Primary pump speed providing design heat pump flow in cooling mode" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and cfg.have_pumChiWatPriVar)); + parameter Real yPumChiWatSec_min( + final unit="1", + final min=0, + final max=1)=0.1 + "Secondary CHW pump minimum speed" + annotation (Dialog(group= + "Information provided by testing, adjusting, and balancing contractor", + enable=cfg.have_chiWat and cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater + and cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None)); + parameter Real schHea[:, 2](start=[ + 0, 1; + 24 * 3600, 1])=[ + 0, 1; + 24 * 3600, 1] + "Heating mode enable schedule" + annotation (Dialog(enable=not cfg.have_inpSch and + cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater, + group="Plant enable")); + parameter Real schCoo[:, 2](start=[ + 0, 1; + 24 * 3600, 1])=[ + 0, 1; + 24 * 3600, 1] + "Cooling mode enable schedule" + annotation (Dialog(enable=not cfg.have_inpSch and + cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater, + group="Plant enable")); + // HACK(AntoineGautier): + // Using cfg.nHp for size(staEqu, 2) is not supported by Dymola which fails to "evaluate and check the size declaration". + // So the size is kept unassigned and a check is performed at initialization. + // Furthermore, a start value cannot be provided as the number of plant stages is not known beforehand. + // If provided, there will likely be a mismatch between assigned value and start value. + // Therefore, no enable annotation can be used. + parameter Real staEqu[:, :]( + each final max=1, + each final min=0, + each final unit="1") + "Staging matrix – Equipment required for each stage" + annotation (Dialog(group="Equipment staging and rotation")); + parameter Real plrSta( + final max=1, + final min=0, + start=0.9, + final unit="1")=0.9 + "Staging part load ratio" + annotation (Dialog(group="Equipment staging and rotation", + enable=cfg.typCtl==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater)); + annotation ( + defaultComponentName="datCtl", + Documentation( + info=" +

+This record provides the set of parameters for +heat pump plant controllers that can be found within + +Buildings.Templates.Plants.HeatPumps.Components.Controls. +

+")); +end Controller; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Data/HeatPumpGroup.mo b/Buildings/Templates/Plants/HeatPumps/Components/Data/HeatPumpGroup.mo new file mode 100644 index 00000000000..61b988302c3 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Data/HeatPumpGroup.mo @@ -0,0 +1,185 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Data; +record HeatPumpGroup + extends Modelica.Icons.Record; + parameter Integer nHp( + final min=1) + "Number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=false)); + parameter Buildings.Templates.Components.Types.HeatPump typ + "Equipment type" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=false)); + parameter Boolean is_rev + "Set to true for reversible heat pumps, false for heating only" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=false)); + parameter Buildings.Templates.Components.Types.HeatPumpModel typMod + "Type of heat pump model" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=false)); + // Default fluid properties + parameter Modelica.Units.SI.SpecificHeatCapacity cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq + "HW default specific heat capacity" + annotation (Dialog(group="Configuration", + enable=false)); + /* + cpChiWat_default is for internal use only. + It is the same as cpChiWat_default for reversible HP. + Non-reversible HP that can be controlled to produce either HW or CHW + shall be modeled with chiller components (as a chiller/heater). + */ + final parameter Modelica.Units.SI.SpecificHeatCapacity cpChiWat_default= + cpHeaWat_default + "CHW default specific heat capacity"; + parameter Modelica.Units.SI.SpecificHeatCapacity cpSou_default=if typ == + Buildings.Templates.Components.Types.HeatPump.AirToWater then Buildings.Utilities.Psychrometrics.Constants.cpAir + else Buildings.Utilities.Psychrometrics.Constants.cpWatLiq + "Source fluid default specific heat capacity" + annotation (Dialog(group="Configuration", + enable=false)); + // RFE: Declare array parameters for unequally sized units. + // The current implementation only supports equally sized units. + parameter Modelica.Units.SI.MassFlowRate mHeaWatHp_flow_nominal( + final min=0) + "HW mass flow rate - Each heat pump" + annotation (Evaluate=true, + Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpHeaWatHp_nominal( + min=0, + start=Buildings.Templates.Data.Defaults.dpChiWatChi) + "Pressure drop at design HW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.HeatFlowRate capHeaHp_nominal + "Heating capacity - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.Temperature THeaWatSupHp_nominal( + final min=273.15) + "(Highest) HW supply temperature - Each heat pump" + annotation (Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.Temperature THeaWatRetHp_nominal= + THeaWatSupHp_nominal - abs(capHeaHp_nominal) / cpHeaWat_default / + mHeaWatHp_flow_nominal + "HW return temperature - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.MassFlowRate mChiWatHp_flow_nominal( + start=0, + final min=0) + "CHW mass flow rate - Each heat pump" + annotation (Evaluate=true, + Dialog(group="Nominal condition", + enable=is_rev)); + final parameter Modelica.Units.SI.PressureDifference dpChiWatHp_nominal= + dpHeaWatHp_nominal *(mChiWatHp_flow_nominal / mHeaWatHp_flow_nominal) ^ 2 + "Pressure drop at design CHW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.HeatFlowRate capCooHp_nominal( + start=0) + "Cooling capacity - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=is_rev)); + parameter Modelica.Units.SI.Temperature TChiWatSupHp_nominal( + start=Buildings.Templates.Data.Defaults.TChiWatSup, + final min=253.15) + "(Lowest) CHW supply temperature - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=is_rev)); + final parameter Modelica.Units.SI.Temperature TChiWatRetHp_nominal=if is_rev + then TChiWatSupHp_nominal + abs(capCooHp_nominal) / cpChiWat_default / + mChiWatHp_flow_nominal else Buildings.Templates.Data.Defaults.TChiWatRet + "CHW return temperature - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=is_rev)); + parameter Modelica.Units.SI.Temperature TSouHeaHp_nominal( + start=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + final min=220) + "OAT or source fluid supply temperature (evaporator entering) in heating mode - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.MassFlowRate mSouWwHeaHp_flow_nominal( + start=mHeaWatHp_flow_nominal, + final min=0) + "Source fluid mass flow rate in heating mode - Each heat pump" + annotation (Evaluate=true, + Dialog(group="Nominal condition", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + parameter Modelica.Units.SI.PressureDifference dpSouWwHeaHp_nominal( + min=0, + start=Buildings.Templates.Data.Defaults.dpChiWatChi) + "Source fluid pressure drop in heating mode - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + final parameter Modelica.Units.SI.MassFlowRate mSouHeaHp_flow_nominal=if typ == + Buildings.Templates.Components.Types.HeatPump.WaterToWater then mSouWwHeaHp_flow_nominal + else Buildings.Templates.Data.Defaults.mAirFloByCapChi * abs(capHeaHp_nominal) + "Source fluid mass flow rate in heating mode - Each heat pump" + annotation (Evaluate=true); + final parameter Modelica.Units.SI.PressureDifference dpSouHeaHp_nominal=if typ == + Buildings.Templates.Components.Types.HeatPump.WaterToWater then dpSouWwHeaHp_nominal + else Buildings.Templates.Data.Defaults.dpAirChi + "Source fluid pressure drop in heating mode - Each heat pump"; + parameter Modelica.Units.SI.Temperature TSouCooHp_nominal( + start=Buildings.Templates.Data.Defaults.TOutHpCoo, + final min=273.15) + "OAT or source fluid supply temperature (condenser entering) in cooling mode - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=is_rev)); + parameter Modelica.Units.SI.MassFlowRate mSouWwCooHp_flow_nominal( + start=mChiWatHp_flow_nominal, + final min=0) + "Source fluid mass flow rate in cooling mode - Each heat pump" + annotation (Evaluate=true, + Dialog(group="Nominal condition", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater and is_rev)); + final parameter Modelica.Units.SI.MassFlowRate mSouCooHp_flow_nominal=if typ == + Buildings.Templates.Components.Types.HeatPump.WaterToWater then mSouWwCooHp_flow_nominal + else Buildings.Templates.Data.Defaults.mAirFloByCapChi * abs(capCooHp_nominal) + "Source fluid mass flow rate in cooling mode - Each heat pump" + annotation (Evaluate=true); + final parameter Modelica.Units.SI.PressureDifference dpSouCooHp_nominal= + dpSouHeaHp_nominal *(mSouCooHp_flow_nominal / mSouHeaHp_flow_nominal) ^ 2 + "Source fluid pressure drop in cooling mode - Each heat pump"; + replaceable parameter Buildings.Fluid.HeatPumps.Data.EquationFitReversible.Generic perFitHp( + dpHeaLoa_nominal=dpHeaWatHp_nominal, + dpHeaSou_nominal=dpSouHeaHp_nominal, + hea( + Q_flow=abs(capHeaHp_nominal), + P=0, + mLoa_flow=mHeaWatHp_flow_nominal, + mSou_flow=mSouHeaHp_flow_nominal, + coeQ={1, 0, 0, 0, 0}, + coeP={1, 0, 0, 0, 0}, + TRefLoa=THeaWatRetHp_nominal, + TRefSou=TSouHeaHp_nominal), + coo( + Q_flow=if is_rev then - abs(capCooHp_nominal) else - 1, + P=0, + mLoa_flow=mChiWatHp_flow_nominal, + mSou_flow=mSouCooHp_flow_nominal, + coeQ={1, 0, 0, 0, 0}, + coeP={1, 0, 0, 0, 0}, + TRefLoa=TChiWatRetHp_nominal, + TRefSou=TSouCooHp_nominal)) + constrainedby Buildings.Fluid.HeatPumps.Data.EquationFitReversible.Generic + "Performance data - Equation fit model - Each heat pump" + annotation (Dialog(enable=typMod==Buildings.Templates.Components.Types.HeatPumpModel.EquationFit), + choicesAllMatching=true, + Placement(transformation(extent={{-8,-40},{8,-24}}))); + annotation ( + defaultComponentPrefixes="parameter", + defaultComponentName="datHp", + Documentation(info=" +

+This record provides the set of parameters for heat pump group models +that can be found within + +Buildings.Templates.Plants.HeatPumps.Components.HeatPumpGroups. +

+

+Only identical heat pumps are currently supported. +

+")); +end HeatPumpGroup; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Data/package.mo b/Buildings/Templates/Plants/HeatPumps/Components/Data/package.mo new file mode 100644 index 00000000000..0c219b8eb9e --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Data/package.mo @@ -0,0 +1,11 @@ +within Buildings.Templates.Plants.HeatPumps.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/Plants/HeatPumps/Components/Data/package.order b/Buildings/Templates/Plants/HeatPumps/Components/Data/package.order new file mode 100644 index 00000000000..62f5cba34cf --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Data/package.order @@ -0,0 +1,2 @@ +Controller +HeatPumpGroup diff --git a/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/AirToWater.mo b/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/AirToWater.mo new file mode 100644 index 00000000000..533afb57ce9 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/AirToWater.mo @@ -0,0 +1,40 @@ +within Buildings.Templates.Plants.HeatPumps.Components.HeatPumpGroups; +model AirToWater + "Air-to-water heat pump group" + extends Buildings.Templates.Plants.HeatPumps.Components.Interfaces.PartialHeatPumpGroup( + redeclare final package MediumSou=MediumAir, + final typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + final typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit); + Buildings.Templates.Components.HeatPumps.AirToWater hp[nHp]( + redeclare each final package MediumHeaWat=MediumHeaWat, + redeclare each final package MediumAir=MediumAir, + each final is_rev=is_rev, + final dat=datHp, + each final allowFlowReversal=allowFlowReversal, + each final energyDynamics=energyDynamics, + each final have_preDroChiHeaWat=have_preDroChiHeaWat, + each final have_preDroSou=have_preDroSou) + "Heat pump unit" + annotation (Placement(transformation(extent={{10,-10},{-10,10}}))); +equation + for i in 1:nHp loop + connect(busWea, hp[i].busWea) + annotation (Line(points={{40,200},{40,10},{6,10}},color={255,204,51},thickness=0.5)); + end for; + connect(ports_aChiHeaWat, hp.port_a) + annotation (Line(points={{120,200},{120,0},{10,0}},color={0,127,255})); + connect(hp.port_b, ports_bChiHeaWat) + annotation (Line(points={{-10,0},{-120,0},{-120,200}},color={0,127,255})); + connect(busHp, hp.bus) + annotation (Line(points={{0,160},{0,10}},color={255,204,51},thickness=0.5)); + connect(ports_aSou, hp.port_aSou) + annotation (Line(points={{-120,-200},{-120,-10},{-10,-10}},color={0,127,255})); + connect(ports_bSou, hp.port_bSou) + annotation (Line(points={{120,-200},{120,-10},{10,-10}},color={0,127,255})); + annotation ( + defaultComponentName="hp", Documentation(info=" +

+This model represents a group of heat pumps. +

+")); +end AirToWater; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.mo b/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.mo new file mode 100644 index 00000000000..49ae155ba9d --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.mo @@ -0,0 +1,11 @@ +within Buildings.Templates.Plants.HeatPumps.Components; +package HeatPumpGroups "Models for heat pump groups" + extends Modelica.Icons.VariantsPackage; + annotation ( + Documentation( + info=" +

+This package contains models of heat pump groups. +

+")); +end HeatPumpGroups; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.order b/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.order new file mode 100644 index 00000000000..971b641363f --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/HeatPumpGroups/package.order @@ -0,0 +1 @@ +AirToWater diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialController.mo b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialController.mo new file mode 100644 index 00000000000..aacd12b97cb --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialController.mo @@ -0,0 +1,264 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Interfaces; +block PartialController "Interface for heat pump plant controller" + /* + The following bindings are for parameters that are propagated *up* + from the controller to the plant configuration record. + All other configuration parameters (e.g. nHp) are propagated *down* + from the plant configuration record to the controller. + */ + parameter Buildings.Templates.Plants.HeatPumps.Configuration.HeatPumpPlant cfg( + typCtl=typ, + nAirHan=nAirHan, + nEquZon=nEquZon, + have_senDpHeaWatRemWir=have_senDpHeaWatRemWir, + nSenDpHeaWatRem=nSenDpHeaWatRem, + have_senDpChiWatRemWir=have_senDpChiWatRemWir, + nSenDpChiWatRem=nSenDpChiWatRem) + "Plant configuration parameters" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=false)); + parameter Buildings.Templates.Plants.HeatPumps.Components.Data.Controller dat( + cfg=cfg) + "Parameter record for controller"; + final parameter Integer nHp=cfg.nHp + "Number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Buildings.Templates.Plants.HeatPumps.Types.Controller typ + "Type of controller" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Integer nAirHan( + final min=if typ <> Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop + 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.Plants.HeatPumps.Types.Controller.OpenLoop)); + parameter Integer nEquZon( + final min=if typ <> Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop + 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.Plants.HeatPumps.Types.Controller.OpenLoop)); + parameter Boolean have_senVHeaWatPri_select(start=false) + "Set to true for plants with primary HW flow sensor" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop and + cfg.have_heaWat and not cfg.have_hrc and have_senVHeaWatSec)); + final parameter Boolean have_senVHeaWatPri=cfg.have_heaWat and + (if cfg.have_hrc or not have_senVHeaWatSec then true else have_senVHeaWatPri_select) + "Set to true for plants with primary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + // Secondary flow sensor required for secondary HW pump staging. + final parameter Boolean have_senVHeaWatSec= + cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Set to true for plants with secondary HW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_senVChiWatPri_select(start=false) + "Set to true for plants with primary CHW flow sensor" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop and + cfg.have_chiWat and not cfg.have_hrc and have_senVChiWatSec)); + final parameter Boolean have_senVChiWatPri=cfg.have_chiWat and + (if cfg.have_hrc or not have_senVChiWatSec then true + else have_senVChiWatPri_select) + "Set to true for plants with primary CHW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + // Secondary flow sensor required for secondary CHW pump staging. + final parameter Boolean have_senVChiWatSec= + cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Set to true for plants with secondary CHW flow sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_senTHeaWatPriRet_select(start=false) + "Set to true for plants with primary HW return temperature sensor" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop and + cfg.have_heaWat and not cfg.have_hrc and have_senTHeaWatSecRet)); + final parameter Boolean have_senTHeaWatPriRet=cfg.have_heaWat and + (if cfg.have_hrc or not have_senTHeaWatSecRet then true else have_senTHeaWatPriRet_select) + "Set to true for plants with primary HW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_senTChiWatPriRet_select(start=false) + "Set to true for plants with primary CHW return temperature sensor" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop and + cfg.have_chiWat and not cfg.have_hrc and have_senTChiWatSecRet)); + final parameter Boolean have_senTChiWatPriRet=cfg.have_chiWat and + (if cfg.have_hrc or not have_senTChiWatSecRet then true else have_senTChiWatPriRet_select) + "Set to true for plants with primary CHW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + // For primary-secondary plants, SHWST sensor is required for plant staging. + final parameter Boolean have_senTHeaWatSecSup= + cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Set to true for plants with secondary HW supply temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + // For primary-secondary plants, SCHWST sensor is required for plant staging. + final parameter Boolean have_senTChiWatSecSup= + cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Set to true for plants with secondary CHW supply temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration")); + parameter Boolean have_senTHeaWatSecRet(start=false) + "Set to true for plants with secondary HW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop and + cfg.typPumHeaWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None)); + parameter Boolean have_senTChiWatSecRet(start=false) + "Set to true for plants with secondary CHW return temperature sensor" + annotation (Evaluate=true, Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop and + cfg.typPumChiWatSec<>Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None)); + parameter Boolean have_senDpHeaWatRemWir=false + "Set to true for remote HW differential pressure sensor(s) hardwired to plant or pump controller" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop)); + parameter Integer nSenDpHeaWatRem( + final min=if typ <> Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop + 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.Plants.HeatPumps.Types.Controller.OpenLoop)); + parameter Boolean have_senDpChiWatRemWir=have_senDpHeaWatRemWir + "Set to true for remote CHW differential pressure sensor(s) hardwired to plant or pump controller" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=cfg.have_chiWat and typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop)); + parameter Integer nSenDpChiWatRem( + final min=if typ <> Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop + then 1 else 0)=1 + "Number of remote CHW differential pressure sensors used for CHW pump speed control" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=cfg.have_chiWat and typ<>Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop)); + parameter Boolean have_inpSch(start=false)=false + "Set to true to provide schedule via software input point" + annotation (Dialog(group="Plant enable", + enable=typ==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater), + Evaluate=true); + final parameter Real schHea[:, 2]=dat.schHea + "Heating mode enable schedule" + annotation (Dialog(enable=not have_inpSch and + typ==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater, + group="Plant enable")); + final parameter Real schCoo[:, 2]=dat.schCoo + "Cooling mode enable schedule" + annotation (Dialog(enable=not have_inpSch and + typ==Buildings.Templates.Plants.HeatPumps.Types.Controller.AirToWater, + group="Plant enable")); + Buildings.Templates.Plants.HeatPumps.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 busHp[nHp] + "Heat pump control bus" + annotation (Placement(transformation(extent={{-260,320},{-220,360}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatPri + if cfg.typPumHeaWatPri<>Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + "Primary HW pump control bus" + annotation (Placement(transformation(extent={{-260,160},{-220,200}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatSec + if cfg.typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary HW pump control bus" + annotation (Placement(transformation(extent={{-260,120},{-220,160}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumChiWatPri + if cfg.typPumChiWatPri<>Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + "Primary CHW pump control bus" + annotation (Placement(transformation(extent={{-260,-220},{-220,-180}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumChiWatSec + if cfg.typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + "Secondary CHW pump control bus" + annotation (Placement(transformation(extent={{-260,-260},{-220,-220}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValHeaWatHpInlIso[nHp] + if cfg.have_heaWat and cfg.have_valHpInlIso + "Heat pump inlet HW isolation valve control bus" + annotation (Placement(transformation(extent={{-260,280},{-220,320}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValHeaWatHpOutIso[nHp] + if cfg.have_heaWat and cfg.have_valHpOutIso + "Heat pump outlet HW isolation valve control bus" + annotation (Placement(transformation(extent={{-260,240},{-220,280}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValChiWatHpInlIso[nHp] + if cfg.have_chiWat and cfg.have_valHpInlIso + "Heat pump inlet CHW isolation valve control bus" + annotation (Placement(transformation(extent={{-260,-100},{-220,-60}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValChiWatHpOutIso[nHp] + if cfg.have_chiWat and cfg.have_valHpOutIso + "Heat pump outlet CHW isolation valve control bus" + annotation (Placement(transformation(extent={{-260,-140},{-220,-100}}), + iconTransformation(extent={{-466,50},{-426,90}}))); +equation + /* Control point connection - start */ + connect(busPumHeaWatPri, bus.pumHeaWatPri); + connect(busPumChiWatPri, bus.pumChiWatPri); + connect(busPumChiWatSec, bus.pumChiWatSec); + connect(busPumHeaWatSec, bus.pumHeaWatSec); + connect(busHp, bus.hp); + connect(busValHeaWatHpInlIso, bus.valHeaWatHpInlIso); + connect(busValHeaWatHpOutIso, bus.valHeaWatHpOutIso); + connect(busValChiWatHpInlIso, bus.valChiWatHpInlIso); + connect(busValChiWatHpOutIso, bus.valChiWatHpOutIso); + /* Control point connection - stop */ + annotation ( + Icon( + coordinateSystem( + preserveAspectRatio=false), + graphics={ + Rectangle( + extent={{-100,100},{100,-100}}, + lineColor={0,0,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-150,150},{150,110}}, + textString="%name", + textColor={0,0,255})}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-260,-380},{260,380}})), + Documentation( + info=" +

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

+", + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PartialController; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialHeatPumpGroup.mo b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialHeatPumpGroup.mo new file mode 100644 index 00000000000..a1bd7818c69 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/PartialHeatPumpGroup.mo @@ -0,0 +1,331 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Interfaces; +model PartialHeatPumpGroup "Interface for heat pump group" + replaceable package MediumHeaWat=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium" + annotation (__ctrlFlow(enable=false)); + /* + MediumChiWat is for internal use only. + It is the same as MediumHeaWat for reversible HP. + Non-reversible HP that can be controlled to produce either HW or CHW + shall be modeled with chiller components (as a chiller/heater). + */ + final package MediumChiWat=MediumHeaWat + "CHW medium"; + /* + Derived classes representing AWHP shall use: + redeclare final package MediumSou = MediumAir + */ + replaceable package MediumSou=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Source-side medium" + annotation (Dialog(enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater), + __ctrlFlow(enable=false)); + replaceable package MediumAir=Buildings.Media.Air + constrainedby Modelica.Media.Interfaces.PartialMedium + "Air medium" + annotation (Dialog(enable=typ==Buildings.Templates.Components.Types.HeatPump.AirToWater), + __ctrlFlow(enable=false)); + parameter Integer nHp( + final min=1) + "Number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Buildings.Templates.Components.Types.HeatPump typ + "Equipment type" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean is_rev + "Set to true for reversible heat pumps, false for heating only" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Buildings.Templates.Components.Types.HeatPumpModel typMod= + Buildings.Templates.Components.Types.HeatPumpModel.EquationFit + "Type of heat pump model" + annotation (Evaluate=true, + Dialog(group="Configuration"), + __ctrlFlow(enable=false)); + parameter Buildings.Templates.Plants.HeatPumps.Components.Data.HeatPumpGroup dat( + nHp=nHp, + typ=typ, + is_rev=is_rev, + typMod=typMod, + cpHeaWat_default=cpHeaWat_default, + cpSou_default=cpSou_default) + "Design and operating parameters" + annotation (Placement(transformation(extent={{170,170},{190,190}})), + __ctrlFlow(enable=false)); + final parameter Buildings.Templates.Components.Data.HeatPump datHp[nHp]( + each final is_rev=is_rev, + each final typ=typ, + each final typMod=typMod, + each final cpHeaWat_default=cpHeaWat_default, + each final cpSou_default=cpSou_default, + each final mHeaWat_flow_nominal=dat.mHeaWatHp_flow_nominal, + each final mSouWwCoo_flow_nominal=dat.mSouWwCooHp_flow_nominal, + each final TSouHea_nominal=dat.TSouHeaHp_nominal, + each final mChiWat_flow_nominal=dat.mChiWatHp_flow_nominal, + each final dpSouWwHea_nominal=dat.dpSouWwHeaHp_nominal, + each final THeaWatSup_nominal=dat.THeaWatSupHp_nominal, + each final dpHeaWat_nominal=dat.dpHeaWatHp_nominal, + each final mSouWwHea_flow_nominal=dat.mSouWwHeaHp_flow_nominal, + each final TSouCoo_nominal=dat.TSouCooHp_nominal, + each final perFit=dat.perFitHp, + each final capCoo_nominal=dat.capCooHp_nominal, + each final TChiWatSup_nominal=dat.TChiWatSupHp_nominal, + each final capHea_nominal=dat.capHeaHp_nominal) + "Design and operating parameters - Each heat pump"; + final parameter Modelica.Units.SI.MassFlowRate mHeaWatHp_flow_nominal=dat.mHeaWatHp_flow_nominal + "Design HW mass flow rate - Each heat pump"; + final parameter Modelica.Units.SI.HeatFlowRate capHeaHp_nominal=dat.capHeaHp_nominal + "Design heating capacity - Each heat pump"; + final parameter Modelica.Units.SI.HeatFlowRate QHeaHp_flow_nominal=abs(capHeaHp_nominal) + "Design heating heat flow rate - Each heat pump"; + final parameter Modelica.Units.SI.PressureDifference dpHeaWatHp_nominal=dat.dpHeaWatHp_nominal + "Design HW pressure drop - Each heat pump"; + final parameter Modelica.Units.SI.Temperature THeaWatSupHp_nominal=dat.THeaWatSupHp_nominal + "Design HW supply temperature - Each heat pump"; + final parameter Modelica.Units.SI.Temperature THeaWatRetHp_nominal=dat.THeaWatRetHp_nominal + "Design HW return temperature - Each heat pump"; + final parameter Modelica.Units.SI.MassFlowRate mChiWatHp_flow_nominal=dat.mChiWatHp_flow_nominal + "Design CHW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.PressureDifference dpChiWatHp_nominal=dat.dpChiWatHp_nominal + "Design CHW pressure drop - Each heat pump"; + final parameter Modelica.Units.SI.HeatFlowRate capCooHp_nominal=dat.capCooHp_nominal + "Design cooling capacity - Each heat pump"; + final parameter Modelica.Units.SI.HeatFlowRate QCooHp_flow_nominal=- abs(capCooHp_nominal) + "Design cooling heat flow rate - Each heat pump"; + final parameter Modelica.Units.SI.Temperature TChiWatSupHp_nominal=dat.TChiWatSupHp_nominal + "Design CHW supply temperature - Each heat pump"; + final parameter Modelica.Units.SI.Temperature TChiWatRetHp_nominal=dat.TChiWatRetHp_nominal + "Design CHW return temperature - Each heat pump"; + final parameter Modelica.Units.SI.MassFlowRate mSouHeaHp_flow_nominal=dat.mSouHeaHp_flow_nominal + "Design source fluid mass flow rate in heating mode - Each heat pump"; + final parameter Modelica.Units.SI.PressureDifference dpSouHeaHp_nominal=dat.dpSouHeaHp_nominal + "Design source fluid pressure drop in heating mode - Each heat pump"; + final parameter Modelica.Units.SI.MassFlowRate mSouCooHp_flow_nominal=dat.mSouCooHp_flow_nominal + "Design source fluid mass flow rate in cooling mode - Each heat pump"; + final parameter Modelica.Units.SI.PressureDifference dpSouCooHp_nominal=dat.dpSouCooHp_nominal + "Designs source fluid pressure drop in cooling mode - Each heat pump"; + final parameter Modelica.Units.SI.Temperature TSouCooHp_nominal=dat.TSouCooHp_nominal + "Design OAT or source fluid supply temperature (condenser entering) in cooling mode - Each heat pump"; + final parameter Modelica.Units.SI.Temperature TSouHeaHp_nominal=dat.TSouHeaHp_nominal + "Design OAT or source fluid supply temperature (evaporator entering) in heating mode - Each heat pump"; + 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 + "Load side flow reversal: false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation (Dialog(tab="Assumptions"), + Evaluate=true); + parameter Boolean allowFlowReversalSou=true + "Source side flow reversal: false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation (Dialog(tab="Assumptions", + enable=Buildings.Templates.Components.Types.HeatPump.WaterToWater), + Evaluate=true); + parameter Boolean have_preDroChiHeaWat=true + "Set to true for CHW/HW pressure drop computed by this model, false for external computation" + annotation (Evaluate=true, + Dialog(tab="Assumptions")); + parameter Boolean have_preDroSou=true + "Set to true for source fluid pressure drop computed by this model, false for external computation" + annotation (Evaluate=true, + Dialog(tab="Assumptions", + enable=Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + final parameter MediumHeaWat.SpecificHeatCapacity cpHeaWat_default= + MediumHeaWat.specificHeatCapacityCp(staHeaWat_default) + "HW default specific heat capacity"; + final parameter MediumHeaWat.ThermodynamicState staHeaWat_default=MediumHeaWat.setState_pTX( + T=THeaWatSupHp_nominal, + p=MediumHeaWat.p_default, + X=MediumHeaWat.X_default) + "HW default state"; + final parameter MediumChiWat.SpecificHeatCapacity cpChiWat_default= + MediumChiWat.specificHeatCapacityCp(staChiWat_default) + "CHW default specific heat capacity"; + final parameter MediumChiWat.ThermodynamicState staChiWat_default=MediumChiWat.setState_pTX( + T=TChiWatSupHp_nominal, + p=MediumChiWat.p_default, + X=MediumChiWat.X_default) + "CHW default state"; + final parameter MediumSou.SpecificHeatCapacity cpSou_default=MediumSou.specificHeatCapacityCp(staSou_default) + "Source fluid default specific heat capacity"; + final parameter MediumSou.ThermodynamicState staSou_default=MediumSou.setState_pTX( + T=TSouHeaHp_nominal, + p=MediumSou.p_default, + X=MediumSou.X_default) + "Source fluid default state"; + Modelica.Fluid.Interfaces.FluidPorts_b ports_bChiHeaWat[nHp]( + redeclare each final package Medium=MediumHeaWat, + each m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + each h_outflow( + start=MediumHeaWat.h_default, + nominal=MediumHeaWat.h_default)) + "CHW/HW supply" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={-120,200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={-500,400}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aChiHeaWat[nHp]( + redeclare each final package Medium=MediumHeaWat, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=MediumHeaWat.h_default, + nominal=MediumHeaWat.h_default)) + "CHW/HW return" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={120,200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={500,400}))); + Modelica.Fluid.Interfaces.FluidPorts_b ports_bSou[nHp]( + redeclare each final package Medium=MediumSou, + each m_flow( + max=if allowFlowReversalSou then + Modelica.Constants.inf else 0), + each h_outflow( + start=MediumSou.h_default, + nominal=MediumSou.h_default)) + "Source fluid return (from heat pumps)" + annotation (Placement(iconVisible=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater, + transformation(extent={{-10,-40},{10,40}},rotation=90,origin={120,-200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={500,-398}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aSou[nHp]( + redeclare each final package Medium=MediumSou, + each m_flow( + min=if allowFlowReversalSou then - Modelica.Constants.inf else 0), + each h_outflow( + start=MediumSou.h_default, + nominal=MediumSou.h_default)) + "Source fluid supply (to heat pumps)" + annotation (Placement(iconVisible=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater, + transformation(extent={{-10,-40},{10,40}},rotation=90,origin={-120,-200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={-500,-400}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus bus + "Plant control bus" + annotation (Placement(transformation(extent={{-20,180},{20,220}}), + iconTransformation(extent={{-20,380},{20,420}}))); + Buildings.BoundaryConditions.WeatherData.Bus busWea + if typ == Buildings.Templates.Components.Types.HeatPump.AirToWater + "Weather bus" + annotation (Placement(transformation(extent={{20,180},{60,220}}), + iconTransformation(extent={{-220,380},{-180,420}}))); + // Diagnostics + parameter Boolean show_T=false + "= true, if actual temperature at port is computed" + annotation (Dialog(tab="Advanced",group="Diagnostics"),HideResult=true); + MediumHeaWat.ThermodynamicState sta_aChiHeaWat[nHp]=MediumHeaWat.setState_phX(ports_aChiHeaWat.p, noEvent(actualStream(ports_aChiHeaWat.h_outflow)), noEvent(actualStream(ports_aChiHeaWat.Xi_outflow))) + if show_T + "CHW/HW medium properties in port_aChiHeaWat"; + MediumHeaWat.ThermodynamicState sta_bChiHeaWat[nHp]=MediumHeaWat.setState_phX(ports_bChiHeaWat.p, noEvent(actualStream(ports_bChiHeaWat.h_outflow)), noEvent(actualStream(ports_bChiHeaWat.Xi_outflow))) + if show_T + "CHW/HW medium properties in port_bChiHeaWat"; + MediumSou.ThermodynamicState sta_aSou[nHp]=MediumSou.setState_phX(ports_aSou.p, noEvent(actualStream(ports_aSou.h_outflow)), noEvent(actualStream(ports_aSou.Xi_outflow))) + if show_T + "Source medium properties in port_aSou"; + MediumSou.ThermodynamicState sta_bSou[nHp]=MediumSou.setState_phX(ports_bSou.p, noEvent(actualStream(ports_bSou.h_outflow)), noEvent(actualStream(ports_bSou.Xi_outflow))) + if show_T + "Source medium properties in port_bSou"; +protected + Buildings.Templates.Components.Interfaces.Bus busHp[nHp] + "Heat pump control bus" + annotation (Placement(transformation(extent={{-20,140},{20,180}}), + iconTransformation(extent={{-522,206},{-482,246}}))); +equation + connect(bus.hp, busHp) + annotation (Line(points={{0,200},{0,200},{0,160}},color={255,204,51},thickness=0.5)); + annotation (Diagram(coordinateSystem(extent={{-200,-200},{200,200}})), Icon( + coordinateSystem(preserveAspectRatio=false, extent={{-2400,-400},{2400, + 400}}), graphics={ + Bitmap( + extent={{1880,160},{1960,240}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg", + visible=nHp >= 1), + Rectangle( + extent={{2240,400},{1960,0}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nHp >= 1), + Text( + extent={{1960,250},{2240,150}}, + textColor={0,0,0}, + visible=nHp >= 1, + textString="HP-1"), + Bitmap( + extent={{1080,160},{1160,240}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg", + visible=nHp >= 2), + Rectangle( + extent={{1440,400},{1160,0}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nHp >= 2), + Text( + extent={{1160,250},{1440,150}}, + textColor={0,0,0}, + visible=nHp >= 2, + textString="HP-2"), + Bitmap( + extent={{280,160},{360,240}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg", + visible=nHp >= 3), + Rectangle( + extent={{640,400},{360,0}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nHp >= 3), + Text( + extent={{360,250},{640,150}}, + textColor={0,0,0}, + visible=nHp >= 3, + textString="HP-3"), + Bitmap( + extent={{-520,160},{-440,240}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg", + visible=nHp >= 4), + Rectangle( + extent={{-160,400},{-440,0}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nHp >= 4), + Text( + extent={{-440,250},{-160,150}}, + textColor={0,0,0}, + visible=nHp >= 4, + textString="HP-4"), + Bitmap( + extent={{-1320,160},{-1240,240}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg", + visible=nHp >= 5), + Rectangle( + extent={{-960,400},{-1240,0}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nHp >= 5), + Text( + extent={{-1240,250},{-960,150}}, + textColor={0,0,0}, + visible=nHp >= 5, + textString="HP-5"), + Bitmap( + extent={{-2120,160},{-2040,240}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Boilers/ControllerOnboard.svg", + visible=nHp >= 6), + Rectangle( + extent={{-1760,400},{-2040,0}}, + lineColor={0,0,0}, + lineThickness=1, + visible=nHp >= 6), + Text( + extent={{-2040,250},{-1760,150}}, + textColor={0,0,0}, + visible=nHp >= 6, + textString="HP-6")}), + Documentation(info=" +

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

+")); +end PartialHeatPumpGroup; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.mo b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.mo new file mode 100644 index 00000000000..15254aed0fd --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.mo @@ -0,0 +1,11 @@ +within Buildings.Templates.Plants.HeatPumps.Components; +package Interfaces "Interface classes" + extends Modelica.Icons.InterfacesPackage; + annotation ( + Documentation( + info=" +

+This package contains interface classes. +

+")); +end Interfaces; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.order b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.order new file mode 100644 index 00000000000..6112600b18a --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Interfaces/package.order @@ -0,0 +1,2 @@ +PartialController +PartialHeatPumpGroup diff --git a/Buildings/Templates/Plants/HeatPumps/Components/PumpsPrimaryDedicated.mo b/Buildings/Templates/Plants/HeatPumps/Components/PumpsPrimaryDedicated.mo new file mode 100644 index 00000000000..5721bb03f62 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/PumpsPrimaryDedicated.mo @@ -0,0 +1,868 @@ +within Buildings.Templates.Plants.HeatPumps.Components; +model PumpsPrimaryDedicated + "Dedicated primary pumps" + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (__ctrlFlow(enable=false)); + parameter Integer nHp(min=1) + "Number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Configuration")); + /* RFE(AntoineGautier): Add support for multiple pumps for each heat pump. + Currently, only one dedicated CHW or HW pump for each HP is supported. + */ + final parameter Integer nPum=if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + then nHp else 0 + "Number of primary pumps" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumPri + "Type of primary pump arrangement" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean have_pumChiWatPriDed(start=false) + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + parameter Boolean have_pumHeaWatPriVar(start=false) + "Set to true for variable speed primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + parameter Boolean have_pumChiWatPriVar(start=false) + "Set to true for variable speed primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumChiWatPriDed)); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumHeaWat( + typ=if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + then Buildings.Templates.Components.Types.Pump.Multiple else Buildings.Templates.Components.Types.Pump.None, + nPum=nPum) + "HW pump parameters" + annotation (Dialog(enable=typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated), + Placement(transformation(extent={{170,170},{190,190}}))); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumChiWat( + typ=if have_pumChiWatPriDed then Buildings.Templates.Components.Types.Pump.Multiple + else Buildings.Templates.Components.Types.Pump.None, + nPum=if have_pumChiWatPriDed then nPum else 0) + "CHW pump parameters" + annotation (Dialog(enable=typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumChiWatPriDed), + Placement(transformation(extent={{170,130},{190,150}}))); + parameter Modelica.Units.SI.PressureDifference dpValCheHeaWat_nominal[nPum]( + each final min=0, + start=fill(if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + then Buildings.Templates.Data.Defaults.dpValChe else 0, nPum))=fill( + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + then Buildings.Templates.Data.Defaults.dpValChe else 0, nPum) + "HW pump check valve pressure drop at design HW pump flow rate" + annotation (Dialog(group="Nominal condition", + enable=typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + parameter Modelica.Units.SI.PressureDifference dpValCheChiWat_nominal[if have_pumChiWatPriDed then nPum else 0]( + each final min=0, + start=fill(if have_pumChiWatPriDed then Buildings.Templates.Data.Defaults.dpValChe + else 0, if have_pumChiWatPriDed then nPum else 0))=fill(if + have_pumChiWatPriDed then Buildings.Templates.Data.Defaults.dpValChe else 0, + if have_pumChiWatPriDed then nPum else 0) + "CHW pump check valve pressure drop at design CHW pump flow rate" + annotation (Dialog(group="Nominal condition", enable=have_pumChiWatPriDed)); + 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 Modelica.Units.SI.Time tau=1 + "Time constant at nominal flow" + annotation (Dialog(tab="Dynamics",group="Nominal condition", + enable=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState), + __ctrlFlow(enable=false)); + parameter Boolean allowFlowReversal=true + "Set to false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation (Dialog(tab="Assumptions"), + Evaluate=true); + Modelica.Fluid.Interfaces.FluidPorts_b ports_bChiHeaWat[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + or typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumChiWatPriDed + "CHW/HW supply (to primary loop)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={-100,200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=270,origin={-500,400}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aChiHeaWat[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + "CHW/HW return (from primary loop)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={100,200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=270,origin={500,400}))); + Modelica.Fluid.Interfaces.FluidPorts_b ports_bChiHeaWatHp[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + "CHW/HW return (HP entering)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={100,-200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={500,-400}))); + Modelica.Fluid.Interfaces.FluidPorts_b ports_bHeaWat[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumChiWatPriDed + "HW supply (to primary loop)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={-180,200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={-660,400}))); + Modelica.Fluid.Interfaces.FluidPorts_b ports_bChiWat[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumChiWatPriDed + "CHW supply (to primary loop)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={-20,200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={-340,400}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aChiHeaWatHp[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + "CHW/HW supply (HP leaving)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={-100,-200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={-500,-400}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus bus + "Plant control bus" + annotation (Placement(transformation(extent={{20,180},{60,220}}), + iconTransformation(extent={{-20,380},{20,420}}))); + Buildings.Templates.Components.Pumps.Multiple pumHeaWat( + redeclare final package Medium=Medium, + final have_var=have_pumHeaWatPriVar, + final have_varCom=false, + final nPum=nPum, + final dat=datPumHeaWat, + final dpValChe_nominal=dpValCheHeaWat_nominal, + final allowFlowReversal=allowFlowReversal, + final tau=tau, + final energyDynamics=energyDynamics) + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Dedicated primary (HW) Pumps" + annotation (Placement(transformation(extent={{-130,-70},{-150,-50}}))); + Buildings.Templates.Components.Pumps.Multiple pumChiWat( + redeclare final package Medium=Medium, + final have_var=have_pumChiWatPriVar, + final have_varCom=false, + final nPum=if have_pumChiWatPriDed then nPum else 0, + final dat=datPumChiWat, + final dpValChe_nominal=dpValCheChiWat_nominal, + final allowFlowReversal=allowFlowReversal, + final tau=tau, + final energyDynamics=energyDynamics) + if have_pumChiWatPriDed + "Dedicated primary CHW pumps - Optional" + annotation (Placement(transformation(extent={{-48,-70},{-28,-50}}))); + Buildings.Templates.Components.Routing.PassThroughFluid pasHdr[nHp]( + redeclare each final package Medium = Medium) if typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Headered + "Direct fluid pass-through for headered primary pumps" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-100,-140}))); + Fluid.FixedResistances.Junction junDedSep[nPum]( + redeclare each final package Medium =Medium, + final m_flow_nominal={{ + max(datPumHeaWat.m_flow_nominal[i], datPumChiWat.m_flow_nominal[i]), + -datPumHeaWat.m_flow_nominal[i], + -datPumChiWat.m_flow_nominal[i]} for i in 1:nPum}, + dp_nominal=fill(fill(0, 3), nPum), + each final energyDynamics=energyDynamics, + each final portFlowDirection_1=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional else + Modelica.Fluid.Types.PortFlowDirection.Entering, + each final portFlowDirection_2=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional else + Modelica.Fluid.Types.PortFlowDirection.Leaving, + each final portFlowDirection_3=if allowFlowReversal then + Modelica.Fluid.Types.PortFlowDirection.Bidirectional else + Modelica.Fluid.Types.PortFlowDirection.Leaving) + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumChiWatPriDed + "Fluid junction for separate dedicated primary pumps" annotation (Placement( + transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-80,-140}))); + Buildings.Templates.Components.Routing.PassThroughFluid pasDedCom[nHp]( + redeclare each final package Medium = Medium) if typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Dedicated and not + have_pumChiWatPriDed + "Direct fluid pass-through for common dedicated primary pumps" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-120,-140}))); +protected + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatPri + "Primary HW pump control bus" + annotation (Placement(transformation(extent={{-20,-120},{20,-80}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumChiWatPri + if have_pumChiWatPriDed + "Primary CHW pump control bus" + annotation (Placement(transformation(extent={{-20,-70},{20,-30}}), + iconTransformation(extent={{-466,50},{-426,90}}))); +equation + connect(bus.pumHeaWatPri, busPumHeaWatPri) + annotation (Line(points={{40,200},{40,-100},{0,-100}}, + color={255,204,51},thickness=0.5)); + connect(bus.pumChiWatPri, busPumChiWatPri) + annotation (Line(points={{40,200},{40,-50},{0,-50}},color={255,204,51},thickness=0.5)); + connect(pumHeaWat.ports_b, ports_bHeaWat) + annotation (Line(points={{-150,-60},{-180,-60},{-180,200}}, + color={0,127,255})); + connect(pumHeaWat.ports_b, ports_bChiHeaWat) + annotation (Line(points={{-150,-60},{-160,-60},{-160,180},{-100,180},{-100, + 200}}, + color={0,127,255})); + connect(pumChiWat.ports_b, ports_bChiWat) + annotation (Line(points={{-28,-60},{-20,-60},{-20,200}}, + color={0,127,255})); + connect(busPumHeaWatPri, pumHeaWat.bus) + annotation (Line(points={{0,-100},{-140,-100},{-140,-50}}, color={255,204,51},thickness=0.5)); + connect(busPumChiWatPri, pumChiWat.bus) + annotation (Line(points={{0,-50},{-38,-50}},color={255,204,51},thickness=0.5)); + connect(ports_aChiHeaWat, ports_bChiHeaWatHp) + annotation (Line(points={{100,200},{100,-200}},color={0,127,255})); + connect(ports_aChiHeaWatHp, pasHdr.port_a) + annotation (Line(points={{-100,-200},{-100,-150}}, color={0,127,255})); + connect(pasHdr.port_b, ports_bChiHeaWat) + annotation (Line(points={{-100,-130},{-100,200}}, color={0,127,255})); + connect(junDedSep.port_3, pumChiWat.ports_a) annotation (Line(points={{-70, + -140},{-60,-140},{-60,-60},{-48,-60}}, + color={0,127,255})); + connect(ports_aChiHeaWatHp, pasDedCom.port_a) annotation (Line(points={{-100, + -200},{-120,-200},{-120,-150}}, color={0,127,255})); + connect(pasDedCom.port_b, pumHeaWat.ports_a) annotation (Line(points={{-120, + -130},{-120,-60},{-130,-60}}, + color={0,127,255})); + connect(ports_aChiHeaWatHp, junDedSep.port_1) annotation (Line(points={{-100, + -200},{-80,-200},{-80,-150}}, color={0,127,255})); + connect(junDedSep.port_2, pumHeaWat.ports_a) annotation (Line(points={{-80, + -130},{-80,-60},{-130,-60}}, + color={0,127,255})); + annotation ( + defaultComponentName="pumPri", + Diagram( + coordinateSystem( + extent={{-200,-200},{200,200}})), + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-2400,-400},{2400,400}}), graphics={ + Line( + points={{2000,60},{2000,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nHp >= 1), + Line( + points={{2000,400},{2000,60}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 1), + Line( + points={{2200,400},{2200,-400}}, + color={0,0,0}, + thickness=5, + pattern=LinePattern.Dash, + visible=nHp >= 1), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 1, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={2022,10}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 1, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={2000,260}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumHeaWatPriVar and nHp >= 1, + extent={{2080,-50},{2180,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{2020,-40},{2020,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 1), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 1, + extent={{-50,-50},{50,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={1822,10}, + rotation=90), + Line( + points={{1800,400},{1800,60}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 1), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 1, + extent={{-40,-40},{40,40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={1800,260}, + rotation=90), + Line( + points={{1820,-40},{1820,-200},{2020,-200}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 1), + Bitmap( + visible=have_pumChiWatPriDed and have_pumChiWatPriVar and nHp >= 1, + extent={{1660,-50},{1760,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{2066,0},{2080,0}}, + color={0,0,0}, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 1), + Line( + points={{1760,0},{1778,0}}, + color={0,0,0}, + visible=have_pumChiWatPriDed and nHp >= 1), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumHeaWatPriVar and nHp >= 1, + extent={{2080,-50},{2180,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Bitmap( + visible=have_pumChiWatPriDed and not have_pumChiWatPriVar and nHp >= + 1, + extent={{1660,-104},{1760,-4}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + points={{-2000,60},{-2000,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nHp >= 6), + Line( + points={{-2000,400},{-2000,60}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 6), + Line( + points={{-1800,400},{-1800,-400}}, + color={0,0,0}, + thickness=5, + pattern=LinePattern.Dash, + visible=nHp >= 6), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 6, + extent={{-50,-50},{50,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={-1978,10}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 6, + extent={{-40,-40},{40,40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={-2000,260}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumHeaWatPriVar and nHp >= 6, + extent={{-1920,-50},{-1820,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{-1980,-40},{-1980,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 6), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 6, + extent={{-50,-50},{50,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={-2178,10}, + rotation=90), + Line( + points={{-2200,400},{-2200,60}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 6), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 6, + extent={{-40,-40},{40,40}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={-2200,260}, + rotation=90), + Line( + points={{-2180,-40},{-2180,-200},{-1980,-200}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 6), + Bitmap( + visible=have_pumChiWatPriDed and have_pumChiWatPriVar and nHp >= 6, + extent={{-2340,-50},{-2240,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{-1934,0},{-1920,0}}, + color={0,0,0}, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 6), + Line( + points={{-2240,0},{-2222,0}}, + color={0,0,0}, + visible=have_pumChiWatPriDed and nHp >= 6), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumHeaWatPriVar and nHp >= 6, + extent={{-1920,-50},{-1820,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Bitmap( + visible=have_pumChiWatPriDed and not have_pumChiWatPriVar and nHp >= 6, + extent={{-2340,-50},{-2240,50}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + points={{-1200,60},{-1200,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nHp >= 5), + Line( + points={{-1200,400},{-1200,60}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 5), + Line( + points={{-1000,400},{-1000,-400}}, + color={0,0,0}, + thickness=5, + pattern=LinePattern.Dash, + visible=nHp >= 5), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 5, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={-1178,10}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 5, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={-1200,260}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumHeaWatPriVar and nHp >= 5, + extent={{-1120,-50},{-1020,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{-1180,-40},{-1180,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 5), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 5, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={-1378,10}, + rotation=90), + Line( + points={{-1400,400},{-1400,60}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 5), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 5, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={-1400,260}, + rotation=90), + Line( + points={{-1380,-40},{-1380,-200},{-1180,-200}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 5), + Bitmap( + visible=have_pumChiWatPriDed and have_pumChiWatPriVar and nHp >= 5, + extent={{-1540,-50},{-1440,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{-1134,0},{-1120,0}}, + color={0,0,0}, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 5), + Line( + points={{-1440,0},{-1422,0}}, + color={0,0,0}, + visible=have_pumChiWatPriDed and nHp >= 5), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumHeaWatPriVar and nHp >= 5, + extent={{-1120,-50},{-1020,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Bitmap( + visible=have_pumChiWatPriDed and not have_pumChiWatPriVar and nHp >= + 5, + extent={{-1540,-50},{-1440,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + points={{-400,60},{-400,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nHp >= 4), + Line( + points={{-400,400},{-400,60}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 4), + Line( + points={{-200,400},{-200,-400}}, + color={0,0,0}, + thickness=5, + pattern=LinePattern.Dash, + visible=nHp >= 4), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 4, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={-378,10}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 4, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={-400,260}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumHeaWatPriVar and nHp >= 4, + extent={{-320,-50},{-220,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{-380,-40},{-380,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 4), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 4, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={-578,10}, + rotation=90), + Line( + points={{-600,400},{-600,60}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 4), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 4, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={-600,260}, + rotation=90), + Line( + points={{-580,-40},{-580,-200},{-380,-200}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 4), + Bitmap( + visible=have_pumChiWatPriDed and have_pumChiWatPriVar and nHp >= 4, + extent={{-740,-50},{-640,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{-334,0},{-320,0}}, + color={0,0,0}, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 4), + Line( + points={{-640,0},{-622,0}}, + color={0,0,0}, + visible=have_pumChiWatPriDed and nHp >= 4), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumHeaWatPriVar and nHp >= 4, + extent={{-320,-50},{-220,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Bitmap( + visible=have_pumChiWatPriDed and not have_pumChiWatPriVar and nHp >= + 4, + extent={{-740,-50},{-640,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + points={{400,60},{400,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nHp >= 3), + Line( + points={{400,400},{400,60}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 3), + Line( + points={{600,400},{600,-400}}, + color={0,0,0}, + thickness=5, + pattern=LinePattern.Dash, + visible=nHp >= 3), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 3, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={422,10}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 3, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={400,260}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumHeaWatPriVar and nHp >= 3, + extent={{480,-50},{580,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{420,-40},{420,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 3), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 3, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={222,10}, + rotation=90), + Line( + points={{200,400},{200,60}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 3), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 3, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={200,260}, + rotation=90), + Line( + points={{220,-40},{220,-200},{420,-200}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 3), + Bitmap( + visible=have_pumChiWatPriDed and have_pumChiWatPriVar and nHp >= 3, + extent={{60,-50},{160,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{466,0},{480,0}}, + color={0,0,0}, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 3), + Line( + points={{160,0},{178,0}}, + color={0,0,0}, + visible=have_pumChiWatPriDed and nHp >= 3), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumHeaWatPriVar and nHp >= 3, + extent={{480,-50},{580,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Bitmap( + visible=have_pumChiWatPriDed and not have_pumChiWatPriVar and nHp >= + 3, + extent={{60,-50},{160,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Line( + points={{1200,60},{1200,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and nHp >= 2), + Line( + points={{1200,400},{1200,60}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 2), + Line( + points={{1400,400},{1400,-400}}, + color={0,0,0}, + thickness=5, + pattern=LinePattern.Dash, + visible=nHp >= 2), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 2, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={1222,10}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 2, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={1200,260}, + rotation=90), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and have_pumHeaWatPriVar and nHp >= 2, + extent={{1280,-50},{1380,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{1220,-40},{1220,-400}}, + color={0,0,0}, + thickness=5, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 2), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 2, + extent={{-50,-50},{50,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Pumps/Single.svg", + origin={1022,10}, + rotation=90), + Line( + points={{1000,400},{1000,60}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 2), + Bitmap( + visible=have_pumChiWatPriDed and nHp >= 2, + extent={{-40,-40},{40,40}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/Check.svg", + origin={1000,260}, + rotation=90), + Line( + points={{1020,-40},{1020,-200},{1220,-200}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 2), + Bitmap( + visible=have_pumChiWatPriDed and have_pumChiWatPriVar and nHp >= 2, + extent={{860,-50},{960,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/VFD.svg"), + Line( + points={{1266,0},{1280,0}}, + color={0,0,0}, + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and nHp >= 2), + Line( + points={{960,0},{978,0}}, + color={0,0,0}, + visible=have_pumChiWatPriDed and nHp >= 2), + Bitmap( + visible=typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and not have_pumHeaWatPriVar and nHp >= 2, + extent={{1280,-50},{1380,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg"), + Bitmap( + visible=have_pumChiWatPriDed and not have_pumChiWatPriVar and nHp >= + 2, + extent={{860,-50},{960,50}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/MotorStarter.svg")}), + Documentation(revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+", info=" +

+This model represents dedicated primary HW pumps and, optionally, +separate dedicated primary CHW pumps if the parameter +have_pumChiWatPriDed is set to true. +The pump components are connected to the heat pump outlet, +in a \"pump away\" configuration. +Variable speed or constant speed pumps can be modeled by +setting the parameters have_pumHeaWatPriVar +and have_pumChiWatPriVar. +If headered pumps are modeled +(typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Headered), +this component resolves to a direct fluid pass-through. +

+")); +end PumpsPrimaryDedicated; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Validation/HeatPumpGroupAirToWater.mo b/Buildings/Templates/Plants/HeatPumps/Components/Validation/HeatPumpGroupAirToWater.mo new file mode 100644 index 00000000000..b22dd0e9779 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Validation/HeatPumpGroupAirToWater.mo @@ -0,0 +1,386 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Validation; +model HeatPumpGroupAirToWater + "Validation model for heat pump group" + extends Modelica.Icons.Example; + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "CHW/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 Data.Controller datCtlPlaAwNrv( + cfg( + have_hrc = false, + have_inpSch = false, + have_chiWat=false, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=false, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + have_pumChiWatPriDed=false, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=hpAwNrv.is_rev, + typ=hpAwNrv.typ, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=hpAwNrv.cpChiWat_default, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + have_valHpInlIso=false, + have_valHpOutIso=false, + typMod=hpAwNrv.typMod, + cpHeaWat_default=hpAwNrv.cpHeaWat_default, + cpSou_default=hpAwNrv.cpSou_default, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=hpAwNrv.nHp, + nPumHeaWatPri=hpAwNrv.nHp, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=hpAwNrv.nHp, + nSenDpHeaWatRem=1, + nSenDpChiWatRem=1, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=datHpAwNrv.THeaWatSupHp_nominal, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlPlaAwNrv.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlPlaAwNrv.cfg.nSenDpHeaWatRem), + staEqu={fill(1, hpAwNrv.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-260,40},{-240,60}}))); + parameter Data.Controller datCtlPlaAw( + cfg( + have_hrc = false, + have_inpSch = false, + have_chiWat=true, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=true, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + have_pumChiWatPriDed=false, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=hpAw.is_rev, + typ=hpAw.typ, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=hpAw.cpChiWat_default, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + have_valHpInlIso=true, + have_valHpOutIso=true, + typMod=hpAw.typMod, + cpHeaWat_default=hpAw.cpHeaWat_default, + cpSou_default=hpAw.cpSou_default, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=hpAw.nHp, + nPumHeaWatPri=hpAw.nHp, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=hpAw.nHp, + nSenDpHeaWatRem=1, + nSenDpChiWatRem=1, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=datHpAw.THeaWatSupHp_nominal, + TChiWatSup_nominal=datHpAw.TChiWatSupHp_nominal, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlPlaAw.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlPlaAw.cfg.nSenDpHeaWatRem), + staEqu={fill(1, hpAw.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-260,-200},{-240,-180}}))); + + parameter Buildings.Templates.Plants.HeatPumps.Components.Data.HeatPumpGroup datHpAwNrv( + final cpHeaWat_default=hpAwNrv.cpHeaWat_default, + final cpSou_default=hpAwNrv.cpSou_default, + final nHp=hpAwNrv.nHp, + final typ=hpAwNrv.typ, + final is_rev=hpAwNrv.is_rev, + final typMod=hpAwNrv.typMod, + mHeaWatHp_flow_nominal=datHpAwNrv.capHeaHp_nominal / abs(datHpAwNrv.THeaWatSupHp_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWatHp_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHeaHp_nominal=500E3, + THeaWatSupHp_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TSouHeaHp_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + perFitHp( + hea( + P=datHpAwNrv.capHeaHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={- 4.2670305442, - 0.7381077035, 6.0049480456, 0, 0}, + coeP={- 4.9107455513, 5.3665308366, 0.5447612754, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpHeaLow))) + "Non-reversible AWHP parameters" + annotation (Placement(transformation(extent={{-220,40},{-200,60}}))); + parameter Buildings.Templates.Plants.HeatPumps.Components.Data.HeatPumpGroup datHpAw( + final cpHeaWat_default=hpAw.cpHeaWat_default, + final cpSou_default=hpAw.cpSou_default, + final nHp=hpAw.nHp, + final typ=hpAw.typ, + final is_rev=hpAw.is_rev, + final typMod=hpAw.typMod, + mHeaWatHp_flow_nominal=datHpAw.capHeaHp_nominal / abs(datHpAw.THeaWatSupHp_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWatHp_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHeaHp_nominal=500E3, + THeaWatSupHp_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TSouHeaHp_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + mChiWatHp_flow_nominal=datHpAw.capCooHp_nominal / abs(datHpAw.TChiWatSupHp_nominal - + Buildings.Templates.Data.Defaults.TChiWatRet) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + capCooHp_nominal=500E3, + TChiWatSupHp_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + TSouCooHp_nominal=Buildings.Templates.Data.Defaults.TOutHpCoo, + perFitHp( + hea( + P=datHpAw.capHeaHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={- 4.2670305442, - 0.7381077035, 6.0049480456, 0, 0}, + coeP={- 4.9107455513, 5.3665308366, 0.5447612754, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpHeaLow), + coo( + P=datHpAw.capCooHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwCoo, + coeQ={- 2.2545246871, 6.9089257665, - 3.6548225094, 0, 0}, + coeP={- 5.8086010402, 1.6894933858, 5.1167787436, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.TChiWatRet, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpCoo))) + "Reversible AWHP parameters" + annotation (Placement(transformation(extent={{-220,-200},{-200,-180}}))); + Fluid.Sources.Boundary_pT sup( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=hpAwNrv.nHp) + "Boundary condition at distribution system supply" + annotation (Placement(transformation(extent={{120,130},{100,150}}))); + Fluid.Sources.Boundary_pT inlHp1( + redeclare final package Medium=Medium, + use_p_in=true, + use_T_in=true, + nPorts=hpAwNrv.nHp) + "Boundary conditions at HP inlet" + annotation (Placement(transformation(extent={{-120,150},{-100,170}}))); + BoundaryConditions.WeatherData.ReaderTMY3 weaDat( + filNam=Modelica.Utilities.Files.loadResource( + "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos")) + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=0, + origin={180,160}))); + Fluid.Sensors.TemperatureTwoPort TRet1[hpAwNrv.nHp]( + redeclare each final package Medium=Medium, + each final m_flow_nominal=datHpAwNrv.mHeaWatHp_flow_nominal) + "Return temperature" + annotation (Placement(transformation(extent={{-80,150},{-60,170}}))); + Fluid.Sensors.TemperatureTwoPort TSup1[hpAwNrv.nHp]( + redeclare each final package Medium=Medium, + each final m_flow_nominal=datHpAwNrv.mHeaWatHp_flow_nominal) + "Supply temperature" + annotation (Placement(transformation(extent={{60,130},{80,150}}))); + Controls.OpenLoop ctlPlaAwNrv( + final cfg=datCtlPlaAwNrv.cfg, + final dat=datCtlPlaAwNrv) + "Plant controller" + annotation (Placement(transformation(extent={{10,170},{-10,190}}))); + HeatPumpGroups.AirToWater hpAwNrv( + redeclare final package MediumHeaWat=Medium, + nHp=3, + is_rev=false, + final dat=datHpAwNrv, + final energyDynamics=energyDynamics) + "Non reversible AWHP" + annotation (Placement(transformation(extent={{280,40},{-200,120}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin THeaWatRet( + amplitude=datHpAwNrv.THeaWatSupHp_nominal - datHpAwNrv.THeaWatRetHp_nominal, + freqHz=3 / 3000, + y(final unit="K", + displayUnit="degC"), + offset=datHpAwNrv.THeaWatRetHp_nominal, + startTime=0) + "HW return temperature value" + annotation (Placement(transformation(extent={{-290,130},{-270,150}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pHeaWatInl( + k=sup.p + datHpAwNrv.dpHeaWatHp_nominal) + "HW inlet pressure" + annotation (Placement(transformation(extent={{-290,170},{-270,190}}))); + HeatPumpGroups.AirToWater hpAw( + redeclare final package MediumHeaWat=Medium, + nHp=3, + is_rev=true, + final dat=datHpAw, + final energyDynamics=energyDynamics) + "Reversible AWHP" + annotation (Placement(transformation(extent={{280,-200},{-200,-120}}))); + Controls.OpenLoop ctlPlaAw( + final cfg=datCtlPlaAw.cfg, + final dat=datCtlPlaAw) + "Plant controller" + annotation (Placement(transformation(extent={{-20,-30},{-40,-10}}))); + Fluid.Sources.Boundary_pT inlHp( + redeclare final package Medium=Medium, + use_p_in=true, + use_T_in=true, + nPorts=hpAwNrv.nHp) + "Boundary conditions at HP inlet" + annotation (Placement(transformation(extent={{-120,-50},{-100,-30}}))); + Fluid.Sensors.TemperatureTwoPort TRet[hpAw.nHp]( + redeclare each final package Medium=Medium, + each final m_flow_nominal=datHpAw.mHeaWatHp_flow_nominal) + "Return temperature" + annotation (Placement(transformation(extent={{-80,-50},{-60,-30}}))); + Fluid.Sources.Boundary_pT sup1( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=hpAwNrv.nHp) + "Boundary condition at distribution system supply" + annotation (Placement(transformation(extent={{120,-50},{100,-30}}))); + Fluid.Sensors.TemperatureTwoPort TSup[hpAw.nHp]( + redeclare each final package Medium=Medium, + each final m_flow_nominal=datHpAw.mHeaWatHp_flow_nominal) + "Supply temperature" + annotation (Placement(transformation(extent={{60,-50},{80,-30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin THeaWatRet1( + amplitude=datHpAw.THeaWatSupHp_nominal - datHpAw.THeaWatRetHp_nominal, + freqHz=3 / 3000, + y(final unit="K", + displayUnit="degC"), + offset=datHpAw.THeaWatRetHp_nominal, + startTime=0) + "HW return temperature value" + annotation (Placement(transformation(extent={{-290,-70},{-270,-50}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Sin TChiWatRet( + amplitude=datHpAw.TChiWatRetHp_nominal - datHpAw.TChiWatSupHp_nominal, + freqHz=3 / 3000, + y(final unit="K", + displayUnit="degC"), + offset=datHpAw.TChiWatRetHp_nominal, + startTime=0) + "CHW return temperature value" + annotation (Placement(transformation(extent={{-290,-110},{-270,-90}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pHeaWatInl1( + k=sup.p + hpAw.dpHeaWatHp_nominal) + "HW inlet pressure" + annotation (Placement(transformation(extent={{-290,10},{-270,30}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant pChiWatInl( + k=sup.p + hpAw.dpChiWatHp_nominal) + "CHW inlet pressure" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={-280,-20}))); + Buildings.Controls.OBC.CDL.Reals.Switch TRetAct + "Active return temperature" + annotation (Placement(transformation(extent={{-240,-90},{-220,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Switch pInl_rel + "Active inlet gaupe pressure" + annotation (Placement(transformation(extent={{-240,-10},{-220,10}}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus busPla + "Plant controller" + annotation (Placement(iconVisible=false,transformation(extent={{-20,-20},{20,20}}), + iconTransformation(extent={{-548,-190},{-508,-150}}))); + Buildings.Templates.Components.Interfaces.Bus busHp[hpAw.nHp] + "HP control bus" + annotation (Placement(iconVisible=false,transformation(extent={{-120,-20},{-80,20}}), + iconTransformation(extent={{-536,100},{-496,140}}))); +equation + connect(ctlPlaAwNrv.bus, hpAwNrv.bus) + annotation (Line(points={{10,180},{40,180},{40,120}}, + color={255,204,51},thickness=0.5)); + connect(inlHp1.ports, TRet1.port_a) + annotation (Line(points={{-100,160},{-80,160}},color={0,127,255})); + connect(TRet1.port_b, hpAwNrv.ports_aChiHeaWat) + annotation (Line(points={{-60,160},{-10,160},{-10,120}},color={0,127,255})); + connect(hpAwNrv.ports_bChiHeaWat, TSup1.port_a) + annotation (Line(points={{90,120},{90,140},{60,140}},color={0,127,255})); + connect(TSup1.port_b, sup.ports) + annotation (Line(points={{80,140},{100,140}},color={0,127,255})); + connect(weaDat.weaBus, hpAwNrv.busWea) + annotation (Line(points={{170,160},{60,160},{60,120}},color={255,204,51},thickness=0.5)); + connect(THeaWatRet.y, inlHp1.T_in) + annotation (Line(points={{-268,140},{-140,140},{-140,164},{-122,164}},color={0,0,127})); + connect(pHeaWatInl.y, inlHp1.p_in) + annotation (Line(points={{-268,180},{-140,180},{-140,168},{-122,168}},color={0,0,127})); + connect(weaDat.weaBus, hpAw.busWea) + annotation (Line(points={{170,160},{160,160},{160,0},{60,0},{60,-120}}, + color={255,204,51},thickness=0.5)); + connect(ctlPlaAw.bus, hpAw.bus) + annotation (Line(points={{-20,-20},{40,-20},{40,-120}}, + color={255,204,51},thickness=0.5)); + connect(inlHp.ports, TRet.port_a) + annotation (Line(points={{-100,-40},{-80,-40}},color={0,127,255})); + connect(TRet.port_b, hpAw.ports_aChiHeaWat) + annotation (Line(points={{-60,-40},{-10,-40},{-10,-120}}, + color={0,127,255})); + connect(TSup.port_b, sup1.ports) + annotation (Line(points={{80,-40},{100,-40}},color={0,127,255})); + connect(hpAw.ports_bChiHeaWat, TSup.port_a) + annotation (Line(points={{90,-120},{90,-40},{60,-40}}, + color={0,127,255})); + connect(THeaWatRet1.y, TRetAct.u1) + annotation (Line(points={{-268,-60},{-260,-60},{-260,-72},{-242,-72}},color={0,0,127})); + connect(TChiWatRet.y, TRetAct.u3) + annotation (Line(points={{-268,-100},{-250,-100},{-250,-88},{-242,-88}}, + color={0,0,127})); + connect(pHeaWatInl1.y, pInl_rel.u1) + annotation (Line(points={{-268,20},{-260,20},{-260,8},{-242,8}},color={0,0,127})); + connect(pChiWatInl.y, pInl_rel.u3) + annotation (Line(points={{-268,-20},{-260,-20},{-260,-8},{-242,-8}},color={0,0,127})); + connect(pInl_rel.y, inlHp.p_in) + annotation (Line(points={{-218,0},{-132,0},{-132,-32},{-122,-32}},color={0,0,127})); + connect(TRetAct.y, inlHp.T_in) + annotation (Line(points={{-218,-80},{-132,-80},{-132,-36},{-122,-36}},color={0,0,127})); + connect(busPla, ctlPlaAw.bus) + annotation (Line(points={{0,0},{0,-20},{-20,-20}},color={255,204,51},thickness=0.5)); + connect(busPla.hp, busHp) + annotation (Line(points={{0,0},{-100,0}},color={255,204,51},thickness=0.5)); + connect(busHp[1].y1Hea, pInl_rel.u2) + annotation (Line(points={{-100,0},{-100,20},{-250,20},{-250,0},{-242,0}}, + color={255,204,51},thickness=0.5)); + connect(pInl_rel.u2, TRetAct.u2) + annotation (Line(points={{-242,0},{-250,0},{-250,-80},{-242,-80}},color={255,0,255})); + annotation ( + Diagram( + coordinateSystem( + extent={{-300,-220},{300,220}})), + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Components/Validation/HeatPumpGroupAirToWater.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StartTime=10497600.0, + StopTime=10505600.0), + Documentation( + info=" +

+This model validates the model + +Buildings.Templates.Plants.HeatPumps.Components.HeatPumpGroups.AirToWater +in a configuration in which the heat pump components are exposed +to a constant differential pressure and a varying +return temperature. +

+

+The model is configured to represent either a non-reversible heat pump +(component hpAwNrv) or a reversible heat pump +(component hpAw) that switches between cooling and heating +mode. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end HeatPumpGroupAirToWater; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Validation/PumpsPrimaryDedicated.mo b/Buildings/Templates/Plants/HeatPumps/Components/Validation/PumpsPrimaryDedicated.mo new file mode 100644 index 00000000000..f75e6661008 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Validation/PumpsPrimaryDedicated.mo @@ -0,0 +1,694 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Validation; +model PumpsPrimaryDedicated + "Validation model for dedicated primary pump component" + extends Modelica.Icons.Example; + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "CHW/HW medium"; + parameter Boolean use_spePumIni = false + "Set to true to compute pump speed at initialization, false to use default value" + annotation(Evaluate=true); + 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")); + // Calculation of pump speed to meet design flow. + parameter Real r_N[pumPriHea.nPum]( + each final fixed=false, + each start=1, + each final unit="1") + "Relative revolution, r_N=N/N_nominal"; + parameter Real r_NDef[pumPriHea.nPum]( + each start=1, + each final unit="1")=fill(0.85, pumPriHea.nPum) + "Default value for relative revolution, r_N=N/N_nominal"; + parameter Data.Controller datCtl( + cfg( + have_pumHeaWatPriVar=false, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=false, + have_valHpInlIso=true, + have_chiWat=true, + have_pumChiWatPriDed=false, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=true, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=2, + nPumHeaWatPri=2, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=0, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtl.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtl.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtl.cfg.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-160,290},{-140,310}}))); + parameter Data.Controller datCtlNoDed( + cfg( + have_pumHeaWatPriVar=false, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=false, + have_valHpInlIso=true, + have_chiWat=true, + have_pumChiWatPriDed=false, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=true, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Headered, + nHp=2, + nPumHeaWatPri=2, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=0, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlNoDed.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlNoDed.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtlNoDed.cfg.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-160,110},{-140,130}}))); + parameter Data.Controller datCtlSep( + cfg( + have_pumHeaWatPriVar=false, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=false, + have_valHpInlIso=true, + have_chiWat=true, + have_pumChiWatPriDed=true, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=true, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=2, + nPumHeaWatPri=2, + nPumChiWatPri=2, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlSep.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlSep.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtlSep.cfg.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-160,-130},{-140,-110}}))); + parameter Data.Controller datCtlHea( + cfg( + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=false, + have_valHpInlIso=false, + have_chiWat=false, + have_pumChiWatPriDed=false, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=false, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=2, + nPumHeaWatPri=2, + nPumChiWatPri=0, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlHea.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlHea.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtlHea.cfg.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-160,-370},{-140,-350}}))); + parameter Data.HeatPumpGroup datHp( + final nHp=2, + final typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + final is_rev=true, + final typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + mHeaWatHp_flow_nominal=datHp.capHeaHp_nominal / abs(datHp.THeaWatSupHp_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWatHp_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHeaHp_nominal=500E3, + THeaWatSupHp_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TSouHeaHp_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + mChiWatHp_flow_nominal=datHp.capCooHp_nominal / abs(datHp.TChiWatSupHp_nominal - + Buildings.Templates.Data.Defaults.TChiWatRet) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + capCooHp_nominal=500E3, + TChiWatSupHp_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + TSouCooHp_nominal=Buildings.Templates.Data.Defaults.TOutHpCoo, + perFitHp( + hea( + P=datHp.capHeaHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={- 4.2670305442, - 0.7381077035, 6.0049480456, 0, 0}, + coeP={- 4.9107455513, 5.3665308366, 0.5447612754, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpHeaLow), + coo( + P=datHp.capCooHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwCoo, + coeQ={- 2.2545246871, 6.9089257665, - 3.6548225094, 0, 0}, + coeP={- 5.8086010402, 1.6894933858, 5.1167787436, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.TChiWatRet, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpCoo))) + "HP parameters" + annotation (Placement(transformation(extent={{-160,220},{-140,240}}))); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumPriCom( + typ=Buildings.Templates.Components.Types.Pump.Multiple, + nPum=datHp.nHp, + m_flow_nominal=fill(max(datHp.mHeaWatHp_flow_nominal, datHp.mChiWatHp_flow_nominal), + datHp.nHp), + dp_nominal=fill(max(datHp.dpHeaWatHp_nominal, datHp.dpChiWatHp_nominal) + + Buildings.Templates.Data.Defaults.dpValChe + max(max(valChiWatIsoCom.dpValve_nominal), + max(valHeaWatIsoCom.dpValve_nominal)), datHp.nHp)) + "Primary pump parameters" + annotation (Placement(transformation(extent={{-120,220},{-100,240}}))); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumHeaWat( + typ=Buildings.Templates.Components.Types.Pump.Multiple, + nPum=datHp.nHp, + m_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, datHp.nHp), + dp_nominal=fill(datHp.dpHeaWatHp_nominal + Buildings.Templates.Data.Defaults.dpValChe + + max(valHeaWatIsoCom.dpValve_nominal), datHp.nHp)) + "Dedicated primary HW pump parameters" + annotation (Placement(transformation(extent={{-160,-200},{-140,-180}}))); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumChiWat( + typ=Buildings.Templates.Components.Types.Pump.Multiple, + nPum=datHp.nHp, + m_flow_nominal=fill(datHp.mChiWatHp_flow_nominal, datHp.nHp), + dp_nominal=fill(datHp.dpChiWatHp_nominal + Buildings.Templates.Data.Defaults.dpValChe + + max(valHeaWatIsoCom.dpValve_nominal), datHp.nHp)) + "Dedicated primary CHW pump parameters" + annotation (Placement(transformation(extent={{-120,-200},{-100,-180}}))); + parameter Buildings.Templates.Components.Data.PumpMultiple datPumHeaWatHea( + typ=Buildings.Templates.Components.Types.Pump.Multiple, + nPum=datHp.nHp, + m_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, datHp.nHp), + dp_nominal=1.5 * fill(datHp.dpHeaWatHp_nominal + Buildings.Templates.Data.Defaults.dpValChe + + max(valHeaWatIsoCom.dpValve_nominal), datHp.nHp)) + "Dedicated primary HW pump parameters – Heating-only system" + annotation (Placement(transformation(extent={{-160,-200},{-140,-180}}))); + final parameter Buildings.Templates.Components.Data.PumpSingle datPumSin[ + pumPriCom.nHp]( + each typ=datPumPriCom.typ, + m_flow_nominal=datPumPriCom.m_flow_nominal, + dp_nominal=datPumPriCom.dp_nominal, + per=datPumPriCom.per, + each rho_default=datPumPriCom.rho_default) + "Cast multiple pump record into single pump record array"; + final parameter Buildings.Templates.Components.Data.PumpSingle datPumHeaWatHeaSin[pumPriHea.nHp]( + each typ=datPumHeaWatHea.typ, + m_flow_nominal=datPumHeaWatHea.m_flow_nominal, + dp_nominal=datPumHeaWatHea.dp_nominal, + per=datPumHeaWatHea.per, + each rho_default=datPumHeaWatHea.rho_default) + "Cast multiple pump record into single pump record array"; + Buildings.Templates.Plants.HeatPumps.Components.PumpsPrimaryDedicated + pumPriCom( + redeclare final package Medium = Medium, + nHp=2, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + have_pumChiWatPriDed=false, + have_pumHeaWatPriVar=false, + have_pumChiWatPriVar=false, + datPumHeaWat=datPumPriCom, + final energyDynamics=energyDynamics) + "Primary pumps - Heating and cooling system with common constant speed dedicated primary pumps" + annotation (Placement(transformation(extent={{-240,160},{240,240}}))); + Fluid.FixedResistances.PressureDrop hpCom[pumPriCom.nHp]( + redeclare each final package Medium = Medium, + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dp_nominal=datHp.dpHeaWatHp_nominal) "Heat pump HX" + annotation (Placement(transformation(extent={{10,150},{-10,170}}))); + Fluid.Sources.Boundary_pT ret( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=datHp.nHp) + "Boundary condition at return" + annotation (Placement(transformation(extent={{80,270},{60,290}}))); + Controls.OpenLoop ctl( + final cfg=datCtl.cfg, + final dat=datCtl) + "Plant controller" + annotation (Placement(transformation(extent={{-100,290},{-120,310}}))); + Buildings.Templates.Plants.HeatPumps.Components.PumpsPrimaryDedicated + pumPriNoDed( + redeclare final package Medium = Medium, + nHp=2, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Headered, + have_pumChiWatPriDed=false, + have_pumHeaWatPriVar=false, + have_pumChiWatPriVar=false, + datPumHeaWat=datPumPriCom, + final energyDynamics=energyDynamics) + "No dedicated primary pumps (headered pumps)" + annotation (Placement(transformation(extent={{-240,-60},{240,20}}))); + Fluid.FixedResistances.PressureDrop hpHdr[pumPriCom.nHp]( + redeclare each final package Medium = Medium, + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dp_nominal=datHp.dpHeaWatHp_nominal) + "Heat pump HX" + annotation (Placement(transformation(extent={{10,-70},{-10,-50}}))); + Fluid.Sources.Boundary_pT ret1( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=datHp.nHp) + "Boundary condition at return" + annotation (Placement(transformation(extent={{70,70},{50,90}}))); + Controls.OpenLoop ctlNoDed( + final cfg=datCtlNoDed.cfg, + final dat=datCtlNoDed) + "Plant controller" + annotation (Placement(transformation(extent={{-100,110},{-120,130}}))); + Buildings.Templates.Components.Pumps.Multiple pumPriHdr( + have_var=false, + final energyDynamics=energyDynamics, + nPum=2, + dat=datPumPriCom) "Headered primary pumps" + annotation (Placement(transformation(extent={{-70,50},{-50,70}}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus busPla + "Plant control bus" + annotation (Placement(iconVisible=false,transformation(extent={{-100,100},{-60, + 140}}), + iconTransformation(extent={{-332,42},{-292,82}}))); + Buildings.Templates.Plants.HeatPumps.Components.PumpsPrimaryDedicated pumPriSep( + redeclare final package Medium=Medium, + nHp=2, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + have_pumChiWatPriDed=true, + have_pumHeaWatPriVar=false, + have_pumChiWatPriVar=false, + datPumHeaWat=datPumHeaWat, + final datPumChiWat=datPumChiWat, + final energyDynamics=energyDynamics) + "Primary pumps - Heating and cooling system with separate constant speed dedicated CHW pumps" + annotation (Placement(transformation(extent={{-240,-260},{240,-180}}))); + Fluid.Sources.Boundary_pT ret2( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=datHp.nHp) + "Boundary condition at return" + annotation (Placement(transformation(extent={{90,-150},{70,-130}}))); + Controls.OpenLoop ctlSep( + final cfg=datCtlSep.cfg, + final dat=datCtlSep) + "Plant controller" + annotation (Placement(transformation(extent={{-100,-130},{-120,-110}}))); + Fluid.FixedResistances.PressureDrop hpSep[pumPriCom.nHp]( + redeclare each final package Medium = Medium, + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dp_nominal=datHp.dpHeaWatHp_nominal) "Heat pump HX" + annotation (Placement(transformation(extent={{10,-270},{-10,-250}}))); + Buildings.Templates.Components.Actuators.Valve valHeaWatIsoCom[datHp.nHp]( + redeclare each final package Medium = Medium, + each typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition, + dat( + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValIso, + dpFixed_nominal= + Buildings.Templates.Utilities.computeBalancingPressureDrop( + m_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, datHp.nHp), + dp_nominal=pumPriCom.dpValCheHeaWat_nominal*(datHp.mHeaWatHp_flow_nominal + /max(datHp.mHeaWatHp_flow_nominal, datHp.mChiWatHp_flow_nominal))^2 .+ + fill(datHp.dpHeaWatHp_nominal, datHp.nHp) .+ valHeaWatIsoCom.dpValve_nominal, + datPum=datPumSin)), + each from_dp=true) "Primary HW loop isolation valve" + annotation (Placement(transformation(extent={{-30,270},{-10,290}}))); + Buildings.Templates.Components.Actuators.Valve valChiWatIsoCom[datHp.nHp]( + redeclare each final package Medium = Medium, + each typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition, + dat( + each m_flow_nominal=datHp.mChiWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValIso, + dpFixed_nominal= + Buildings.Templates.Utilities.computeBalancingPressureDrop( + m_flow_nominal=fill(datHp.mChiWatHp_flow_nominal, datHp.nHp), + dp_nominal=pumPriCom.dpValCheHeaWat_nominal*(datHp.mChiWatHp_flow_nominal + /max(datHp.mHeaWatHp_flow_nominal, datHp.mChiWatHp_flow_nominal))^2 .+ + fill(datHp.dpChiWatHp_nominal, datHp.nHp) .+ valChiWatIsoCom.dpValve_nominal, + datPum=datPumSin)), + each from_dp=true) "Primary CHW loop isolation valve" + annotation (Placement(transformation(extent={{10,250},{30,270}}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus busPla1 + "Plant control bus" + annotation (Placement(iconVisible=false,transformation(extent={{-90,280},{-50,320}}), + iconTransformation(extent={{-332,42},{-292,82}}))); + Buildings.Templates.Components.Actuators.Valve valChiWatIsoHdr[datHp.nHp]( + redeclare each final package Medium = Medium, + each typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition, + dat( + each m_flow_nominal=datHp.mChiWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValIso, + dpFixed_nominal= + Buildings.Templates.Utilities.computeBalancingPressureDrop( + m_flow_nominal=fill(datHp.mChiWatHp_flow_nominal, datHp.nHp), + dp_nominal=pumPriHdr.dpValChe_nominal*(datHp.mChiWatHp_flow_nominal/ + max(datHp.mHeaWatHp_flow_nominal, datHp.mChiWatHp_flow_nominal))^2 .+ + fill(datHp.dpChiWatHp_nominal, datHp.nHp) .+ valChiWatIsoCom.dpValve_nominal, + datPum=datPumSin)), + each from_dp=true) "Primary CHW loop isolation valve" + annotation (Placement(transformation(extent={{10,50},{30,70}}))); + Buildings.Templates.Components.Actuators.Valve valHeaWatIsoHdr[datHp.nHp]( + redeclare each final package Medium = Medium, + each typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition, + dat( + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValIso, + dpFixed_nominal= + Buildings.Templates.Utilities.computeBalancingPressureDrop( + m_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, datHp.nHp), + dp_nominal=pumPriHdr.dpValChe_nominal*(datHp.mHeaWatHp_flow_nominal/ + max(datHp.mHeaWatHp_flow_nominal, datHp.mChiWatHp_flow_nominal))^2 .+ + fill(datHp.dpHeaWatHp_nominal, datHp.nHp) .+ valHeaWatIsoCom.dpValve_nominal, + datPum=datPumSin)), + each from_dp=true) "Primary HW loop isolation valve" + annotation (Placement(transformation(extent={{-30,70},{-10,90}}))); + Buildings.Templates.Components.Actuators.Valve valHeaWatIsoSep[datHp.nHp]( + redeclare each final package Medium=Medium, + each typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition, + dat( + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValIso), + each from_dp=true, + each linearized=true) + "Primary HW loop isolation valve" + annotation (Placement(transformation(extent={{-30,-150},{-10,-130}}))); + Buildings.Templates.Components.Actuators.Valve valChiWatIsoSep[datHp.nHp]( + redeclare each final package Medium=Medium, + each typ=Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition, + dat( + each m_flow_nominal=datHp.mChiWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValIso), + each from_dp=true, + each linearized=true) + "Primary CHW loop isolation valve" + annotation (Placement(transformation(extent={{10,-170},{30,-150}}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus busPla2 + "Plant control bus" + annotation (Placement(iconVisible=false,transformation(extent={{-100,-140},{-60,-100}}), + iconTransformation(extent={{-332,42},{-292,82}}))); + Buildings.Templates.Plants.HeatPumps.Components.PumpsPrimaryDedicated pumPriHea( + redeclare final package Medium=Medium, + nHp=2, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + have_pumChiWatPriDed=false, + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=false, + datPumHeaWat=datPumHeaWatHea, + final energyDynamics=energyDynamics) + "Primary pumps - Heating-only system with variable speed dedicated primary pumps" + annotation (Placement(transformation(extent={{-240,-460},{240,-380}}))); + Fluid.Sources.Boundary_pT ret3( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=1) + "Boundary condition at return" + annotation (Placement(transformation(extent={{90,-350},{70,-330}}))); + Controls.OpenLoop ctlHea( + final cfg=datCtlHea.cfg, + final dat=datCtlHea, + yPumHeaWatPriDed(k=r_N)) + "Plant controller" + annotation (Placement(transformation(extent={{-100,-370},{-120,-350}}))); + Fluid.FixedResistances.PressureDrop hpHea[pumPriCom.nHp]( + redeclare each final package Medium = Medium, + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dp_nominal=datHp.dpHeaWatHp_nominal) "Heat pump HX" + annotation (Placement(transformation(extent={{10,-470},{-10,-450}}))); + Fluid.FixedResistances.PressureDrop priHeaWat( + redeclare final package Medium=Medium, + final m_flow_nominal=sum(datPumHeaWat.m_flow_nominal), + final dp_nominal=0) + "Primary HW loop" + annotation (Placement(transformation(extent={{-10,-350},{10,-330}}))); +initial equation + // Calculation of pump speed to provide design flow. + if use_spePumIni then + fill(0, pumPriHea.nHp)=Buildings.Templates.Utilities.computeBalancingPressureDrop( + m_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, pumPriHea.nHp), + dp_nominal=pumPriHea.dpValCheHeaWat_nominal .+ fill(datHp.dpHeaWatHp_nominal, pumPriHea.nHp) .+ + fill(Buildings.Templates.Data.Defaults.dpValIso, pumPriHea.nHp), + datPum=datPumHeaWatHeaSin, + r_N=r_N); + else + r_N=r_NDef; + end if; +equation + for i in 1:(pumPriHea.nHp) loop + connect(pumPriHea.ports_bChiHeaWat[i], priHeaWat.port_a) + annotation (Line(points={{-50,-380},{-50,-340},{-10,-340}}, + color={0,127,255})); + connect(priHeaWat.port_b, pumPriHea.ports_aChiHeaWat[i]) + annotation (Line(points={{10,-340},{50,-340},{50,-380}},color={0,127,255})); + end for; + connect(pumPriCom.ports_bChiHeaWatHp, hpCom.port_a) + annotation (Line(points={{50,160},{10,160}}, color={0,127,255})); + connect(hpCom.port_b, pumPriCom.ports_aChiHeaWatHp) + annotation (Line(points={{-10,160},{-50,160}}, color={0,127,255})); + connect(pumPriNoDed.ports_bChiHeaWatHp, hpHdr.port_a) + annotation (Line(points={{50,-60},{10,-60}}, color={0,127,255})); + connect(hpHdr.port_b, pumPriNoDed.ports_aChiHeaWatHp) + annotation (Line(points={{-10,-60},{-50,-60}}, color={0,127,255})); + connect(pumPriNoDed.ports_bChiHeaWat, pumPriHdr.ports_a) + annotation (Line(points={{-50,20},{-80,20},{-80,60},{-70,60}}, color={0,127,255})); + connect(ctlNoDed.bus, busPla) + annotation (Line(points={{-100,120},{-80,120}},color={255,204,51},thickness=0.5)); + connect(busPla.pumHeaWatPri, pumPriHdr.bus) + annotation (Line(points={{-80,120},{-60,120},{-60,70}},color={255,204,51},thickness=0.5)); + connect(pumPriSep.ports_bChiHeaWatHp, hpSep.port_a) + annotation (Line(points={{50,-260},{10,-260}}, color={0,127,255})); + connect(hpSep.port_b, pumPriSep.ports_aChiHeaWatHp) + annotation (Line(points={{-10,-260},{-50,-260}}, color={0,127,255})); + connect(pumPriCom.ports_bChiHeaWat, valHeaWatIsoCom.port_a) annotation (Line( + points={{-50,240},{-50,280},{-30,280}}, color={0,127,255})); + connect(valHeaWatIsoCom.port_b, pumPriCom.ports_aChiHeaWat) + annotation (Line(points={{-10,280},{50,280},{50,240}}, color={0,127,255})); + connect(pumPriCom.ports_bChiHeaWat, valChiWatIsoCom.port_a) annotation (Line( + points={{-50,240},{-50,260},{10,260}}, color={0,127,255})); + connect(valChiWatIsoCom.port_b, pumPriCom.ports_aChiHeaWat) + annotation (Line(points={{30,260},{50,260},{50,240}}, color={0,127,255})); + connect(ctl.bus, busPla1) + annotation (Line(points={{-100,300},{-70,300}},color={255,204,51},thickness=0.5)); + connect(busPla1.valHeaWatHpInlIso, valHeaWatIsoCom.bus) annotation (Line( + points={{-70,300},{-20,300},{-20,290}}, + color={255,204,51}, + thickness=0.5)); + connect(busPla1.valChiWatHpInlIso, valChiWatIsoCom.bus) annotation (Line( + points={{-70,300},{20,300},{20,270}}, + color={255,204,51}, + thickness=0.5)); + connect(ret.ports, valHeaWatIsoCom.port_b) + annotation (Line(points={{60,280},{-10,280}}, color={0,127,255})); + connect(pumPriHdr.ports_b, valChiWatIsoHdr.port_a) + annotation (Line(points={{-50,60},{10,60}}, color={0,127,255})); + connect(pumPriHdr.ports_b, valHeaWatIsoHdr.port_a) annotation (Line(points={{-50, + 60},{-40,60},{-40,80},{-30,80}}, color={0,127,255})); + connect(valHeaWatIsoHdr.port_b, pumPriNoDed.ports_aChiHeaWat) + annotation (Line(points={{-10,80},{50,80},{50,20}}, color={0,127,255})); + connect(valChiWatIsoHdr.port_b, pumPriNoDed.ports_aChiHeaWat) + annotation (Line(points={{30,60},{50,60},{50,20}}, color={0,127,255})); + connect(ret1.ports, valHeaWatIsoHdr.port_b) + annotation (Line(points={{50,80},{-10,80}}, color={0,127,255})); + connect(busPla.valHeaWatHpInlIso, valHeaWatIsoHdr.bus) annotation (Line( + points={{-80,120},{-20,120},{-20,90}}, + color={255,204,51}, + thickness=0.5)); + connect(busPla.valChiWatHpInlIso, valChiWatIsoHdr.bus) annotation (Line( + points={{-80,120},{20,120},{20,70}}, + color={255,204,51}, + thickness=0.5)); + connect(busPla1, pumPriCom.bus) annotation (Line( + points={{-70,300},{0,300},{0,240}}, + color={255,204,51}, + thickness=0.5)); + connect(busPla2.valHeaWatHpInlIso, valHeaWatIsoSep.bus) + annotation (Line(points={{-80,-120},{-20,-120},{-20,-130}},color={255,204,51},thickness=0.5)); + connect(busPla2.valChiWatHpInlIso, valChiWatIsoSep.bus) + annotation (Line(points={{-80,-120},{20,-120},{20,-150}}, color={255,204,51},thickness=0.5)); + connect(ctlSep.bus, busPla2) + annotation (Line(points={{-100,-120},{-80,-120}},color={255,204,51},thickness=0.5)); + connect(pumPriSep.ports_bHeaWat, valHeaWatIsoSep.port_a) + annotation (Line(points={{-66,-180},{-66,-140},{-30,-140}},color={0,127,255})); + connect(pumPriSep.ports_bChiWat, valChiWatIsoSep.port_a) + annotation (Line(points={{-34,-180},{-34,-160},{10,-160}}, color={0,127,255})); + connect(valHeaWatIsoSep.port_b, pumPriSep.ports_aChiHeaWat) + annotation (Line(points={{-10,-140},{50,-140},{50,-180}}, + color={0,127,255})); + connect(valChiWatIsoSep.port_b, pumPriSep.ports_aChiHeaWat) + annotation (Line(points={{30,-160},{50,-160},{50,-180}}, color={0,127,255})); + connect(busPla2, pumPriSep.bus) + annotation (Line(points={{-80,-120},{0,-120},{0,-180}}, color={255,204,51},thickness=0.5)); + connect(pumPriHea.ports_bChiHeaWatHp, hpHea.port_a) + annotation (Line(points={{50,-460},{10,-460}}, color={0,127,255})); + connect(hpHea.port_b, pumPriHea.ports_aChiHeaWatHp) + annotation (Line(points={{-10,-460},{-50,-460}}, color={0,127,255})); + connect(ctlHea.bus, pumPriHea.bus) + annotation (Line(points={{-100,-360},{0,-360},{0,-380}}, color={255,204,51},thickness=0.5)); + connect(ret2.ports, valHeaWatIsoSep.port_b) + annotation (Line(points={{70,-140},{-10,-140}}, color={0,127,255})); + connect(ret3.ports[1], priHeaWat.port_b) + annotation (Line(points={{70,-340},{10,-340}}, color={0,127,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Components/Validation/PumpsPrimaryDedicated.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StopTime=5000.0), + Diagram( + coordinateSystem( + extent={{-300,-520},{300,360}})), + Documentation(info=" +

+This model validates the model + +Buildings.Templates.Plants.HeatPumps.Components.PumpsPrimaryDedicated +for the following configurations. +

+
    +
  • +Heating and cooling system with common constant speed dedicated primary pumps: +component pumPriCom. +
  • +
  • +Heating and cooling system with headered constant speed primary pumps: +component pumPriHdr. +
  • +
  • +Heating and cooling system with separate constant speed dedicated HW and CHW pumps: +component pumPriSep. +
  • +
  • +Heating-only system with variable speed dedicated primary pumps: +component pumPriHea. +
  • +
+

+In each configuration, two identical heat pumps are represented by fixed flow resistances +(components hp*). +

+

+The model uses open loop controls and the simulation allows verifying that design flow +is obtained in each loop and each heat pump when the pumps are enabled. +

+

+In the configurations with common constant speed dedicated primary pumps or +headered constant speed primary pumps, this requires adjusting the +design pressure drop of the balancing valves which are modeled by fixed flow +resistances in the isolation valve components +valHeaWatIso* and valChiWatIso*. +This adjustment is done programmatically using the function + +Buildings.Templates.Utilities.computeBalancingPressureDrop. +

+

+Similarly, in the configuration with variable speed pumps pumPriHea, +the design head of the pumps is voluntarily chosen higher than necessary +and the required pump speed needed to provide the design HP flow is computed +at initialization by solving for a balancing valve pressure drop of zero. +Note that this requires solving a numerical Jacobian at initialization. +Although this is handled well by various Modelica tools, the parameter +use_spePumIni allows switching to a default value in +this validation model for better integration into the continuous integration +test workflow. +

+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end PumpsPrimaryDedicated; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Validation/ValvesIsolation.mo b/Buildings/Templates/Plants/HeatPumps/Components/Validation/ValvesIsolation.mo new file mode 100644 index 00000000000..aa872c51043 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Validation/ValvesIsolation.mo @@ -0,0 +1,482 @@ +within Buildings.Templates.Plants.HeatPumps.Components.Validation; +model ValvesIsolation + "Validation model for isolation valve component" + extends Modelica.Icons.Example; + parameter Buildings.Templates.Plants.HeatPumps.Types.Controller typCtl= + Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop; + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "CHW/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 Data.Controller datCtl( + cfg( + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=valIsoCom.have_valHpOutIso, + have_valHpInlIso=valIsoCom.have_valHpInlIso, + have_chiWat=valIsoCom.have_chiWat, + have_pumChiWatPriDed=valIsoCom.have_pumChiWatPriDed, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=true, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=2, + nPumHeaWatPri=2, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=0, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, + datCtl.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, + datCtl.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtl.cfg.nHp)}) "Controller parameters" + annotation (Placement(transformation(extent={{-80,370},{-60,390}}))); + parameter Data.Controller datCtlHeaInl( + cfg( + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=valIsoHeaInl.have_valHpOutIso, + have_valHpInlIso=valIsoHeaInl.have_valHpInlIso, + have_chiWat=valIsoHeaInl.have_chiWat, + have_pumChiWatPriDed=valIsoHeaInl.have_pumChiWatPriDed, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None, + is_rev=false, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=2, + nPumHeaWatPri=2, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=0, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlHeaInl.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlHeaInl.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtlHeaInl.cfg.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-80,110},{-60,130}}))); + parameter Data.Controller datCtlSep( + cfg( + have_pumHeaWatPriVar=true, + have_pumChiWatPriVar=false, + have_inpSch=false, + have_hrc=false, + have_valHpOutIso=valIsoSep.have_valHpOutIso, + have_valHpInlIso=valIsoSep.have_valHpInlIso, + have_chiWat=valIsoSep.have_chiWat, + have_pumChiWatPriDed=valIsoSep.have_pumChiWatPriDed, + typPumHeaWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumHeaWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + typDis=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only, + nPumChiWatSec=0, + rhoHeaWat_default=Buildings.Media.Water.d_const, + typCtl=Buildings.Templates.Plants.HeatPumps.Types.Controller.OpenLoop, + is_rev=true, + typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + rhoChiWat_default=Buildings.Media.Water.d_const, + cpChiWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_hotWat=false, + have_valChiWatMinByp=false, + have_valHeaWatMinByp=false, + typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + cpHeaWat_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + cpSou_default=Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + have_senDpChiWatRemWir=true, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + nHp=2, + nPumHeaWatPri=2, + have_heaWat=true, + nPumHeaWatSec=0, + rhoSou_default=Buildings.Media.Air.dStp, + have_senDpHeaWatRemWir=true, + typPumChiWatSec=Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None, + nPumChiWatPri=2, + nSenDpHeaWatRem=0, + nSenDpChiWatRem=0, + nAirHan=0, + nEquZon=0), + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + dpChiWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpChiWatRemSet_max, datCtlSep.cfg.nSenDpChiWatRem), + dpHeaWatRemSet_max=fill(Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max, datCtlSep.cfg.nSenDpHeaWatRem), + staEqu={fill(1, datCtlSep.cfg.nHp)}) + "Controller parameters" + annotation (Placement(transformation(extent={{-80,-130},{-60,-110}}))); + parameter Data.HeatPumpGroup datHp( + final nHp=2, + final typ=Buildings.Templates.Components.Types.HeatPump.AirToWater, + final is_rev=true, + final typMod=Buildings.Templates.Components.Types.HeatPumpModel.EquationFit, + mHeaWatHp_flow_nominal=datHp.capHeaHp_nominal / abs(datHp.THeaWatSupHp_nominal - + Buildings.Templates.Data.Defaults.THeaWatRetMed) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWatHp_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + capHeaHp_nominal=500E3, + THeaWatSupHp_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TSouHeaHp_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + mChiWatHp_flow_nominal=datHp.capCooHp_nominal / abs(datHp.TChiWatSupHp_nominal - + Buildings.Templates.Data.Defaults.TChiWatRet) / Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + capCooHp_nominal=500E3, + TChiWatSupHp_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + TSouCooHp_nominal=Buildings.Templates.Data.Defaults.TOutHpCoo, + perFitHp( + hea( + P=datHp.capHeaHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={- 4.2670305442, - 0.7381077035, 6.0049480456, 0, 0}, + coeP={- 4.9107455513, 5.3665308366, 0.5447612754, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.THeaWatRetMed, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpHeaLow), + coo( + P=datHp.capCooHp_nominal / Buildings.Templates.Data.Defaults.COPHpAwCoo, + coeQ={- 2.2545246871, 6.9089257665, - 3.6548225094, 0, 0}, + coeP={- 5.8086010402, 1.6894933858, 5.1167787436, 0, 0}, + TRefLoa=Buildings.Templates.Data.Defaults.TChiWatRet, + TRefSou=Buildings.Templates.Data.Defaults.TOutHpCoo))) + "HP parameters" + annotation (Placement(transformation(extent={{-40,190},{-20,210}}))); + Buildings.Templates.Plants.HeatPumps.Components.ValvesIsolation valIsoCom( + redeclare final package Medium = Medium, + nHp=2, + have_chiWat=true, + have_valHpInlIso=true, + have_valHpOutIso=true, + have_pumChiWatPriDed=false, + final mHeaWatHp_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, valIsoCom.nHp), + dpHeaWatHp_nominal=fill(datHp.dpHeaWatHp_nominal, valIsoCom.nHp), + mChiWatHp_flow_nominal=fill(datHp.mChiWatHp_flow_nominal, valIsoCom.nHp), + final energyDynamics=energyDynamics, + y_start=0) + "Isolation valves - Heating and cooling system with common dedicated primary HW and CHW pumps" + annotation (Placement(transformation(extent={{-240,220},{240,360}}))); + Fluid.FixedResistances.PressureDrop hpCom[valIsoCom.nHp]( + redeclare each final package Medium = Medium, + m_flow_nominal=valIsoCom.mHeaWatHp_flow_nominal, + dp_nominal=fill(0, valIsoCom.nHp)) + "Heat pump HX with zero fluid resistance: pressure drop computed in valve component" + annotation (Placement(transformation(extent={{10,210},{-10,230}}))); + Fluid.Sources.Boundary_pT retChiWat( + redeclare final package Medium = Medium, + p=supChiWat.p + max(valIsoCom.dpChiWat_nominal), + T=Buildings.Templates.Data.Defaults.TChiWatRet, + nPorts=1) "Boundary condition at CHW return" + annotation (Placement(transformation(extent={{280,300},{260,320}}))); + Fluid.Sources.Boundary_pT retHeaWat( + redeclare final package Medium = Medium, + p=supHeaWat.p + max(valIsoCom.dpHeaWat_nominal), + T=Buildings.Templates.Data.Defaults.THeaWatRetMed, + nPorts=1) "Boundary condition at HW return" + annotation (Placement(transformation(extent={{-280,320},{-260,340}}))); + Fluid.Sources.Boundary_pT supChiWat( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pChiWat_rel_nominal + 101325, + nPorts=1) + "Boundary condition at CHW supply" + annotation (Placement(transformation(extent={{280,340},{260,360}}))); + Fluid.Sources.Boundary_pT supHeaWat( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=1) + "Boundary condition at HW supply" + annotation (Placement(transformation(extent={{-280,280},{-260,300}}))); + Controls.OpenLoop ctl( + final cfg=datCtl.cfg, + final dat=datCtl) + "Plant controller" + annotation (Placement(transformation(extent={{-30,370},{-50,390}}))); + Buildings.Templates.Plants.HeatPumps.Components.ValvesIsolation valIsoHeaInl( + redeclare final package Medium = Medium, + nHp=2, + have_chiWat=false, + have_pumChiWatPriDed=false, + have_valHpInlIso=true, + have_valHpOutIso=false, + final mHeaWatHp_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, valIsoCom.nHp), + dpHeaWatHp_nominal=fill(datHp.dpHeaWatHp_nominal, valIsoCom.nHp), + mChiWatHp_flow_nominal=fill(datHp.mChiWatHp_flow_nominal, valIsoCom.nHp), + final energyDynamics=energyDynamics, + y_start=0) + "Isolation valves - Heating-only system with isolation valves at HP inlet" + annotation (Placement(transformation(extent={{-240,-40},{240,100}}))); + Fluid.FixedResistances.PressureDrop hpHea[valIsoHeaInl.nHp]( + redeclare each final package Medium=Medium, + m_flow_nominal=valIsoHeaInl.mHeaWatHp_flow_nominal, + dp_nominal=fill(0, valIsoHeaInl.nHp)) + "Heat pump HX with zero fluid resistance: pressure drop computed in valve component" + annotation (Placement(transformation(extent={{10,-50},{-10,-30}}))); + Fluid.Sources.Boundary_pT retHeaWat1( + redeclare final package Medium=Medium, + p=supHeaWat1.p + max(valIsoHeaInl.dpHeaWat_nominal), + T=Buildings.Templates.Data.Defaults.THeaWatRetMed, + nPorts=1) + "Boundary condition at HW return" + annotation (Placement(transformation(extent={{-280,60},{-260,80}}))); + Fluid.Sources.Boundary_pT supHeaWat1( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=1) + "Boundary condition at HW supply" + annotation (Placement(transformation(extent={{-280,20},{-260,40}}))); + Controls.OpenLoop ctlHeaInl( + final cfg=datCtlHeaInl.cfg, + final dat=datCtlHeaInl) + "Plant controller" + annotation (Placement(transformation(extent={{-30,110},{-50,130}}))); + Buildings.Templates.Plants.HeatPumps.Components.ValvesIsolation valIsoSep( + redeclare final package Medium = Medium, + nHp=2, + have_chiWat=true, + have_valHpInlIso=true, + have_valHpOutIso=false, + have_pumChiWatPriDed=true, + final mHeaWatHp_flow_nominal=fill(datHp.mHeaWatHp_flow_nominal, valIsoCom.nHp), + dpHeaWatHp_nominal=fill(datHp.dpHeaWatHp_nominal, valIsoCom.nHp), + mChiWatHp_flow_nominal=fill(datHp.mChiWatHp_flow_nominal, valIsoCom.nHp), + final energyDynamics=energyDynamics, + y_start=0, + from_dp=false) + "Isolation valves - Heating and cooling system with separate dedicated primary HW and CHW pumps" + annotation (Placement(transformation(extent={{-240,-280},{240,-140}}))); + Fluid.FixedResistances.PressureDrop hpSep[valIsoSep.nHp]( + redeclare each final package Medium=Medium, + m_flow_nominal=valIsoSep.mHeaWatHp_flow_nominal, + dp_nominal=fill(0, valIsoSep.nHp)) + "Heat pump HX with zero fluid resistance: pressure drop computed in valve component" + annotation (Placement(transformation(extent={{10,-370},{-10,-350}}))); + Fluid.Sources.Boundary_pT supHeaWat2( + redeclare final package Medium=Medium, + p=Buildings.Templates.Data.Defaults.pHeaWat_rel_nominal + 101325, + nPorts=2) + "Boundary condition at HW supply" + annotation (Placement(transformation(extent={{-280,-200},{-260,-180}}))); + Controls.OpenLoop ctlSep( + final cfg=datCtlSep.cfg, + final dat=datCtlSep) + "Plant controller" + annotation (Placement(transformation(extent={{-30,-130},{-50,-110}}))); + Fluid.Movers.Preconfigured.SpeedControlled_y pumChiWatPri[2]( + redeclare each final package Medium=Medium, + each addPowerToMedium=false, + each m_flow_nominal=datHp.mChiWatHp_flow_nominal, + each final energyDynamics=energyDynamics, + dp_nominal=valIsoSep.dpChiWat_nominal + cheValChiWat.dpValve_nominal) + "Primary CHW pump" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=-90, + origin={-34,-334}))); + Fluid.Movers.Preconfigured.SpeedControlled_y pumHeaWatPri[2]( + redeclare each final package Medium=Medium, + each addPowerToMedium=false, + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each final energyDynamics=energyDynamics, + dp_nominal=valIsoSep.dpHeaWat_nominal + cheValHeaWat.dpValve_nominal) + "Primary HW pump" + annotation (Placement(transformation(extent={{10,-10},{-10,10}},rotation=-90, + origin={-66,-320}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus busPla + "Plant controller" + annotation (Placement(iconVisible=false,transformation(extent={{80,-140},{120, + -100}}), + iconTransformation(extent={{-548,-190},{-508,-150}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal yPumHeaWatPri[2] + "Primary HW pump speed command" + annotation (Placement(transformation(extent={{80,-336},{60,-316}}))); + Buildings.Controls.OBC.CDL.Conversions.BooleanToReal yPumChiWatPri[2] + "Primary CHW pump speed command" + annotation (Placement(transformation(extent={{110,-356},{90,-336}}))); + Buildings.Templates.Components.Interfaces.Bus busPumHeaWatPri + "Primary HW pump control bus" + annotation (Placement(iconVisible=false,transformation(extent={{100,-346},{140, + -306}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busPumChiWatPri + "Primary CHW pump control bus" + annotation (Placement(iconVisible=false,transformation(extent={{120,-366},{160, + -326}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Fluid.FixedResistances.CheckValve cheValHeaWat[2]( + redeclare each final package Medium=Medium, + each m_flow_nominal=datHp.mHeaWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValChe) + "Check valve" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-66,-296}))); + Fluid.FixedResistances.CheckValve cheValChiWat[2]( + redeclare each final package Medium=Medium, + each m_flow_nominal=datHp.mChiWatHp_flow_nominal, + each dpValve_nominal=Buildings.Templates.Data.Defaults.dpValChe) + "Check valve" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-34,-306}))); +equation + connect(retHeaWat.ports[1], valIsoCom.port_aHeaWat) annotation (Line(points={{-260, + 330},{-240,330}}, color={0,127,255})); + connect(retChiWat.ports[1], valIsoCom.port_aChiWat) + annotation (Line(points={{260,310},{240,310}}, color={0,127,255})); + connect(valIsoCom.port_bChiWat, supChiWat.ports[1]) + annotation (Line(points={{240,350},{260,350}}, color={0,127,255})); + connect(valIsoCom.port_bHeaWat, supHeaWat.ports[1]) annotation (Line(points={{-240, + 290},{-260,290}}, color={0,127,255})); + connect(ctl.bus, valIsoCom.bus) annotation (Line( + points={{-30,380},{0,380},{0,330}}, + color={255,204,51}, + thickness=0.5)); + connect(retHeaWat1.ports[1], valIsoHeaInl.port_aHeaWat) + annotation (Line(points={{-260,70},{-240,70}}, color={0,127,255})); + connect(valIsoHeaInl.port_bHeaWat, supHeaWat1.ports[1]) + annotation (Line(points={{-240,30},{-260,30}}, color={0,127,255})); + connect(ctlHeaInl.bus, valIsoHeaInl.bus) + annotation (Line(points={{-30,120},{0,120},{0,70}}, color={255,204,51},thickness=0.5)); + connect(valIsoCom.ports_bChiHeaWatHp, hpCom.port_a) + annotation (Line(points={{50,220},{10,220}}, color={0,127,255})); + connect(hpCom.port_b, valIsoCom.ports_aChiHeaWatHp) + annotation (Line(points={{-10,220},{-50,220}}, color={0,127,255})); + connect(valIsoHeaInl.ports_bChiHeaWatHp, hpHea.port_a) + annotation (Line(points={{50,-40},{10,-40}}, color={0,127,255})); + connect(hpHea.port_b, valIsoHeaInl.ports_aChiHeaWatHp) + annotation (Line(points={{-10,-40},{-50,-40}}, color={0,127,255})); + connect(valIsoSep.port_bHeaWat, supHeaWat2.ports[1]) + annotation (Line(points={{-240,-210},{-260,-210},{-260,-191}}, + color={0,127,255})); + connect(ctlSep.bus, valIsoSep.bus) + annotation (Line(points={{-30,-120},{0,-120},{0,-170}}, color={255,204,51},thickness=0.5)); + connect(valIsoSep.ports_bChiHeaWatHp, hpSep.port_a) + annotation (Line(points={{50,-280},{50,-360},{10,-360}},color={0,127,255})); + connect(supHeaWat2.ports[2], valIsoSep.port_aHeaWat) + annotation (Line(points={{-260,-189},{-260,-170},{-240,-170}}, + color={0,127,255})); + connect(ctlSep.bus, busPla) + annotation (Line(points={{-30,-120},{100,-120}}, + color={255,204,51},thickness=0.5)); + connect(busPla.pumHeaWatPri, busPumHeaWatPri) + annotation (Line(points={{100,-120},{280,-120},{280,-326},{120,-326}}, + color={255,204,51},thickness=0.5)); + connect(busPumHeaWatPri.y1, yPumHeaWatPri.u) + annotation (Line(points={{120,-326},{82,-326}},color={255,204,51},thickness=0.5)); + connect(yPumHeaWatPri.y, pumHeaWatPri.y) + annotation (Line(points={{58,-326},{0,-326},{0,-320},{-54,-320}}, color={0,0,127})); + connect(busPla.pumChiWatPri, busPumChiWatPri) + annotation (Line(points={{100,-120},{280,-120},{280,-346},{140,-346}}, + color={255,204,51},thickness=0.5)); + connect(busPumChiWatPri.y1, yPumChiWatPri.u) + annotation (Line(points={{140,-346},{112,-346}}, + color={255,204,51},thickness=0.5)); + connect(yPumChiWatPri.y, pumChiWatPri.y) + annotation (Line(points={{88,-346},{0,-346},{0,-334},{-22,-334}}, color={0,0,127})); + connect(pumHeaWatPri.port_b, cheValHeaWat.port_a) + annotation (Line(points={{-66,-310},{-66,-306}},color={0,127,255})); + connect(cheValHeaWat.port_b, valIsoSep.ports_aHeaWatHp) + annotation (Line(points={{-66,-286},{-66,-280}},color={0,127,255})); + connect(cheValChiWat.port_b, valIsoSep.ports_aChiWatHp) + annotation (Line(points={{-34,-296},{-34,-280}}, color={0,127,255})); + connect(pumChiWatPri.port_b, cheValChiWat.port_a) + annotation (Line(points={{-34,-324},{-34,-316}},color={0,127,255})); + connect(hpSep.port_b, pumChiWatPri.port_a) annotation (Line(points={{-10,-360}, + {-34,-360},{-34,-344}}, color={0,127,255})); + connect(hpSep.port_b, pumHeaWatPri.port_a) annotation (Line(points={{-10,-360}, + {-66,-360},{-66,-330}}, color={0,127,255})); + connect(valIsoSep.port_bChiWat, valIsoSep.port_aChiWat) annotation (Line( + points={{240,-150},{260,-150},{260,-190},{240,-190},{240,-190}}, color= + {0,127,255})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Components/Validation/ValvesIsolation.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StopTime=5000.0), + Diagram( + coordinateSystem( + extent={{-300,-400},{300,400}})), + Documentation(revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+", info=" +

+This model validates the model + +Buildings.Templates.Plants.HeatPumps.Components.ValvesIsolation +for the following configurations. +

+
    +
  • +Heating and cooling system with common dedicated primary HW and CHW pumps +and isolation valves at both heat pump inlet and outlet: +component valIsoCom. +
  • +
  • +Heating-only system with isolation valves at heat pump inlet: +component valIsoHeaInl. +
  • +
  • +Heating and cooling system with separate dedicated primary HW and CHW pumps +and isolation valves at heat pump inlet: +component valIsoSep. +
  • +
+

+In each configuration, two identical heat pumps are represented by fixed +flow resistances (components hp*). +

+

+The model uses open loop controls and the simulation allows verifying that design +flow is obtained in each loop and each heat pump when the valves are open. +

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

+This package contains validation models for the classes within + +Buildings.Templates.Plants.HeatPumps.Components. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/Validation/package.order b/Buildings/Templates/Plants/HeatPumps/Components/Validation/package.order new file mode 100644 index 00000000000..2fae7671638 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/Validation/package.order @@ -0,0 +1,3 @@ +HeatPumpGroupAirToWater +PumpsPrimaryDedicated +ValvesIsolation diff --git a/Buildings/Templates/Plants/HeatPumps/Components/ValvesIsolation.mo b/Buildings/Templates/Plants/HeatPumps/Components/ValvesIsolation.mo new file mode 100644 index 00000000000..997b4cd520c --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/ValvesIsolation.mo @@ -0,0 +1,1229 @@ +within Buildings.Templates.Plants.HeatPumps.Components; +model ValvesIsolation + "Heat pump isolation valves" + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Medium model" + annotation (__ctrlFlow(enable=false)); + final parameter Buildings.Templates.Components.Types.Valve typ= + Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + "Valve type" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Integer nHp( + final min=1) + "Number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean have_chiWat + "Set to true if the plant provides CHW" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean have_valHpInlIso + "Set to true for isolation valves at HP inlet" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean have_valHpOutIso + "Set to true for isolation valves at HP outlet" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean have_pumChiWatPriDed( + start=false) + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=have_chiWat)); + parameter Modelica.Units.SI.MassFlowRate mHeaWatHp_flow_nominal[nHp]( + each final min=0, + each start=0) + "HW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpHeaWatHp_nominal[nHp]( + each final min=0, + each start=Buildings.Templates.Data.Defaults.dpChiWatChi) + "Pressure drop at design HW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpBalHeaWatHp_nominal[nHp]( + each final min=0)=fill(0, nHp) + "Balancing valve pressure drop at design HW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.MassFlowRate mChiWatHp_flow_nominal[nHp]( + each start=0, + each final min=0) + "CHW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=have_chiWat)); + final parameter Modelica.Units.SI.PressureDifference dpChiWatHp_nominal[nHp]= + dpHeaWatHp_nominal .*(mChiWatHp_flow_nominal ./ mHeaWatHp_flow_nominal) .^ 2 + "Pressure drop at design CHW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=have_chiWat)); + parameter Modelica.Units.SI.PressureDifference dpBalChiWatHp_nominal[nHp]( + each final min=0, + each start=0)=fill(0, nHp) + "Balancing valve pressure drop at design CHW mass flow rate - Each heat pump" + annotation (Dialog(group="Nominal condition", + enable=have_chiWat)); + parameter Modelica.Units.SI.PressureDifference dpValveHeaWat_nominal[nHp]=fill(Buildings.Templates.Data.Defaults.dpValIso, nHp) + "HW isolation valve pressure drop: identical for inlet and outlet valves" + annotation (Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.PressureDifference dpFixedHeaWat_nominal[nHp]= + dpHeaWatHp_nominal + dpBalHeaWatHp_nominal + "Fixed HW pressure drop: HP + balancing valve" + annotation (Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.PressureDifference dpHeaWat_nominal[nHp]= + dpFixedHeaWat_nominal +(if have_valHpOutIso then dpValveHeaWat_nominal else fill(0, nHp)) + + (if have_valHpInlIso then dpValveHeaWat_nominal else fill(0, nHp)) + "Total HW pressure drop: fixed + valves" + annotation (Dialog(group="Nominal condition")); + parameter Modelica.Units.SI.PressureDifference dpValveChiWat_nominal[nHp]( + each start=0)=fill(Buildings.Templates.Data.Defaults.dpValIso, nHp) + "Isolation valve CHW pressure drop: identical for inlet and outlet valves" + annotation (Dialog(group="Nominal condition", + enable=have_chiWat)); + final parameter Modelica.Units.SI.PressureDifference dpFixedChiWat_nominal[nHp]= + if have_chiWat then dpChiWatHp_nominal + dpBalChiWatHp_nominal else fill(0, nHp) + "Total fixed CHW pressure drop" + annotation (Dialog(group="Nominal condition", + enable=have_chiWat)); + final parameter Modelica.Units.SI.PressureDifference dpChiWat_nominal[nHp]= + dpFixedChiWat_nominal +(if have_chiWat and have_valHpOutIso then dpValveChiWat_nominal + else fill(0, nHp)) +(if have_chiWat and have_valHpInlIso then dpValveChiWat_nominal + else fill(0, nHp)) + "Total CHW pressure drop: fixed + valves" + annotation (Dialog(group="Nominal condition", + enable=have_chiWat)); + final parameter Buildings.Templates.Components.Data.Valve datValHeaWatHpOutIso[nHp]( + each typ=typ, + m_flow_nominal=mHeaWatHp_flow_nominal, + dpValve_nominal=dpValveHeaWat_nominal, + dpFixed_nominal=dpFixedHeaWat_nominal) + "Heat pump outlet HW isolation valve parameters" + annotation (Placement(transformation(extent={{-30,80},{-10,100}}))); + // dpFixed_nominal only applied to inlet valves if there is no outlet valve. + final parameter Buildings.Templates.Components.Data.Valve datValHeaWatHpInlIso[nHp]( + each typ=typ, + m_flow_nominal=mHeaWatHp_flow_nominal, + dpValve_nominal=dpValveHeaWat_nominal, + dpFixed_nominal=if not have_valHpOutIso then dpFixedHeaWat_nominal else fill(0, nHp)) + "Heat pump inlet HW isolation valve parameters" + annotation (Placement(transformation(extent={{-30,80},{-10,100}}))); + final parameter Buildings.Templates.Components.Data.Valve datValChiWatHpOutIso[nHp]( + each typ=typ, + m_flow_nominal=mChiWatHp_flow_nominal, + dpValve_nominal=dpValveChiWat_nominal, + dpFixed_nominal=dpFixedChiWat_nominal) + "Heat pump outlet CHW isolation valve parameters" + annotation (Placement(transformation(extent={{10,80},{30,100}}))); + // dpFixed_nominal only applied to inlet valves if there is no outlet valve. + final parameter Buildings.Templates.Components.Data.Valve datValChiWatHpInlIso[nHp]( + each typ=typ, + m_flow_nominal=mChiWatHp_flow_nominal, + dpValve_nominal=dpValveChiWat_nominal, + dpFixed_nominal=if not have_valHpOutIso then dpFixedChiWat_nominal else fill(0, nHp)) + "Heat pump inlet CHW isolation valve parameters" + annotation (Placement(transformation(extent={{10,80},{30,100}}))); + 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 Modelica.Units.SI.Time tau=10 + "Time constant at nominal flow" + annotation (Dialog(tab="Dynamics",group="Nominal condition", + enable=energyDynamics<>Modelica.Fluid.Types.Dynamics.SteadyState), + __ctrlFlow(enable=false)); + parameter Boolean allowFlowReversal=true + "Set to false to simplify equations, assuming, but not enforcing, no flow reversal" + annotation (Dialog(tab="Assumptions"), + Evaluate=true); + parameter Boolean use_inputFilter=energyDynamics <> Modelica.Fluid.Types.Dynamics.SteadyState + "= true, if opening is filtered with a 2nd order CriticalDamping filter" + annotation (__ctrlFlow(enable=false), + Dialog(tab="Dynamics",group="Filtered opening", + enable=have_valHpInlIso or have_valHpOutIso)); + parameter Modelica.Units.SI.Time riseTime=120 + "Rise time of the filter (time to reach 99.6 % of an opening step)" + annotation (__ctrlFlow(enable=false), + Dialog(tab="Dynamics",group="Filtered opening", + enable=use_inputFilter and have_valHpInlIso or have_valHpOutIso)); + parameter Modelica.Blocks.Types.Init init=Modelica.Blocks.Types.Init.InitialOutput + "Type of initialization (no init/steady state/initial state/initial output)" + annotation (__ctrlFlow(enable=false), + Dialog(tab="Dynamics",group="Filtered opening", + enable=use_inputFilter and have_valHpInlIso or have_valHpOutIso)); + parameter Real y_start=1 + "Initial position of actuator" + annotation (__ctrlFlow(enable=false), + Dialog(tab="Dynamics",group="Filtered opening", + enable=use_inputFilter and have_valHpInlIso or have_valHpOutIso)); + parameter Boolean from_dp=true + "= true, use m_flow = f(dp) else dp = f(m_flow)" + annotation (Evaluate=true, + Dialog(tab="Advanced", + enable=have_valHpInlIso or have_valHpOutIso)); + parameter Boolean linearized=true + "= true, use linear relation between m_flow and dp for any flow rate" + annotation (Evaluate=true, + Dialog(tab="Advanced", + enable=have_valHpInlIso or have_valHpOutIso)); + Modelica.Fluid.Interfaces.FluidPort_b port_bChiWat( + redeclare final package Medium=Medium, + m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if have_chiWat + "CHW supply (to primary loop)" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-100,200}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={2400,600}))); + Modelica.Fluid.Interfaces.FluidPort_a port_aChiWat( + redeclare final package Medium=Medium, + m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if have_chiWat + "CHW return (from primary loop)" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={180,200}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=0, + origin={2400,200}))); + Modelica.Fluid.Interfaces.FluidPort_b port_bHeaWat( + redeclare final package Medium=Medium, + m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + "HW supply (to primary loop)" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={-180,200}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={-2400,0}))); + Modelica.Fluid.Interfaces.FluidPort_a port_aHeaWat( + redeclare final package Medium=Medium, + m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + "HW return (from primary loop)" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={100,200}), iconTransformation( + extent={{-10,-10},{10,10}}, + rotation=180, + origin={-2400,400}))); + Modelica.Fluid.Interfaces.FluidPorts_b ports_bChiHeaWatHp[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + "CHW/HW return (HP entering)" + annotation (Placement(transformation(extent={{-10,-40},{10,40}},rotation=90, + origin={100,-200}), + iconTransformation(extent={{-10,-40},{10,40}},rotation=90,origin={500,-700}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aChiHeaWatHp[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if not have_pumChiWatPriDed + "CHW/HW supply (HP leaving)" + annotation (Placement(transformation( + extent={{-10,-40},{10,40}}, + rotation=90, + origin={-100,-200}), iconTransformation( + extent={{-10,-40},{10,40}}, + rotation=90, + origin={-500,-700}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aHeaWatHp[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if have_pumChiWatPriDed + "HW supply (HP leaving)" + annotation (Placement(transformation( + extent={{-10,-40},{10,40}}, + rotation=90, + origin={-180,-200}), iconTransformation( + extent={{-10,-40},{10,40}}, + rotation=90, + origin={-660,-700}))); + Modelica.Fluid.Interfaces.FluidPorts_a ports_aChiWatHp[nHp]( + redeclare each final package Medium=Medium, + each m_flow( + min=if allowFlowReversal then - Modelica.Constants.inf else 0), + each h_outflow( + start=Medium.h_default, + nominal=Medium.h_default)) + if have_pumChiWatPriDed + "CHW supply (HP leaving)" + annotation (Placement(transformation( + extent={{-10,-40},{10,40}}, + rotation=90, + origin={-20,-200}), iconTransformation( + extent={{-10,-40},{10,40}}, + rotation=90, + origin={-340,-700}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus bus + "Plant control bus" + annotation (Placement(transformation(extent={{-20,180},{20,220}}), + iconTransformation(extent={{-20,380},{20,420}}))); + Buildings.Templates.Components.Actuators.Valve valHeaWatHpOutIso[nHp]( + redeclare each final package Medium=Medium, + final dat=datValHeaWatHpOutIso, + each final typ=typ, + each final use_inputFilter=use_inputFilter, + each final riseTime=riseTime, + each final init=init, + each final y_start=y_start, + each final from_dp=from_dp, + each final linearized=linearized) + if have_valHpOutIso + "HP outlet HW isolation valve" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-180,0}))); + Buildings.Templates.Components.Actuators.Valve valChiWatHpOutIso[nHp]( + redeclare each final package Medium=Medium, + final dat=datValChiWatHpOutIso, + each final typ=typ, + each final use_inputFilter=use_inputFilter, + each final riseTime=riseTime, + each final init=init, + each final y_start=y_start, + each final from_dp=from_dp, + each final linearized=linearized) + if have_valHpOutIso and have_chiWat + "HP outlet CHW isolation valve" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-100,0}))); + Buildings.Templates.Components.Actuators.Valve valHeaWatHpInlIso[nHp]( + redeclare each final package Medium=Medium, + final dat=datValHeaWatHpInlIso, + each final typ=typ, + each final use_inputFilter=use_inputFilter, + each final riseTime=riseTime, + each final init=init, + each final y_start=y_start, + each final from_dp=from_dp, + each final linearized=linearized) + if have_valHpInlIso + "HP inlet HW isolation valve" + annotation (Placement(transformation(extent={{10,10},{-10,-10}},rotation=90, + origin={100,0}))); + Buildings.Templates.Components.Actuators.Valve valChiWatHpInlIso[nHp]( + redeclare each final package Medium=Medium, + final dat=datValChiWatHpInlIso, + each final typ=typ, + each final use_inputFilter=use_inputFilter, + each final riseTime=riseTime, + each final init=init, + each final y_start=y_start, + each final from_dp=from_dp, + each final linearized=linearized) + if have_valHpInlIso and have_chiWat + "HP inlet CHW isolation valve" + annotation (Placement(transformation(extent={{10,10},{-10,-10}},rotation=90, + origin={180,0}))); + Buildings.Templates.Components.Routing.PassThroughFluid pasHeaWatHpOut[nHp]( + redeclare each final package Medium=Medium) + if not have_valHpOutIso + "Direct fluid pass-through" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-160,0}))); + Buildings.Templates.Components.Routing.PassThroughFluid pasChiWatHpOut[nHp]( + redeclare each final package Medium=Medium) + if not have_valHpOutIso and have_chiWat + "Direct fluid pass-through" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=90, + origin={-80,0}))); + Fluid.Delays.DelayFirstOrder junHeaWatSup( + redeclare final package Medium=Medium, + final tau=tau, + final m_flow_nominal=sum(mHeaWatHp_flow_nominal), + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final prescribedHeatFlowRate=false, + final nPorts=nHp + 1) + "Fluid volume at junction" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={-160,50}))); + Fluid.Delays.DelayFirstOrder junChiWatSup( + redeclare final package Medium=Medium, + final tau=tau, + final m_flow_nominal=sum(mChiWatHp_flow_nominal), + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final prescribedHeatFlowRate=false, + final nPorts=nHp + 1) + if have_chiWat + "Fluid volume at junction" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={-82,50}))); + Fluid.Delays.DelayFirstOrder junHeaWatRet( + redeclare final package Medium=Medium, + final tau=tau, + final m_flow_nominal=sum(mHeaWatHp_flow_nominal), + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final prescribedHeatFlowRate=false, + final nPorts=nHp + 1) + "Fluid volume at junction" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={80,50}))); + /* + HW pressure drop computed in this component in the absence of isolation valves + at both inlet and outlet. + */ + Fluid.FixedResistances.PressureDrop pasHeaWatHpInl[nHp]( + redeclare each final package Medium=Medium, + final m_flow_nominal=mHeaWatHp_flow_nominal, + final dp_nominal=if not have_valHpInlIso and not have_valHpOutIso then dpFixedHeaWat_nominal + else fill(0, nHp)) + if not have_valHpInlIso + "Direct fluid pass-through with optional fluid resistance" + annotation (Placement(transformation(extent={{10,10},{-10,-10}},rotation=90, + origin={80,0}))); + /* + CHW pressure drop computed in this component in the absence of isolation valves + at both inlet and outlet. + */ + Fluid.FixedResistances.PressureDrop pasChiWatHpInl[nHp]( + redeclare each final package Medium=Medium, + final m_flow_nominal=mChiWatHp_flow_nominal, + final dp_nominal=if not have_valHpInlIso and not have_valHpOutIso then dpFixedChiWat_nominal + else fill(0, nHp)) + if not have_valHpInlIso and have_chiWat + "Direct fluid pass-through with optional fluid resistance" + annotation (Placement(transformation(extent={{10,10},{-10,-10}},rotation=90, + origin={160,0}))); + Fluid.Delays.DelayFirstOrder junChiWatRet( + redeclare final package Medium=Medium, + final tau=tau, + final m_flow_nominal=sum(mChiWatHp_flow_nominal), + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + final prescribedHeatFlowRate=false, + final nPorts=nHp + 1) + if have_chiWat + "Fluid volume at junction" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={160,50}))); +protected + Buildings.Templates.Components.Interfaces.Bus busValHeaWatHpInlIso[nHp] + if have_valHpInlIso + "Heat pump inlet HW isolation valve control bus" + annotation (Placement(transformation(extent={{40,140},{80,180}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValHeaWatHpOutIso[nHp] + if have_valHpOutIso + "Heat pump outlet HW isolation valve control bus" + annotation (Placement(transformation(extent={{-80,140},{-40,180}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValChiWatHpInlIso[nHp] + if have_chiWat and have_valHpInlIso + "Heat pump inlet CHW isolation valve control bus" + annotation (Placement(transformation(extent={{10,160},{50,200}}), + iconTransformation(extent={{-466,50},{-426,90}}))); + Buildings.Templates.Components.Interfaces.Bus busValChiWatHpOutIso[nHp] + if have_chiWat and have_valHpOutIso + "Heat pump outlet CHW isolation valve control bus" + annotation (Placement(transformation(extent={{-50,160},{-10,200}}), + iconTransformation(extent={{-466,50},{-426,90}}))); +equation + connect(bus.valHeaWatHpInlIso, busValHeaWatHpInlIso) + annotation (Line(points={{0,200},{0,160},{60,160}},color={255,204,51},thickness=0.5)); + connect(bus.valHeaWatHpOutIso, busValHeaWatHpOutIso) + annotation (Line(points={{0,200},{0,160},{-60,160}},color={255,204,51},thickness=0.5)); + connect(bus.valChiWatHpInlIso, busValChiWatHpInlIso) + annotation (Line(points={{0,200},{0,180},{30,180}},color={255,204,51},thickness=0.5)); + connect(bus.valChiWatHpOutIso, busValChiWatHpOutIso) + annotation (Line(points={{0,200},{0,180},{-30,180}},color={255,204,51},thickness=0.5)); + connect(ports_aHeaWatHp, valHeaWatHpOutIso.port_a) + annotation (Line(points={{-180,-200},{-180,-10}},color={0,127,255})); + connect(ports_aChiHeaWatHp, valHeaWatHpOutIso.port_a) + annotation (Line(points={{-100,-200},{-120,-200},{-120,-20},{-180,-20},{ + -180,-10}}, + color={0,127,255})); + connect(ports_aChiHeaWatHp, valChiWatHpOutIso.port_a) + annotation (Line(points={{-100,-200},{-100,-200},{-100,-10}},color={0,127,255})); + connect(ports_aChiWatHp, valChiWatHpOutIso.port_a) + annotation (Line(points={{-20,-200},{-20,-20},{-100,-20},{-100,-10}}, color={0,127,255})); + connect(ports_aHeaWatHp, pasHeaWatHpOut.port_a) + annotation (Line(points={{-180,-200},{-160,-200},{-160,-10}}, color={0,127,255})); + connect(ports_aChiHeaWatHp, pasHeaWatHpOut.port_a) + annotation (Line(points={{-100,-200},{-120,-200},{-120,-20},{-160,-20},{ + -160,-10}}, + color={0,127,255})); + connect(ports_aChiHeaWatHp, pasChiWatHpOut.port_a) + annotation (Line(points={{-100,-200},{-80,-200},{-80,-10}}, color={0,127,255})); + connect(ports_aChiWatHp, pasChiWatHpOut.port_a) + annotation (Line(points={{-20,-200},{-20,-20},{-80,-20},{-80,-10}}, + color={0,127,255})); + connect(valHeaWatHpOutIso.port_b, junHeaWatSup.ports[1:nHp]) + annotation (Line(points={{-180,10},{-180,20},{-160,20},{-160,40}},color={0,127,255})); + connect(pasHeaWatHpOut.port_b, junHeaWatSup.ports[1:nHp]) + annotation (Line(points={{-160,10},{-160,40}},color={0,127,255})); + connect(junHeaWatSup.ports[nHp + 1], port_bHeaWat) + annotation (Line(points={{-160,40},{-180,40},{-180,200}},color={0,127,255})); + connect(valChiWatHpOutIso.port_b, junChiWatSup.ports[1:nHp]) + annotation (Line(points={{-100,10},{-100,20},{-82,20},{-82,40}},color={0,127,255})); + connect(pasChiWatHpOut.port_b, junChiWatSup.ports[1:nHp]) + annotation (Line(points={{-80,10},{-80,40},{-82,40}},color={0,127,255})); + connect(port_bChiWat, junChiWatSup.ports[nHp + 1]) + annotation (Line(points={{-100,200},{-100,40},{-82,40}},color={0,127,255})); + connect(port_aHeaWat, junHeaWatRet.ports[nHp + 1]) + annotation (Line(points={{100,200},{100,40},{80,40}},color={0,127,255})); + connect(junHeaWatRet.ports[1:nHp], valHeaWatHpInlIso.port_a) + annotation (Line(points={{80,40},{80,20},{100,20},{100,10}},color={0,127,255})); + connect(pasHeaWatHpInl.port_a, junHeaWatRet.ports[1:nHp]) + annotation (Line(points={{80,10},{80,26},{80,40},{80,40}},color={0,127,255})); + connect(port_aChiWat, junChiWatRet.ports[nHp + 1]) + annotation (Line(points={{180,200},{180,40},{160,40}},color={0,127,255})); + connect(valChiWatHpInlIso.port_a, junChiWatRet.ports[1:nHp]) + annotation (Line(points={{180,10},{180,20},{160,20},{160,40}},color={0,127,255})); + connect(pasChiWatHpInl.port_a, junChiWatRet.ports[1:nHp]) + annotation (Line(points={{160,10},{160,26},{160,40},{160,40}},color={0,127,255})); + connect(pasHeaWatHpInl.port_b, ports_bChiHeaWatHp) + annotation (Line(points={{80,-10},{80,-200},{100,-200}}, color={0,127,255})); + connect(valHeaWatHpInlIso.port_b, ports_bChiHeaWatHp) + annotation (Line(points={{100,-10},{100,-200}},color={0,127,255})); + connect(pasChiWatHpInl.port_b, ports_bChiHeaWatHp) + annotation (Line(points={{160,-10},{160,-180},{100,-180},{100,-200}},color={0,127,255})); + connect(valChiWatHpInlIso.port_b, ports_bChiHeaWatHp) + annotation (Line(points={{180,-10},{180,-180},{100,-180},{100,-200}}, + color={0,127,255})); + connect(busValHeaWatHpInlIso, valHeaWatHpInlIso.bus) + annotation (Line(points={{60,160},{110,160},{110,0}},color={255,204,51},thickness=0.5)); + connect(busValChiWatHpInlIso, valChiWatHpInlIso.bus) + annotation (Line(points={{30,180},{190,180},{190,0}},color={255,204,51},thickness=0.5)); + connect(busValChiWatHpOutIso, valChiWatHpOutIso.bus) + annotation (Line(points={{-30,180},{-110,180},{-110,0}},color={255,204,51},thickness=0.5)); + connect(busValHeaWatHpOutIso, valHeaWatHpOutIso.bus) + annotation (Line(points={{-60,160},{-190,160},{-190,0}},color={255,204,51},thickness=0.5)); + + annotation ( + defaultComponentName="valIso", + Diagram( + coordinateSystem( + extent={{-200,-200},{200,200}})), + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-2400,-700},{2400,700}}), graphics={ + Line( + points={{1000,-160},{1000,-700}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 2), + Line( + points={{200,-160},{200,-700}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 3), + Line( + points={{-600,-160},{-600,-700}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 4), + Line( + points={{-1400,-160},{-1400,-700}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 5), + Line( + points={{-2200,-160},{-2200,-700}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 6), + Line( + points={{1800,-160},{1800,-700}}, + color={0,0,0}, + thickness=5, + visible=have_pumChiWatPriDed and nHp >= 1), + Line( + points={{2400,200},{2400,-400},{2200,-400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=have_chiWat and nHp >= 1), + Line( + points={{1800,-160},{1800,600},{2400,600}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and nHp >= 1), + Bitmap( + visible=have_chiWat and have_valHpOutIso and nHp >= 1, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={1800,-200}), + Line( points={{-2400,400},{2200,400},{2200,-700}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nHp >= 1), + Bitmap( + visible=have_valHpInlIso and nHp >= 1, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={2200,-200}), + Bitmap( + visible=have_chiWat and nHp >= 1 and have_valHpInlIso, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={2400,-200}), + Line( visible=have_chiWat and nHp >= 1 and have_valHpInlIso, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={2370,-200}, + rotation=-90), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and nHp >= 1 and have_valHpInlIso, + extent={{2260,-240},{2340,-160}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpInlIso and nHp >= 1, + extent={{2060,-240},{2140,-160}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_valHpInlIso and nHp >= 1, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={2170,-200}, + rotation=-90), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpOutIso and nHp >= 1, + extent={{1860,-240},{1940,-160}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and have_valHpOutIso and nHp >= 1, + extent={{1660,-240},{1740,-160}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_chiWat and have_valHpOutIso and nHp >= 1, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={1770,-200}, + rotation=-90), + Rectangle( + extent={{1780,20},{1820,-20}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 1), + Line( + points={{1000,-160},{1000,600},{1800,600}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and nHp >= 2), + Bitmap( + visible=have_chiWat and have_valHpOutIso and nHp >= 2, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={1000,-200}), + Line( points={{1400,400},{1400,-700}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nHp >= 2), + Bitmap( + visible=have_valHpInlIso and nHp >= 2, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={1400,-200}), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and nHp >= 2 and have_valHpInlIso, + extent={{1460,-240},{1540,-160}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpInlIso and nHp >= 2, + extent={{1260,-240},{1340,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_valHpInlIso and nHp >= 2, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={1370,-200}, + rotation=-90), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpOutIso and nHp >= 2, + extent={{1060,-240},{1140,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and have_valHpOutIso and nHp >= 2, + extent={{860,-240},{940,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_chiWat and have_valHpOutIso and nHp >= 2, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={970,-200}, + rotation=-90), + Rectangle( + extent={{980,20},{1020,-20}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 2), + Line( points={{1200,4},{1200,-696}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 2), + Bitmap( + visible=have_valHpOutIso and nHp >= 2, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={1200,-200}), + Line( visible=have_valHpOutIso and nHp >= 2, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={1170,-200}, + rotation=-90), + Line( + points={{200,-160},{200,600},{1000,600}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and nHp >= 3), + Bitmap( + visible=have_chiWat and have_valHpOutIso and nHp >= 3, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={200,-200}), + Line( points={{600,400},{600,-700}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nHp >= 3), + Bitmap( + visible=have_valHpInlIso and nHp >= 3, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={600,-200}), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpInlIso and nHp >= 3, + extent={{460,-240},{540,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_valHpInlIso and nHp >= 3, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={570,-200}, + rotation=-90), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpOutIso and nHp >= 3, + extent={{260,-240},{340,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and have_valHpOutIso and nHp >= 3, + extent={{60,-240},{140,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_chiWat and have_valHpOutIso and nHp >= 3, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={170,-200}, + rotation=-90), + Rectangle( + extent={{180,20},{220,-20}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 3), + Line( points={{400,0},{400,-700}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 3), + Bitmap( + visible=have_valHpOutIso and nHp >= 3, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={400,-200}), + Line( visible=have_valHpOutIso and nHp >= 3, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={370,-200}, + rotation=-90), + Line( + points={{-600,-160},{-600,600},{200,600}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and nHp >= 4), + Bitmap( + visible=have_chiWat and have_valHpOutIso and nHp >= 4, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-600,-200}), + Line( points={{-200,400},{-200,-700}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nHp >= 4), + Bitmap( + visible=have_valHpInlIso and nHp >= 4, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-200,-200}), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpInlIso and nHp >= 4, + extent={{-340,-240},{-260,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_valHpInlIso and nHp >= 4, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-230,-200}, + rotation=-90), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpOutIso and nHp >= 4, + extent={{-540,-240},{-460,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and have_valHpOutIso and nHp >= 4, + extent={{-740,-240},{-660,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_chiWat and have_valHpOutIso and nHp >= 4, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-630,-200}, + rotation=-90), + Rectangle( + extent={{-620,20},{-580,-20}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 4), + Line( points={{-400,0},{-400,-700}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 4), + Bitmap( + visible=have_valHpOutIso and nHp >= 4, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-400,-200}), + Line( visible=have_valHpOutIso and nHp >= 4, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-430,-200}, + rotation=-90), + Line( + points={{-1400,-160},{-1400,600},{-600,600}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and nHp >= 5), + Bitmap( + visible=have_chiWat and have_valHpOutIso and nHp >= 5, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-1400,-200}), + Line( points={{-1000,400},{-1000,-700}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nHp >= 5), + Bitmap( + visible=have_valHpInlIso and nHp >= 5, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-1000,-200}), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpInlIso and nHp >= 5, + extent={{-1140,-240},{-1060,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_valHpInlIso and nHp >= 5, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-1030,-200}, + rotation=-90), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpOutIso and nHp >= 5, + extent={{-1340,-240},{-1260,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and have_valHpOutIso and nHp >= 5, + extent={{-1540,-240},{-1460,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_chiWat and have_valHpOutIso and nHp >= 5, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-1430,-200}, + rotation=-90), + Rectangle( + extent={{-1420,20},{-1380,-20}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 5), + Line( points={{-1200,0},{-1200,-700}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 5), + Bitmap( + visible=have_valHpOutIso and nHp >= 5, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-1200,-200}), + Line( visible=have_valHpOutIso and nHp >= 5, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-1230,-200}, + rotation=-90), + Line( + points={{-2200,-160},{-2200,600},{-1400,600}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and nHp >= 6), + Bitmap( + visible=have_chiWat and have_valHpOutIso and nHp >= 6, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-2200,-200}), + Line( points={{-1800,400},{-1800,-700}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=nHp >= 6), + Bitmap( + visible=have_valHpInlIso and nHp >= 6, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-1800,-200}), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpInlIso and nHp >= 6, + extent={{-1940,-240},{-1860,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_valHpInlIso and nHp >= 6, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-1830,-200}, + rotation=-90), + Bitmap( + visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_valHpOutIso and nHp >= 6, + extent={{-2140,-240},{-2060,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and have_valHpOutIso and nHp >= 6, + extent={{-2340,-240},{-2260,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( visible=have_chiWat and have_valHpOutIso and nHp >= 6, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-2230,-200}, + rotation=-90), + Rectangle( + extent={{-2220,20},{-2180,-22}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 6), + Line( points={{-2000,0},{-2000,-700}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 6), + Bitmap( + visible=have_valHpOutIso and nHp >= 6, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-2000,-200}), + Line( visible=have_valHpOutIso and nHp >= 6, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-2030,-200}, + rotation=-90), + Line( points={{-2400,0},{2000,0},{2000,-700}}, + color={0,0,0}, + thickness=5, + visible=nHp >= 1), + Bitmap( + visible=have_valHpOutIso and nHp >= 1, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={2000,-200}), + Line( visible=have_valHpOutIso and nHp >= 1, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={1970,-200}, + rotation=-90), + Line(points={{1820,-508}}, color={0,0,0}), + Line( + points={{160,150},{0,150},{0,-50}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and not have_pumChiWatPriDed and nHp >= 1, + origin={1950,-400}, + rotation=90), + Line( + points={{160,150},{0,150},{0,-50}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and not have_pumChiWatPriDed and nHp >= 2, + origin={1150,-400}, + rotation=90), + Line( + points={{160,150},{0,150},{0,-50}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and not have_pumChiWatPriDed and nHp >= 3, + origin={350,-400}, + rotation=90), + Line( + points={{160,150},{0,150},{0,-50}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and not have_pumChiWatPriDed and nHp >= 4, + origin={-450,-400}, + rotation=90), + Line( + points={{160,150},{0,150},{0,-50}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and not have_pumChiWatPriDed and nHp >= 5, + origin={-1250,-400}, + rotation=90), + Line( + points={{160,150},{0,150},{0,-50}}, + color={0,0,0}, + thickness=5, + visible=have_chiWat and not have_pumChiWatPriDed and nHp >= 6, + origin={-2050,-400}, + rotation=90), + Rectangle( + extent={{2180,220},{2220,178}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 2), + Line( + points={{2400,200},{1600,200},{1600,-400},{1400,-400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=have_chiWat and nHp >= 2), + Bitmap( + visible=have_chiWat and nHp >= 2 and have_valHpInlIso, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={1600,-200}), + Line( visible=have_chiWat and nHp >= 2 and have_valHpInlIso, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={1570,-200}, + rotation=-90), + Rectangle( + extent={{1380,220},{1420,178}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 3), + Line( + points={{1600,200},{800,200},{800,-400},{600,-400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=have_chiWat and nHp >= 3), + Bitmap( + visible=have_chiWat and nHp >= 3 and have_valHpInlIso, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={800,-200}), + Line( visible=have_chiWat and nHp >= 3 and have_valHpInlIso, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={770,-200}, + rotation=-90), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and nHp >= 3 and have_valHpInlIso, + extent={{660,-240},{740,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Rectangle( + extent={{580,220},{620,180}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 4), + Rectangle( + extent={{-220,220},{-180,180}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 5), + Rectangle( + extent={{-1020,220},{-980,180}}, + lineColor={0,0,0}, + lineThickness=1, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + pattern=LinePattern.None, + visible=have_chiWat and nHp >= 6), + Line( + points={{800,200},{0,200},{0,-400},{-200,-400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=have_chiWat and nHp >= 4), + Bitmap( + visible=have_chiWat and nHp >= 4 and have_valHpInlIso, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={0,-200}), + Line( visible=have_chiWat and nHp >= 4 and have_valHpInlIso, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-30,-200}, + rotation=-90), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and nHp >= 4 and have_valHpInlIso, + extent={{-140,-240},{-60,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( + points={{0,200},{-800,200},{-800,-400},{-1000,-400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=have_chiWat and nHp >= 5), + Bitmap( + visible=have_chiWat and nHp >= 5 and have_valHpInlIso, + extent={{-100,-100},{100,100}}, + fileName= + "modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-800,-200}), + Line( visible=have_chiWat and nHp >= 5 and have_valHpInlIso, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-830,-200}, + rotation=-90), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and nHp >= 5 and have_valHpInlIso, + extent={{-940,-240},{-860,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg"), + Line( + points={{-800,200},{-1600,200},{-1600,-400},{-1800,-400}}, + color={0,0,0}, + pattern=LinePattern.Dash, + thickness=5, + visible=have_chiWat and nHp >= 6), + Bitmap( + visible=have_chiWat and nHp >= 6 and have_valHpInlIso, + extent={{-100,-100},{100,100}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Valves/TwoWay.svg", + rotation=360, + origin={-1600,-200}), + Line( visible=have_chiWat and nHp >= 6 and have_valHpInlIso, + points={{0,30},{0,-30}}, + color={0,0,0}, + origin={-1630,-200}, + rotation=-90), + Bitmap(visible=typ == Buildings.Templates.Components.Types.Valve.TwoWayTwoPosition + and have_chiWat and nHp >= 6 and have_valHpInlIso, + extent={{-1740,-240},{-1660,-160}}, + fileName="modelica://Buildings/Resources/Images/Templates/Components/Actuators/TwoPosition.svg")}), + Documentation( + info=" +

+This model represents the heat pump isolation valves. +The isolation valves are modeled as two-way two-position +valves, which can be located at the heat pump inlet and/or +outlet depending on the settings of the parameters have_valHpInlIso +and have_valHpOutIso. +It is assumed that the heat pumps always provide heating hot water. +Optionally, chilled water return and supply and the associated isolation valves +can be modeled by setting the parameter have_chiWat to true. +

+

Implementation details

+

+By default, the isolation valves are modeled considering a linear +variation of the pressure drop with the flow rate (linearized=true), +as opposed to the quadratic relationship usually considered for +a turbulent flow regime. +By limiting the size of the system of nonlinear equations, this setting +reduces the risk of solver failure and the time to solution. +", revisions=" +

    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+")); +end ValvesIsolation; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/package.mo b/Buildings/Templates/Plants/HeatPumps/Components/package.mo new file mode 100644 index 00000000000..aec862402dd --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/package.mo @@ -0,0 +1,14 @@ +within Buildings.Templates.Plants.HeatPumps; +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.Plants.HeatPumps. +

+")); +end Components; diff --git a/Buildings/Templates/Plants/HeatPumps/Components/package.order b/Buildings/Templates/Plants/HeatPumps/Components/package.order new file mode 100644 index 00000000000..426b14e3579 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Components/package.order @@ -0,0 +1,7 @@ +PumpsPrimaryDedicated +ValvesIsolation +Controls +HeatPumpGroups +Data +Validation +Interfaces diff --git a/Buildings/Templates/Plants/HeatPumps/Configuration/HeatPumpPlant.mo b/Buildings/Templates/Plants/HeatPumps/Configuration/HeatPumpPlant.mo new file mode 100644 index 00000000000..be40d255458 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Configuration/HeatPumpPlant.mo @@ -0,0 +1,138 @@ +within Buildings.Templates.Plants.HeatPumps.Configuration; +record HeatPumpPlant + "Configuration parameters for heat pump plant" + extends Modelica.Icons.Record; + // Generic + parameter Buildings.Templates.Components.Types.HeatPump typ + "Type of heat pump" + annotation (Evaluate=true); + parameter Buildings.Templates.Components.Types.HeatPumpModel typMod + "Type of heat pump model" + annotation (Evaluate=true); + parameter Boolean have_heaWat + "Set to true if the plant provides HW" + annotation (Evaluate=true); + parameter Boolean have_hotWat + "Set to true if the plant provides DHW" + annotation (Evaluate=true); + parameter Boolean have_chiWat + "Set to true if the plant provides CHW" + annotation (Evaluate=true); + parameter Boolean have_hrc + "Set to true for plants with a sidestream heat recovery chiller" + annotation (Evaluate=true); + parameter Integer nHp + "Number of heat pumps" + annotation (Evaluate=true); + parameter Boolean is_rev + "Set to true for reversible heat pumps, false for heating only" + annotation (Evaluate=true); + parameter Boolean have_valHpInlIso + "Set to true for isolation valves at HP inlet" + annotation (Evaluate=true); + parameter Boolean have_valHpOutIso + "Set to true for isolation valves at HP outlet" + annotation (Evaluate=true); + parameter Buildings.Templates.Plants.HeatPumps.Types.Controller typCtl + "Type of controller" + annotation (Evaluate=true); + parameter Integer nAirHan + "Number of air handling units served by the plant" + annotation (Evaluate=true); + parameter Integer nEquZon + "Number of terminal units (zone equipment) served by the plant" + annotation (Evaluate=true); + // Default fluid properties + parameter Modelica.Units.SI.Density rhoHeaWat_default + "HW default density" + annotation (Evaluate=true); + parameter Modelica.Units.SI.SpecificHeatCapacity cpHeaWat_default + "HW default specific heat capacity" + annotation (Evaluate=true); + parameter Modelica.Units.SI.Density rhoChiWat_default + "CHW default density" + annotation (Evaluate=true); + parameter Modelica.Units.SI.SpecificHeatCapacity cpChiWat_default + "CHW default specific heat capacity" + annotation (Evaluate=true); + parameter Modelica.Units.SI.Density rhoSou_default + "Source fluid default density" + annotation (Evaluate=true); + parameter Modelica.Units.SI.SpecificHeatCapacity cpSou_default + "Source fluid default specific heat capacity" + annotation (Evaluate=true); + // HW loop + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumHeaWatPri + "Type of primary HW pumps" + annotation (Evaluate=true); + parameter Integer nPumHeaWatPri + "Number of primary HW pumps" + annotation (Evaluate=true); + parameter Integer nPumHeaWatSec + "Number of secondary HW pumps" + annotation (Evaluate=true); + parameter Boolean have_valHeaWatMinByp + "Set to true if the HW loop has a minimum flow bypass valve" + annotation (Evaluate=true); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumPri + "Type of primary pump arrangement" + annotation (Evaluate=true); + parameter Boolean have_pumHeaWatPriVar + "Set to true for variable speed primary HW pumps" + annotation (Evaluate=true); + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary typPumHeaWatSec + "Type of secondary HW pumps" + annotation (Evaluate=true); + parameter Buildings.Templates.Plants.HeatPumps.Types.Distribution typDis + "Type of CHW/HW distribution system" + annotation (Evaluate=true); + parameter Boolean have_senDpHeaWatRemWir + "Set to true for remote HW differential pressure sensor(s) hardwired to plant or pump controller" + annotation (Evaluate=true); + parameter Integer nSenDpHeaWatRem + "Number of remote HW differential pressure sensors used for HW pump speed control" + annotation (Evaluate=true); + // CHW loop + parameter Boolean have_pumChiWatPriDed + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true); + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumChiWatPri + "Type of primary CHW pumps" + annotation (Evaluate=true); + parameter Integer nPumChiWatPri + "Number of primary CHW pumps" + annotation (Evaluate=true); + parameter Integer nPumChiWatSec + "Number of secondary CHW pumps" + annotation (Evaluate=true); + parameter Boolean have_valChiWatMinByp + "Set to true if the CHW loop has a minimum flow bypass valve" + annotation (Evaluate=true); + parameter Boolean have_pumChiWatPriVar + "Set to true for variable speed primary CHW pumps" + annotation (Evaluate=true); + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary typPumChiWatSec + "Type of secondary CHW pumps" + annotation (Evaluate=true); + parameter Boolean have_senDpChiWatRemWir + "Set to true for remote CHW differential pressure sensor(s) hardwired to plant or pump controller" + annotation (Evaluate=true); + parameter Integer nSenDpChiWatRem + "Number of remote CHW differential pressure sensors used for CHW pump speed control" + annotation (Evaluate=true); + parameter Boolean have_inpSch + "Set to true to provide schedule via software input point" + annotation (Evaluate=true); + annotation ( + defaultComponentPrefixes="parameter", + defaultComponentName="cfg", + Documentation( + info=" +

+This record provides the set of configuration parameters for +the heat pump plant models within + +Buildings.Templates.Plants.HeatPumps. +

+")); +end HeatPumpPlant; diff --git a/Buildings/Templates/Plants/HeatPumps/Configuration/package.mo b/Buildings/Templates/Plants/HeatPumps/Configuration/package.mo new file mode 100644 index 00000000000..8febf249dd3 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Configuration/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.Plants.HeatPumps; +package Configuration "Records for configuration parameters" + extends Modelica.Icons.MaterialPropertiesPackage; + annotation (Documentation(info=" +

+This package provides records for configuration parameters. +

+")); +end Configuration; diff --git a/Buildings/Templates/Plants/HeatPumps/Configuration/package.order b/Buildings/Templates/Plants/HeatPumps/Configuration/package.order new file mode 100644 index 00000000000..e15cae8bbc9 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Configuration/package.order @@ -0,0 +1 @@ +HeatPumpPlant diff --git a/Buildings/Templates/Plants/HeatPumps/Data/HeatPumpPlant.mo b/Buildings/Templates/Plants/HeatPumps/Data/HeatPumpPlant.mo new file mode 100644 index 00000000000..309f5f718d6 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Data/HeatPumpPlant.mo @@ -0,0 +1,127 @@ +within Buildings.Templates.Plants.HeatPumps.Data; +record HeatPumpPlant + "Record for heat pump plant" + extends Modelica.Icons.Record; + // Generic + parameter Buildings.Templates.Plants.HeatPumps.Configuration.HeatPumpPlant cfg + "Configuration parameters" + annotation (Dialog(enable=false)); + parameter String id="" + "System tag" + annotation (Dialog(tab="Advanced")); + parameter Buildings.Templates.Plants.HeatPumps.Components.Data.Controller ctl( + final cfg=cfg) + "Controller" + annotation (Dialog(group="Controls")); + parameter Buildings.Templates.Plants.HeatPumps.Components.Data.HeatPumpGroup + hp( + final typ=cfg.typ, + final nHp=cfg.nHp, + final is_rev=cfg.is_rev, + final typMod=cfg.typMod, + final cpHeaWat_default=cfg.cpHeaWat_default, + final cpSou_default=cfg.cpSou_default, + TChiWatSupHp_nominal=ctl.TChiWatSup_nominal, + capCooHp_nominal=ctl.capCooHp_nominal, + mHeaWatHp_flow_nominal=ctl.VHeaWatHp_flow_nominal*cfg.rhoHeaWat_default, + capHeaHp_nominal=ctl.capHeaHp_nominal, + mChiWatHp_flow_nominal=ctl.VChiWatHp_flow_nominal*cfg.rhoChiWat_default, + THeaWatSupHp_nominal=ctl.THeaWatSup_nominal) + "Heat pumps" + annotation (Dialog(group="Heat pumps")); + // HW loop + parameter Buildings.Templates.Components.Data.PumpMultiple pumHeaWatPri( + final nPum=cfg.nPumHeaWatPri, + final rho_default=cfg.rhoHeaWat_default, + final typ=if cfg.typPumHeaWatPri <> Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + then Buildings.Templates.Components.Types.Pump.Multiple else Buildings.Templates.Components.Types.Pump.None, + m_flow_nominal=fill(hp.nHp * ( + if cfg.have_chiWat and cfg.typPumChiWatPri==Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None then + max(hp.mHeaWatHp_flow_nominal, hp.mChiWatHp_flow_nominal) else hp.mHeaWatHp_flow_nominal) / + max(cfg.nPumHeaWatPri, 1), + cfg.nPumHeaWatPri)) + "Primary HW pumps" + annotation (Dialog(group="Primary HW loop")); + final parameter Buildings.Templates.Components.Data.PumpSingle pumHeaWatPriSin[max(cfg.nPumHeaWatPri, 1)]( + each typ=pumHeaWatPri.typ, + m_flow_nominal=if pumHeaWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then {0} else pumHeaWatPri.m_flow_nominal, + dp_nominal=if pumHeaWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then {0} else pumHeaWatPri.dp_nominal, + per( + pressure( + V_flow=if pumHeaWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then + [0] else pumHeaWatPri.per.pressure.V_flow, + dp=if pumHeaWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then + [0] else pumHeaWatPri.per.pressure.dp)), + each rho_default=pumHeaWatPri.rho_default) + "Cast multiple pump record into single pump record array"; + parameter Buildings.Templates.Components.Data.PumpMultiple pumHeaWatSec( + final nPum=cfg.nPumHeaWatSec, + final rho_default=cfg.rhoHeaWat_default, + final typ=if cfg.typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.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=cfg.have_heaWat and cfg.typPumHeaWatSec==Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized)); + // CHW loop + parameter Buildings.Templates.Components.Data.PumpMultiple pumChiWatPri( + final nPum=cfg.nPumChiWatPri, + final rho_default=cfg.rhoChiWat_default, + final typ=if cfg.typPumChiWatPri <> Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + then Buildings.Templates.Components.Types.Pump.Multiple else Buildings.Templates.Components.Types.Pump.None, + m_flow_nominal=fill(hp.mChiWatHp_flow_nominal * hp.nHp / max(cfg.nPumChiWatPri, 1), cfg.nPumChiWatPri)) + "Primary CHW pumps" + annotation (Dialog(group="Primary CHW loop", + enable=cfg.typPumChiWatPri<>Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None)); + final parameter Buildings.Templates.Components.Data.PumpSingle pumChiWatPriSin[max(cfg.nPumChiWatPri, 1)]( + each typ=pumChiWatPri.typ, + m_flow_nominal=if pumChiWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then {0} else pumChiWatPri.m_flow_nominal, + dp_nominal=if pumChiWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then {0} else pumChiWatPri.dp_nominal, + per( + pressure( + V_flow=if pumChiWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then + [ + 0] else pumChiWatPri.per.pressure.V_flow, + dp=if pumChiWatPri.typ == Buildings.Templates.Components.Types.Pump.None + then + [ + 0] else pumChiWatPri.per.pressure.dp)), + each rho_default=pumChiWatPri.rho_default) + "Cast multiple pump record into single pump record array"; + parameter Buildings.Templates.Components.Data.PumpMultiple pumChiWatSec( + final nPum=cfg.nPumChiWatSec, + final rho_default=cfg.rhoChiWat_default, + final typ=if cfg.typPumChiWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + then Buildings.Templates.Components.Types.Pump.Multiple else Buildings.Templates.Components.Types.Pump.None) + "Secondary CHW pumps" + annotation (Dialog(group="Secondary CHW loop", + enable=cfg.typPumChiWatSec==Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized)); + annotation ( + defaultComponentName="dat", + Documentation( + info=" +

+This record provides the set of sizing and operating parameters for +the heat pump plant models within + +Buildings.Templates.Plants.HeatPumps. +

+

+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 HeatPumpPlant; diff --git a/Buildings/Templates/Plants/HeatPumps/Data/package.mo b/Buildings/Templates/Plants/HeatPumps/Data/package.mo new file mode 100644 index 00000000000..14334eb8a65 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Data/package.mo @@ -0,0 +1,11 @@ +within Buildings.Templates.Plants.HeatPumps; +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/Plants/HeatPumps/Data/package.order b/Buildings/Templates/Plants/HeatPumps/Data/package.order new file mode 100644 index 00000000000..e15cae8bbc9 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Data/package.order @@ -0,0 +1 @@ +HeatPumpPlant diff --git a/Buildings/Templates/Plants/HeatPumps/Interfaces/Bus.mo b/Buildings/Templates/Plants/HeatPumps/Interfaces/Bus.mo new file mode 100644 index 00000000000..98cba382fc0 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Interfaces/Bus.mo @@ -0,0 +1,16 @@ +within Buildings.Templates.Plants.HeatPumps.Interfaces; +expandable connector Bus + "Control bus for heat pump plant" + extends Modelica.Icons.SignalBus; + annotation ( + defaultComponentName="bus", + Documentation( + info=" +

+ This expandable connector provides a standard interface for + all control signals of the heat pump plant models within + + Buildings.Templates.Plants.HeatPumps. +

+ ")); +end Bus; diff --git a/Buildings/Templates/Plants/HeatPumps/Interfaces/PartialHeatPumpPlant.mo b/Buildings/Templates/Plants/HeatPumps/Interfaces/PartialHeatPumpPlant.mo new file mode 100644 index 00000000000..8f57e405b53 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Interfaces/PartialHeatPumpPlant.mo @@ -0,0 +1,772 @@ +within Buildings.Templates.Plants.HeatPumps.Interfaces; +partial model PartialHeatPumpPlant + "Interface class for heat pump plant" + replaceable package MediumHeaWat=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "HW medium" + annotation (Dialog(enable=have_heaWat), + __ctrlFlow(enable=false)); + replaceable package MediumHotWat=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "DHW medium" + annotation (Dialog(enable=have_hotWat), + __ctrlFlow(enable=false)); + replaceable package MediumChiWat=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "CHW medium" + annotation (Dialog(enable=have_chiWat), + __ctrlFlow(enable=false)); + /* + Derived classes representing AWHP shall use: + redeclare final package MediumSou = MediumAir + */ + replaceable package MediumSou=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Source-side medium" + annotation (Dialog(enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater), + __ctrlFlow(enable=false)); + replaceable package MediumAir=Buildings.Media.Air + constrainedby Modelica.Media.Interfaces.PartialMedium + "Air medium" + annotation (Dialog(enable=typ==Buildings.Templates.Components.Types.HeatPump.AirToWater), + __ctrlFlow(enable=false)); + // The current implementation only supports plants that provide HHW. + final parameter Boolean have_heaWat=true + "Set to true if the plant provides HW" + annotation (Evaluate=true, + Dialog(group="Configuration")); + parameter Boolean have_chiWat=true + "Set to true if the plant provides CHW" + annotation (Evaluate=true, + Dialog(group="Configuration")); + // RFE: To be exposed for templates that include optional DHW service. + final parameter Boolean have_hotWat=false + "Set to true if the plant provides DHW" + annotation (Evaluate=true, + Dialog(group="Configuration")); + // RFE(AntoineGautier): Add option for sidestream HRC. Always excluded for now. + final parameter Boolean have_hrc( + start=false)=false + "Set to true for plants with a sidestream heat recovery chiller" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=have_heaWat and have_chiWat)); + parameter Buildings.Templates.Components.Types.HeatPump typ + "Type of heat pump" + annotation (Evaluate=true, + Dialog(group="Heat pumps")); + parameter Buildings.Templates.Plants.HeatPumps.Configuration.HeatPumpPlant cfg( + final cpChiWat_default=cpChiWat_default, + final cpHeaWat_default=cpHeaWat_default, + final cpSou_default=cpSou_default, + final have_chiWat=have_chiWat, + final have_heaWat=have_heaWat, + final have_hrc=have_hrc, + final have_hotWat=have_hotWat, + final have_pumHeaWatPriVar=have_pumHeaWatPriVar, + final have_pumChiWatPriVar=have_pumChiWatPriVar, + final have_pumChiWatPriDed=have_pumChiWatPriDed, + final have_valChiWatMinByp=have_valChiWatMinByp, + final have_valHeaWatMinByp=have_valHeaWatMinByp, + final have_valHpInlIso=have_valHpInlIso, + final have_valHpOutIso=have_valHpOutIso, + final is_rev=is_rev, + final nHp=nHp, + final nPumChiWatPri=nPumChiWatPri, + final nPumChiWatSec=nPumChiWatSec, + final nPumHeaWatPri=nPumHeaWatPri, + final nPumHeaWatSec=nPumHeaWatSec, + final rhoChiWat_default=rhoChiWat_default, + final rhoHeaWat_default=rhoHeaWat_default, + final rhoSou_default=rhoSou_default, + final typ=typ, + final typArrPumPri=typArrPumPri, + final typDis=typDis, + final typPumChiWatPri=typPumChiWatPri, + final typPumHeaWatPri=typPumHeaWatPri, + final typPumChiWatSec=typPumChiWatSec, + final typPumHeaWatSec=typPumHeaWatSec, + final typCtl=ctl.typ, + final nAirHan=ctl.nAirHan, + final nEquZon=ctl.nEquZon, + final have_senDpHeaWatRemWir=ctl.have_senDpHeaWatRemWir, + final nSenDpHeaWatRem=ctl.nSenDpHeaWatRem, + final have_senDpChiWatRemWir=ctl.have_senDpChiWatRemWir, + final nSenDpChiWatRem=ctl.nSenDpChiWatRem, + final have_inpSch=ctl.have_inpSch) + "Configuration parameters" + annotation (__ctrlFlow(enable=false)); + parameter Buildings.Templates.Plants.HeatPumps.Data.HeatPumpPlant dat( + cfg=cfg) + "Design and operating parameters" + annotation (Placement(transformation(extent={{-120,360},{-100,380}}))); + // RFE(AntoineGautier): Allow specifying subset of units dedicated to HW, CHW or DHW production. + parameter Integer nHp( + final min=1, + start=1) + "Total number of heat pumps" + annotation (Evaluate=true, + Dialog(group="Heat pumps")); + parameter Boolean is_rev + "Set to true for reversible heat pumps, false for heating only" + annotation (Evaluate=true, + Dialog(group="Heat pumps")); + // Plants with AWHP. + // RFE(AntoineGautier): Add constant primary-only option. + final parameter Buildings.Templates.Plants.HeatPumps.Types.Distribution typDis_select1( + start=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2)= + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2 + "Type of distribution system" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ==Buildings.Templates.Components.Types.HeatPump.AirToWater), + choices( + choice=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2 + "Constant primary - Variable secondary centralized")); + // Plants with WWHP. + parameter Buildings.Templates.Plants.HeatPumps.Types.Distribution typDis_select2( + start=Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2) + "Type of distribution system" + annotation (Evaluate=true, + Dialog(group="Configuration", + enable=typ==Buildings.Templates.Components.Types.HeatPump.WaterToWater)); + final parameter Buildings.Templates.Plants.HeatPumps.Types.Distribution typDis= + if typ == Buildings.Templates.Components.Types.HeatPump.AirToWater then typDis_select1 + else typDis_select2 + "Type of distribution system" + annotation (Evaluate=true); + final parameter Boolean have_valHpInlIso=if not have_chiWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Dedicated then false + else true + "Set to true for isolation valves at HP inlet" + annotation (Evaluate=true); + final parameter Boolean have_valHpOutIso=if not have_chiWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Dedicated then false + elseif nHp == 1 then false elseif have_pumChiWatPriDed then false else true + "Set to true for isolation valves at HP outlet" + annotation (Evaluate=true); + parameter Buildings.Templates.Components.Types.PumpArrangement typArrPumPri= + Buildings.Templates.Components.Types.PumpArrangement.Dedicated + "Type of primary pump arrangement" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + final parameter Boolean have_bypHeaWatFix= + have_heaWat and typDis <> Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + and typDis <> Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + "Set to true if the HW loop has a fixed bypass" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + final parameter Boolean have_valHeaWatMinByp=have_heaWat and typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + "Set to true if the HW loop has a minimum flow bypass valve" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + // Constant primary plants with dedicated primary pumps. + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumHeaWatPri_select1( + start=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable)= + Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Type of primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_heaWat and typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and (typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2)), + choices( + choice=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Constant + "Constant speed pump specified separately", + choice=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Variable speed pump specified separately")); + // Constant primary plants with headered primary pumps. + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumHeaWatPri_select2( + start=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable)= + Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Type of primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_heaWat and typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and (typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2)), + choices(choice=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Constant + "Constant speed pump specified separately", + choice=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Variable speed pump specified separately")); + // Variable primary plants with headered primary pumps require variable speed pumps. + final parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumHeaWatPri= + if have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated + and (typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2) + then typPumHeaWatPri_select1 elseif have_heaWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Headered and (typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only or typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2) + then typPumHeaWatPri_select2 elseif have_heaWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Dedicated and (typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only or typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2) then + Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + elseif have_heaWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and (typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2) + then Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable else + Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + "Type of primary HW pumps" + annotation (Evaluate=true); + final parameter Boolean have_pumHeaWatPriVar= + typPumHeaWatPri == Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Set to true for variable speed primary HW pumps" + annotation (Evaluate=true); + parameter Integer nPumHeaWatPri_select( + final min=0, + start=0)=nHp + "Number of primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_heaWat and typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + final parameter Integer nPumHeaWatPri=if have_heaWat then (if typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Headered then nPumHeaWatPri_select + else nHp) else 0 + "Number of primary HW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + // RFE: Only centralized secondary HW pumps are currently supported for primary-secondary plants. + final parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary typPumHeaWatSec= + if have_heaWat and (typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2 + or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2) + then Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + else Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Type of secondary HW pumps" + annotation (Evaluate=true, + Dialog(group="Secondary HW loop")); + // Primary-secondary plants. + parameter Integer nPumHeaWatSec_select( + final min=0)=nHp + "Number of secondary HW pumps" + annotation (Evaluate=true, + Dialog(group="Secondary HW loop", + enable=have_heaWat and (typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2 + or typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2))); + final parameter Integer nPumHeaWatSec( + final min=0)=if not have_heaWat or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + then 0 else nPumHeaWatSec_select + "Number of secondary HW pumps" + annotation (Evaluate=true, + Dialog(group="Secondary HW loop")); + // Plants with dedicated primary pumps. + parameter Boolean have_pumChiWatPriDed_select( + start=false)=false + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_chiWat and typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Dedicated)); + final parameter Boolean have_pumChiWatPriDed=if have_chiWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Dedicated then have_pumChiWatPriDed_select + else false + "Set to true for plants with separate dedicated primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + final parameter Boolean have_bypChiWatFix= + have_chiWat and typDis <> Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + and typDis <> Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + "Set to true if the CHW loop has a fixed bypass" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + final parameter Boolean have_valChiWatMinByp=have_chiWat and typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + "Set to true if the CHW loop has a minimum flow bypass valve" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + // Constant primary plants with separate dedicated primary CHW pumps. + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumChiWatPri_select1( + start=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable)= + typPumHeaWatPri + "Type of primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_pumChiWatPriDed and (typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2))); + // Constant primary plants with headered primary pumps. + parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumChiWatPri_select2( + start=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable)= + typPumHeaWatPri + "Type of primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_chiWat and typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered + and (typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2)), + choices(choice=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Constant + "Constant speed pump specified separately", + choice=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Variable speed pump specified separately")); + // Variable primary plants with headered primary CHW pumps require variable speed pumps. + final parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary typPumChiWatPri= + if have_pumChiWatPriDed and (typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2) + then typPumChiWatPri_select1 elseif have_chiWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Headered and (typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only or typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2) + then typPumChiWatPri_select2 elseif have_pumChiWatPriDed and (typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only or typDis == + Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2) then + Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + elseif have_chiWat and typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Headered + and (typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2) + then Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable else + Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + "Type of primary CHW pumps" + annotation (Evaluate=true); + final parameter Boolean have_pumChiWatPriVar= + typPumChiWatPri == Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable + "Set to true for variable speed primary CHW pumps" + annotation (Evaluate=true); + // Plants with headered primary CHW pumps. + parameter Integer nPumChiWatPri_select( + final min=0, + start=0)=nHp + "Number of primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop", + enable=have_chiWat and typArrPumPri==Buildings.Templates.Components.Types.PumpArrangement.Headered)); + final parameter Integer nPumChiWatPri=if have_chiWat and typArrPumPri == + Buildings.Templates.Components.Types.PumpArrangement.Headered then nPumChiWatPri_select + elseif have_pumChiWatPriDed then nHp else 0 + "Number of primary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Primary loop")); + // RFE: Currently, only centralized secondary CHW pumps are supported for primary-secondary plants. + final parameter Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary typPumChiWatSec= + if have_chiWat and (typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2 + or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2) + then Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.Centralized + else Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + "Type of secondary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Secondary CHW loop")); + parameter Integer nPumChiWatSec_select( + final min=0)=nHp + "Number of secondary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Secondary CHW loop", + enable=have_chiWat and (typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Variable2 + or typDis==Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1And2))); + final parameter Integer nPumChiWatSec( + final min=0)=if not have_chiWat or typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + then 0 else nPumChiWatSec_select + "Number of secondary CHW pumps" + annotation (Evaluate=true, + Dialog(group="Secondary CHW loop")); + // Design and operating parameters. + final parameter Modelica.Units.SI.MassFlowRate mHeaWatPri_flow_nominal=if have_heaWat + then dat.hp.mHeaWatHp_flow_nominal * nHp else 0 + "Primary HW mass flow rate" + annotation (Evaluate=true); + final parameter Modelica.Units.SI.MassFlowRate mHeaWat_flow_nominal=if have_heaWat + then (if typPumHeaWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + then mHeaWatPri_flow_nominal else sum(dat.pumHeaWatSec.m_flow_nominal)) else 0 + "HW mass flow rate (total, distributed to consumers)" + annotation (Evaluate=true); + final parameter Modelica.Units.SI.HeatFlowRate capHea_nominal=if have_heaWat + then abs(dat.hp.capHeaHp_nominal) * nHp else 0 + "Heating capacity - All units"; + final parameter Modelica.Units.SI.HeatFlowRate QHea_flow_nominal= + capHea_nominal + "Heating heat flow rate - All units"; + final parameter Modelica.Units.SI.Temperature THeaWatSup_nominal=dat.ctl.THeaWatSup_nominal + "Maximum HW supply temperature"; + final parameter Modelica.Units.SI.Temperature THeaWatRet_nominal= + THeaWatSup_nominal - QHea_flow_nominal / cpHeaWat_default / + mHeaWat_flow_nominal + "HW return temperature"; + final parameter Modelica.Units.SI.MassFlowRate mChiWatPri_flow_nominal=if have_chiWat + then dat.hp.mChiWatHp_flow_nominal * nHp else 0 + "Primary CHW mass flow rate" + annotation (Evaluate=true); + final parameter Modelica.Units.SI.MassFlowRate mChiWat_flow_nominal=if have_chiWat + then (if typPumChiWatSec == Buildings.Templates.Plants.HeatPumps.Types.PumpsSecondary.None + then mChiWatPri_flow_nominal else sum(dat.pumChiWatSec.m_flow_nominal)) else 0 + "CHW mass flow rate - Total, distributed to consumers" + annotation (Evaluate=true); + final parameter Modelica.Units.SI.HeatFlowRate capCoo_nominal=if have_chiWat + then abs(dat.hp.capCooHp_nominal) * nHp else 0 + "Cooling capacity - All units"; + final parameter Modelica.Units.SI.HeatFlowRate QCoo_flow_nominal=- + capCoo_nominal + "Cooling heat flow rate - All units"; + final parameter Modelica.Units.SI.Temperature TChiWatSup_nominal=dat.ctl.TChiWatSup_nominal + "Minimum CHW supply temperature"; + final parameter Modelica.Units.SI.Temperature TChiWatRet_nominal=if is_rev + then TChiWatSup_nominal - QCoo_flow_nominal / cpChiWat_default / + mChiWat_flow_nominal else Buildings.Templates.Data.Defaults.TChiWatRet + "CHW return temperature - Each heat pump" + annotation (Dialog(group="Nominal condition")); + final parameter Modelica.Units.SI.Temperature TSouHea_nominal=dat.hp.TSouHeaHp_nominal + "OAT or source fluid supply temperature (evaporator entering) in heating mode - Each heat pump"; + final parameter Modelica.Units.SI.Temperature TSouCoo_nominal=dat.hp.TSouCooHp_nominal + "OAT or source fluid supply temperature (evaporator entering) in cooling mode - Each heat pump"; + // Dynamics and miscellaneous parameterss. + 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 MediumHeaWat.Density rhoHeaWat_default=MediumHeaWat.density(staHeaWat_default) + "HW default density" + annotation (Evaluate=true); + final parameter MediumHeaWat.SpecificHeatCapacity cpHeaWat_default= + MediumHeaWat.specificHeatCapacityCp(staHeaWat_default) + "HW default specific heat capacity" + annotation (Evaluate=true); + final parameter MediumHeaWat.ThermodynamicState staHeaWat_default=MediumHeaWat.setState_pTX( + T=THeaWatSup_nominal, + p=MediumHeaWat.p_default, + X=MediumHeaWat.X_default) + "HW default state" + annotation (Evaluate=true); + final parameter MediumChiWat.Density rhoChiWat_default=MediumChiWat.density(staChiWat_default) + "CHW default density" + annotation (Evaluate=true); + final parameter MediumChiWat.SpecificHeatCapacity cpChiWat_default= + MediumChiWat.specificHeatCapacityCp(staChiWat_default) + "CHW default specific heat capacity" + annotation (Evaluate=true); + final parameter MediumChiWat.ThermodynamicState staChiWat_default=MediumChiWat.setState_pTX( + T=TChiWatSup_nominal, + p=MediumChiWat.p_default, + X=MediumChiWat.X_default) + "CHW default state" + annotation (Evaluate=true); + /* + Source fluid default state = heating mode: + - Impact of difference between TSouHea_nominal and TSouCoo_nominal on cp is about 0.5 %. + - Impact of difference between TSouHea_nominal and TSouCoo_nominal on rho is about 2 %, + with rhoSouHea_nominal > rhoSouCoo_nominal, so conservative for pump sizing. + */ + final parameter MediumSou.Density rhoSou_default=MediumSou.density(staSou_default) + "Source fluid default density" + annotation (Evaluate=true); + final parameter MediumSou.SpecificHeatCapacity cpSou_default=MediumSou.specificHeatCapacityCp(staSou_default) + "Source fluid default specific heat capacity" + annotation (Evaluate=true); + final parameter MediumSou.ThermodynamicState staSou_default=MediumSou.setState_pTX( + T=TSouHea_nominal, + p=MediumSou.p_default, + X=MediumSou.X_default) + "Source fluid default state" + annotation (Evaluate=true); + Modelica.Fluid.Interfaces.FluidPort_a port_aHeaWat( + redeclare final package Medium=MediumHeaWat, + m_flow( + final min=if allowFlowReversal then - Modelica.Constants.inf else 0), + h_outflow( + start=MediumHeaWat.h_default, + nominal=MediumHeaWat.h_default)) + if have_heaWat + "HW return" + annotation (Placement(transformation(extent={{590,-370},{610,-350}}), + iconTransformation(extent={{190,-190},{210,-170}}))); + Modelica.Fluid.Interfaces.FluidPort_b port_bHeaWat( + redeclare final package Medium=MediumHeaWat, + m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + h_outflow( + start=MediumHeaWat.h_default, + nominal=MediumHeaWat.h_default)) + if have_heaWat + "HW supply" + annotation (Placement(transformation(extent={{590,-290},{610,-270}}), + iconTransformation(extent={{190,-110},{210,-90}}))); + Modelica.Fluid.Interfaces.FluidPort_a port_aChiWat( + redeclare final package Medium=MediumChiWat, + m_flow( + final min=if allowFlowReversal then - Modelica.Constants.inf else 0), + h_outflow( + start=MediumChiWat.h_default, + nominal=MediumChiWat.h_default)) + if have_chiWat + "CHW return" + annotation (Placement(transformation(extent={{590,-10},{610,10}}), + iconTransformation(extent={{190,-50},{210,-30}}))); + Modelica.Fluid.Interfaces.FluidPort_b port_bChiWat( + redeclare final package Medium=MediumChiWat, + m_flow( + max=if allowFlowReversal then + Modelica.Constants.inf else 0), + h_outflow( + start=MediumChiWat.h_default, + nominal=MediumChiWat.h_default)) + if have_chiWat + "CHW supply" + annotation (Placement(transformation(extent={{590,70},{610,90}}), + iconTransformation(extent={{190,30},{210,50}}))); + Buildings.Templates.Plants.HeatPumps.Interfaces.Bus bus + "Plant control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}},rotation=90, + origin={-600,320}), + iconTransformation(extent={{-20,-20},{20,20}},rotation=90,origin={-200,180}))); + Buildings.Templates.AirHandlersFans.Interfaces.Bus busAirHan[cfg.nAirHan] + if cfg.nAirHan > 0 + "Air handling unit control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}},rotation=-90, + origin={600,340}), + iconTransformation(extent={{-20,-20},{20,20}},rotation=-90,origin={200,180}))); + Buildings.Templates.ZoneEquipment.Interfaces.Bus busEquZon[cfg.nEquZon] + if cfg.nEquZon > 0 + "Terminal unit control bus" + annotation (Placement(transformation(extent={{-20,-20},{20,20}},rotation=-90, + origin={600,300}), + iconTransformation(extent={{-20,-20},{20,20}},rotation=-90,origin={200,120}))); + BoundaryConditions.WeatherData.Bus busWea + "Weather bus" + annotation (Placement(transformation(extent={{-20,380},{20,420}}), + iconTransformation(extent={{-20,180},{20,220}}))); + replaceable Buildings.Templates.Plants.HeatPumps.Components.Interfaces.PartialController ctl + constrainedby + Buildings.Templates.Plants.HeatPumps.Components.Interfaces.PartialController( + final cfg=cfg, + final dat=dat.ctl) + "Plant controller" + annotation ( + Dialog(group="Controls"), + Placement(transformation(extent={{460,310},{480,330}}))); + // Miscellaneous + Buildings.Fluid.Sources.Outside out( + redeclare replaceable package Medium=Buildings.Media.Air, + nPorts=1) + "Outdoor air conditions" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=-90, + origin={0,380}))); + Buildings.Fluid.Sensors.Temperature TOut( + redeclare replaceable package Medium=Buildings.Media.Air, + warnAboutOnePortConnection=false) + "OA temperature" + annotation (Placement(transformation(extent={{-30,370},{-10,390}}))); +initial equation + if typArrPumPri == Buildings.Templates.Components.Types.PumpArrangement.Dedicated then + assert(nPumHeaWatPri == nHp, "In " + getInstanceName() + ": " + + "In case of dedicated primary HW pumps, the number pumps (=" + String(nPumHeaWatPri) + + ") must be equal to the number of heat pumps (=" + String(nHp) + ")."); + end if; + if have_pumChiWatPriDed then + assert(nPumChiWatPri == nHp, "In " + getInstanceName() + ": " + + "In case of separate dedicated primary CHW pumps, the number pumps (=" + + String(nPumChiWatPri) + ") must be equal to the number of heat pumps (=" + + String(nHp) + ")."); + end if; +equation + /* Control point connection - start */ + connect(TOut.T, bus.TOut); + /* Control point connection - stop */ + connect(bus, ctl.bus) + annotation (Line(points={{-600,320},{460,320}}, color={255,204,51},thickness=0.5)); + connect(ctl.busAirHan, busAirHan) + annotation (Line(points={{480,326},{580,326},{580,340},{600,340}}, color={255,204,51},thickness=0.5)); + connect(ctl.busEquZon, busEquZon) + annotation (Line(points={{480,314},{580,314},{580,300},{600,300}}, color={255,204,51},thickness=0.5)); + connect(busWea, out.weaBus) + annotation (Line(points={{0,400},{0,390},{0.2,390}},color={255,204,51},thickness=0.5)); + connect(out.ports[1], TOut.port) + annotation (Line(points={{0,370},{-20,370}}, + color={0,127,255})); + annotation ( + defaultComponentName="plaHp", + Icon( + coordinateSystem( + preserveAspectRatio=false, + extent={{-200,-200},{200,200}}), + graphics={ + Line( + points={{20,-100},{20,-180},{200,-180}}, + color={28,108,200}, + thickness=5, + pattern=LinePattern.Dash, + visible=have_chiWat), + Line( + points={{0,40},{0,-100},{-40,-100}}, + color={28,108,200}, + thickness=5, + origin={160,-100}, + rotation=-90, + visible=have_chiWat), + Rectangle( + extent={{-200,200},{200,-200}}, + lineColor={0,0,255}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Text( + extent={{-151,-212},{149,-252}}, + textColor={0,0,255}, + textString="%name"), + Line( + points={{20,-40},{20,-100},{-60,-100}}, + color={238,46,47}, + pattern=LinePattern.Dash, + thickness=5), + Line( + points={{-60,60},{20,60},{20,-40}}, + color={238,46,47}, + thickness=5, + pattern=LinePattern.Dash), + Line( + points={{100,-100},{100,-180}}, + color={238,46,47}, + thickness=5, + visible=have_heaWat), + Rectangle( + extent={{-160,130},{-60,30}}, + lineColor={0,0,255}, + pattern=LinePattern.None, + fillColor={95,95,95}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-130,100},{-90,60}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-122,96},{-126,68}}, + color={0,0,0}), + Line( + points={{-98,96},{-94,68}}, + color={0,0,0}), + Rectangle( + extent={{-160,-32},{-60,-132}}, + lineColor={0,0,255}, + pattern=LinePattern.None, + fillColor={95,95,95}, + fillPattern=FillPattern.Solid), + Ellipse( + extent={{-130,-62},{-90,-102}}, + lineColor={0,0,0}, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid), + Line( + points={{-122,-66},{-126,-94}}, + color={0,0,0}), + Line( + points={{-98,-66},{-94,-94}}, + color={0,0,0}), + Line( + points={{100,38},{100,-42}}, + color={28,108,200}, + thickness=5, + visible=have_chiWat), + Line( + points={{0,40},{0,-100}}, + color={28,108,200}, + thickness=5, + visible=have_chiWat, + origin={160,40}, + rotation=-90), + Line( + points={{0,40},{0,-140}}, + color={28,108,200}, + thickness=5, + visible=have_chiWat, + origin={160,-40}, + rotation=-90, + pattern=LinePattern.Dash), + Line( + points={{-60,-60},{60,-60},{60,40}}, + color={238,46,47}, + thickness=5), + Line( + points={{-60,100},{60,100},{60,40}}, + color={238,46,47}, + thickness=5), + Ellipse( + extent={{-40,-40},{0,-80}}, + lineColor={0,0,0}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}), + Polygon( + points={{-20,-41},{-20,-79},{-1,-60},{-20,-41}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255}), + 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={{0,40},{0,-100},{-40,-100}}, + color={238,46,47}, + thickness=5, + visible=have_heaWat, + origin={160,-100}, + rotation=-90), + Line( + points={{0,40},{0,-140},{-80,-140}}, + color={238,46,47}, + thickness=5, + visible=have_heaWat, + pattern=LinePattern.Dash, + origin={160,-180}, + rotation=-90), + Ellipse( + extent={{130,-80},{170,-120}}, + lineColor={0,0,0}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}, + startAngle=0, + endAngle=360, + visible=have_heaWat and typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None), + Polygon( + points={{150,-81},{150,-119},{169,-100},{150,-81}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255}, + visible=have_heaWat and typPumHeaWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None), + Ellipse( + extent={{130,60},{170,20}}, + lineColor={0,0,0}, + fillPattern=FillPattern.Sphere, + fillColor={0,100,199}, + startAngle=0, + endAngle=360, + visible=have_chiWat and typPumChiWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None), + Polygon( + points={{150,59},{150,21},{169,40},{150,59}}, + lineColor={0,0,0}, + pattern=LinePattern.None, + fillPattern=FillPattern.HorizontalCylinder, + fillColor={255,255,255}, + visible=have_chiWat and typPumChiWatSec<>Buildings.Templates.HeatingPlants.HotWater.Types.PumpsSecondary.None)}), + Diagram( + coordinateSystem( + preserveAspectRatio=false, + extent={{-600,-400},{600,400}})), + Documentation( + revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+", + info=" +

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

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

+This package contains interface classes. +

+")); +end Interfaces; diff --git a/Buildings/Templates/Plants/HeatPumps/Interfaces/package.order b/Buildings/Templates/Plants/HeatPumps/Interfaces/package.order new file mode 100644 index 00000000000..395e1f57ca1 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Interfaces/package.order @@ -0,0 +1,2 @@ +Bus +PartialHeatPumpPlant diff --git a/Buildings/Templates/Plants/HeatPumps/Types.mo b/Buildings/Templates/Plants/HeatPumps/Types.mo new file mode 100644 index 00000000000..eced4ebe8bf --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Types.mo @@ -0,0 +1,48 @@ +within Buildings.Templates.Plants.HeatPumps; +package Types + "Package with type definitions" + extends Modelica.Icons.TypesPackage; + type Controller = enumeration( + AirToWater + "Controller for AWHP plant", + OpenLoop + "Open loop controller") + "Enumeration to specify the plant controller"; + type Distribution = enumeration( + Constant1Only + "Constant primary-only", + Variable1Only + "Variable primary-only", + Constant1Variable2 + "Constant primary - Variable secondary centralized", + Variable1And2 + "Variable primary - Variable secondary centralized") + "Enumeration to specify the type of CHW/HW distribution system"; + type PumpsPrimary = enumeration( + Constant + "Constant speed pump specified separately", + Variable + "Variable speed pump specified separately", + None + "No pump") + "Enumeration to specify the type of primary pumps"; + type PumpsSecondary = enumeration( + None + "No secondary pumps (primary-only)", + Centralized + "Variable secondary centralized") + "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/Plants/HeatPumps/Validation/AirToWater.mo b/Buildings/Templates/Plants/HeatPumps/Validation/AirToWater.mo new file mode 100644 index 00000000000..dc1438e2bd2 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/AirToWater.mo @@ -0,0 +1,386 @@ +within Buildings.Templates.Plants.HeatPumps.Validation; +model AirToWater + "Validation of AWHP plant template" + extends Modelica.Icons.Example; + replaceable package Medium=Buildings.Media.Water + constrainedby Modelica.Media.Interfaces.PartialMedium + "Main medium (common for CHW and HW)"; + parameter Boolean have_chiWat=true + "Set to true if the plant provides CHW" + annotation (Evaluate=true, + Dialog(group="Configuration")); + inner parameter UserProject.Data.AllSystems datAll( + pla(final cfg=pla.cfg)) + "Plant parameters" + annotation (Placement(transformation(extent={{-120,160},{-100,180}}))); + 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 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")); + BoundaryConditions.WeatherData.ReaderTMY3 weaDat( + filNam=Modelica.Utilities.Files.loadResource( + "modelica://Buildings/Resources/weatherdata/USA_CA_San.Francisco.Intl.AP.724940_TMY3.mos")) + "Outdoor conditions" + annotation (Placement(transformation(extent={{-10,-10},{10,10}},rotation=0, + origin={-170,-40}))); + Fluid.HeatExchangers.SensibleCooler_T loaHeaWat( + redeclare final package Medium=Medium, + final m_flow_nominal=pla.mHeaWat_flow_nominal, + show_T=true, + final dp_nominal=0, + final energyDynamics=energyDynamics, + tau=300, + QMin_flow=-pla.capHea_nominal) + "HW system approximated by prescribed return temperature" + annotation (Placement(transformation(extent={{70,-110},{90,-90}}))); + Fluid.HeatExchangers.Heater_T loaChiWat( + redeclare final package Medium=Medium, + final m_flow_nominal=pla.mChiWat_flow_nominal, + show_T=true, + final dp_nominal=0, + final energyDynamics=energyDynamics, + tau=300, + QMax_flow=pla.capCoo_nominal) + if have_chiWat + "CHW system system approximated by prescribed return temperature" + annotation (Placement(transformation(extent={{70,-50},{90,-30}}))); + Fluid.Actuators.Valves.TwoWayEqualPercentage valDisHeaWat( + redeclare final package Medium=Medium, + m_flow_nominal=pla.mHeaWat_flow_nominal, + dpValve_nominal=3E4, + dpFixed_nominal=datAll.pla.ctl.dpHeaWatRemSet_max[1] - 3E4) + "Distribution system approximated by variable flow resistance" + annotation (Placement(transformation(extent={{110,-110},{130,-90}}))); + Fluid.Actuators.Valves.TwoWayEqualPercentage valDisChiWat( + redeclare final package Medium=Medium, + m_flow_nominal=pla.mChiWat_flow_nominal, + dpValve_nominal=3E4, + dpFixed_nominal=datAll.pla.ctl.dpChiWatRemSet_max[1] - 3E4) + if have_chiWat + "Distribution system approximated by variable flow resistance" + annotation (Placement(transformation(extent={{110,-50},{130,-30}}))); + Buildings.Templates.Plants.HeatPumps.AirToWater pla( + redeclare final package MediumHeaWat=Medium, + final dat=datAll.pla, + final have_chiWat=have_chiWat, + nHp=3, + typArrPumPri=Buildings.Templates.Components.Types.PumpArrangement.Dedicated, + typPumHeaWatPri_select2=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Variable, + typPumChiWatPri_select1=Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.Constant, + final energyDynamics=energyDynamics, + final allowFlowReversal=allowFlowReversal, + show_T=true, + ctl( + nAirHan=1, + nEquZon=0, + have_senVHeaWatPri_select=true, + have_senVChiWatPri_select=true, + have_senTHeaWatPriRet_select=true, + have_senTChiWatPriRet_select=true, + have_senTHeaWatSecRet=true, + have_senTChiWatSecRet=true, + have_senDpHeaWatRemWir=true)) + "Heat pump plant" + annotation (Placement(transformation(extent={{-80,-100},{-40,-60}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant TDum( + k=293.15, + y(final unit="K", + displayUnit="degC")) + "Placeholder signal for request generator" + annotation (Placement(transformation(extent={{-180,130},{-160,150}}))); + Fluid.Sensors.RelativePressure dpHeaWatRem_1( + redeclare final package Medium = Medium) + "HW differential pressure at one remote location" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={40,-120}))); + Fluid.Sensors.RelativePressure dpChiWatRem_1( + redeclare final package Medium = Medium) if have_chiWat + "CHW differential pressure at one remote location" + annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={40,-60}))); + Buildings.Controls.OBC.ASHRAE.G36.AHUs.MultiZone.VAV.SetPoints.PlantRequests reqPlaRes( + final heaCoi=Buildings.Controls.OBC.ASHRAE.G36.Types.HeatingCoil.WaterBased, final + cooCoi=if have_chiWat then Buildings.Controls.OBC.ASHRAE.G36.Types.CoolingCoil.WaterBased + else Buildings.Controls.OBC.ASHRAE.G36.Types.CoolingCoil.None) + "Plant and reset request" + annotation (Placement(transformation(extent={{90,102},{70,122}}))); + AirHandlersFans.Interfaces.Bus busAirHan "AHU control bus" annotation ( + Placement(transformation(extent={{-60,100},{-20,140}}),iconTransformation( + extent={{-340,-140},{-300,-100}}))); + Interfaces.Bus busPla "Plant control bus" annotation (Placement( + transformation(extent={{-100,-40},{-60,0}}), iconTransformation(extent + ={{-370,-70},{-330,-30}}))); + Buildings.Controls.OBC.CDL.Routing.RealVectorFilter dpChiWatRem( + final nin=pla.cfg.nSenDpChiWatRem, + final nout=pla.cfg.nSenDpChiWatRem) if have_chiWat + "Gather all remote CHW differential pressure signals" + annotation (Placement(transformation(extent={{10,10},{-10,30}}))); + Buildings.Controls.OBC.CDL.Routing.RealVectorFilter dpHeaWatRem( + final nin=pla.cfg.nSenDpHeaWatRem, + final nout=pla.cfg.nSenDpHeaWatRem) + "Gather all remote HW differential pressure signals" + annotation (Placement(transformation(extent={{10,-30},{-10,-10}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.TimeTable ratFlo( + table=[0,0,0; 5,0,0; 7,1,0; 12,0.2,0.2; 16,0,1; 22,0.1,0.1; 24,0,0], + timeScale=3600) + "Source signal for flow rate ratio – Index 1 for HW, 2 for CHW" + annotation (Placement(transformation(extent={{-180,70},{-160,90}}))); + Buildings.Controls.OBC.CDL.Reals.PID ctlEquZon[if have_chiWat then 2 else 1]( + each k=0.1, + each Ti=60, + each final reverseActing=true) "Zone equipment controller" + annotation (Placement(transformation(extent={{70,70},{90,90}}))); + Buildings.Controls.OBC.CDL.Reals.MultiplyByParameter norFlo[if have_chiWat + then 2 else 1]( + k=if have_chiWat then {1/pla.mHeaWat_flow_nominal,1/pla.mChiWat_flow_nominal} + else {1/pla.mHeaWat_flow_nominal}) + "Normalize flow rate" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=90, + origin={180,0}))); + Fluid.Sensors.MassFlowRate mChiWat_flow( + redeclare final package Medium = Medium) if have_chiWat + "CHW mass flow rate" annotation ( + Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={160,-60}))); + Fluid.Sensors.MassFlowRate mHeaWat_flow(redeclare final package Medium = + Medium) "HW mass flow rate" annotation (Placement(transformation( + extent={{-10,-10},{10,10}}, + rotation=-90, + origin={160,-120}))); + Buildings.Controls.OBC.CDL.Reals.AddParameter TChiWatRet(p=pla.TChiWatRet_nominal + - pla.TChiWatSup_nominal) if have_chiWat + "Prescribed CHW return temperature" + annotation (Placement(transformation(extent={{-130,30},{-110,50}}))); + Buildings.Controls.OBC.CDL.Reals.AddParameter THeaWatRet(p=pla.THeaWatRet_nominal + - pla.THeaWatSup_nominal) "Prescribed HW return temperature" + annotation (Placement(transformation(extent={{-130,-10},{-110,10}}))); + Buildings.Controls.OBC.CDL.Reals.Max max2 "Limit prescribed HWRT" + annotation (Placement(transformation(extent={{-90,-10},{-70,10}}))); + Buildings.Controls.OBC.CDL.Reals.Min min1 if have_chiWat + "Limit prescribed CHWRT" + annotation (Placement(transformation(extent={{-90,30},{-70,50}}))); + Buildings.Controls.OBC.CDL.Integers.Multiply mulInt[4] + "Importance multiplier" + annotation (Placement(transformation(extent={{0,110},{-20,130}}))); + Buildings.Controls.OBC.CDL.Integers.Sources.Constant cst[4](each k=10) + "Constant" + annotation (Placement(transformation(extent={{40,150},{20,170}}))); + Buildings.Fluid.FixedResistances.PressureDrop pipHeaWat( + redeclare final package Medium =Medium, + final m_flow_nominal=pla.mHeaWat_flow_nominal, + final dp_nominal=max( + max(datAll.pla.pumHeaWatPri.dp_nominal), + max(datAll.pla.pumHeaWatSec.dp_nominal)) - datAll.pla.ctl.dpHeaWatRemSet_max[1]) + "Piping" + annotation (Placement(transformation(extent={{10,-150},{-10,-130}}))); + Buildings.Fluid.FixedResistances.PressureDrop pipChiWat( + redeclare final package Medium =Medium, + final m_flow_nominal=pla.mChiWat_flow_nominal, + final dp_nominal=max( + max(datAll.pla.pumChiWatPri.dp_nominal), + max(datAll.pla.pumChiWatSec.dp_nominal)) - datAll.pla.ctl.dpChiWatRemSet_max[1]) + if have_chiWat + "Piping" + annotation (Placement(transformation(extent={{10,-90},{-10,-70}}))); + Buildings.Controls.OBC.CDL.Reals.Sources.Constant con(k=293.15) + "Constant limiting prescribed return temperature" + annotation (Placement(transformation(extent={{-180,10},{-160,30}}))); + Controls.Utilities.PlaceholderInteger ph[2](each final have_inp=have_chiWat, + each final u_internal=0) "Placeholder value" + annotation (Placement(transformation(extent={{40,114},{20,134}}))); +equation + if have_chiWat then + connect(mulInt[3].y, busAirHan.reqResChiWat) + annotation (Line(points={{-22,120},{-40,120}}, color={255,127,0})); + connect(mulInt[4].y, busAirHan.reqPlaChiWat) + annotation (Line(points={{-22,120},{-40,120}}, color={255,127,0})); + end if; + connect(weaDat.weaBus, pla.busWea) + annotation (Line(points={{-160,-40},{-60,-40},{-60,-60}}, + color={255,204,51},thickness=0.5)); + connect(pla.port_bChiWat, loaChiWat.port_a) + annotation (Line(points={{-40,-76},{-20,-76},{-20,-40},{70,-40}}, + color={0,127,255})); + connect(loaChiWat.port_b, valDisChiWat.port_a) + annotation (Line(points={{90,-40},{110,-40}}, + color={0,127,255})); + connect(loaHeaWat.port_b, valDisHeaWat.port_a) + annotation (Line(points={{90,-100},{110,-100}}, + color={0,127,255})); + connect(pla.port_bHeaWat, loaHeaWat.port_a) + annotation (Line(points={{-40,-90},{-20,-90},{-20,-100},{70,-100}}, + color={0,127,255})); + connect(loaChiWat.port_a, dpChiWatRem_1.port_a) + annotation (Line(points={{70,-40},{40,-40},{40,-50}}, color={0,127,255})); + connect(dpHeaWatRem_1.port_a, loaHeaWat.port_a) annotation (Line(points={{40,-110}, + {40,-100},{70,-100}}, color={0,127,255})); + connect(TDum.y, reqPlaRes.TAirSup) annotation (Line(points={{-158,140},{100, + 140},{100,120},{92,120}},color={0,0,127})); + connect(TDum.y, reqPlaRes.TAirSupSet) annotation (Line(points={{-158,140},{ + 100,140},{100,115},{92,115}}, + color={0,0,127})); + connect(busAirHan, pla.busAirHan[1]) annotation (Line( + points={{-40,120},{-40,-62}}, + color={255,204,51}, + thickness=0.5)); + connect(pla.bus, busPla) annotation (Line( + points={{-80,-62},{-80,-20}}, + color={255,204,51}, + thickness=0.5)); + connect(dpHeaWatRem.y, busPla.dpHeaWatRem) + annotation (Line(points={{-12,-20},{-80,-20}}, color={0,0,127})); + connect(dpChiWatRem.y, busPla.dpChiWatRem) + annotation (Line(points={{-12,20},{-20,20},{-20,-18},{-80,-18},{-80,-20}}, + color={0,0,127})); + connect(valDisChiWat.y_actual, reqPlaRes.uCooCoiSet) annotation (Line(points={{125,-33}, + {140,-33},{140,109},{92,109}}, color={0,0,127})); + connect(valDisHeaWat.y_actual, reqPlaRes.uHeaCoiSet) annotation (Line(points={{125,-93}, + {136,-93},{136,104},{92,104}}, color={0,0,127})); + connect(dpHeaWatRem_1.p_rel, dpHeaWatRem.u[1]) annotation (Line(points={{31,-120}, + {20,-120},{20,-20},{12,-20}}, + color={0,0,127})); + connect(dpChiWatRem_1.p_rel, dpChiWatRem.u[1]) annotation (Line(points={{31,-60}, + {22,-60},{22,20},{12,20}}, + color={0,0,127})); + connect(valDisChiWat.port_b, mChiWat_flow.port_a) annotation (Line(points={{130,-40}, + {160,-40},{160,-50}}, color={0,127,255})); + connect(mChiWat_flow.port_b, dpChiWatRem_1.port_b) annotation (Line(points={{160, + -70},{160,-80},{40,-80},{40,-70}}, color={0,127,255})); + connect(valDisHeaWat.port_b, mHeaWat_flow.port_a) annotation (Line(points={{130, + -100},{160,-100},{160,-110}}, color={0,127,255})); + connect(mHeaWat_flow.port_b, dpHeaWatRem_1.port_b) annotation (Line(points={{160, + -130},{160,-140},{40,-140},{40,-130}}, color={0,127,255})); + connect(mHeaWat_flow.m_flow, norFlo[1].u) annotation (Line(points={{171,-120}, + {180,-120},{180,-12}}, color={0,0,127})); + connect(mChiWat_flow.m_flow, norFlo[2].u) + annotation (Line(points={{171,-60},{180,-60},{180,-12}}, color={0,0,127})); + connect(norFlo.y, ctlEquZon.u_m) annotation (Line(points={{180,12},{180,60},{80, + 60},{80,68}}, color={0,0,127})); + connect(ratFlo.y[1:(if have_chiWat then 2 else 1)], ctlEquZon.u_s) + annotation (Line(points={{-158,80},{68,80}}, color={0,0,127})); + connect(ctlEquZon[2].y, valDisChiWat.y) annotation (Line(points={{92,80},{100, + 80},{100,-20},{120,-20},{120,-28}}, color={0,0,127})); + connect(ctlEquZon[1].y, valDisHeaWat.y) annotation (Line(points={{92,80},{100, + 80},{100,-84},{120,-84},{120,-88}}, color={0,0,127})); + connect(busPla.THeaWatPriSup, THeaWatRet.u) annotation (Line( + points={{-80,-20},{-140,-20},{-140,0},{-132,0}}, + color={255,204,51}, + thickness=0.5)); + connect(busPla.TChiWatPriSup, TChiWatRet.u) annotation (Line( + points={{-80,-20},{-140,-20},{-140,40},{-132,40}}, + color={255,204,51}, + thickness=0.5)); + connect(TChiWatRet.y,min1. u1) annotation (Line(points={{-108,40},{-100,40},{-100, + 46},{-92,46}}, color={0,0,127})); + connect(min1.y, loaChiWat.TSet) annotation (Line(points={{-68,40},{62,40},{62, + -32},{68,-32}}, color={0,0,127})); + connect(max2.y, loaHeaWat.TSet) annotation (Line(points={{-68,0},{60,0},{60,-92}, + {68,-92}}, color={0,0,127})); + connect(cst.y, mulInt.u1) annotation (Line(points={{18,160},{6,160},{6,126},{2, + 126}}, color={255,127,0})); + connect(mulInt[1].y, busAirHan.reqResHeaWat) annotation (Line(points={{-22,120}, + {-30,120},{-30,120},{-40,120}}, color={255,127,0})); + connect(mulInt[2].y, busAirHan.reqPlaHeaWat) + annotation (Line(points={{-22,120},{-40,120}}, color={255,127,0})); + connect(pipHeaWat.port_b, pla.port_aHeaWat) annotation (Line(points={{-10,-140}, + {-30,-140},{-30,-98},{-40,-98}}, color={0,127,255})); + connect(pipChiWat.port_b, pla.port_aChiWat) annotation (Line(points={{-10,-80}, + {-20,-80},{-20,-84},{-40,-84}}, color={0,127,255})); + connect(mChiWat_flow.port_b, pipChiWat.port_a) annotation (Line(points={{160,-70}, + {160,-80},{10,-80}}, color={0,127,255})); + connect(mHeaWat_flow.port_b, pipHeaWat.port_a) annotation (Line(points={{160,-130}, + {160,-140},{10,-140}}, color={0,127,255})); + connect(con.y, min1.u2) annotation (Line(points={{-158,20},{-100,20},{-100,34}, + {-92,34}}, color={0,0,127})); + connect(con.y, max2.u1) annotation (Line(points={{-158,20},{-100,20},{-100,6}, + {-92,6}}, color={0,0,127})); + connect(THeaWatRet.y, max2.u2) annotation (Line(points={{-108,0},{-100,0},{ + -100,-6},{-92,-6}}, color={0,0,127})); + connect(reqPlaRes.yChiWatResReq, ph[1].u) annotation (Line(points={{68,120},{ + 50,120},{50,124},{42,124}}, color={255,127,0})); + connect(reqPlaRes.yChiPlaReq, ph[2].u) annotation (Line(points={{68,115},{50, + 115},{50,124},{42,124}}, color={255,127,0})); + connect(reqPlaRes.yHotWatResReq, mulInt[1].u2) annotation (Line(points={{68, + 109},{12,109},{12,114},{2,114}}, color={255,127,0})); + connect(reqPlaRes.yHotWatPlaReq, mulInt[2].u2) annotation (Line(points={{68, + 104},{12,104},{12,114},{2,114}}, color={255,127,0})); + connect(ph[1].y, mulInt[3].u2) annotation (Line(points={{18,124},{12,124},{12, + 114},{2,114}}, color={255,127,0})); + connect(ph[2].y, mulInt[4].u2) annotation (Line(points={{18,124},{12,124},{12, + 114},{2,114}}, color={255,127,0})); + annotation ( + __Dymola_Commands( + file= + "modelica://Buildings/Resources/Scripts/Dymola/Templates/Plants/HeatPumps/Validation/AirToWater.mos" + "Simulate and plot"), + experiment( + Tolerance=1e-6, + StopTime=86400.0), + Documentation( + info=" +

+This model validates + +Buildings.Templates.Plants.HeatPumps.AirToWater +by simulating a 24-hour period with overlapping heating and +cooling loads. +The heating loads reach their peak value first, the cooling loads reach it last. +

+

+Three equally sized heat pumps are modeled. All can be lead/lag alternated. +A unique aggregated load is modeled on each loop by means of a cooling or heating +component controlled to maintain a constant ΔT +and a modulating valve controlled to track a prescribed flow rate. +An importance multiplier of 10 is applied to the plant requests +and reset requests generated from the valve position. +

+

+The user can toggle the top-level parameter have_chiWat +to switch between a cooling and heating system (the default setting) +to a heating-only system. +Advanced equipment and control options can be modified via the parameter +dialog of the plant component. +

+

+Simulating this model shows how the plant responds to a varying load by +

+
    +
  • +staging or unstaging the AWHPs and associated primary pumps, +
  • +
  • +rotating lead/lag alternate equipment to ensure even wear, +
  • +
  • +resetting the supply temperature and remote differential pressure +in both the CHW and HW loops based on the valve position, +
  • +
  • +staging and controlling the secondary pumps to meet the +remote differential pressure setpoint. +
  • +
+", revisions=" +
    +
  • +March 29, 2024, by Antoine Gautier:
    +First implementation. +
  • +
+"), + Diagram( + coordinateSystem( + extent={{-200,-200},{200,200}}))); +end AirToWater; diff --git a/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/AllSystems.mo b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/AllSystems.mo new file mode 100644 index 00000000000..29b78074952 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/AllSystems.mo @@ -0,0 +1,84 @@ +within Buildings.Templates.Plants.HeatPumps.Validation.UserProject.Data; +class AllSystems + "Top-level (whole building) system parameters" + extends Buildings.Templates.Data.AllSystems( + sysUni=Buildings.Templates.Types.Units.SI, + stdEne=Buildings.Controls.OBC.ASHRAE.G36.Types.EnergyStandard.ASHRAE90_1, + stdVen=Buildings.Controls.OBC.ASHRAE.G36.Types.VentilationStandard.ASHRAE62_1, + ashCliZon=Buildings.Controls.OBC.ASHRAE.G36.Types.ASHRAEClimateZone.Zone_3B); + parameter Buildings.Templates.Plants.HeatPumps.Data.HeatPumpPlant pla( + hp( + capHeaHp_nominal=500E3, + capCooHp_nominal=500E3, + mHeaWatHp_flow_nominal=pla.hp.capHeaHp_nominal/abs(pla.ctl.THeaWatSup_nominal + - Buildings.Templates.Data.Defaults.THeaWatRetMed)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + mChiWatHp_flow_nominal=pla.hp.capCooHp_nominal/abs(pla.ctl.TChiWatSup_nominal + - Buildings.Templates.Data.Defaults.TChiWatRet)/Buildings.Utilities.Psychrometrics.Constants.cpWatLiq, + dpHeaWatHp_nominal=Buildings.Templates.Data.Defaults.dpHeaWatHp, + TSouHeaHp_nominal=Buildings.Templates.Data.Defaults.TOutHpHeaLow, + TSouCooHp_nominal=Buildings.Templates.Data.Defaults.TOutHpCoo, + perFitHp(hea( + P=pla.hp.capHeaHp_nominal/Buildings.Templates.Data.Defaults.COPHpAwHea, + coeQ={-4.2670305442,-0.7381077035,6.0049480456,0,0}, + coeP={-4.9107455513,5.3665308366,0.5447612754,0,0}, + TRefLoa=pla.hp.THeaWatRetHp_nominal, + TRefSou=pla.hp.TSouHeaHp_nominal), coo( + P=pla.hp.capCooHp_nominal/Buildings.Templates.Data.Defaults.COPHpAwCoo, + coeQ={-2.2545246871,6.9089257665,-3.6548225094,0,0}, + coeP={-5.8086010402,1.6894933858,5.1167787436,0,0}, + TRefLoa=pla.hp.TChiWatRetHp_nominal, + TRefSou=pla.hp.TSouCooHp_nominal))), + pumHeaWatPri(dp_nominal=fill( + (if pla.cfg.have_chiWat and pla.cfg.typPumChiWatPri==Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + then max(pla.hp.dpHeaWatHp_nominal, pla.hp.dpChiWatHp_nominal) else pla.hp.dpHeaWatHp_nominal) *1.2, pla.cfg.nPumHeaWatPri) + .+ (if pla.cfg.typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or pla.cfg.typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + then Buildings.Templates.Data.Defaults.dpHeaWatLocSet_max else 0)), + pumHeaWatSec( + m_flow_nominal=fill( + pla.ctl.VHeaWatSec_flow_nominal*Buildings.Media.Water.d_const/max(1,pla.cfg.nPumHeaWatSec), pla.cfg.nPumHeaWatSec), + dp_nominal=fill(Buildings.Templates.Data.Defaults.dpHeaWatLocSet_max, pla.cfg.nPumHeaWatSec)), + pumChiWatPri(dp_nominal=fill(pla.hp.dpChiWatHp_nominal*1.2, pla.cfg.nPumChiWatPri) + .+ (if pla.cfg.typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Constant1Only + or pla.cfg.typDis == Buildings.Templates.Plants.HeatPumps.Types.Distribution.Variable1Only + then Buildings.Templates.Data.Defaults.dpChiWatLocSet_max else 0)), + pumChiWatSec( + m_flow_nominal=fill( + pla.ctl.VChiWatSec_flow_nominal*Buildings.Media.Water.d_const/max(1,pla.cfg.nPumChiWatSec), pla.cfg.nPumChiWatSec), + dp_nominal=fill(Buildings.Templates.Data.Defaults.dpChiWatLocSet_max, pla.cfg.nPumChiWatSec)), + ctl( + THeaWatSupSet_min=298.15, + VHeaWatSec_flow_nominal=pla.cfg.nHp * pla.ctl.VHeaWatHp_flow_nominal / 1.1, + TChiWatSupSet_max=288.15, + VChiWatSec_flow_nominal=pla.cfg.nHp * pla.ctl.VChiWatHp_flow_nominal / 1.1, + dpChiWatRemSet_max={Buildings.Templates.Data.Defaults.dpChiWatRemSet_max}, + dpHeaWatRemSet_max={Buildings.Templates.Data.Defaults.dpHeaWatRemSet_max}, + THeaWatSup_nominal=Buildings.Templates.Data.Defaults.THeaWatSupMed, + TOutChiWatLck=273.15, + TOutHeaWatLck=Buildings.Templates.Data.Defaults.TOutHeaWatLck, + VHeaWatHp_flow_nominal=pla.hp.mHeaWatHp_flow_nominal/Buildings.Media.Water.d_const, + VChiWatHp_flow_nominal=pla.hp.mChiWatHp_flow_nominal/Buildings.Media.Water.d_const, + capHeaHp_nominal=pla.hp.capHeaHp_nominal, + capCooHp_nominal=pla.hp.capCooHp_nominal, + TChiWatSup_nominal=Buildings.Templates.Data.Defaults.TChiWatSup, + yPumChiWatPriSet=if pla.cfg.have_chiWat and pla.cfg.typPumChiWatPri==Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + then pla.hp.mChiWatHp_flow_nominal/max(pla.hp.mHeaWatHp_flow_nominal, pla.hp.mChiWatHp_flow_nominal) else 1, + yPumHeaWatPriSet=if pla.cfg.have_chiWat and pla.cfg.typPumChiWatPri==Buildings.Templates.Plants.HeatPumps.Types.PumpsPrimary.None + then pla.hp.mHeaWatHp_flow_nominal/max(pla.hp.mHeaWatHp_flow_nominal, pla.hp.mChiWatHp_flow_nominal) else 1, + staEqu={fill(i/pla.cfg.nHp, pla.cfg.nHp) for i in 1:pla.cfg.nHp})) + "Parameters for heat pump plant" + annotation (Dialog(group="Plants"), + Placement(transformation(extent={{-10,0},{10,20}}))); + + annotation ( + defaultComponentPrefixes="inner parameter", + defaultComponentName="datAll", + Documentation( + info=" +

+This class provides the set of sizing and operating parameters for +the whole HVAC system. +It is aimed for validation purposes only. +

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

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

+")); +end Data; diff --git a/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/package.order b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/package.order new file mode 100644 index 00000000000..3831742ec60 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/Data/package.order @@ -0,0 +1 @@ +AllSystems diff --git a/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.mo b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.mo new file mode 100644 index 00000000000..0080c5049a9 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.mo @@ -0,0 +1,11 @@ +within Buildings.Templates.Plants.HeatPumps.Validation; +package UserProject "Package with configured models" + extends Modelica.Icons.VariantsPackage; + annotation ( + Documentation( + info=" +

+This package contains models used for validation purposes. +

+")); +end UserProject; diff --git a/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.order b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.order new file mode 100644 index 00000000000..0b7088ec633 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/UserProject/package.order @@ -0,0 +1 @@ +Data diff --git a/Buildings/Templates/Plants/HeatPumps/Validation/package.mo b/Buildings/Templates/Plants/HeatPumps/Validation/package.mo new file mode 100644 index 00000000000..8d54b9e0ff9 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/package.mo @@ -0,0 +1,18 @@ +within Buildings.Templates.Plants.HeatPumps; +package Validation "Package with validation models" + extends Modelica.Icons.ExamplesPackage; + annotation ( + Documentation( + info=" +

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

+

+The models also illustrate parameter propagation from the top-level +HVAC system record datAll. +

+")); +end Validation; diff --git a/Buildings/Templates/Plants/HeatPumps/Validation/package.order b/Buildings/Templates/Plants/HeatPumps/Validation/package.order new file mode 100644 index 00000000000..71336f7e6e9 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/Validation/package.order @@ -0,0 +1,2 @@ +AirToWater +UserProject diff --git a/Buildings/Templates/Plants/HeatPumps/package.mo b/Buildings/Templates/Plants/HeatPumps/package.mo new file mode 100644 index 00000000000..6d48e499260 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/package.mo @@ -0,0 +1,9 @@ +within Buildings.Templates.Plants; +package HeatPumps "Heat pump plant" + extends Modelica.Icons.Package; + annotation ( + Documentation( + info=" +

This package contains templates for heat pump plants.

+")); +end HeatPumps; diff --git a/Buildings/Templates/Plants/HeatPumps/package.order b/Buildings/Templates/Plants/HeatPumps/package.order new file mode 100644 index 00000000000..215baa2eb40 --- /dev/null +++ b/Buildings/Templates/Plants/HeatPumps/package.order @@ -0,0 +1,7 @@ +AirToWater +Components +Configuration +Data +Types +Validation +Interfaces diff --git a/Buildings/Templates/Plants/package.mo b/Buildings/Templates/Plants/package.mo new file mode 100644 index 00000000000..ce672ee403f --- /dev/null +++ b/Buildings/Templates/Plants/package.mo @@ -0,0 +1,10 @@ +within Buildings.Templates; +package Plants + "Central plants" + extends Modelica.Icons.Package; + annotation ( + Documentation( + info=" +

This package contains templates for central plants.

+")); +end Plants; diff --git a/Buildings/Templates/Plants/package.order b/Buildings/Templates/Plants/package.order new file mode 100644 index 00000000000..fd79608553d --- /dev/null +++ b/Buildings/Templates/Plants/package.order @@ -0,0 +1,2 @@ +Controls +HeatPumps diff --git a/Buildings/Templates/Utilities/computeBalancingPressureDrop.mo b/Buildings/Templates/Utilities/computeBalancingPressureDrop.mo new file mode 100644 index 00000000000..4f03c83310f --- /dev/null +++ b/Buildings/Templates/Utilities/computeBalancingPressureDrop.mo @@ -0,0 +1,49 @@ +within Buildings.Templates.Utilities; +function computeBalancingPressureDrop + "Compute the design pressure drop of a balancing valve" + extends Modelica.Icons.Function; + input Modelica.Units.SI.MassFlowRate m_flow_nominal + "Design mass flow rate (target)"; + input Modelica.Units.SI.PressureDifference dp_nominal + "Pressure drop of equipment in series at design flow rate"; + input Buildings.Templates.Components.Data.PumpSingle datPum + "Pump parameters"; + input Real r_N(unit="1")=1 + "Relative revolution, r_N=N/N_nominal"; + output Modelica.Units.SI.PressureDifference dpBal_nominal + "Pressure drop of balancing valve at design flow rate"; +protected + Modelica.Units.SI.PressureDifference dpPum_nominal = + Buildings.Fluid.Movers.BaseClasses.Characteristics.pressure( + V_flow=m_flow_nominal / datPum.rho_default, + r_N=r_N, + d=Buildings.Utilities.Math.Functions.splineDerivatives( + x=datPum.per.pressure.V_flow, + y=datPum.per.pressure.dp), + dpMax=max(datPum.per.pressure.dp), + V_flow_max=max(datPum.per.pressure.V_flow), + per=Buildings.Fluid.Movers.BaseClasses.Characteristics.flowParametersInternal( + n=size(datPum.per.pressure.V_flow, 1), + V_flow=datPum.per.pressure.V_flow, + dp=datPum.per.pressure.dp)) + "Pump head at target design flow"; +algorithm + dpBal_nominal := dpPum_nominal - dp_nominal; + annotation (Documentation(info=" +

+Given the design mass flow rate, the design pressure drop +of all equipment in series, the pump parameters and the +pump speed, the function returns the pressure drop +of a balancing valve at design flow, so that the total +pressure drop is equal to the pump head. +

+

+The model + +Buildings.Templates.Plants.HeatPumps.Components.Validation.PumpsPrimaryDedicated +serves as a validation model for this function and illustrates how the function +can be used to calculate either the design pressure drop of balancing +valves or the primary pump speed required to provide the design flow. +

+")); +end computeBalancingPressureDrop; diff --git a/Buildings/Templates/Utilities/package.mo b/Buildings/Templates/Utilities/package.mo new file mode 100644 index 00000000000..098f8d76ed8 --- /dev/null +++ b/Buildings/Templates/Utilities/package.mo @@ -0,0 +1,27 @@ +within Buildings.Templates; +package Utilities "Package with utility functions" + extends Modelica.Icons.Package; + + annotation ( + Icon(coordinateSystem(extent={{-100.0,-100.0},{100.0,100.0}}), graphics={ + Polygon( + origin={1.3835,-4.1418}, + rotation=45.0, + fillColor={64,64,64}, + pattern=LinePattern.None, + fillPattern=FillPattern.Solid, + points={{-15.0,93.333},{-15.0,68.333},{0.0,58.333},{15.0,68.333},{15.0,93.333},{20.0,93.333},{25.0,83.333},{25.0,58.333},{10.0,43.333},{10.0,-41.667},{25.0,-56.667},{25.0,-76.667},{10.0,-91.667},{0.0,-91.667},{0.0,-81.667},{5.0,-81.667},{15.0,-71.667},{15.0,-61.667},{5.0,-51.667},{-5.0,-51.667},{-15.0,-61.667},{-15.0,-71.667},{-5.0,-81.667},{0.0,-81.667},{0.0,-91.667},{-10.0,-91.667},{-25.0,-76.667},{-25.0,-56.667},{-10.0,-41.667},{-10.0,43.333},{-25.0,58.333},{-25.0,83.333},{-20.0,93.333}}), + Polygon( + origin={10.1018,5.218}, + rotation=-45.0, + fillColor={255,255,255}, + fillPattern=FillPattern.Solid, + points={{-15.0,87.273},{15.0,87.273},{20.0,82.273},{20.0,27.273},{10.0,17.273},{10.0,7.273},{20.0,2.273},{20.0,-2.727},{5.0,-2.727},{5.0,-77.727},{10.0,-87.727},{5.0,-112.727},{-5.0,-112.727},{-10.0,-87.727},{-5.0,-77.727},{-5.0,-2.727},{-20.0,-2.727},{-20.0,2.273},{-10.0,7.273},{-10.0,17.273},{-20.0,27.273},{-20.0,82.273}})}), + Documentation(revisions=" +", info=" +

+This package contains utility functions that are used +in HVAC system templates. +

+")); +end Utilities; diff --git a/Buildings/Templates/Utilities/package.order b/Buildings/Templates/Utilities/package.order new file mode 100644 index 00000000000..b5898f9cd5b --- /dev/null +++ b/Buildings/Templates/Utilities/package.order @@ -0,0 +1 @@ +computeBalancingPressureDrop diff --git a/Buildings/Templates/package.order b/Buildings/Templates/package.order index 9c28253a22a..1cd7704ac04 100644 --- a/Buildings/Templates/package.order +++ b/Buildings/Templates/package.order @@ -1,6 +1,8 @@ UsersGuide AirHandlersFans Components +Plants +Utilities ZoneEquipment Data Types