From cb6f10805eea80ca74d900621dab7022eb05047c Mon Sep 17 00:00:00 2001 From: mjwitte Date: Fri, 8 Mar 2019 08:52:14 -0600 Subject: [PATCH 01/15] Temporary fix in GetCoilDesFlowT to protect against array bounds violation --- src/EnergyPlus/ReportSizingManager.cc | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/EnergyPlus/ReportSizingManager.cc b/src/EnergyPlus/ReportSizingManager.cc index 9e11bdcf160..9b6653dd558 100644 --- a/src/EnergyPlus/ReportSizingManager.cc +++ b/src/EnergyPlus/ReportSizingManager.cc @@ -4441,7 +4441,7 @@ namespace ReportSizingManager { int PeakLoadType; int DDAtTotPeak; int TimeStepAtTotPeak; - int TimeStepAtPeak; + int TimeStepAtPeak(0); Real64 ZoneCoolLoadSum(0); // sum of zone cooling loads at the peak [W] Real64 AvgZoneTemp(0); // average zone temperature [C] Real64 AvgSupTemp; // average supply temperature for bypass control [C] @@ -4451,16 +4451,18 @@ namespace ReportSizingManager { CoolCapCtrl = SysSizInput(SysNum).CoolCapControl; PeakLoadType = SysSizInput(SysNum).CoolingPeakLoadType; DDAtSensPeak = SysSizPeakDDNum(SysNum).SensCoolPeakDD; - TimeStepAtSensPeak = SysSizPeakDDNum(SysNum).TimeStepAtSensCoolPk(DDAtSensPeak); - DDAtFlowPeak = SysSizPeakDDNum(SysNum).CoolFlowPeakDD; - TimeStepAtFlowPeak = SysSizPeakDDNum(SysNum).TimeStepAtCoolFlowPk(DDAtFlowPeak); - DDAtTotPeak = SysSizPeakDDNum(SysNum).TotCoolPeakDD; - TimeStepAtTotPeak = SysSizPeakDDNum(SysNum).TimeStepAtTotCoolPk(DDAtTotPeak); + if (DDAtSensPeak > 0) { + TimeStepAtSensPeak = SysSizPeakDDNum(SysNum).TimeStepAtSensCoolPk(DDAtSensPeak); + DDAtFlowPeak = SysSizPeakDDNum(SysNum).CoolFlowPeakDD; + TimeStepAtFlowPeak = SysSizPeakDDNum(SysNum).TimeStepAtCoolFlowPk(DDAtFlowPeak); + DDAtTotPeak = SysSizPeakDDNum(SysNum).TotCoolPeakDD; + TimeStepAtTotPeak = SysSizPeakDDNum(SysNum).TimeStepAtTotCoolPk(DDAtTotPeak); - if (PeakLoadType == TotalCoolingLoad) { - TimeStepAtPeak = TimeStepAtTotPeak; - } else { - TimeStepAtPeak = TimeStepAtSensPeak; + if (PeakLoadType == TotalCoolingLoad) { + TimeStepAtPeak = TimeStepAtTotPeak; + } else { + TimeStepAtPeak = TimeStepAtSensPeak; + } } if (CoolCapCtrl == VAV) { DesExitTemp = FinalSysSizing(SysNum).CoolSupTemp; @@ -4468,6 +4470,9 @@ namespace ReportSizingManager { } else if (CoolCapCtrl == OnOff) { DesExitTemp = FinalSysSizing(SysNum).CoolSupTemp; DesFlow = DataAirFlowUsedForSizing; + } else if (TimeStepAtPeak == 0) { + ShowFatalError("GetCoilDesFlow: AirLoopHVAC=" + SysSizInput(SysNum).AirPriLoopName + + " Central Cooling Capacity Control Method requires zone thermostats to calculate timestep loads."); } else if (CoolCapCtrl == VT) { if (FinalSysSizing(SysNum).CoolingPeakLoadType == SensibleCoolingLoad) { ZoneCoolLoadSum = CalcSysSizing(SysNum).SumZoneCoolLoadSeq(TimeStepAtPeak); From 3adf350ba35542632d89dfc50157c493c520bd1e Mon Sep 17 00:00:00 2001 From: mjwitte Date: Fri, 8 Mar 2019 08:54:44 -0600 Subject: [PATCH 02/15] UnitarySystem fix humidity setpoint controls --- src/EnergyPlus/UnitarySystem.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/EnergyPlus/UnitarySystem.cc b/src/EnergyPlus/UnitarySystem.cc index 3379d63a396..6820c16e0d5 100644 --- a/src/EnergyPlus/UnitarySystem.cc +++ b/src/EnergyPlus/UnitarySystem.cc @@ -10406,7 +10406,7 @@ namespace UnitarySystems { // and if coolReheat, check hum rat as well if (((NoLoadTempOut - DesOutTemp) < Acc) && ((NoLoadHumRatOut - DesOutHumRat) < HumRatAcc)) { PartLoadFrac = 0.0; - } else if (SensibleLoad) { // need to turn on compressor to see if load is met + } else { // need to turn on compressor to see if load is met PartLoadFrac = 1.0; CompOn = 1; m_WSHPRuntimeFrac = 1.0; @@ -10571,7 +10571,9 @@ namespace UnitarySystems { (this->m_TESOpMode == PackagedThermalStorageCoil::OffMode || this->m_TESOpMode == PackagedThermalStorageCoil::ChargeOnlyMode)) { PartLoadFrac = 0.0; - } else { + } else if (!SensibleLoad) { + PartLoadFrac = 0.0; + } else if (SensibleLoad) { Par[9] = double(AirLoopNum); Par[10] = 0.0; @@ -10866,6 +10868,7 @@ namespace UnitarySystems { FullOutput = DataLoopNode::Node(InletNode).MassFlowRate * (Psychrometrics::PsyHFnTdbW(DataLoopNode::Node(OutletNode).Temp, DataLoopNode::Node(OutletNode).HumRat) - Psychrometrics::PsyHFnTdbW(DataLoopNode::Node(InletNode).Temp, DataLoopNode::Node(OutletNode).HumRat)); + FullLoadHumRatOut = DataLoopNode::Node(OutletNode).HumRat; // Check to see if the system can meet the load with the compressor off // If NoOutput is lower than (more cooling than required) or very near the ReqOutput, do not run the compressor @@ -10906,6 +10909,7 @@ namespace UnitarySystems { FullOutput = DataLoopNode::Node(InletNode).MassFlowRate * (Psychrometrics::PsyHFnTdbW(DataLoopNode::Node(OutletNode).Temp, DataLoopNode::Node(InletNode).HumRat) - Psychrometrics::PsyHFnTdbW(DataLoopNode::Node(InletNode).Temp, DataLoopNode::Node(InletNode).HumRat)); + FullLoadHumRatOut = DataLoopNode::Node(OutletNode).HumRat; // Since we are cooling, we expect FullOutput to be < 0 and FullOutput < NoCoolOutput // Check that this is the case; IF not set PartLoadFrac = 0.0 (off) and return From 53543cbbe87b275aae665c86f3ff58bd275aaa12 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Sun, 10 Mar 2019 13:10:19 -0500 Subject: [PATCH 03/15] ChW controller improve temperature and humidity control --- src/EnergyPlus/HVACControllers.cc | 88 ++++++---------------------- src/EnergyPlus/HVACControllers.hh | 4 +- src/EnergyPlus/SimAirServingZones.cc | 28 +++++++++ 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/src/EnergyPlus/HVACControllers.cc b/src/EnergyPlus/HVACControllers.cc index e177213311a..090384de7da 100644 --- a/src/EnergyPlus/HVACControllers.cc +++ b/src/EnergyPlus/HVACControllers.cc @@ -1280,54 +1280,23 @@ namespace HVACControllers { } } else if (SELECT_CASE_var == iTemperatureAndHumidityRatio) { // 'TemperatureAndHumidityRatio' - ControllerProps(ControlNum).SensedValue = Node(SensedNode).Temp; - // Setpoint temp calculated once each HVAC time step to identify approach temp and whether or not humrat control is necessary - // WARNING: The scheme for computing the setpoint for the dual temperature and humidity ratio - // control strategy breaks down whenever the sensed node temperature is modified by - // a controller fired after the current one. Indeed the final sensed node temperature - // is likely to have changed in the meantime if the other controller is active, - // thereby invalidating the setpoint calculation for the other controller performed - // earlier on the air loop. + if (ControllerProps(ControlNum).HumRatCtrlOverride) { + // Humidity ratio control + ControllerProps(ControlNum).SensedValue = Node(SensedNode).HumRat; + } else { + // Temperature control + ControllerProps(ControlNum).SensedValue = Node(SensedNode).Temp; + } if (!ControllerProps(ControlNum).IsSetPointDefinedFlag) { - // NOTE: For TEMPANDHUMRAT control the computed value ControllerProps(ControlNum)%SetPointValue - // depends on: - // - Node(SensedNode)%HumRatMax - // - Node(SensedNode)%Temp - // - Node(SensedNode)%HumRat - if ((Node(SensedNode).HumRatMax > 0) && (Node(SensedNode).HumRat > Node(SensedNode).HumRatMax)) { - // Setpoint can only be computed once per time step - // Check if outlet air humidity ratio is greater than the set point. If so, calculate new temperature based set point. - // See routine CalcSimpleController() for the sequence of operations. - // Calculate the approach temperature (difference between SA dry-bulb temp and SA dew point temp) - ApproachTemp = Node(SensedNode).Temp - PsyTdpFnWPb(Node(SensedNode).HumRat, OutBaroPress); - // Calculate the dew point temperature at the SA humidity ratio setpoint - DesiredDewPoint = PsyTdpFnWPb(Node(SensedNode).HumRatMax, OutBaroPress); - // Adjust the calculated dew point temperature by the approach temp. Should be within 0.3C of air temperature. - HumidityControlTempSetPoint = DesiredDewPoint + min(0.3, ApproachTemp); - // NOTE: The next line introduces a potential discontinuity into the residual function - // which could prevent the root finder from finding the root it if were done at each - // controller iteration. For this reason we perform the setpoint calculation only - // once at the beginning of the controller and air loop simulation. - // Use lower of temperature and humidity based set point. - // See routine CalcSimpleController() for the sequence of operations. - ControllerProps(ControlNum).SetPointValue = min( - Node(SensedNode).TempSetPoint, - HumidityControlTempSetPoint); // Pure temperature setpoint | Temperature setpoint to achieve the humidity ratio setpoint - // Don't allow set point temperature to be below the actuator node water temperature - ControllerProps(ControlNum).SetPointValue = - max(ControllerProps(ControlNum).SetPointValue, Node(ControllerProps(ControlNum).ActuatedNode).Temp); - // Overwrite the "pure" temperature setpoint with the actual setpoint that takes into - // account the humidity ratio setpoint. - // NOTE: Check that this does not create side-effects somewhere else in the code. - Node(SensedNode).TempSetPoint = ControllerProps(ControlNum).SetPointValue; - // Finally indicate thate the setpoint has been computed - ControllerProps(ControlNum).IsSetPointDefinedFlag = true; + if (ControllerProps(ControlNum).HumRatCtrlOverride) { + // Humidity ratio control + ControllerProps(ControlNum).SetPointValue = Node(SensedNode).HumRatMax; } else { // Pure temperature setpoint control strategy ControllerProps(ControlNum).SetPointValue = Node(SensedNode).TempSetPoint; - // Finally indicate thate the setpoint has been computed - ControllerProps(ControlNum).IsSetPointDefinedFlag = true; } + // Finally indicate thate the setpoint has been computed + ControllerProps(ControlNum).IsSetPointDefinedFlag = true; } } else if (SELECT_CASE_var == iHumidityRatio) { // 'HumidityRatio' @@ -1465,6 +1434,10 @@ namespace HVACControllers { (0.001 / (2100.0 * max(ControllerProps(ControlNum).MaxVolFlowActuated, SmallWaterVolFlow))) * (HVACEnergyToler / 10.0); // do not let the controller tolerance exceed 1/10 of the loop temperature tolerance. ControllerProps(ControlNum).Offset = min(0.1 * HVACTemperatureToler, ControllerProps(ControlNum).Offset); + if (ControllerProps(ControlNum).ControlVar == HVACControllers::iTemperatureAndHumidityRatio) { + // for temperature and humidity control, need tighter tolerance if humidity control kicks in + ControllerProps(ControlNum).Offset = ControllerProps(ControlNum).Offset*0.1; + } ReportSizingOutput(ControllerProps(ControlNum).ControllerType, ControllerProps(ControlNum).ControllerName, "Controller Convergence Tolerance", @@ -1587,33 +1560,8 @@ namespace HVACControllers { FindRootSimpleController(ControlNum, FirstHVACIteration, IsConvergedFlag, IsUpToDateFlag, ControllerName); } else { - - // We need to evaluate the sensed node temperature with the max actuated value before - // we can compute the actual setpoint for the dual humidity ratio / temperature strategy. - { - auto const SELECT_CASE_var(ControllerProps(ControlNum).ControlVar); - if ((SELECT_CASE_var == iTemperature) || (SELECT_CASE_var == iHumidityRatio) || (SELECT_CASE_var == iFlow)) { - // Always start with min point by default for the other control strategies - ControllerProps(ControlNum).NextActuatedValue = RootFinders(ControlNum).MinPoint.X; - - } else if (SELECT_CASE_var == iTemperatureAndHumidityRatio) { - if (!ControllerProps(ControlNum).IsSetPointDefinedFlag) { - // Always start with max point if setpoint not yet computed. See routine InitController(). - ControllerProps(ControlNum).NextActuatedValue = RootFinders(ControlNum).MaxPoint.X; - } else { - // If setpoint already exists (i.e., HumRatMax <= 0) then try min point first as in simple - // temperature control case. - ControllerProps(ControlNum).NextActuatedValue = RootFinders(ControlNum).MinPoint.X; - } - - } else { - // Should never happen - ShowSevereError("CalcSimpleController: HVAC controller failed at " + CreateHVACStepFullString()); - ShowContinueError(" Controller name=" + ControllerProps(ControlNum).ControllerName); - ShowContinueError(" Unrecognized control variable type=" + TrimSigDigits(ControllerProps(ControlNum).ControlVar)); - ShowFatalError("Preceding error causes program termination."); - } - } + // Always start with min point by default + ControllerProps(ControlNum).NextActuatedValue = RootFinders(ControlNum).MinPoint.X; } // Process current iterate and compute next candidate if needed diff --git a/src/EnergyPlus/HVACControllers.hh b/src/EnergyPlus/HVACControllers.hh index a7fe4364943..b327ed614c3 100644 --- a/src/EnergyPlus/HVACControllers.hh +++ b/src/EnergyPlus/HVACControllers.hh @@ -233,6 +233,8 @@ namespace HVACControllers { bool BypassControllerCalc; // set true for OA sys water coils int AirLoopControllerIndex; // index to controller on specific air loop + bool HumRatCtrlOverride; // true if TemperatureAndHumidityRatio control switches to humidity ratio control + // Default Constructor ControllerPropsType() : ControllerType_Num(ControllerSimple_Type), ControlVar(iNoControlVariable), ActuatorVar(0), Action(iNoAction), InitFirstPass(true), @@ -242,7 +244,7 @@ namespace HVACControllers { ActuatedNodePlantLoopNum(0), ActuatedNodePlantLoopSide(0), ActuatedNodePlantLoopBranchNum(0), SensedNode(0), IsSetPointDefinedFlag(false), SetPointValue(0.0), SensedValue(0.0), DeltaSensed(0.0), Offset(0.0), HumRatCntrlType(0), Range(0.0), Limit(0.0), TraceFileUnit(0), FirstTraceFlag(true), BadActionErrCount(0), BadActionErrIndex(0), FaultyCoilSATFlag(false), - FaultyCoilSATIndex(0), FaultyCoilSATOffset(0.0), BypassControllerCalc(false), AirLoopControllerIndex(0) + FaultyCoilSATIndex(0), FaultyCoilSATOffset(0.0), BypassControllerCalc(false), AirLoopControllerIndex(0), HumRatCtrlOverride(false) { } }; diff --git a/src/EnergyPlus/SimAirServingZones.cc b/src/EnergyPlus/SimAirServingZones.cc index 6c6be49829c..05c540408ec 100644 --- a/src/EnergyPlus/SimAirServingZones.cc +++ b/src/EnergyPlus/SimAirServingZones.cc @@ -2864,6 +2864,9 @@ namespace SimAirServingZones { // E.g., actuator inlet water flow for (int AirLoopControlNum = 1; AirLoopControlNum <= PrimaryAirSystem(AirLoopNum).NumControllers; ++AirLoopControlNum) { + // For temperature and humidity control reset humidity control override + HVACControllers::ControllerProps(PrimaryAirSystem(AirLoopNum).ControllerIndex(AirLoopControlNum)).HumRatCtrlOverride = false; + // BypassOAController is true here since we do not want to simulate the controller if it has already been simulated in the OA system // ControllerConvergedFlag is returned true here for water coils in OA system ManageControllers(PrimaryAirSystem(AirLoopNum).ControllerName(AirLoopControlNum), @@ -2960,6 +2963,31 @@ namespace SimAirServingZones { // not converge ControllerConvergedFlag = PrimaryAirSystem(AirLoopNum).ControlConverged(AirLoopControlNum); IsUpToDateFlag = true; + } else { + { + auto &thisController(HVACControllers::ControllerProps(PrimaryAirSystem(AirLoopNum).ControllerIndex(AirLoopControlNum))); + if (thisController.ControlVar == HVACControllers::iTemperatureAndHumidityRatio) { + // For temperature and humidity control, after temperature control is converged, check if humidity setpoint is met + if (!thisController.HumRatCtrlOverride) { + if (Node(thisController.SensedNode).HumRat > (Node(thisController.SensedNode).HumRatMax + thisController.Offset)) { + // Turn on humdity control and restart controller + ControllerConvergedFlag = false; + thisController.HumRatCtrlOverride = true; + IsUpToDateFlag = false; + ManageControllers(PrimaryAirSystem(AirLoopNum).ControllerName(AirLoopControlNum), + PrimaryAirSystem(AirLoopNum).ControllerIndex(AirLoopControlNum), + FirstHVACIteration, + AirLoopNum, + iControllerOpWarmRestart, + ControllerConvergedFlag, + IsUpToDateFlag, + BypassOAController, + AllowWarmRestartFlag); + SimAirLoopComponents(AirLoopNum, FirstHVACIteration); + } + } + } + } } } // End of the Convergence Iteration From 7683df869e915af86fa6d4dc5c8048c8619e0bc9 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 07:53:37 -0500 Subject: [PATCH 04/15] ChW controller - delete now unused variables --- src/EnergyPlus/HVACControllers.cc | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/EnergyPlus/HVACControllers.cc b/src/EnergyPlus/HVACControllers.cc index 090384de7da..e6f0a81e190 100644 --- a/src/EnergyPlus/HVACControllers.cc +++ b/src/EnergyPlus/HVACControllers.cc @@ -935,7 +935,6 @@ namespace HVACControllers { // MODIFIED Jan. 2004, Shirey/Raustad (FSEC), // MODIFIED Feb. 2006, Dimitri Curtil (LBNL), Moved first call convergence test code to ResetController() // Jul. 2016, R. Zhang (LBNL), Applied the water coil supply air temperature sensor offset fault model - // RE-ENGINEERED na // PURPOSE OF THIS SUBROUTINE: // This subroutine is for initializations of the Controller Components. @@ -943,11 +942,6 @@ namespace HVACControllers { // METHODOLOGY EMPLOYED: // Uses the status flags to trigger events. - // REFERENCES: - // na - - // Using/Aliasing - using DataEnvironment::OutBaroPress; using DataGlobals::DoingSizing; using DataGlobals::KickOffSimulation; using DataGlobals::WarmupFlag; @@ -969,35 +963,14 @@ namespace HVACControllers { using SetPointManager::iCtrlVarType_MaxHumRat; using SetPointManager::iCtrlVarType_MinHumRat; - // Locals - // SUBROUTINE ARGUMENT DEFINITIONS: - - // SUBROUTINE PARAMETER DEFINITIONS: static std::string const RoutineName("InitController"); - // INTERFACE BLOCK SPECIFICATIONS - // na - - // DERIVED TYPE DEFINITIONS - // na - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: int ActuatedNode; int SensedNode; int ControllerIndex; static Array1D_bool MyEnvrnFlag; static Array1D_bool MySizeFlag; static Array1D_bool MyPlantIndexsFlag; - //////////// hoisted into namespace //////////////////////////////////////////////// - // static bool MyOneTimeFlag( true ); // InitControllerOneTimeFlag - // static bool MySetPointCheckFlag( true ); // InitControllerSetPointCheckFlag - //////////////////////////////////////////////////////////////////////////////////// - // Supply Air Temp Setpoint when 'TemperatureAndHumidityRatio' control is used - Real64 HumidityControlTempSetPoint; - // Difference between SA dry-bulb and dew-point temperatures - Real64 ApproachTemp; - // Desired dew point temperature setpoint for 'TemperatureAndHumidityRatio' control - Real64 DesiredDewPoint; Real64 rho; // local fluid density if (InitControllerOneTimeFlag) { From 6c08857ae04695e09b7517c0432b93c442341815 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 15:41:27 -0500 Subject: [PATCH 05/15] Revised fix in GetCoilDesFlowT to protect against array bounds violation 7211 --- src/EnergyPlus/ReportSizingManager.cc | 29 ++++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/EnergyPlus/ReportSizingManager.cc b/src/EnergyPlus/ReportSizingManager.cc index 9b6653dd558..ff0827ad527 100644 --- a/src/EnergyPlus/ReportSizingManager.cc +++ b/src/EnergyPlus/ReportSizingManager.cc @@ -4433,20 +4433,20 @@ namespace ReportSizingManager { using DataEnvironment::StdRhoAir; // FUNCTION LOCAL VARIABLE DECLARATIONS: - int DDAtSensPeak; - int TimeStepAtSensPeak; - int DDAtFlowPeak; - int TimeStepAtFlowPeak; + int DDAtSensPeak(0); + int TimeStepAtSensPeak(0); + int DDAtFlowPeak(0); + int TimeStepAtFlowPeak(0); int CoolCapCtrl; // type of coil capacity control int PeakLoadType; - int DDAtTotPeak; - int TimeStepAtTotPeak; + int DDAtTotPeak(0); + int TimeStepAtTotPeak(0); int TimeStepAtPeak(0); Real64 ZoneCoolLoadSum(0); // sum of zone cooling loads at the peak [W] Real64 AvgZoneTemp(0); // average zone temperature [C] - Real64 AvgSupTemp; // average supply temperature for bypass control [C] - Real64 TotFlow; // total flow for bypass control [m3/s] - Real64 MixTemp; // mixed air temperature at the peak [C] + Real64 AvgSupTemp(0.0); // average supply temperature for bypass control [C] + Real64 TotFlow(0.0); // total flow for bypass control [m3/s] + Real64 MixTemp(0.0); // mixed air temperature at the peak [C] CoolCapCtrl = SysSizInput(SysNum).CoolCapControl; PeakLoadType = SysSizInput(SysNum).CoolingPeakLoadType; @@ -4463,16 +4463,21 @@ namespace ReportSizingManager { } else { TimeStepAtPeak = TimeStepAtSensPeak; } + } else { + if ((CoolCapCtrl == VT) || (CoolCapCtrl == Bypass)) { + ShowWarningError("GetCoilDesFlow: AirLoopHVAC=" + SysSizInput(SysNum).AirPriLoopName + + "has no time of peak cooling load for sizing."); + ShowContinueError("Using Central Cooling Capacity Control Method=VAV instead of Bypass or VT."); + CoolCapCtrl = VAV; + } } + if (CoolCapCtrl == VAV) { DesExitTemp = FinalSysSizing(SysNum).CoolSupTemp; DesFlow = FinalSysSizing(SysNum).MassFlowAtCoolPeak / StdRhoAir; } else if (CoolCapCtrl == OnOff) { DesExitTemp = FinalSysSizing(SysNum).CoolSupTemp; DesFlow = DataAirFlowUsedForSizing; - } else if (TimeStepAtPeak == 0) { - ShowFatalError("GetCoilDesFlow: AirLoopHVAC=" + SysSizInput(SysNum).AirPriLoopName + - " Central Cooling Capacity Control Method requires zone thermostats to calculate timestep loads."); } else if (CoolCapCtrl == VT) { if (FinalSysSizing(SysNum).CoolingPeakLoadType == SensibleCoolingLoad) { ZoneCoolLoadSum = CalcSysSizing(SysNum).SumZoneCoolLoadSeq(TimeStepAtPeak); From 119c5bc0a57a57383e70d2dc448e0f0ebc6f64ef Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 15:43:09 -0500 Subject: [PATCH 06/15] ChW controller - cleanup and move humctrl check into HVACControllers --- src/EnergyPlus/HVACControllers.cc | 81 +++++++++------------------- src/EnergyPlus/HVACControllers.hh | 10 +--- src/EnergyPlus/SimAirServingZones.cc | 28 ---------- 3 files changed, 28 insertions(+), 91 deletions(-) diff --git a/src/EnergyPlus/HVACControllers.cc b/src/EnergyPlus/HVACControllers.cc index e6f0a81e190..1d3c9b4129d 100644 --- a/src/EnergyPlus/HVACControllers.cc +++ b/src/EnergyPlus/HVACControllers.cc @@ -413,25 +413,20 @@ namespace HVACControllers { { auto const SELECT_CASE_var(Operation); if (SELECT_CASE_var == iControllerOpColdStart) { + // For temperature and humidity control reset humidity control override + HVACControllers::ControllerProps(ControlNum).HumRatCtrlOverride = false; + // If a iControllerOpColdStart call, reset the actuator inlet flows ResetController(ControlNum, FirstHVACIteration, false, IsConvergedFlag); - // CALL InitController(ControlNum, FirstHVACIteration, IsConvergedFlag) // Update the current Controller to the outlet nodes UpdateController(ControlNum); - // Report the current Controller - ReportController(ControlNum); - } else if (SELECT_CASE_var == iControllerOpWarmRestart) { // If a iControllerOpWarmRestart call, set the actuator inlet flows to previous solution ResetController(ControlNum, FirstHVACIteration, true, IsConvergedFlag); - // CALL InitController(ControlNum, FirstHVACIteration, IsConvergedFlag) // Update the current Controller to the outlet nodes UpdateController(ControlNum); - // Report the current Controller - ReportController(ControlNum); - } else if (SELECT_CASE_var == iControllerOpIterate) { // With the correct ControlNum Initialize all Controller related parameters InitController(ControlNum, FirstHVACIteration, IsConvergedFlag); @@ -452,8 +447,8 @@ namespace HVACControllers { // Update the current Controller to the outlet nodes UpdateController(ControlNum); - // Report the current Controller - ReportController(ControlNum); + CheckTempAndHumRatCtrl(ControlNum, IsConvergedFlag, FirstHVACIteration); + } else if (SELECT_CASE_var == iControllerOpEnd) { // With the correct ControlNum Initialize all Controller related parameters @@ -473,9 +468,6 @@ namespace HVACControllers { } } - // Report the current Controller - ReportController(ControlNum); - } else { ShowFatalError("ManageControllers: Invalid Operation passed=" + TrimSigDigits(Operation) + ", Controller name=" + ControllerName); } @@ -2245,52 +2237,31 @@ namespace HVACControllers { // End of Update subroutines for the Controller Module // ***************************************************************************** - // Beginning of Reporting subroutines for the Controller Module - // ***************************************************************************** - - void ReportController(int const EP_UNUSED(ControlNum)) // unused1208 + void CheckTempAndHumRatCtrl(int const ControlNum, bool &IsConvergedFlag, bool const FirstHVACIteration) { - // SUBROUTINE INFORMATION: - // AUTHOR - // DATE WRITTEN - // MODIFIED na - // RE-ENGINEERED na - - // PURPOSE OF THIS SUBROUTINE: - // This subroutine needs a description. - - // METHODOLOGY EMPLOYED: - // Needs description, as appropriate. - - // REFERENCES: - // na - - // USE STATEMENTS: - // na - - // Locals - // SUBROUTINE ARGUMENT DEFINITIONS: - - // SUBROUTINE PARAMETER DEFINITIONS: - // na - - // INTERFACE BLOCK SPECIFICATIONS - // na - - // DERIVED TYPE DEFINITIONS - // na - - // SUBROUTINE LOCAL VARIABLE DECLARATIONS: - // na - - // Still needs to report the Controller power from this component - // Write(*,*)=ControllerProps(ControlNum)%ControllerPower + { + auto &thisController(ControllerProps(ControlNum)); + if (IsConvergedFlag) { + if (thisController.ControlVar == iTemperatureAndHumidityRatio) { + // For temperature and humidity control, after temperature control is converged, check if humidity setpoint is met + if (!thisController.HumRatCtrlOverride) { + if (Node(thisController.SensedNode).HumRat > (Node(thisController.SensedNode).HumRatMax + thisController.Offset)) { + // Turn on humdity control and restart controller + IsConvergedFlag = false; + thisController.HumRatCtrlOverride = true; + // IsUpToDateFlag = false; + // Do a cold start reset, same as iControllerOpColdStart + ResetController(ControlNum, FirstHVACIteration, false, IsConvergedFlag); + // Update the current Controller to the outlet nodes + UpdateController(ControlNum); + } + } + } + } + } } - // End of Reporting subroutines for the Controller Module - // ***************************************************************************** - void ExitCalcController(int const ControlNum, Real64 const NextActuatedValue, int const Mode, bool &IsConvergedFlag, bool &IsUpToDateFlag) { diff --git a/src/EnergyPlus/HVACControllers.hh b/src/EnergyPlus/HVACControllers.hh index b327ed614c3..5d79583781b 100644 --- a/src/EnergyPlus/HVACControllers.hh +++ b/src/EnergyPlus/HVACControllers.hh @@ -352,6 +352,8 @@ namespace HVACControllers { bool CheckMaxActiveController(int const ControlNum); + void CheckTempAndHumRatCtrl(int const ControlNum, bool &IsConvergedFlag, bool const FirstHVACIteration); + void SaveSimpleController(int const ControlNum, bool const FirstHVACIteration, bool const IsConvergedFlag); // End Algorithm Section of the Module @@ -365,14 +367,6 @@ namespace HVACControllers { // End of Update subroutines for the Controller Module // ***************************************************************************** - // Beginning of Reporting subroutines for the Controller Module - // ***************************************************************************** - - void ReportController(int const ControlNum); // unused1208 - - // End of Reporting subroutines for the Controller Module - // ***************************************************************************** - void ExitCalcController(int const ControlNum, Real64 const NextActuatedValue, int const Mode, bool &IsConvergedFlag, bool &IsUpToDateFlag); // Beginning of Statistics subroutines for the Controller Module diff --git a/src/EnergyPlus/SimAirServingZones.cc b/src/EnergyPlus/SimAirServingZones.cc index 05c540408ec..6c6be49829c 100644 --- a/src/EnergyPlus/SimAirServingZones.cc +++ b/src/EnergyPlus/SimAirServingZones.cc @@ -2864,9 +2864,6 @@ namespace SimAirServingZones { // E.g., actuator inlet water flow for (int AirLoopControlNum = 1; AirLoopControlNum <= PrimaryAirSystem(AirLoopNum).NumControllers; ++AirLoopControlNum) { - // For temperature and humidity control reset humidity control override - HVACControllers::ControllerProps(PrimaryAirSystem(AirLoopNum).ControllerIndex(AirLoopControlNum)).HumRatCtrlOverride = false; - // BypassOAController is true here since we do not want to simulate the controller if it has already been simulated in the OA system // ControllerConvergedFlag is returned true here for water coils in OA system ManageControllers(PrimaryAirSystem(AirLoopNum).ControllerName(AirLoopControlNum), @@ -2963,31 +2960,6 @@ namespace SimAirServingZones { // not converge ControllerConvergedFlag = PrimaryAirSystem(AirLoopNum).ControlConverged(AirLoopControlNum); IsUpToDateFlag = true; - } else { - { - auto &thisController(HVACControllers::ControllerProps(PrimaryAirSystem(AirLoopNum).ControllerIndex(AirLoopControlNum))); - if (thisController.ControlVar == HVACControllers::iTemperatureAndHumidityRatio) { - // For temperature and humidity control, after temperature control is converged, check if humidity setpoint is met - if (!thisController.HumRatCtrlOverride) { - if (Node(thisController.SensedNode).HumRat > (Node(thisController.SensedNode).HumRatMax + thisController.Offset)) { - // Turn on humdity control and restart controller - ControllerConvergedFlag = false; - thisController.HumRatCtrlOverride = true; - IsUpToDateFlag = false; - ManageControllers(PrimaryAirSystem(AirLoopNum).ControllerName(AirLoopControlNum), - PrimaryAirSystem(AirLoopNum).ControllerIndex(AirLoopControlNum), - FirstHVACIteration, - AirLoopNum, - iControllerOpWarmRestart, - ControllerConvergedFlag, - IsUpToDateFlag, - BypassOAController, - AllowWarmRestartFlag); - SimAirLoopComponents(AirLoopNum, FirstHVACIteration); - } - } - } - } } } // End of the Convergence Iteration From 9451557f4b0d31408c5cae00088d62ccf80c03a0 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 18:25:07 -0500 Subject: [PATCH 07/15] ChW controller - remove unused FirstHVACIteration args --- src/EnergyPlus/HVACControllers.cc | 21 +++++++++------------ src/EnergyPlus/HVACControllers.hh | 5 ++--- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/EnergyPlus/HVACControllers.cc b/src/EnergyPlus/HVACControllers.cc index 1d3c9b4129d..5c075a00cff 100644 --- a/src/EnergyPlus/HVACControllers.cc +++ b/src/EnergyPlus/HVACControllers.cc @@ -401,7 +401,7 @@ namespace HVACControllers { if (ControllerProps(ControlNum).InitFirstPass) { // Coil must first be sized to: // Initialize ControllerProps(ControlNum)%MinActuated and ControllerProps(ControlNum)%MaxActuated - InitController(ControlNum, FirstHVACIteration, IsConvergedFlag); + InitController(ControlNum, IsConvergedFlag); ControllerProps(ControlNum).InitFirstPass = false; } @@ -417,19 +417,19 @@ namespace HVACControllers { HVACControllers::ControllerProps(ControlNum).HumRatCtrlOverride = false; // If a iControllerOpColdStart call, reset the actuator inlet flows - ResetController(ControlNum, FirstHVACIteration, false, IsConvergedFlag); + ResetController(ControlNum, false, IsConvergedFlag); // Update the current Controller to the outlet nodes UpdateController(ControlNum); } else if (SELECT_CASE_var == iControllerOpWarmRestart) { // If a iControllerOpWarmRestart call, set the actuator inlet flows to previous solution - ResetController(ControlNum, FirstHVACIteration, true, IsConvergedFlag); + ResetController(ControlNum, true, IsConvergedFlag); // Update the current Controller to the outlet nodes UpdateController(ControlNum); } else if (SELECT_CASE_var == iControllerOpIterate) { // With the correct ControlNum Initialize all Controller related parameters - InitController(ControlNum, FirstHVACIteration, IsConvergedFlag); + InitController(ControlNum, IsConvergedFlag); // No initialization needed: should have been done before // Simulate the correct Controller with the current ControlNum @@ -447,12 +447,12 @@ namespace HVACControllers { // Update the current Controller to the outlet nodes UpdateController(ControlNum); - CheckTempAndHumRatCtrl(ControlNum, IsConvergedFlag, FirstHVACIteration); + CheckTempAndHumRatCtrl(ControlNum, IsConvergedFlag); } else if (SELECT_CASE_var == iControllerOpEnd) { // With the correct ControlNum Initialize all Controller related parameters - InitController(ControlNum, FirstHVACIteration, IsConvergedFlag); + InitController(ControlNum, IsConvergedFlag); // No initialization needed: should have been done before // Check convergence for the correct Controller with the current ControlNum @@ -805,7 +805,7 @@ namespace HVACControllers { // Beginning Initialization Section of the Module //****************************************************************************** - void ResetController(int const ControlNum, bool const EP_UNUSED(FirstHVACIteration), bool const DoWarmRestartFlag, bool &IsConvergedFlag) + void ResetController(int const ControlNum, bool const DoWarmRestartFlag, bool &IsConvergedFlag) { // SUBROUTINE INFORMATION: @@ -917,7 +917,6 @@ namespace HVACControllers { } void InitController(int const ControlNum, - bool const EP_UNUSED(FirstHVACIteration), // TRUE if first full HVAC iteration in an HVAC timestep bool &IsConvergedFlag) { @@ -2237,7 +2236,7 @@ namespace HVACControllers { // End of Update subroutines for the Controller Module // ***************************************************************************** - void CheckTempAndHumRatCtrl(int const ControlNum, bool &IsConvergedFlag, bool const FirstHVACIteration) + void CheckTempAndHumRatCtrl(int const ControlNum, bool &IsConvergedFlag) { { @@ -2252,9 +2251,7 @@ namespace HVACControllers { thisController.HumRatCtrlOverride = true; // IsUpToDateFlag = false; // Do a cold start reset, same as iControllerOpColdStart - ResetController(ControlNum, FirstHVACIteration, false, IsConvergedFlag); - // Update the current Controller to the outlet nodes - UpdateController(ControlNum); + ResetController(ControlNum, false, IsConvergedFlag); } } } diff --git a/src/EnergyPlus/HVACControllers.hh b/src/EnergyPlus/HVACControllers.hh index 5d79583781b..432354b725a 100644 --- a/src/EnergyPlus/HVACControllers.hh +++ b/src/EnergyPlus/HVACControllers.hh @@ -318,10 +318,9 @@ namespace HVACControllers { // Beginning Initialization Section of the Module //****************************************************************************** - void ResetController(int const ControlNum, bool const FirstHVACIteration, bool const DoWarmRestartFlag, bool &IsConvergedFlag); + void ResetController(int const ControlNum, bool const DoWarmRestartFlag, bool &IsConvergedFlag); void InitController(int const ControlNum, - bool const FirstHVACIteration, // TRUE if first full HVAC iteration in an HVAC timestep bool &IsConvergedFlag); void SizeController(int const ControlNum); @@ -352,7 +351,7 @@ namespace HVACControllers { bool CheckMaxActiveController(int const ControlNum); - void CheckTempAndHumRatCtrl(int const ControlNum, bool &IsConvergedFlag, bool const FirstHVACIteration); + void CheckTempAndHumRatCtrl(int const ControlNum, bool &IsConvergedFlag); void SaveSimpleController(int const ControlNum, bool const FirstHVACIteration, bool const IsConvergedFlag); From d136c4c8b92bba4f0f873770ff63c4b81679bfef Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 18:26:47 -0500 Subject: [PATCH 08/15] SetActuatedBranchFlowRate - avoid array bounds errors - move early escape to top --- src/EnergyPlus/PlantUtilities.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/PlantUtilities.cc b/src/EnergyPlus/PlantUtilities.cc index 6d40d7586b1..2afa1a3c98a 100644 --- a/src/EnergyPlus/PlantUtilities.cc +++ b/src/EnergyPlus/PlantUtilities.cc @@ -402,6 +402,12 @@ namespace PlantUtilities { // Set flow on node and branch while honoring constraints on actuated node auto &a_node(DataLoopNode::Node(ActuatedNode)); + if (LoopNum == 0 || LoopSideNum == 0) { + // early in simulation before plant loops are setup and found + a_node.MassFlowRate = CompFlow; + return; + } + auto &loop_side(DataPlant::PlantLoop(LoopNum).LoopSide(LoopSideNum)); // store original flow @@ -495,10 +501,6 @@ namespace PlantUtilities { DataLoopNode::Node(NodeNum).MassFlowRate = a_node_MasFlowRate; DataLoopNode::Node(NodeNum).MassFlowRateRequest = a_node_MasFlowRateRequest; } - - } else { - // early in simulation before plant loops are setup and found - a_node.MassFlowRate = CompFlow; } } From 56330bd72032d65a3faba27f90fadeaafcb98746 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 18:28:22 -0500 Subject: [PATCH 09/15] GetCoilDesFlowT_NoPeak - new unit test and cleanup --- .../unit/ReportSizingManager.unit.cc | 109 ++++++++++++------ 1 file changed, 75 insertions(+), 34 deletions(-) diff --git a/tst/EnergyPlus/unit/ReportSizingManager.unit.cc b/tst/EnergyPlus/unit/ReportSizingManager.unit.cc index 23be167ace5..7f5ed5325fe 100644 --- a/tst/EnergyPlus/unit/ReportSizingManager.unit.cc +++ b/tst/EnergyPlus/unit/ReportSizingManager.unit.cc @@ -83,8 +83,6 @@ using namespace EnergyPlus::ReportSizingManager; TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT) { - ShowMessage("Begin Test: ReportSizingManager, GetCoilDesFlowT"); - // setup global allocation DataSizing::SysSizInput.allocate(1); DataSizing::SysSizPeakDDNum.allocate(1); @@ -125,12 +123,14 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT) // Single path for VAV DataSizing::SysSizInput(1).CoolCapControl = DataSizing::VAV; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); EXPECT_DOUBLE_EQ(0.002, designFlowValue); // Single path for OnOff DataSizing::SysSizInput(1).CoolCapControl = DataSizing::OnOff; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); EXPECT_DOUBLE_EQ(0.2, designFlowValue); @@ -139,12 +139,14 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT) DataSizing::SysSizInput(1).CoolCapControl = DataSizing::VT; DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq(1) = 10; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).DesCoolVolFlow, designFlowValue); // CoolSupTemp < calculated value DataSizing::SysSizInput(1).CoolCapControl = DataSizing::VT; DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq(1) = 15; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_NEAR(13.00590, designExitTemp, 0.0001); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).DesCoolVolFlow, designFlowValue); @@ -154,11 +156,13 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT) DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq(1) = 13; DataSizing::CalcSysSizing(1).MixTempAtCoolPeak = 15; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(10, designExitTemp); EXPECT_NEAR(0.119823, designFlowValue, 0.0001); // MixTemp < DesExitTemp DataSizing::CalcSysSizing(1).MixTempAtCoolPeak = 5; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(10, designExitTemp); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).DesCoolVolFlow, designFlowValue); @@ -169,6 +173,7 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT) DataSizing::SysSizInput(1).CoolCapControl = DataSizing::VT; DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq(1) = 10; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).DesCoolVolFlow, designFlowValue); // And a bypass case @@ -176,20 +181,77 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT) DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq(1) = 13; DataSizing::CalcSysSizing(1).MixTempAtCoolPeak = 15; ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); EXPECT_DOUBLE_EQ(10, designExitTemp); EXPECT_NEAR(0.119823, designFlowValue, 0.0001); - // tear down - DataSizing::DataAirFlowUsedForSizing = 0.0; - DataSizing::CalcSysSizing(1).SumZoneCoolLoadSeq.deallocate(); - DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq.deallocate(); - DataSizing::SysSizPeakDDNum(1).TimeStepAtSensCoolPk.deallocate(); - DataSizing::SysSizPeakDDNum(1).TimeStepAtCoolFlowPk.deallocate(); - DataSizing::SysSizPeakDDNum(1).TimeStepAtTotCoolPk.deallocate(); - DataSizing::SysSizInput.deallocate(); - DataSizing::SysSizPeakDDNum.deallocate(); - DataSizing::FinalSysSizing.deallocate(); - DataSizing::CalcSysSizing.deallocate(); +} +TEST_F(EnergyPlusFixture, ReportSizingManager_GetCoilDesFlowT_NoPeak) +{ + // setup global allocation + DataSizing::SysSizInput.allocate(1); + DataSizing::SysSizPeakDDNum.allocate(1); + DataSizing::FinalSysSizing.allocate(1); + DataSizing::CalcSysSizing.allocate(1); + DataSizing::CalcSysSizing(1).SumZoneCoolLoadSeq.allocate(1); + DataSizing::CalcSysSizing(1).CoolZoneAvgTempSeq.allocate(1); + DataSizing::SysSizPeakDDNum(1).TimeStepAtSensCoolPk.allocate(1); + DataSizing::SysSizPeakDDNum(1).TimeStepAtCoolFlowPk.allocate(1); + DataSizing::SysSizPeakDDNum(1).TimeStepAtTotCoolPk.allocate(1); + + // one-time global initialization + int const DesignDayForPeak = 0; + DataSizing::SysSizPeakDDNum(1).SensCoolPeakDD = DesignDayForPeak; + DataSizing::SysSizPeakDDNum(1).CoolFlowPeakDD = DesignDayForPeak; + DataSizing::SysSizPeakDDNum(1).TotCoolPeakDD = DesignDayForPeak; + DataSizing::FinalSysSizing(1).CoolSupTemp = 10; + DataSizing::FinalSysSizing(1).MassFlowAtCoolPeak = 2.0; + DataSizing::FinalSysSizing(1).DesCoolVolFlow = 0.15; + DataSizing::DataAirFlowUsedForSizing = 0.2; + DataEnvironment::StdRhoAir = 1000; + DataSizing::CalcSysSizing(1).SumZoneCoolLoadSeq(1) = 1250000; + + // one-time argument initialization + int const sysNum = 1; + Real64 const CpAir = 4179; + + // argument return values + Real64 designFlowValue; + Real64 designExitTemp; + + DataSizing::SysSizInput(1).CoolingPeakLoadType = DataSizing::TotalCoolingLoad; + DataSizing::FinalSysSizing(1).CoolingPeakLoadType = DataSizing::TotalCoolingLoad; + + // Single path for VAV + DataSizing::SysSizInput(1).CoolCapControl = DataSizing::VAV; + ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); + EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); + EXPECT_DOUBLE_EQ(0.002, designFlowValue); + + // Single path for OnOff + DataSizing::SysSizInput(1).CoolCapControl = DataSizing::OnOff; + ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + EXPECT_FALSE(has_err_output(true)); + EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); + EXPECT_DOUBLE_EQ(0.2, designFlowValue); + + // VT + // CoolSupTemp > calculated value + DataSizing::SysSizInput(1).CoolCapControl = DataSizing::VT; + ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + // Expect warning and same result as VAV + EXPECT_TRUE(has_err_output(true)); + EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); + EXPECT_DOUBLE_EQ(0.002, designFlowValue); + + // Bypass + DataSizing::SysSizInput(1).CoolCapControl = DataSizing::Bypass; + ReportSizingManager::GetCoilDesFlowT(sysNum, CpAir, designFlowValue, designExitTemp); + // Expect warning and same result as VAV + EXPECT_TRUE(has_err_output(true)); + EXPECT_DOUBLE_EQ(DataSizing::FinalSysSizing(1).CoolSupTemp, designExitTemp); + EXPECT_DOUBLE_EQ(0.002, designFlowValue); } TEST_F(EnergyPlusFixture, ReportSizingManager_RequestSizingSystem) { @@ -259,13 +321,6 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_RequestSizingSystem) ReportSizingManager::RequestSizing(CompType, CompName, SizingType, SizingString, SizingResult, PrintWarning, CallingRoutine); EXPECT_NEAR(19234.6, SizingResult, 0.1); - // clean - DataSizing::NumSysSizInput = 0; - FinalSysSizing.deallocate(); - PrimaryAirSystem.deallocate(); - SysSizInput.deallocate(); - UnitarySysEqSizing.deallocate(); - OASysEqSizing.deallocate(); } TEST_F(EnergyPlusFixture, ReportSizingManager_RequestSizingSystemWithFans) @@ -464,19 +519,10 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_RequestSizingSystemWithFans) ReportSizingManager::RequestSizing(CompType, CompName, SizingType, SizingString, SizingResult, PrintWarning, CallingRoutine); EXPECT_NEAR(expectedDXCoilSize, SizingResult, 0.1); - // clean - DataSizing::NumSysSizInput = 0; - FinalSysSizing.deallocate(); - PrimaryAirSystem.deallocate(); - SysSizInput.deallocate(); - UnitarySysEqSizing.deallocate(); - OASysEqSizing.deallocate(); } TEST_F(EnergyPlusFixture, ReportSizingManager_RequestSizingZone) { - ShowMessage("Begin Test: ReportSizingManager, RequestSizingZone"); - int const ZoneNum = 1; std::string CompName; // component name std::string CompType; // component type @@ -538,11 +584,6 @@ TEST_F(EnergyPlusFixture, ReportSizingManager_RequestSizingZone) ReportSizingManager::RequestSizing(CompType, CompName, SizingType, SizingString, SizingResult, PrintWarning, CallingRoutine); EXPECT_NEAR(5770.4, SizingResult, 0.1); - // clean - DataSizing::NumZoneSizingInput = 0; - FinalZoneSizing.deallocate(); - ZoneEqSizing.deallocate(); - ZoneSizingInput.deallocate(); } TEST_F(SQLiteFixture, ReportSizingManager_SQLiteRecordReportSizingOutputTest) From ee06f4eb9f684e1cf896943cdd6822d83d0412d5 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 18:29:02 -0500 Subject: [PATCH 10/15] HVACControllers_CheckTempAndHumRatCtrl unit test --- tst/EnergyPlus/unit/HVACControllers.unit.cc | 96 +++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/tst/EnergyPlus/unit/HVACControllers.unit.cc b/tst/EnergyPlus/unit/HVACControllers.unit.cc index de2e0d8225d..4e348e4eef1 100644 --- a/tst/EnergyPlus/unit/HVACControllers.unit.cc +++ b/tst/EnergyPlus/unit/HVACControllers.unit.cc @@ -680,4 +680,100 @@ TEST_F(EnergyPlusFixture, HVACControllers_CoilSystemCoolingWaterOnOutsideAirSyst SimAirServingZones::CheckWaterCoilIsOnAirLoop(CoilTypeNum, CompType, CompName, WaterCoilOnAirLoop); EXPECT_TRUE(WaterCoilOnAirLoop); } +TEST_F(EnergyPlusFixture, HVACControllers_CheckTempAndHumRatCtrl) +{ + HVACControllers::ControllerProps.allocate(1); + HVACControllers::RootFinders.allocate(1); + bool isConverged = true; + int const controlNum = 1; + auto &thisController(ControllerProps(1)); + thisController.ControlVar = HVACControllers::iTemperatureAndHumidityRatio; + thisController.Offset = 0.0001; + int sensedNode = 1; + thisController.SensedNode = sensedNode; + DataLoopNode::Node.allocate(2); + DataLoopNode::Node(sensedNode).Temp = 21.2; + DataLoopNode::Node(sensedNode).HumRatMax = 0.001; + thisController.ActuatedNode = 2; + thisController.ActuatedNodePlantLoopBranchNum = 0; + thisController.ActuatedNodePlantLoopNum = 0; + thisController.ActuatedNodePlantLoopSide = 0; + + // Case 1 - not converged yet, no override yet, return untouched + isConverged = false; + thisController.HumRatCtrlOverride = false; + thisController.SetPointValue = 21.1; + thisController.IsSetPointDefinedFlag = true; + thisController.NumCalcCalls = 5; + DataLoopNode::Node(sensedNode).HumRat = 0.0011; + + HVACControllers::CheckTempAndHumRatCtrl(controlNum, isConverged); + EXPECT_FALSE(isConverged); + EXPECT_FALSE(thisController.HumRatCtrlOverride); + EXPECT_NEAR(thisController.SetPointValue, 21.1, 0.0001); + EXPECT_TRUE(thisController.IsSetPointDefinedFlag); + EXPECT_EQ(thisController.NumCalcCalls,5); + + // Case 2 - converged, override true, return untouched + isConverged = true; + thisController.HumRatCtrlOverride = true; + thisController.SetPointValue = 21.1; + thisController.IsSetPointDefinedFlag = true; + thisController.NumCalcCalls = 5; + DataLoopNode::Node(sensedNode).HumRat = 0.0011; + + HVACControllers::CheckTempAndHumRatCtrl(controlNum, isConverged); + EXPECT_TRUE(isConverged); + EXPECT_TRUE(thisController.HumRatCtrlOverride); + EXPECT_NEAR(thisController.SetPointValue, 21.1, 0.0001); + EXPECT_TRUE(thisController.IsSetPointDefinedFlag); + EXPECT_EQ(thisController.NumCalcCalls, 5); + + // Case 3 - converged, override false, humrathumratMax+Offset, return with everything reset + isConverged = true; + thisController.HumRatCtrlOverride = false; + thisController.SetPointValue = 21.1; + thisController.IsSetPointDefinedFlag = true; + thisController.NumCalcCalls = 5; + DataLoopNode::Node(sensedNode).HumRat = DataLoopNode::Node(sensedNode).HumRatMax + 0.002; + + HVACControllers::CheckTempAndHumRatCtrl(controlNum, isConverged); + EXPECT_FALSE(isConverged); + EXPECT_TRUE(thisController.HumRatCtrlOverride); + EXPECT_NEAR(thisController.SetPointValue, 0.0, 0.0001); + EXPECT_FALSE(thisController.IsSetPointDefinedFlag); + EXPECT_EQ(thisController.NumCalcCalls, 0); + + // Case 5 - converged, override false, humrat>humratMax+Offset, temp only controller, return untouched + isConverged = true; + thisController.HumRatCtrlOverride = false; + thisController.SetPointValue = 21.1; + thisController.IsSetPointDefinedFlag = true; + thisController.NumCalcCalls = 5; + DataLoopNode::Node(sensedNode).HumRat = DataLoopNode::Node(sensedNode).HumRatMax - 0.001; + thisController.ControlVar = HVACControllers::iTemperature; + + HVACControllers::CheckTempAndHumRatCtrl(controlNum, isConverged); + EXPECT_TRUE(isConverged); + EXPECT_FALSE(thisController.HumRatCtrlOverride); + EXPECT_NEAR(thisController.SetPointValue, 21.1, 0.0001); + EXPECT_TRUE(thisController.IsSetPointDefinedFlag); + EXPECT_EQ(thisController.NumCalcCalls, 5); + +} } // namespace EnergyPlus From 3f5a7e24b406250976780864427226b558392ed0 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 11 Mar 2019 21:35:16 -0500 Subject: [PATCH 11/15] UnitarySystemModel_WaterCoilSPControl_Latent unit test --- tst/EnergyPlus/unit/UnitarySystem.unit.cc | 257 ++++++++++++++++++++++ 1 file changed, 257 insertions(+) diff --git a/tst/EnergyPlus/unit/UnitarySystem.unit.cc b/tst/EnergyPlus/unit/UnitarySystem.unit.cc index fde619a30dc..26d145da5bd 100644 --- a/tst/EnergyPlus/unit/UnitarySystem.unit.cc +++ b/tst/EnergyPlus/unit/UnitarySystem.unit.cc @@ -2635,6 +2635,263 @@ TEST_F(ZoneUnitarySysTest, UnitarySystemModel_WaterCoilSPControl) // EXPECT_LT( Node( suppHeatingCoilWaterInletNodeIndex ).MassFlowRate, Node( suppHeatingCoilWaterInletNodeIndex ).MassFlowRateMaxAvail ); } +TEST_F(ZoneUnitarySysTest, UnitarySystemModel_WaterCoilSPControl_Latent) +{ + + std::string const idf_objects = delimited_string({ + + "AirLoopHVAC:UnitarySystem,", + " Unitary System Model, !- Name", + " Setpoint, !- Control Type", + " East Zone, !- Controlling Zone or Thermostat Location", + " CoolReheat, !- Dehumidification Control Type", + " AlwaysOne, !- Availability Schedule Name", + " Water Cooling Coil Air Inlet Node, !- Air Inlet Node Name", + " Zone Inlet Node, !- Air Outlet Node Name", + " Fan:OnOff, !- Supply Fan Object Type", + " Supply Fan 1, !- Supply Fan Name", + " DrawThrough, !- Fan Placement", + " AlwaysOne, !- Supply Air Fan Operating Mode Schedule Name", + " , !- Heating Coil Object Type", + " , !- Heating Coil Name", + " , !- DX Heating Coil Sizing Ratio", + " Coil:Cooling:Water, !- Cooling Coil Object Type", + " Water Cooling Coil, !- Cooling Coil Name", + " , !- Use DOAS DX Cooling Coil", + " 5.0, !- DOAS DX Cooling Coil Leaving Minimum Air Temperature{ C }", + " LatentOrSensibleLoadControl, !- Latent Load Control", + " , !- Supplemental Heating Coil Object Type", + " , !- Supplemental Heating Coil Name", + " SupplyAirFlowRate, !- Supply Air Flow Rate Method During Cooling Operation", + " 1.6, !- Supply Air Flow Rate During Cooling Operation{ m3/s }", + " , !- Supply Air Flow Rate Per Floor Area During Cooling Operation{ m3/s-m2 }", + " , !- Fraction of Autosized Design Cooling Supply Air Flow Rate", + " , !- Design Supply Air Flow Rate Per Unit of Capacity During Cooling Operation{ m3/s-W }", + " SupplyAirFlowRate, !- Supply air Flow Rate Method During Heating Operation", + " 1.6, !- Supply Air Flow Rate During Heating Operation{ m3/s }", + " , !- Supply Air Flow Rate Per Floor Area during Heating Operation{ m3/s-m2 }", + " , !- Fraction of Autosized Design Heating Supply Air Flow Rate", + " , !- Design Supply Air Flow Rate Per Unit of Capacity During Heating Operation{ m3/s-W }", + " SupplyAirFlowRate, !- Supply Air Flow Rate Method When No Cooling or Heating is Required", + " 0.8, !- Supply Air Flow Rate When No Cooling or Heating is Required{ m3/s }", + " , !- Supply Air Flow Rate Per Floor Area When No Cooling or Heating is Required{ m3/s-m2 }", + " , !- Fraction of Autosized Design Cooling Supply Air Flow Rate", + " , !- Fraction of Autosized Design Heating Supply Air Flow Rate", + " , !- Design Supply Air Flow Rate Per Unit of Capacity During Cooling Operation{ m3/s-W }", + " , !- Design Supply Air Flow Rate Per Unit of Capacity During Heating Operation{ m3/s-W }", + " 25.0; !- Maximum Supply Air Temperature{ C }", + + "Fan:OnOff,", + " Supply Fan 1, !- Name", + " AlwaysOne, !- Availability Schedule Name", + " 0.7, !- Fan Total Efficiency", + " 600.0, !- Pressure Rise{ Pa }", + " 1.6, !- Maximum Flow Rate{ m3 / s }", + " 0.9, !- Motor Efficiency", + " 1.0, !- Motor In Airstream Fraction", + " Water Cooling Coil Air Outlet Node, !- Air Inlet Node Name", + " Zone Inlet Node; !- Air Outlet Node Name", + + "Coil:Cooling:Water,", + " Water Cooling Coil, !- Name", + " AlwaysOne, !- Availability Schedule Namev", + " 0.0008, !- Design Water Flow Rate { m3 / s }", + " 1.6000, !- Design Air Flow Rate { m3 / s }", + " 7.22, !- Design Inlet Water Temperature { Cv }", + " 24.340, !- Design Inlet Air Temperature { C }", + " 14.000, !- Design Outlet Air Temperature { C }", + " 0.013, !- Design Inlet Air Humidity Ratio { kgWater / kgDryAir }", + " 0.0070, !- Design Outlet Air Humidity Ratio { kgWater / kgDryAir }", + " ChWInletNode, !- Water Inlet Node Name", + " ChWOutletNode, !- Water Outlet Node Name", + " Water Cooling Coil Air Inlet Node, !- Air Inlet Node Name", + " Water Cooling Coil Air Outlet Node, !- Air Outlet Node Name", + " SimpleAnalysis, !- Type of Analysis", + " CrossFlow; !- Heat Exchanger Configuration", + + "ScheduleTypeLimits,", + " Any Number; !- Name", + + "Schedule:Compact,", + " AlwaysOne, !- Name", + " Any Number, !- Schedule Type Limits Name", + " Through: 12/31, !- Field 1", + " For: AllDays, !- Field 2", + " Until: 24:00, 1.0; !- Field 3", + + "Schedule:Compact,", + " Always 20C, !- Name", + " Any Number, !- Schedule Type Limits Name", + " Through: 12/31, !- Field 1", + " For: AllDays, !- Field 2", + " Until: 24:00, 20.0; !- Field 3", + + "SetpointManager:Scheduled,", + " CW Coil Setpoint Manager, !- Name", + " Temperature, !- Control Variable", + " Always 20C, !- Schedule Name", + " Water Cooling Coil Air Outlet Node; !- Setpoint Node or NodeList Name", + + }); + + ASSERT_TRUE(process_idf(idf_objects)); // read idf objects + + UnitarySys mySys; + std::string compName = "UNITARY SYSTEM MODEL"; + bool zoneEquipment = true; + int compTypeOfNum = DataHVACGlobals::UnitarySys_AnyCoilType; + bool FirstHVACIteration = true; + UnitarySys *thisSys; + thisSys = mySys.factory(compTypeOfNum, compName, zoneEquipment, 0); + + DataZoneEquipment::ZoneEquipInputsFilled = true; // indicate zone data is available + thisSys->getUnitarySystemInputData(compName, zoneEquipment, 0, ErrorsFound); // get UnitarySystem input from object above + EXPECT_FALSE(ErrorsFound); // expect no errors + + auto unitarySystemAirInletNodeIndex = UtilityRoutines::FindItemInList("WATER COOLING COIL AIR INLET NODE", DataLoopNode::NodeID); // was Node 1 + auto coolingCoilAirInletNodeIndex = UtilityRoutines::FindItemInList("WATER COOLING COIL AIR INLET NODE", DataLoopNode::NodeID); // was Node 3 + auto coolingCoilAirOutletNodeIndex = UtilityRoutines::FindItemInList("WATER COOLING COIL AIR OUTLET NODE", DataLoopNode::NodeID); // was Node 6 + auto coolingCoilWaterInletNodeIndex = UtilityRoutines::FindItemInList("CHWINLETNODE", DataLoopNode::NodeID); // was Node 10 + auto coolingCoilWaterOutletNodeIndex = UtilityRoutines::FindItemInList("CHWOUTLETNODE", DataLoopNode::NodeID); // was Node 10 + + DataPlant::PlantLoop(1).LoopSide(1).Branch(1).Comp(1).Name = "WATER COOLING COIL"; + DataPlant::PlantLoop(1).LoopSide(1).Branch(1).Comp(1).TypeOf_Num = DataPlant::TypeOf_CoilWaterCooling; + DataPlant::PlantLoop(1).LoopSide(1).Branch(1).Comp(1).NodeNumIn = coolingCoilWaterInletNodeIndex; + DataPlant::PlantLoop(1).LoopSide(1).Branch(1).Comp(1).NodeNumOut = coolingCoilWaterOutletNodeIndex; + + OutputReportPredefined::SetPredefinedTables(); + + // UnitarySystem used as zone equipment will not be modeled when FirstHAVCIteration is true, first time FirstHVACIteration = false will disable + // the 'return' on FirstHVACIteration = true set FirstHVACIteration to false for unit testing to size water coils + FirstHVACIteration = false; + DataGlobals::BeginEnvrnFlag = false; + + // sizing routine will overwrite water coil air and water inlet nodes with design conditions so no need set set up node conditions yet + int AirLoopNum = 0; + int CompIndex = 1; + bool HeatActive = false; + bool CoolActive = true; + int const ZoneOAUnitNum = 0; + Real64 const OAUCoilOutTemp = 0.0; + bool const ZoneEquipment = true; + + thisSys->simulate(thisSys->Name, FirstHVACIteration, AirLoopNum, CompIndex, HeatActive, CoolActive, ZoneOAUnitNum, OAUCoilOutTemp, ZoneEquipment); + + // set up node conditions to test UnitarySystem set point based control + // Unitary system air inlet node + DataLoopNode::Node(unitarySystemAirInletNodeIndex).MassFlowRate = 1.9; + DataLoopNode::Node(unitarySystemAirInletNodeIndex).MassFlowRateMaxAvail = 1.9; // max avail at fan inlet so fan won't limit flow + + // test COOLING condition + DataLoopNode::Node(unitarySystemAirInletNodeIndex).Temp = 24.0; // 24C db + DataLoopNode::Node(unitarySystemAirInletNodeIndex).HumRat = 0.013; // 18C dp + DataLoopNode::Node(unitarySystemAirInletNodeIndex).Enthalpy = 57217.0; + + // Cooling coil air inlet node + DataLoopNode::Node(coolingCoilAirInletNodeIndex).MassFlowRate = 1.9; + DataLoopNode::Node(coolingCoilAirInletNodeIndex).MassFlowRateMax = 1.9; // max at inlet + + // Cooling coil water inlet node + DataLoopNode::Node(coolingCoilWaterInletNodeIndex).Temp = 6.0; + DataLoopNode::Node(coolingCoilWaterInletNodeIndex).Enthalpy = 25321.8; // www.peacesoftware.de/einigewerte/calc_dampf.php5 + + ScheduleManager::Schedule(1).CurrentValue = 1.0; // Enable schedule without calling schedule manager + + DataGlobals::BeginEnvrnFlag = true; // act as if simulation is beginning + + // Case 0 - COOLING mode - no load, sensible or latent + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax = 0.02; + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint = 30.0; + thisSys->simulate(thisSys->Name, FirstHVACIteration, AirLoopNum, CompIndex, HeatActive, CoolActive, ZoneOAUnitNum, OAUCoilOutTemp, ZoneEquipment); + + // check that CW coil air outlet node is < setpoint + EXPECT_LT(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).Temp, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint); + // check that CW coil air outlet node humrat is <= set point + EXPECT_LE(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRat, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax); + // CW air inlet node temp equals CW air outlet node temp + EXPECT_EQ(DataLoopNode::Node(coolingCoilAirInletNodeIndex).Temp, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).Temp); + // CW water inlet node flow is 0 + EXPECT_EQ(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, 0.0); + // CW water node flow is the same at inlet and outlet + EXPECT_EQ(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).MassFlowRate); + // CW water outlet node temp is same as CW inlet node temp + EXPECT_EQ(DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).Temp, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).Temp); + + // if cooling coil meets cooling set point temperature expect cooling coil water flow to be less than max water flow + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMax); + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, + DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMaxAvail); + + // Case 1 - COOLING mode - sensible control only, no extra dehumidification required + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax = 0.02; + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint = 20.0; + thisSys->simulate(thisSys->Name, FirstHVACIteration, AirLoopNum, CompIndex, HeatActive, CoolActive, ZoneOAUnitNum, OAUCoilOutTemp, ZoneEquipment); + + // check that CW coil air outlet node is at set point + EXPECT_NEAR(DataLoopNode::Node( coolingCoilAirOutletNodeIndex ).Temp, DataLoopNode::Node( coolingCoilAirOutletNodeIndex ).TempSetPoint, 0.001 ); + // check that CW coil air outlet node humrat is >= set point + EXPECT_LE(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRat, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax); + // CW air inlet node temp is greater than CW air outlet node temp + EXPECT_GT( DataLoopNode::Node( coolingCoilAirInletNodeIndex ).Temp, DataLoopNode::Node( coolingCoilAirOutletNodeIndex ).Temp ); + // CW water inlet node flow is greater than 0 + EXPECT_GT(DataLoopNode::Node( coolingCoilWaterInletNodeIndex ).MassFlowRate, 0.0 ); + // CW water node flow is the same at inlet and outlet + EXPECT_EQ(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).MassFlowRate); + // CW water outlet node temp is greater than CW inlet node temp + EXPECT_GT( DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).Temp, DataLoopNode::Node( coolingCoilWaterInletNodeIndex ).Temp ); + + // if cooling coil meets cooling set point temperature expect cooling coil water flow to be less than max water flow + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMax); + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, + DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMaxAvail); + + // Case 2 - COOLING mode - sensible and latent load, extra dehumidification required + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax = 0.009; + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint = 20.0; + thisSys->simulate(thisSys->Name, FirstHVACIteration, AirLoopNum, CompIndex, HeatActive, CoolActive, ZoneOAUnitNum, OAUCoilOutTemp, ZoneEquipment); + + // check that CW coil air outlet node is below set point + EXPECT_LT(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).Temp, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint); + // check that CW coil air outlet node humrat is at set point + EXPECT_NEAR(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRat, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax, 0.0001); + // CW air inlet node temp is greater than CW air outlet node temp + EXPECT_GT(DataLoopNode::Node(coolingCoilAirInletNodeIndex).Temp, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).Temp); + // CW water inlet node flow is greater than 0 + EXPECT_GT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, 0.0); + // CW water node flow is the same at inlet and outlet + EXPECT_EQ(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).MassFlowRate); + // CW water outlet node temp is greater than CW inlet node temp + EXPECT_GT(DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).Temp, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).Temp); + + // if cooling coil meets cooling set point temperature expect cooling coil water flow to be less than max water flow + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMax); + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, + DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMaxAvail); + + // Case 3 - COOLING mode - only latent load + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax = 0.009; + DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint = 30.0; + thisSys->simulate(thisSys->Name, FirstHVACIteration, AirLoopNum, CompIndex, HeatActive, CoolActive, ZoneOAUnitNum, OAUCoilOutTemp, ZoneEquipment); + + // check that CW coil air outlet node is below set point + EXPECT_LT(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).Temp, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).TempSetPoint); + // check that CW coil air outlet node humrat is at set point + EXPECT_NEAR(DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRat, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).HumRatMax, 0.0001); + // CW air inlet node temp is greater than CW air outlet node temp + EXPECT_GT(DataLoopNode::Node(coolingCoilAirInletNodeIndex).Temp, DataLoopNode::Node(coolingCoilAirOutletNodeIndex).Temp); + // CW water inlet node flow is greater than 0 + EXPECT_GT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, 0.0); + // CW water node flow is the same at inlet and outlet + EXPECT_EQ(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).MassFlowRate); + // CW water outlet node temp is greater than CW inlet node temp + EXPECT_GT(DataLoopNode::Node(coolingCoilWaterOutletNodeIndex).Temp, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).Temp); + + // if cooling coil meets cooling set point temperature expect cooling coil water flow to be less than max water flow + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMax); + EXPECT_LT(DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRate, + DataLoopNode::Node(coolingCoilWaterInletNodeIndex).MassFlowRateMaxAvail); +} + TEST_F(EnergyPlusFixture, UnitarySystemModel_SetOnOffMassFlowRateTest) { std::string const idf_objects = delimited_string({ From 4471a4e574879f379735ffa59d8def9e173526dc Mon Sep 17 00:00:00 2001 From: mjwitte Date: Tue, 12 Mar 2019 08:37:53 -0500 Subject: [PATCH 12/15] ChW controller - vary offset only if needed for humidity control --- src/EnergyPlus/HVACControllers.cc | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/EnergyPlus/HVACControllers.cc b/src/EnergyPlus/HVACControllers.cc index 5c075a00cff..5ca1ac536b3 100644 --- a/src/EnergyPlus/HVACControllers.cc +++ b/src/EnergyPlus/HVACControllers.cc @@ -413,8 +413,17 @@ namespace HVACControllers { { auto const SELECT_CASE_var(Operation); if (SELECT_CASE_var == iControllerOpColdStart) { - // For temperature and humidity control reset humidity control override - HVACControllers::ControllerProps(ControlNum).HumRatCtrlOverride = false; + // For temperature and humidity control reset humidity control override if it was set + if (HVACControllers::ControllerProps(ControlNum).HumRatCtrlOverride) { + HVACControllers::ControllerProps(ControlNum).HumRatCtrlOverride = false; + // Put the controller tolerance (offset) back to it's original value + RootFinder::SetupRootFinder(RootFinders(ControlNum), + iSlopeDecreasing, + iMethodBrent, + constant_zero, + 1.0e-6, + ControllerProps(ControlNum).Offset); + } // If a iControllerOpColdStart call, reset the actuator inlet flows ResetController(ControlNum, false, IsConvergedFlag); @@ -1398,10 +1407,6 @@ namespace HVACControllers { (0.001 / (2100.0 * max(ControllerProps(ControlNum).MaxVolFlowActuated, SmallWaterVolFlow))) * (HVACEnergyToler / 10.0); // do not let the controller tolerance exceed 1/10 of the loop temperature tolerance. ControllerProps(ControlNum).Offset = min(0.1 * HVACTemperatureToler, ControllerProps(ControlNum).Offset); - if (ControllerProps(ControlNum).ControlVar == HVACControllers::iTemperatureAndHumidityRatio) { - // for temperature and humidity control, need tighter tolerance if humidity control kicks in - ControllerProps(ControlNum).Offset = ControllerProps(ControlNum).Offset*0.1; - } ReportSizingOutput(ControllerProps(ControlNum).ControllerType, ControllerProps(ControlNum).ControllerName, "Controller Convergence Tolerance", @@ -2245,11 +2250,15 @@ namespace HVACControllers { if (thisController.ControlVar == iTemperatureAndHumidityRatio) { // For temperature and humidity control, after temperature control is converged, check if humidity setpoint is met if (!thisController.HumRatCtrlOverride) { - if (Node(thisController.SensedNode).HumRat > (Node(thisController.SensedNode).HumRatMax + thisController.Offset)) { + // For humidity control tolerance, always use 0.0001 which is roughly equivalent to a 0.015C change in dewpoint + if (Node(thisController.SensedNode).HumRat > (Node(thisController.SensedNode).HumRatMax + 1.0e-4)) { // Turn on humdity control and restart controller IsConvergedFlag = false; thisController.HumRatCtrlOverride = true; - // IsUpToDateFlag = false; + if (thisController.Action == iReverseAction) { + // Cooling coil controller should always be ReverseAction, but skip this if not + RootFinder::SetupRootFinder(RootFinders(ControlNum), iSlopeDecreasing, iMethodBrent, constant_zero, 1.0e-6, 1.0e-4); + } // Do a cold start reset, same as iControllerOpColdStart ResetController(ControlNum, false, IsConvergedFlag); } From 7fda469b67538ea3dd2cb5199ad4b80b2658553f Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Mar 2019 11:58:28 -0500 Subject: [PATCH 13/15] UnitarySystem humidity controls - set node conditions in DX calc functions --- src/EnergyPlus/DXCoils.cc | 31 +++++++++++++++++++++++++++++ tst/EnergyPlus/unit/DXCoils.unit.cc | 3 +++ 2 files changed, 34 insertions(+) diff --git a/src/EnergyPlus/DXCoils.cc b/src/EnergyPlus/DXCoils.cc index 33571296474..a60f972aaab 100644 --- a/src/EnergyPlus/DXCoils.cc +++ b/src/EnergyPlus/DXCoils.cc @@ -9523,6 +9523,11 @@ namespace DXCoils { DXCoilFanOpMode(DXCoilNum) = FanOpMode; DXCoil(DXCoilNum).CondInletTemp = CondInletTemp; + // set outlet node conditions + int airOutletNode = DXCoil(DXCoilNum).AirOutNode; + Node(airOutletNode).Temp = DXCoil(DXCoilNum).OutletAirTemp; + Node(airOutletNode).HumRat = DXCoil(DXCoilNum).OutletAirHumRat; + // calc secondary coil if specified if (DXCoil(DXCoilNum).IsSecondaryDXCoilInZone) { CalcSecondaryDXCoils(DXCoilNum); @@ -10181,6 +10186,12 @@ namespace DXCoils { DXCoil(DXCoilNum).CondInletTemp = CondInletTemp; DXCoilTotalCooling(DXCoilNum) = DXCoil(DXCoilNum).TotalCoolingEnergyRate; DXCoilCoolInletAirWBTemp(DXCoilNum) = PsyTwbFnTdbWPb(InletAirDryBulbTemp, InletAirHumRat, OutdoorPressure); + + // set outlet node conditions + int airOutletNode = DXCoil(DXCoilNum).AirOutNode; + Node(airOutletNode).Temp = DXCoil(DXCoilNum).OutletAirTemp; + Node(airOutletNode).HumRat = DXCoil(DXCoilNum).OutletAirHumRat; + } void CalcDXHeatingCoil(int const DXCoilNum, // the number of the DX heating coil to be simulated @@ -10643,6 +10654,11 @@ namespace DXCoils { DXCoilHeatInletAirDBTemp(DXCoilNum) = InletAirDryBulbTemp; DXCoilHeatInletAirWBTemp(DXCoilNum) = InletAirWetBulbC; + // set outlet node conditions + int airOutletNode = DXCoil(DXCoilNum).AirOutNode; + Node(airOutletNode).Temp = DXCoil(DXCoilNum).OutletAirTemp; + Node(airOutletNode).HumRat = DXCoil(DXCoilNum).OutletAirHumRat; + // calc secondary coil if specified if (DXCoil(DXCoilNum).IsSecondaryDXCoilInZone) { CalcSecondaryDXCoils(DXCoilNum); @@ -11148,6 +11164,11 @@ namespace DXCoils { DXCoilOutletHumRat(DXCoilNum) = DXCoil(DXCoilNum).OutletAirHumRat; DXCoil(DXCoilNum).CondInletTemp = CondInletTemp; // Save condenser inlet temp in the data structure + // set outlet node conditions + int airOutletNode = DXCoil(DXCoilNum).AirOutNode; + Node(airOutletNode).Temp = DXCoil(DXCoilNum).OutletAirTemp; + Node(airOutletNode).HumRat = DXCoil(DXCoilNum).OutletAirHumRat; + // calc secondary coil if specified if (DXCoil(DXCoilNum).IsSecondaryDXCoilInZone) { CalcSecondaryDXCoils(DXCoilNum); @@ -12659,6 +12680,11 @@ namespace DXCoils { DXCoilFanOpMode(DXCoilNum) = FanOpMode; DXCoil(DXCoilNum).CondInletTemp = CondInletTemp; // Save condenser inlet temp in the data structure + // set outlet node conditions + int airOutletNode = DXCoil(DXCoilNum).AirOutNode; + Node(airOutletNode).Temp = DXCoil(DXCoilNum).OutletAirTemp; + Node(airOutletNode).HumRat = DXCoil(DXCoilNum).OutletAirHumRat; + // calc secondary coil if specified if (DXCoil(DXCoilNum).IsSecondaryDXCoilInZone) { CalcSecondaryDXCoils(DXCoilNum); @@ -13371,6 +13397,11 @@ namespace DXCoils { DXCoil(DXCoilNum).MSSpeedRatio = SpeedRatio; DXCoil(DXCoilNum).MSCycRatio = CycRatio; + // set outlet node conditions + int airOutletNode = DXCoil(DXCoilNum).AirOutNode; + Node(airOutletNode).Temp = DXCoil(DXCoilNum).OutletAirTemp; + Node(airOutletNode).HumRat = DXCoil(DXCoilNum).OutletAirHumRat; + // calc secondary coil if specified if (DXCoil(DXCoilNum).IsSecondaryDXCoilInZone) { CalcSecondaryDXCoils(DXCoilNum); diff --git a/tst/EnergyPlus/unit/DXCoils.unit.cc b/tst/EnergyPlus/unit/DXCoils.unit.cc index 2cba13f214b..24be5e6175f 100644 --- a/tst/EnergyPlus/unit/DXCoils.unit.cc +++ b/tst/EnergyPlus/unit/DXCoils.unit.cc @@ -252,6 +252,9 @@ TEST_F(EnergyPlusFixture, DXCoils_Test1) DXCoilPartLoadRatio.allocate(1); DXCoilFanOpMode.allocate(1); + DataLoopNode::Node.allocate(1); + DXCoil(CoilIndex).AirOutNode = 1; + Real64 SpeedRatio = 0.0; Real64 CycRatio = 1.0; int SpeedNum = 2; From 7883673754eacf6b9eb4e436fb6ccd1e6db44351 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Mar 2019 12:16:16 -0500 Subject: [PATCH 14/15] UnitarySystem humidity controls - fix unit test --- tst/EnergyPlus/unit/DXCoils.unit.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tst/EnergyPlus/unit/DXCoils.unit.cc b/tst/EnergyPlus/unit/DXCoils.unit.cc index 24be5e6175f..bdc7050ff78 100644 --- a/tst/EnergyPlus/unit/DXCoils.unit.cc +++ b/tst/EnergyPlus/unit/DXCoils.unit.cc @@ -429,6 +429,8 @@ TEST_F(EnergyPlusFixture, TestMultiSpeedDefrostCOP) Coil.DefrostStrategy = Resistive; Coil.Name = "DX Heating coil"; Coil.NumOfSpeeds = 2; + DataLoopNode::Node.allocate(1); + Coil.AirOutNode = 1; Coil.MSRatedTotCap.allocate(Coil.NumOfSpeeds); Coil.MSRatedSHR.allocate(Coil.NumOfSpeeds); From 040fa155a7bf3469d9c8b2200fbaa617572ca9f8 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Mar 2019 12:25:26 -0500 Subject: [PATCH 15/15] UnitarySystem humidity controls - fix another unit test --- tst/EnergyPlus/unit/DXCoils.unit.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tst/EnergyPlus/unit/DXCoils.unit.cc b/tst/EnergyPlus/unit/DXCoils.unit.cc index bdc7050ff78..3af844c4ee3 100644 --- a/tst/EnergyPlus/unit/DXCoils.unit.cc +++ b/tst/EnergyPlus/unit/DXCoils.unit.cc @@ -801,6 +801,8 @@ TEST_F(EnergyPlusFixture, TestSingleSpeedDefrostCOP) Coil.DXCoilType = "Coil:Heating:DX:SingleSpeed"; Coil.DXCoilType_Num = CoilDX_HeatingEmpirical; Coil.SchedPtr = DataGlobals::ScheduleAlwaysOn; + DataLoopNode::Node.allocate(1); + Coil.AirOutNode = 1; Coil.RatedSHR(1) = 1.0; Coil.RatedTotCap(1) = 11012.634487601337;