LCOV - code coverage report
Current view: top level - EnergyPlus - SetPointManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 46.4 % 2249 1043
Test Date: 2025-05-22 16:09:37 Functions: 71.7 % 46 33

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cmath>
      50              : 
      51              : // ObjexxFCL Headers
      52              : #include <ObjexxFCL/Array.functions.hh>
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/CurveManager.hh>
      57              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      58              : #include <EnergyPlus/DataAirLoop.hh>
      59              : #include <EnergyPlus/DataAirSystems.hh>
      60              : #include <EnergyPlus/DataConvergParams.hh>
      61              : #include <EnergyPlus/DataEnvironment.hh>
      62              : #include <EnergyPlus/DataHVACGlobals.hh>
      63              : #include <EnergyPlus/DataHeatBalance.hh>
      64              : #include <EnergyPlus/DataIPShortCuts.hh>
      65              : #include <EnergyPlus/DataLoopNode.hh>
      66              : #include <EnergyPlus/DataPrecisionGlobals.hh>
      67              : #include <EnergyPlus/DataZoneControls.hh>
      68              : #include <EnergyPlus/DataZoneEnergyDemands.hh>
      69              : #include <EnergyPlus/DataZoneEquipment.hh>
      70              : #include <EnergyPlus/EMSManager.hh>
      71              : #include <EnergyPlus/FluidProperties.hh>
      72              : #include <EnergyPlus/General.hh>
      73              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      74              : #include <EnergyPlus/NodeInputManager.hh>
      75              : #include <EnergyPlus/OutAirNodeManager.hh>
      76              : #include <EnergyPlus/OutputProcessor.hh>
      77              : #include <EnergyPlus/Plant/DataPlant.hh>
      78              : #include <EnergyPlus/PlantUtilities.hh>
      79              : #include <EnergyPlus/Psychrometrics.hh>
      80              : #include <EnergyPlus/ScheduleManager.hh>
      81              : #include <EnergyPlus/SetPointManager.hh>
      82              : #include <EnergyPlus/UtilityRoutines.hh>
      83              : 
      84              : namespace EnergyPlus::SetPointManager {
      85              : 
      86              : // Module containing the SetPoint Manager routines
      87              : 
      88              : // MODULE INFORMATION:
      89              : //       AUTHOR         Fred Buhl
      90              : //       DATE WRITTEN   July 1998
      91              : //       MODIFIED       Shirey/Raustad (FSEC), Jan 2004
      92              : //                      Nov 2004 - Jan 2005 M. J. Witte, GARD Analytics, Inc.
      93              : //                        Add new setpoint managers:
      94              : //                          SET POINT MANAGER:SINGLE ZONE HEATING and
      95              : //                          SET POINT MANAGER:SINGLE ZONE COOLING
      96              : //                          SET POINT MANAGER:OUTSIDE AIR PRETREAT
      97              : //                        Work supported by ASHRAE research project 1254-RP
      98              : //                      Phil Haves Oct 2004
      99              : //                      B. Griffith Aug. 2006.
     100              : //                      R. Raustad - FSEC: added AllSetPtMgr used for node conflict checks
     101              : //                      July 2010 B.A. Nigusse, FSEC/UCF
     102              : //                        Added new setpoint managers:
     103              : //                          SetpointManager:MultiZone:Heating:Average
     104              : //                          SetpointManager:MultiZone:Cooling:Average
     105              : //                          SetpointManager:MultiZone:MinimumHumidity:Average
     106              : //                          SetpointManager:MultiZone:MaximumHumidity:Average
     107              : //                       22Aug2010 Craig Wray - added Fan:ComponentModel
     108              : //                      Aug 2010 B.A. Nigusse, FSEC/UCF
     109              : //                        Added new setpoint managers:
     110              : //                          SetpointManager:MultiZone:Humidity:Minimum
     111              : //                          SetpointManager:MultiZone:Humidity:Maximum
     112              : //                      July 2011 Chandan Sharma, FSEC/UCF
     113              : //                        Added new setpoint managers:
     114              : //                          SetpointManager:FollowOutdoorAirTemperature
     115              : //                          SetpointManager:FollowSystemNodeTemperature
     116              : //                          SetpointManager:FollowGroundTemperature
     117              : //                      March 2012, Atefe Makhmalbaf and Heejin Cho, PNNL
     118              : //                        Added new setpoint manager:
     119              : //                          SetpointManager:CondenserEnteringReset
     120              : //                      Jan 2022 Wooyoung Jung, Jeremy Lerond and Jian Zhang, PNNL
     121              : //                        Added new setpoint managers:
     122              : //                          SetpointManager:SystemNodeReset:Temperature
     123              : //                          SetpointManager:SystemNodeReset:Humidity
     124              : 
     125              : // PURPOSE OF THIS MODULE:
     126              : // To encapsulate the data and algorithms required to
     127              : // determine all the controller setpoints in the problem.
     128              : 
     129              : // METHODOLOGY EMPLOYED:
     130              : // Previous time step node data will be used, in a set of fixed, precoded algorithms,
     131              : // to determine the current time step's controller setpoints.
     132              : 
     133              : using namespace DataLoopNode;
     134              : using namespace DataAirLoop;
     135              : using namespace Curve;
     136              : using Psychrometrics::PsyCpAirFnW;
     137              : using Psychrometrics::PsyHFnTdbW;
     138              : 
     139              : constexpr std::array<std::string_view, (int)HVAC::CtrlVarType::Num> ctrlVarTypeNames = {"Temperature",
     140              :                                                                                         "MaximumTemperature",
     141              :                                                                                         "MinimumTemperature",
     142              :                                                                                         "HumidityRatio",
     143              :                                                                                         "MaximumHumidityRatio",
     144              :                                                                                         "MinimumHumidityRatio",
     145              :                                                                                         "MassFlowRate",
     146              :                                                                                         "MaximumMassFlowRate",
     147              :                                                                                         "MinimumMassFlowRate"};
     148              : 
     149              : constexpr std::array<std::string_view, (int)HVAC::CtrlVarType::Num> ctrlVarTypeNamesUC = {"TEMPERATURE",
     150              :                                                                                           "MAXIMUMTEMPERATURE",
     151              :                                                                                           "MINIMUMTEMPERATURE",
     152              :                                                                                           "HUMIDITYRATIO",
     153              :                                                                                           "MAXIMUMHUMIDITYRATIO",
     154              :                                                                                           "MINIMUMHUMIDITYRATIO",
     155              :                                                                                           "MASSFLOWRATE",
     156              :                                                                                           "MAXIMUMMASSFLOWRATE",
     157              :                                                                                           "MINIMUMMASSFLOWRATE"};
     158              : 
     159              : constexpr std::array<std::string_view, (int)ControlStrategy::Num> strategyNamesUC = {
     160              :     "TEMPERATUREFIRST",
     161              :     "FLOWFIRST",
     162              : };
     163              : 
     164              : constexpr std::array<std::string_view, (int)SPMType::Num> spmTypeNames = {"SetpointManager:Scheduled",
     165              :                                                                           "SetpointManager:Scheduled:DualSetpoint",
     166              :                                                                           "SetpointManager:OutdoorAirReset",
     167              :                                                                           "SetpointManager:SingleZone:Reheat",
     168              :                                                                           "SetpointManager:SingleZone:Heating",
     169              :                                                                           "SetpointManager:SingleZone:Cooling",
     170              :                                                                           "SetpointManager:SingleZone:Humidity:Minimum",
     171              :                                                                           "SetpointManager:SingleZone:Humidity:Maximum",
     172              :                                                                           "SetpointManager:MixedAir",
     173              :                                                                           "SetpointManager:OutdoorAirPretreat",
     174              :                                                                           "SetpointManager:Warmest",
     175              :                                                                           "SetpointManager:Coldest",
     176              :                                                                           "SetpointManager:WarmestTemperatureFlow",
     177              :                                                                           "SetpointManager:ReturnAirBypassFlow",
     178              :                                                                           "SetpointManager:MultiZone:Cooling:Average",
     179              :                                                                           "SetpointManager:MultiZone:Heating:Average",
     180              :                                                                           "SetpointManager:MultiZone:MinimumHumidity:Average",
     181              :                                                                           "SetpointManager:MultiZone:MaximumHumidity:Average",
     182              :                                                                           "SetpointManager:MultiZone:Humidity:Minimum",
     183              :                                                                           "SetpointManager:MultiZone:Humidity:Maximum",
     184              :                                                                           "SetpointManager:FollowOutdoorAirTemperature",
     185              :                                                                           "SetpointManager:FollowSystemNodeTemperature",
     186              :                                                                           "SetpointManager:FollowGroundTemperature",
     187              :                                                                           "SetpointManager:CondenserEnteringReset",
     188              :                                                                           "SetpointManager:CondenserEnteringReset:Ideal",
     189              :                                                                           "SetpointManager:SingleZone:OneStageCooling",
     190              :                                                                           "SetpointManager:SingleZone:OneStageHeating",
     191              :                                                                           "SetpointManager:ReturnTemperature:ChilledWater",
     192              :                                                                           "SetpointManager:ReturnTemperature:HotWater",
     193              :                                                                           "SetpointManager:ScheduledTES",
     194              :                                                                           "SetpointManager:SystemNodeReset:Temperature",
     195              :                                                                           "SetpointManager:SystemNodeReset:Humidity"};
     196              : 
     197              : constexpr std::array<DataLoopNode::ConnectionObjectType, (int)SPMType::Num> spmNodeObjectTypes = {
     198              :     DataLoopNode::ConnectionObjectType::SetpointManagerScheduled,
     199              :     DataLoopNode::ConnectionObjectType::SetpointManagerScheduledDualSetpoint,
     200              :     DataLoopNode::ConnectionObjectType::SetpointManagerOutdoorAirReset,
     201              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneReheat,
     202              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneHeating,
     203              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneCooling,
     204              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneHumidityMinimum,
     205              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneHumidityMaximum,
     206              :     DataLoopNode::ConnectionObjectType::SetpointManagerMixedAir,
     207              :     DataLoopNode::ConnectionObjectType::SetpointManagerOutdoorAirPretreat,
     208              :     DataLoopNode::ConnectionObjectType::SetpointManagerWarmest,
     209              :     DataLoopNode::ConnectionObjectType::SetpointManagerColdest,
     210              :     DataLoopNode::ConnectionObjectType::SetpointManagerWarmestTemperatureFlow,
     211              :     DataLoopNode::ConnectionObjectType::Invalid, // SPMType::ReturnAirBypass
     212              :     DataLoopNode::ConnectionObjectType::SetpointManagerMultiZoneCoolingAverage,
     213              :     DataLoopNode::ConnectionObjectType::SetpointManagerMultiZoneHeatingAverage,
     214              :     DataLoopNode::ConnectionObjectType::SetpointManagerMultiZoneMinimumHumidityAverage,
     215              :     DataLoopNode::ConnectionObjectType::SetpointManagerMultiZoneMaximumHumidityAverage,
     216              :     DataLoopNode::ConnectionObjectType::SetpointManagerMultiZoneHumidityMinimum,
     217              :     DataLoopNode::ConnectionObjectType::SetpointManagerMultiZoneHumidityMaximum,
     218              :     DataLoopNode::ConnectionObjectType::SetpointManagerFollowOutdoorAirTemperature,
     219              :     DataLoopNode::ConnectionObjectType::SetpointManagerFollowSystemNodeTemperature,
     220              :     DataLoopNode::ConnectionObjectType::SetpointManagerFollowGroundTemperature,
     221              :     DataLoopNode::ConnectionObjectType::SetpointManagerCondenserEnteringReset,
     222              :     DataLoopNode::ConnectionObjectType::SetpointManagerCondenserEnteringResetIdeal,
     223              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneOneStageCooling,
     224              :     DataLoopNode::ConnectionObjectType::SetpointManagerSingleZoneOneStageHeating,
     225              :     DataLoopNode::ConnectionObjectType::SetpointManagerReturnTemperatureChilledWater,
     226              :     DataLoopNode::ConnectionObjectType::SetpointManagerReturnTemperatureHotWater,
     227              :     DataLoopNode::ConnectionObjectType::Invalid, // SPMType::TESScheduled
     228              :     DataLoopNode::ConnectionObjectType::SetpointManagerSystemNodeResetTemperature,
     229              :     DataLoopNode::ConnectionObjectType::SetpointManagerSystemNodeResetHumidity};
     230              : 
     231              : constexpr std::array<std::string_view, (int)SupplyFlowTempStrategy::Num> supplyFlowTempStrategyNamesUC = {"MAXIMUMTEMPERATURE", "MINIMUMTEMPERATURE"};
     232              : 
     233              : // Why?
     234              : constexpr std::array<std::string_view, (int)AirTempType::Num> oaTempTypeNamesUC = {"OUTDOORAIRWETBULB", "OUTDOORAIRDRYBULB"};
     235              : 
     236              : // No really, why?
     237              : constexpr std::array<std::string_view, (int)AirTempType::Num> nodeTempTypeNamesUC = {"NODEWETBULB", "NODEDRYBULB"};
     238              : 
     239              : constexpr std::array<std::string_view, (int)DataEnvironment::GroundTempType::Num> groundTempObjectTypeNamesUC = {
     240              :     "SITE:GROUNDTEMPERATURE:BUILDINGSURFACE",
     241              :     "SITE:GROUNDTEMPERATURE:SHALLOW",
     242              :     "SITE:GROUNDTEMPERATURE:DEEP",
     243              :     "SITE:GROUNDTEMPERATURE:FCFACTORMETHOD"};
     244              : 
     245              : constexpr std::array<std::string_view, (int)ReturnTempType::Num> returnTempTypeNamesUC = {"SCHEDULED", "CONSTANT", "RETURNTEMPERATURESETPOINT"};
     246              : 
     247       208574 : void ManageSetPoints(EnergyPlusData &state)
     248              : {
     249              :     // SUBROUTINE INFORMATION:
     250              :     //       AUTHOR         Russ Taylor, Rick Strand
     251              :     //       DATE WRITTEN   May 1998
     252              :     //       MODIFIED       Fred Buhl May 2000
     253              : 
     254              :     // PURPOSE OF THIS SUBROUTINE:
     255              : 
     256              :     // METHODOLOGY EMPLOYED:
     257              :     // Each flag is checked and the appropriate manager is then called.
     258              : 
     259              :     // First time ManageSetPoints is called, get the input for all the setpoint managers
     260       208574 :     if (state.dataSetPointManager->GetInputFlag) {
     261          102 :         GetSetPointManagerInputs(state);
     262          102 :         state.dataSetPointManager->GetInputFlag = false;
     263              :     }
     264              : 
     265       208574 :     InitSetPointManagers(state);
     266              : 
     267       208574 :     if (state.dataSetPointManager->ManagerOn) {
     268       208082 :         SimSetPointManagers(state);
     269       208082 :         UpdateSetPointManagers(state);
     270              :         // The Mixed Air Setpoint Managers (since they depend on other setpoints, they must be calculated
     271              :         // and updated next to last).
     272       340388 :         for (auto *spm : state.dataSetPointManager->spms) {
     273       132306 :             if (spm->type == SPMType::MixedAir) spm->calculate(state);
     274              :         }
     275       208082 :         UpdateMixedAirSetPoints(state);
     276              :         // The Outside Air Pretreat Setpoint Managers (since they depend on other setpoints, they must be calculated
     277              :         // and updated last).
     278       340388 :         for (auto *spm : state.dataSetPointManager->spms) {
     279       132306 :             if (spm->type == SPMType::OutsideAirPretreat) spm->calculate(state);
     280              :         }
     281              : 
     282       208082 :         UpdateOAPretreatSetPoints(state);
     283              :     }
     284       208574 : } // ManageSetPoints()
     285              : 
     286           12 : int GetSetPointManagerIndex(EnergyPlusData const &state, std::string const &Name)
     287              : {
     288           12 :     auto found = state.dataSetPointManager->spmMap.find(Name);
     289           12 :     return (found != state.dataSetPointManager->spmMap.end()) ? found->second : 0;
     290              : } // GetSetPointManagerIndex()
     291              : 
     292          248 : void GetSetPointManagerInputs(EnergyPlusData &state)
     293              : {
     294              :     // wrapper for GetInput to allow unit testing when fatal inputs are detected
     295          248 :     constexpr std::string_view routineName = "GetSetPointManagerInputs"; // include trailing blank space
     296              : 
     297          248 :     if (state.dataSetPointManager->GetInputFlag) {
     298          247 :         bool ErrorsFound(false);
     299          247 :         GetSetPointManagerInputData(state, ErrorsFound);
     300              : 
     301          247 :         if (ErrorsFound) {
     302            0 :             ShowFatalError(state, format("{}: Errors found in input.  Program terminates.", routineName));
     303              :         }
     304          247 :         state.dataSetPointManager->GetInputFlag = false;
     305              :     }
     306          248 : } // GetSetPointManagerInputs()
     307              : 
     308          248 : void GetSetPointManagerInputData(EnergyPlusData &state, bool &ErrorsFound)
     309              : {
     310              : 
     311              :     // SUBROUTINE INFORMATION:
     312              :     //       AUTHOR         Fred Buhl
     313              :     //       DATE WRITTEN   July 1998
     314              :     //       MODIFIED       Shirey/Raustad (FSEC), Jan 2004
     315              :     //                      Nov 2004 - Jan 2005 M. J. Witte, GARD Analytics, Inc.
     316              :     //                        Add new setpoint managers:
     317              :     //                          SET POINT MANAGER:SINGLE ZONE HEATING and
     318              :     //                          SET POINT MANAGER:SINGLE ZONE COOLING
     319              :     //                          SET POINT MANAGER:OUTSIDE AIR PRETREAT
     320              :     //                        Work supported by ASHRAE research project 1254-RP
     321              :     //                      Haves October 2004
     322              :     //                      Witte (GARD), Sep 2006
     323              :     //                      July 2010 B.A. Nigusse, FSEC/UCF
     324              :     //                        Added new setpoint managers:
     325              :     //                          SetpointManager:MultiZone:Heating:Average
     326              :     //                          SetpointManager:MultiZone:Cooling:Average
     327              :     //                          SetpointManager:MultiZone:MinimumHumidity:Average
     328              :     //                          SetpointManager:MultiZone:MaximumHumidity:Average
     329              :     //                      Aug 2010 B.A. Nigusse, FSEC/UCF
     330              :     //                        Added new setpoint managers:
     331              :     //                          SetpointManager:MultiZone:Humidity:Minimum
     332              :     //                          SetpointManager:MultiZone:Humidity:Maximum
     333              :     //                      Jan 2022 Wooyoung Jung, Jeremy Lerond, and Jian Zhang, PNNL
     334              :     //                        Added new setpoint managers:
     335              :     //                          SetpointManager:SystemNodeReset:Temperature
     336              :     //                          SetpointManager:SystemNodeReset:Humidity
     337              : 
     338              :     // PURPOSE OF THIS SUBROUTINE
     339              :     // Input the SetPointManager data and store it in the SetPtMgrIn array.
     340              :     // Examine the Controllers in the input data and determine which ones
     341              :     // will have their setpoints set by a particular Setpoint Manager.
     342              : 
     343              :     // METHODOLOGY EMPLOYED:
     344              :     // Use the Get routines from the InputProcessor module.
     345              : 
     346              :     // Using/Aliasing
     347              :     using DataZoneEquipment::GetSystemNodeNumberForZone;
     348              :     using General::FindNumberInList;
     349              : 
     350              :     using NodeInputManager::GetNodeNums;
     351              :     using NodeInputManager::GetOnlySingleNode;
     352              :     // Locals
     353              :     // SUBROUTINE PARAMETER DEFINITIONS:
     354              :     static constexpr std::string_view routineName = "GetSetPointManagerInputs";
     355              : 
     356          248 :     std::string cCurrentModuleObject;
     357              : 
     358              :     int NumNodes;
     359          248 :     Array1D_int NodeNums;
     360          248 :     bool NodeListError(false);
     361              :     bool ErrInList;
     362              : 
     363          248 :     auto &ip = state.dataInputProcessing->inputProcessor;
     364              : 
     365          248 :     int NumNums = 0;
     366          248 :     int NumAlphas = 0;
     367          248 :     int NumParams = 0;
     368              : 
     369          248 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
     370          248 :     NodeNums.dimension(NumParams, 0);
     371              : 
     372              :     // Input the data for each Setpoint Manager
     373              : 
     374         8184 :     for (int iSPM = 0; iSPM < (int)SPMType::Num; ++iSPM) {
     375         7936 :         SPMType type = static_cast<SPMType>(iSPM);
     376         7936 :         cCurrentModuleObject = spmTypeNames[iSPM];
     377              : 
     378         7936 :         auto const instances = ip->epJSON.find(cCurrentModuleObject);
     379         7936 :         if (instances == ip->epJSON.end()) continue; // No SetPointManagers of this type
     380              : 
     381          159 :         auto const &props = ip->getObjectSchemaProps(state, cCurrentModuleObject);
     382              : 
     383              : #define PRESERVE_IDF_ORDER
     384              : #ifdef PRESERVE_IDF_ORDER
     385              : 
     386              :         // Try to read these in IDF order (for now, can revert to simpler begin(), ++, end() iterator later)
     387              : 
     388              :         // Begin by grabbing the keys and IDF numbers of the objects.
     389              :         // Have to grab the keys because once you are no longer
     390              :         // dealing with the map iterator, you lose access to the key,
     391              :         // which you also need because it is the object name.
     392              : 
     393          159 :         std::vector<int> idfNums;
     394          159 :         std::vector<std::string> idfKeys;
     395          159 :         int idfFakeNum = 0;
     396          380 :         for (auto instance = instances.value().begin(); instance != instances.value().end(); ++instance) {
     397              :             // If the input comes from epJson then there are no idf_order fields.
     398          221 :             if (state.dataGlobal->isEpJSON || !state.dataGlobal->preserveIDFOrder) {
     399            0 :                 idfNums.push_back(++idfFakeNum);
     400              :             } else {
     401          663 :                 idfNums.push_back(instance.value().at("idf_order").get<int>());
     402              :             }
     403          221 :             idfKeys.push_back(instance.key());
     404              :         }
     405              : 
     406              :         // Now sort the IDF numbers
     407          159 :         std::vector<int> idfSortedNums = idfNums;
     408          159 :         std::sort(idfSortedNums.begin(), idfSortedNums.end());
     409              : 
     410              :         // Iterate through the sorted IDF numbers
     411          380 :         for (int idfSortedNum : idfSortedNums) {
     412              :             // Find that number's position in the epJSON order
     413          221 :             int epJsonNum = std::find(idfNums.begin(), idfNums.end(), idfSortedNum) - idfNums.begin();
     414              :             // Grab the corresponding name
     415          221 :             std::string const &key = idfKeys[epJsonNum];
     416          221 :             auto const &fields = instances.value().at(key);
     417              : 
     418              : #else // !PRESERVE_IDF_ORDER
     419              : 
     420              :         // epJson order
     421              :         for (auto instance = instances.value().begin(); instance != instances.value().end(); ++instance) {
     422              :             std::string const &key = instance.key();
     423              :             auto const &fields = instance.value();
     424              : 
     425              : #endif // PRESERVE_IDF_ORDER
     426              : 
     427          221 :             ip->markObjectAsUsed(cCurrentModuleObject, key);
     428          221 :             std::string name = Util::makeUPPER(key);
     429              : 
     430          221 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, name};
     431              : 
     432          221 :             if (state.dataSetPointManager->spmMap.find(name) != state.dataSetPointManager->spmMap.end()) {
     433            0 :                 ShowSevereDuplicateName(state, eoh);
     434            0 :                 ErrorsFound = true;
     435              :             }
     436              : 
     437          221 :             SPMBase *spm = nullptr;
     438              : 
     439              :             // Create a SetPointManagerObject of the right child type
     440          221 :             switch (type) {
     441          103 :             case SPMType::Scheduled: {
     442          103 :                 spm = new SPMScheduled;
     443          103 :             } break;
     444           12 :             case SPMType::ScheduledDual: {
     445           12 :                 spm = new SPMScheduledDual;
     446           12 :             } break;
     447           12 :             case SPMType::OutsideAir: {
     448           12 :                 spm = new SPMOutsideAir;
     449           12 :             } break;
     450            6 :             case SPMType::SZReheat: {
     451            6 :                 spm = new SPMSingleZoneReheat;
     452            6 :             } break;
     453           11 :             case SPMType::SZHeating:
     454              :             case SPMType::SZCooling: {
     455           11 :                 spm = new SPMSingleZoneTemp;
     456           11 :             } break;
     457            4 :             case SPMType::SZMinHum:
     458              :             case SPMType::SZMaxHum: {
     459            4 :                 spm = new SPMSingleZoneHum;
     460            4 :             } break;
     461           58 :             case SPMType::MixedAir: {
     462           58 :                 spm = new SPMMixedAir;
     463           58 :             } break;
     464            1 :             case SPMType::OutsideAirPretreat: {
     465            1 :                 spm = new SPMOutsideAirPretreat;
     466            1 :             } break;
     467            6 :             case SPMType::Warmest:
     468              :             case SPMType::Coldest: {
     469            6 :                 spm = new SPMTempest;
     470            6 :             } break;
     471            0 :             case SPMType::WarmestTempFlow: {
     472            0 :                 spm = new SPMWarmestTempFlow;
     473            0 :             } break;
     474            0 :             case SPMType::MZCoolingAverage:
     475              :             case SPMType::MZHeatingAverage: {
     476            0 :                 spm = new SPMMultiZoneTemp;
     477            0 :             } break;
     478            0 :             case SPMType::MZMinHumAverage:
     479              :             case SPMType::MZMaxHumAverage:
     480              :             case SPMType::MZMinHum:
     481              :             case SPMType::MZMaxHum: {
     482            0 :                 spm = new SPMMultiZoneHum;
     483            0 :             } break;
     484            0 :             case SPMType::ReturnAirBypass: {
     485            0 :                 spm = new SPMReturnAirBypassFlow;
     486            0 :             } break;
     487            3 :             case SPMType::FollowOutsideAirTemp: {
     488            3 :                 spm = new SPMFollowOutsideAirTemp;
     489            3 :             } break;
     490            0 :             case SPMType::FollowSystemNodeTemp: {
     491            0 :                 spm = new SPMFollowSysNodeTemp;
     492            0 :             } break;
     493            3 :             case SPMType::FollowGroundTemp: {
     494            3 :                 spm = new SPMFollowGroundTemp;
     495            3 :             } break;
     496            0 :             case SPMType::CondenserEnteringTemp: {
     497            0 :                 spm = new SPMCondenserEnteringTemp;
     498            0 :             } break;
     499            0 :             case SPMType::IdealCondenserEnteringTemp: {
     500            0 :                 spm = new SPMIdealCondenserEnteringTemp;
     501            0 :             } break;
     502            0 :             case SPMType::SZOneStageCooling: {
     503            0 :                 spm = new SPMSingleZoneOneStageCooling;
     504            0 :             } break;
     505            0 :             case SPMType::SZOneStageHeating: {
     506            0 :                 spm = new SPMSingleZoneOneStageHeating;
     507            0 :             } break;
     508            0 :             case SPMType::ChilledWaterReturnTemp:
     509              :             case SPMType::HotWaterReturnTemp: {
     510            0 :                 spm = new SPMReturnWaterTemp;
     511            0 :             } break;
     512            0 :             case SPMType::TESScheduled: {
     513            0 :                 spm = new SPMTESScheduled;
     514            0 :             } break;
     515            2 :             case SPMType::SystemNodeTemp:
     516              :             case SPMType::SystemNodeHum: {
     517            2 :                 spm = new SPMSystemNode;
     518            2 :             } break;
     519            0 :             default: {
     520            0 :                 assert(false);
     521              :             } break;
     522              :             } // switch (type)
     523              : 
     524              :             // Set name and append to array
     525          221 :             spm->Name = name;
     526          221 :             spm->type = type;
     527          221 :             state.dataSetPointManager->spms.push_back(spm);
     528          221 :             state.dataSetPointManager->spmMap.insert_or_assign(spm->Name, state.dataSetPointManager->spms.size());
     529              : 
     530              :             // control variable type
     531          442 :             std::string ctrlVarName;
     532          221 :             switch (spm->type) {
     533            0 :             case SPMType::SZMinHum: {
     534            0 :                 spm->ctrlVar = HVAC::CtrlVarType::MinHumRat;
     535            0 :             } break;
     536            4 :             case SPMType::SZMaxHum: {
     537            4 :                 spm->ctrlVar = HVAC::CtrlVarType::MaxHumRat;
     538            4 :             } break;
     539            0 :             case SPMType::MZHeatingAverage:
     540              :             case SPMType::MZCoolingAverage: {
     541            0 :                 spm->ctrlVar = HVAC::CtrlVarType::Temp;
     542            0 :             } break;
     543            0 :             case SPMType::MZMinHumAverage:
     544              :             case SPMType::MZMinHum: {
     545            0 :                 spm->ctrlVar = HVAC::CtrlVarType::MinHumRat;
     546            0 :             } break;
     547            0 :             case SPMType::MZMaxHumAverage:
     548              :             case SPMType::MZMaxHum: {
     549            0 :                 spm->ctrlVar = HVAC::CtrlVarType::MaxHumRat;
     550            0 :             } break;
     551            0 :             case SPMType::SZOneStageCooling:
     552              :             case SPMType::SZOneStageHeating: {
     553            0 :                 spm->ctrlVar = HVAC::CtrlVarType::Temp;
     554            0 :             } break;
     555            0 :             case SPMType::ChilledWaterReturnTemp:
     556              :             case SPMType::HotWaterReturnTemp: {
     557            0 :                 spm->ctrlVar = HVAC::CtrlVarType::Temp;
     558            0 :             } break;
     559            0 :             case SPMType::ReturnAirBypass: {
     560            0 :                 spm->ctrlVar = HVAC::CtrlVarType::MassFlowRate;
     561            0 :             } break;
     562              : 
     563          217 :             default: {
     564          434 :                 ctrlVarName = ip->getAlphaFieldValue(fields, props, "control_variable");
     565          217 :                 spm->ctrlVar = static_cast<HVAC::CtrlVarType>(getEnumValue(ctrlVarTypeNamesUC, ctrlVarName));
     566          217 :             } break;
     567              :             } // switch (spm->type)
     568              : 
     569              :             // Load Min and Max Temp setpoints for some SPMs
     570          221 :             switch (spm->type) {
     571           13 :             case SPMType::OutsideAirPretreat:
     572              :             case SPMType::Warmest:
     573              :             case SPMType::Coldest:
     574              :             case SPMType::WarmestTempFlow:
     575              :             case SPMType::MZCoolingAverage:
     576              :             case SPMType::MZHeatingAverage:
     577              :             case SPMType::FollowOutsideAirTemp:
     578              :             case SPMType::FollowGroundTemp: {
     579           26 :                 spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_setpoint_temperature");
     580           26 :                 spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_setpoint_temperature");
     581           13 :                 if (spm->maxSetTemp < spm->minSetTemp) {
     582            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name));
     583            0 :                     ShowContinueError(state,
     584            0 :                                       format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].",
     585            0 :                                              spm->maxSetTemp,
     586            0 :                                              spm->minSetTemp));
     587              :                 }
     588           13 :             } break;
     589              : 
     590           17 :             case SPMType::SZReheat:
     591              :             case SPMType::SZHeating:
     592              :             case SPMType::SZCooling: {
     593           34 :                 spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_supply_air_temperature");
     594           34 :                 spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_supply_air_temperature");
     595           17 :                 if (spm->maxSetTemp < spm->minSetTemp) {
     596            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name));
     597            0 :                     ShowContinueError(state,
     598            0 :                                       format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].",
     599            0 :                                              spm->maxSetTemp,
     600            0 :                                              spm->minSetTemp));
     601              :                 }
     602           17 :             } break;
     603              : 
     604            0 :             case SPMType::FollowSystemNodeTemp: {
     605            0 :                 spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_limit_setpoint_temperature");
     606            0 :                 spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_limit_setpoint_temperature");
     607            0 :                 if (spm->maxSetTemp < spm->minSetTemp) {
     608            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name));
     609            0 :                     ShowContinueError(state,
     610            0 :                                       format("...maximum_supply_air_temperature=[{:.1R}] is less than minimum_supply_air_temperature=[{:.1R}].",
     611            0 :                                              spm->maxSetTemp,
     612            0 :                                              spm->minSetTemp));
     613              :                 }
     614            0 :             } break;
     615              : 
     616          191 :             default:
     617          191 :                 break;
     618              :             } // switch (spm->type)
     619              : 
     620              :             // Read Min and Max HumRat for some SPMs
     621          221 :             switch (spm->type) {
     622              : 
     623            1 :             case SPMType::OutsideAirPretreat:
     624              :             case SPMType::MZMinHumAverage:
     625              :             case SPMType::MZMaxHumAverage:
     626              :             case SPMType::MZMinHum:
     627              :             case SPMType::MZMaxHum: {
     628            2 :                 spm->minSetHum = ip->getRealFieldValue(fields, props, "minimum_setpoint_humidity_ratio");
     629            2 :                 spm->maxSetHum = ip->getRealFieldValue(fields, props, "maximum_setpoint_humidity_ratio");
     630            1 :                 if (spm->maxSetHum < spm->minSetHum) {
     631            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spm->Name));
     632            0 :                     ShowContinueError(state,
     633            0 :                                       format("...maximum_setpoint_humidity_ratio=[{:.1R}] is less than minimum_setpoint_humidity_ratio=[{:.1R}].",
     634            0 :                                              spm->maxSetHum,
     635            0 :                                              spm->minSetHum));
     636              :                 }
     637              : 
     638              :                 // Because a zero humidity ratio setpoint is a special value indicating "off" or "no load"
     639              :                 // must not allow MinSetHumRat or MaxSetHumRat to be <=0.0
     640            1 :                 if (spm->minSetHum <= 0.0) {
     641            0 :                     ShowWarningError(state, format("{}: {}=\"{}\", invalid value.", routineName, cCurrentModuleObject, spm->Name));
     642            0 :                     ShowContinueError(state, "Minimum setpoint humidity ratio <=0.0, resetting to 0.00001");
     643            0 :                     spm->minSetHum = 0.00001;
     644              :                 }
     645            1 :                 if (spm->maxSetHum <= 0.0) {
     646            0 :                     ShowWarningError(state, format("{}: {}=\"{}\", invalid value.", routineName, cCurrentModuleObject, spm->Name));
     647            0 :                     ShowContinueError(state, "Maximum setpoint humidity ratio <=0.0, resetting to 0.00001");
     648            0 :                     spm->maxSetHum = 0.00001;
     649              :                 }
     650              : 
     651            1 :             } break;
     652          220 :             default:
     653          220 :                 break;
     654              :             } // switch (spm->type)
     655              : 
     656              :             // Read HVAC Air Loop name
     657          221 :             switch (spm->type) {
     658            6 :             case SPMType::Warmest:
     659              :             case SPMType::Coldest:
     660              :             case SPMType::WarmestTempFlow:
     661              :             case SPMType::ReturnAirBypass:
     662              :             case SPMType::MZCoolingAverage:
     663              :             case SPMType::MZHeatingAverage:
     664              :             case SPMType::MZMinHumAverage:
     665              :             case SPMType::MZMaxHumAverage:
     666              :             case SPMType::MZMinHum:
     667              :             case SPMType::MZMaxHum: {
     668           12 :                 spm->airLoopName = ip->getAlphaFieldValue(fields, props, "hvac_air_loop_name");
     669            6 :                 spm->airLoopNum = 0;
     670            6 :             } break;
     671              : 
     672          215 :             default:
     673          215 :                 break;
     674              :             } // switch (spm->type)
     675              : 
     676              :             // Read SPM-specific fields
     677          221 :             switch (spm->type) {
     678              : 
     679              :             // SetpointManager:Scheduled
     680          103 :             case SPMType::Scheduled: {
     681          103 :                 auto *spmS = dynamic_cast<SPMScheduled *>(spm);
     682          103 :                 assert(spmS != nullptr);
     683              : 
     684          206 :                 std::string schedName = ip->getAlphaFieldValue(fields, props, "schedule_name");
     685          103 :                 if ((spmS->sched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
     686            0 :                     ShowSevereItemNotFound(state, eoh, "schedule_name", schedName);
     687            0 :                     ErrorsFound = true;
     688              :                 }
     689          103 :                 spmS->setPt = 0.0;
     690          103 :             } break;
     691              : 
     692              :             // SetpointManager:Scheduled:DualSetpoint
     693           12 :             case SPMType::ScheduledDual: {
     694           12 :                 auto *spmSD = dynamic_cast<SPMScheduledDual *>(spm);
     695           12 :                 assert(spmSD != nullptr);
     696              : 
     697           12 :                 if (spmSD->ctrlVar != HVAC::CtrlVarType::Temp) {
     698            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     699            0 :                     ErrorsFound = true;
     700              :                 }
     701              : 
     702           24 :                 std::string schedHiName = ip->getAlphaFieldValue(fields, props, "high_setpoint_schedule_name");
     703           12 :                 if ((spmSD->hiSched = Sched::GetSchedule(state, Util::makeUPPER(schedHiName))) == nullptr) {
     704            0 :                     ShowSevereItemNotFound(state, eoh, "high_setpoint_schedule_name", schedHiName);
     705            0 :                     ErrorsFound = true;
     706              :                 }
     707              : 
     708           24 :                 std::string schedLoName = ip->getAlphaFieldValue(fields, props, "low_setpoint_schedule_name");
     709           12 :                 if ((spmSD->loSched = Sched::GetSchedule(state, Util::makeUPPER(schedLoName))) == nullptr) {
     710            0 :                     ShowSevereItemNotFound(state, eoh, "low_setpoint_schedule_name", schedLoName);
     711            0 :                     ErrorsFound = true;
     712              :                 }
     713           12 :                 spmSD->setPtHi = 0.0;
     714           12 :                 spmSD->setPtLo = 0.0;
     715              : 
     716           12 :             } break;
     717              : 
     718              :             // SetpointManager:OutdoorAirReset
     719           12 :             case SPMType::OutsideAir: {
     720           12 :                 auto *spmOA = dynamic_cast<SPMOutsideAir *>(spm);
     721           12 :                 assert(spmOA != nullptr);
     722           12 :                 if (spmOA->ctrlVar != HVAC::CtrlVarType::Temp && spmOA->ctrlVar != HVAC::CtrlVarType::MaxTemp &&
     723            4 :                     spmOA->ctrlVar != HVAC::CtrlVarType::MinTemp) {
     724            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     725            0 :                     ErrorsFound = true;
     726              :                 }
     727              : 
     728           24 :                 spmOA->lowSetPt1 = ip->getRealFieldValue(fields, props, "setpoint_at_outdoor_low_temperature");
     729           24 :                 spmOA->low1 = ip->getRealFieldValue(fields, props, "outdoor_low_temperature");
     730           24 :                 spmOA->highSetPt1 = ip->getRealFieldValue(fields, props, "setpoint_at_outdoor_high_temperature");
     731           36 :                 spmOA->high1 = ip->getRealFieldValue(fields, props, "outdoor_high_temperature");
     732              : 
     733              :                 // Get optional input: schedule and 2nd reset rule
     734           24 :                 if (auto foundSched = fields.find("schedule_name"); foundSched != fields.end()) {
     735            3 :                     std::string schedName = Util::makeUPPER(foundSched.value().get<std::string>());
     736            3 :                     if ((spmOA->sched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
     737            0 :                         ShowSevereItemNotFound(state, eoh, "schedule_name", schedName);
     738            0 :                         ErrorsFound = true;
     739            3 :                     } else if (!spmOA->sched->checkMinMaxVals(state, Clusive::In, 1.0, Clusive::In, 2.0)) {
     740            0 :                         Sched::ShowSevereBadMinMax(state, eoh, "schedule_name", schedName, Clusive::In, 1.0, Clusive::In, 2.0);
     741            0 :                         ErrorsFound = true;
     742              :                     }
     743              : 
     744            6 :                     if (auto found = fields.find("setpoint_at_outdoor_low_temperature_2"); found != fields.end())
     745            3 :                         spmOA->lowSetPt2 = found.value().get<Real64>();
     746            6 :                     if (auto found = fields.find("outdoor_low_temperature_2"); found != fields.end()) spmOA->low2 = found.value().get<Real64>();
     747            6 :                     if (auto found = fields.find("setpoint_at_outdoor_high_temperature_2"); found != fields.end())
     748            3 :                         spmOA->highSetPt2 = found.value().get<Real64>();
     749            6 :                     if (auto found = fields.find("outdoor_high_temperature_2"); found != fields.end()) spmOA->high2 = found.value().get<Real64>();
     750            3 :                     if (spmOA->high2 < spmOA->low2) {
     751            0 :                         ShowWarningCustom(state,
     752              :                                           eoh,
     753            0 :                                           format("...{}=[{:.1R}] is less than {}=[{:.1R}].",
     754              :                                                  "outdoor_high_temperature_2",
     755            0 :                                                  spmOA->high2,
     756              :                                                  "outdoor_low_temperature_2",
     757            0 :                                                  spmOA->low2));
     758              :                     }
     759            3 :                 } else { // !foundSched
     760            9 :                     spmOA->sched = nullptr;
     761            9 :                     spmOA->lowSetPt2 = 0.0;
     762            9 :                     spmOA->low2 = 0.0;
     763            9 :                     spmOA->highSetPt2 = 0.0;
     764            9 :                     spmOA->high2 = 0.0;
     765              :                 }
     766           12 :             } break;
     767              : 
     768              :             //  SetpointManager:SingleZone:Reheat
     769            6 :             case SPMType::SZReheat: {
     770            6 :                 auto *spmSZR = dynamic_cast<SPMSingleZoneReheat *>(spm);
     771            6 :                 assert(spmSZR != nullptr);
     772              : 
     773            6 :                 if (spmSZR->ctrlVar != HVAC::CtrlVarType::Temp) {
     774            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     775            0 :                     ErrorsFound = true;
     776              :                 }
     777              : 
     778           12 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
     779              :                 // get the actual zone number of the control zone
     780            6 :                 spmSZR->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
     781            6 :                 if (spmSZR->ctrlZoneNum == 0) {
     782            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
     783            0 :                     ErrorsFound = true;
     784              :                 }
     785            6 :                 spmSZR->setPt = 0.0;
     786              : 
     787           12 :                 spmSZR->zoneNodeNum = GetOnlySingleNode(state,
     788           18 :                                                         ip->getAlphaFieldValue(fields, props, "zone_node_name"),
     789              :                                                         ErrorsFound,
     790            6 :                                                         spmNodeObjectTypes[(int)spm->type],
     791            6 :                                                         spmSZR->Name,
     792              :                                                         DataLoopNode::NodeFluidType::Air,
     793              :                                                         DataLoopNode::ConnectionType::Sensor,
     794              :                                                         NodeInputManager::CompFluidStream::Primary,
     795              :                                                         ObjectIsNotParent);
     796           12 :                 spmSZR->zoneInletNodeNum = GetOnlySingleNode(state,
     797           18 :                                                              ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"),
     798              :                                                              ErrorsFound,
     799            6 :                                                              spmNodeObjectTypes[(int)spm->type],
     800            6 :                                                              spmSZR->Name,
     801              :                                                              DataLoopNode::NodeFluidType::Air,
     802              :                                                              DataLoopNode::ConnectionType::Sensor,
     803              :                                                              NodeInputManager::CompFluidStream::Primary,
     804              :                                                              ObjectIsNotParent);
     805            6 :             } break;
     806              : 
     807              :             // SetpointManager:SingleZone:Heating
     808              :             // SetpointManager:SingleZone:Cooling
     809           11 :             case SPMType::SZHeating:
     810              :             case SPMType::SZCooling: {
     811           11 :                 auto *spmSZTemp = dynamic_cast<SPMSingleZoneTemp *>(spm);
     812           11 :                 assert(spmSZTemp != nullptr);
     813              : 
     814           11 :                 if (spmSZTemp->ctrlVar != HVAC::CtrlVarType::Temp) {
     815            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     816            0 :                     ErrorsFound = true;
     817              :                 }
     818              : 
     819           22 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
     820           11 :                 spmSZTemp->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
     821           11 :                 if (spmSZTemp->ctrlZoneNum == 0) {
     822            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
     823            0 :                     ErrorsFound = true;
     824              :                 }
     825           11 :                 spmSZTemp->setPt = 0.0;
     826              : 
     827           22 :                 spmSZTemp->zoneNodeNum = GetOnlySingleNode(state,
     828           33 :                                                            ip->getAlphaFieldValue(fields, props, "zone_node_name"),
     829              :                                                            ErrorsFound,
     830           11 :                                                            spmNodeObjectTypes[(int)spm->type],
     831           11 :                                                            spmSZTemp->Name,
     832              :                                                            DataLoopNode::NodeFluidType::Air,
     833              :                                                            DataLoopNode::ConnectionType::Sensor,
     834              :                                                            NodeInputManager::CompFluidStream::Primary,
     835              :                                                            ObjectIsNotParent);
     836           22 :                 spmSZTemp->zoneInletNodeNum = GetOnlySingleNode(state,
     837           33 :                                                                 ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"),
     838              :                                                                 ErrorsFound,
     839           11 :                                                                 spmNodeObjectTypes[(int)spm->type],
     840           11 :                                                                 spmSZTemp->Name,
     841              :                                                                 DataLoopNode::NodeFluidType::Air,
     842              :                                                                 DataLoopNode::ConnectionType::Sensor,
     843              :                                                                 NodeInputManager::CompFluidStream::Primary,
     844              :                                                                 ObjectIsNotParent);
     845              : 
     846           11 :             } break;
     847              : 
     848              :             // SetpointManager:SingleZone:Humidity:Minimum
     849              :             // SetpointManager:SingleZone:Humidity:Maximum
     850            4 :             case SPMType::SZMinHum:
     851              :             case SPMType::SZMaxHum: {
     852            4 :                 auto *spmSZHum = dynamic_cast<SPMSingleZoneHum *>(spm);
     853            4 :                 assert(spmSZHum != nullptr);
     854              : 
     855            4 :                 ErrInList = false;
     856            8 :                 std::string ctrlZoneNodeName = ip->getAlphaFieldValue(fields, props, "control_zone_air_node_name");
     857            8 :                 GetNodeNums(state,
     858              :                             ctrlZoneNodeName,
     859              :                             NumNodes,
     860              :                             NodeNums,
     861              :                             ErrInList,
     862              :                             DataLoopNode::NodeFluidType::Air,
     863            4 :                             spmNodeObjectTypes[(int)spm->type],
     864            4 :                             spmSZHum->Name,
     865              :                             DataLoopNode::ConnectionType::Sensor,
     866              :                             NodeInputManager::CompFluidStream::Primary,
     867              :                             ObjectIsNotParent,
     868              :                             false,
     869              :                             "control_zone_air_node_name"); // nodes of zones whose humidity is being controlled
     870              : 
     871            4 :                 if (ErrInList) {
     872            0 :                     ErrorsFound = true;
     873              :                 }
     874              : 
     875              :                 // only allow one control zone for now
     876            4 :                 if (NumNodes > 1) {
     877            0 :                     ShowSevereError(state, format("{}: {}=\"{}\", entered nodelist.", routineName, cCurrentModuleObject, spmSZHum->Name));
     878            0 :                     ShowContinueError(state, format("..invalid ctrl_zone_node_name=\"{}\".", ctrlZoneNodeName));
     879            0 :                     ShowContinueError(state, "..only one control zone is allowed.");
     880            0 :                     ErrorsFound = true;
     881              :                 }
     882              : 
     883            4 :                 spmSZHum->zoneNodeNum = NodeNums(1);
     884            4 :                 spmSZHum->ctrlZoneNum = 0;
     885            4 :             } break;
     886              : 
     887              :             // SetpointManager:MixedAir
     888           58 :             case SPMType::MixedAir: {
     889           58 :                 auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
     890           58 :                 assert(spmMA != nullptr);
     891              : 
     892           58 :                 if (spmMA->ctrlVar != HVAC::CtrlVarType::Temp) {
     893            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     894            0 :                     ErrorsFound = true;
     895              :                 }
     896              : 
     897          116 :                 spmMA->refNodeNum = GetOnlySingleNode(state,
     898          174 :                                                       ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"),
     899              :                                                       ErrorsFound,
     900           58 :                                                       spmNodeObjectTypes[(int)spm->type],
     901           58 :                                                       spmMA->Name,
     902              :                                                       DataLoopNode::NodeFluidType::Air,
     903              :                                                       DataLoopNode::ConnectionType::Sensor,
     904              :                                                       NodeInputManager::CompFluidStream::Primary,
     905              :                                                       ObjectIsNotParent);
     906          116 :                 spmMA->fanInNodeNum = GetOnlySingleNode(state,
     907          174 :                                                         ip->getAlphaFieldValue(fields, props, "fan_inlet_node_name"),
     908              :                                                         ErrorsFound,
     909           58 :                                                         spmNodeObjectTypes[(int)spm->type],
     910           58 :                                                         spmMA->Name,
     911              :                                                         DataLoopNode::NodeFluidType::Air,
     912              :                                                         DataLoopNode::ConnectionType::Sensor,
     913              :                                                         NodeInputManager::CompFluidStream::Primary,
     914              :                                                         ObjectIsNotParent);
     915          116 :                 spmMA->fanOutNodeNum = GetOnlySingleNode(state,
     916          174 :                                                          ip->getAlphaFieldValue(fields, props, "fan_outlet_node_name"),
     917              :                                                          ErrorsFound,
     918           58 :                                                          spmNodeObjectTypes[(int)spm->type],
     919           58 :                                                          spmMA->Name,
     920              :                                                          DataLoopNode::NodeFluidType::Air,
     921              :                                                          DataLoopNode::ConnectionType::Sensor,
     922              :                                                          NodeInputManager::CompFluidStream::Primary,
     923              :                                                          ObjectIsNotParent);
     924           58 :             } break;
     925              : 
     926              :             // SetpointManager:OutdoorAirPretreat
     927            1 :             case SPMType::OutsideAirPretreat: {
     928            1 :                 auto *spmOAP = dynamic_cast<SPMOutsideAirPretreat *>(spm);
     929            1 :                 assert(spmOAP != nullptr);
     930              : 
     931            2 :                 spmOAP->refNodeNum = GetOnlySingleNode(state,
     932            3 :                                                        ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"),
     933              :                                                        ErrorsFound,
     934            1 :                                                        spmNodeObjectTypes[(int)spm->type],
     935            1 :                                                        spmOAP->Name,
     936              :                                                        DataLoopNode::NodeFluidType::Air,
     937              :                                                        DataLoopNode::ConnectionType::Sensor,
     938              :                                                        NodeInputManager::CompFluidStream::Primary,
     939              :                                                        ObjectIsNotParent);
     940            2 :                 spmOAP->mixedOutNodeNum = GetOnlySingleNode(state,
     941            3 :                                                             ip->getAlphaFieldValue(fields, props, "mixed_air_stream_node_name"),
     942              :                                                             ErrorsFound,
     943            1 :                                                             spmNodeObjectTypes[(int)spm->type],
     944            1 :                                                             spmOAP->Name,
     945              :                                                             DataLoopNode::NodeFluidType::Air,
     946              :                                                             DataLoopNode::ConnectionType::Sensor,
     947              :                                                             NodeInputManager::CompFluidStream::Primary,
     948              :                                                             ObjectIsNotParent);
     949            2 :                 spmOAP->oaInNodeNum = GetOnlySingleNode(state,
     950            3 :                                                         ip->getAlphaFieldValue(fields, props, "outdoor_air_stream_node_name"),
     951              :                                                         ErrorsFound,
     952            1 :                                                         spmNodeObjectTypes[(int)spm->type],
     953            1 :                                                         spmOAP->Name,
     954              :                                                         DataLoopNode::NodeFluidType::Air,
     955              :                                                         DataLoopNode::ConnectionType::Sensor,
     956              :                                                         NodeInputManager::CompFluidStream::Primary,
     957              :                                                         ObjectIsNotParent);
     958            2 :                 spmOAP->returnInNodeNum = GetOnlySingleNode(state,
     959            3 :                                                             ip->getAlphaFieldValue(fields, props, "return_air_stream_node_name"),
     960              :                                                             ErrorsFound,
     961            1 :                                                             spmNodeObjectTypes[(int)spm->type],
     962            1 :                                                             spmOAP->Name,
     963              :                                                             DataLoopNode::NodeFluidType::Air,
     964              :                                                             DataLoopNode::ConnectionType::Sensor,
     965              :                                                             NodeInputManager::CompFluidStream::Primary,
     966              :                                                             ObjectIsNotParent);
     967              : 
     968            1 :                 if (std::find(spmOAP->ctrlNodeNums.begin(), spmOAP->ctrlNodeNums.end(), spmOAP->refNodeNum) != spmOAP->ctrlNodeNums.end()) {
     969            0 :                     ShowSevereError(state, format("{}: {}=\"{}\", reference node.", routineName, cCurrentModuleObject, spmOAP->Name));
     970            0 :                     if (spmOAP->ctrlNodeNums.size() > 1) {
     971            0 :                         ShowContinueError(state, "..Reference Node is the same as one of the nodes in SetPoint NodeList");
     972              :                     } else {
     973            0 :                         ShowContinueError(state, "..Reference Node is the same as the SetPoint Node");
     974              :                     }
     975            0 :                     ShowContinueError(state, format("Reference Node Name=\"{}\".", state.dataLoopNodes->NodeID(spmOAP->refNodeNum)));
     976            0 :                     ErrorsFound = true;
     977              :                 }
     978            1 :             } break;
     979              : 
     980              :             // SetpointManager:Warmest
     981              :             // SetpointManager:Coldest
     982            6 :             case SPMType::Warmest:
     983              :             case SPMType::Coldest: {
     984            6 :                 auto *spmEst = dynamic_cast<SPMTempest *>(spm);
     985            6 :                 assert(spmEst != nullptr);
     986              : 
     987            6 :                 if (spmEst->ctrlVar != HVAC::CtrlVarType::Temp) {
     988            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     989            0 :                     ErrorsFound = true;
     990              :                 }
     991              : 
     992           12 :                 std::string strategyName = ip->getAlphaFieldValue(fields, props, "strategy");
     993            6 :                 spmEst->strategy = static_cast<SupplyFlowTempStrategy>(getEnumValue(supplyFlowTempStrategyNamesUC, strategyName));
     994              : 
     995            6 :                 if ((spmEst->type == SPMType::Warmest && spmEst->strategy != SupplyFlowTempStrategy::MaxTemp) ||
     996            6 :                     (spmEst->type == SPMType::Coldest && spmEst->strategy != SupplyFlowTempStrategy::MinTemp)) {
     997            0 :                     ShowSevereInvalidKey(state, eoh, "strategy", strategyName);
     998            0 :                     ErrorsFound = true;
     999              :                 }
    1000            6 :             } break;
    1001              : 
    1002              :             // SetpointManager:WarmestTemperatureFlow
    1003            0 :             case SPMType::WarmestTempFlow: {
    1004            0 :                 auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    1005            0 :                 assert(spmWTF != nullptr);
    1006              : 
    1007            0 :                 if (spmWTF->ctrlVar != HVAC::CtrlVarType::Temp) {
    1008            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1009            0 :                     ErrorsFound = true;
    1010              :                 }
    1011              : 
    1012            0 :                 spmWTF->minTurndown = ip->getRealFieldValue(fields, props, "minimum_turndown_ratio");
    1013            0 :                 if (spmWTF->minTurndown >= 0.8) {
    1014            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spmWTF->Name));
    1015            0 :                     ShowContinueError(state, format("...minimum_turndown_ratio=[{:.2R}] is greater than 0.8;", spmWTF->minTurndown));
    1016            0 :                     ShowContinueError(state, "...typical values for minimum_turndown_ratio are less than 0.8.");
    1017              :                 }
    1018              : 
    1019            0 :                 spmWTF->strategy = static_cast<ControlStrategy>(getEnumValue(strategyNamesUC, ip->getAlphaFieldValue(fields, props, "strategy")));
    1020              : 
    1021            0 :                 SetupOutputVariable(state,
    1022              :                                     "Setpoint Manager Warmest Temperature Critical Zone Number",
    1023              :                                     Constant::Units::None,
    1024            0 :                                     spmWTF->critZoneNum,
    1025              :                                     OutputProcessor::TimeStepType::System,
    1026              :                                     OutputProcessor::StoreType::Average,
    1027            0 :                                     spmWTF->Name);
    1028            0 :                 SetupOutputVariable(state,
    1029              :                                     "Setpoint Manager Warmest Temperature Turndown Flow Fraction",
    1030              :                                     Constant::Units::None,
    1031            0 :                                     spmWTF->turndown,
    1032              :                                     OutputProcessor::TimeStepType::System,
    1033              :                                     OutputProcessor::StoreType::Average,
    1034            0 :                                     spmWTF->Name);
    1035            0 :             } break;
    1036              : 
    1037              :             // SetpointManager:ReturnAirBypassFlow
    1038            0 :             case SPMType::ReturnAirBypass: {
    1039            0 :                 auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    1040            0 :                 assert(spmRAB != nullptr);
    1041              : 
    1042            0 :                 std::string schedName = ip->getAlphaFieldValue(fields, props, "temperature_setpoint_schedule_name");
    1043            0 :                 if ((spmRAB->sched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
    1044            0 :                     ShowSevereItemNotFound(state, eoh, "temperature_setpoint_schedule_name", schedName);
    1045            0 :                     ErrorsFound = true;
    1046              :                 }
    1047            0 :             } break;
    1048              : 
    1049              :             // SetpointManager:FollowOutdoorAirTemperature
    1050            3 :             case SPMType::FollowOutsideAirTemp: {
    1051            3 :                 auto *spmFOAT = dynamic_cast<SPMFollowOutsideAirTemp *>(spm);
    1052            3 :                 assert(spmFOAT != nullptr);
    1053              : 
    1054            3 :                 if (spmFOAT->ctrlVar != HVAC::CtrlVarType::Temp && spmFOAT->ctrlVar != HVAC::CtrlVarType::MaxTemp &&
    1055            0 :                     spmFOAT->ctrlVar != HVAC::CtrlVarType::MinTemp) {
    1056            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1057            0 :                     ErrorsFound = true;
    1058              :                 }
    1059              : 
    1060            3 :                 spmFOAT->refTempType =
    1061            6 :                     static_cast<AirTempType>(getEnumValue(oaTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_temperature_type")));
    1062              : 
    1063            6 :                 spmFOAT->offset = ip->getRealFieldValue(fields, props, "offset_temperature_difference");
    1064            3 :             } break;
    1065              : 
    1066              :             // SetpointManager:FollowSystemNodeTemperature
    1067            0 :             case SPMType::FollowSystemNodeTemp: {
    1068            0 :                 auto *spmFNT = dynamic_cast<SPMFollowSysNodeTemp *>(spm);
    1069            0 :                 assert(spmFNT != nullptr);
    1070              : 
    1071            0 :                 if (spmFNT->ctrlVar != HVAC::CtrlVarType::Temp && spmFNT->ctrlVar != HVAC::CtrlVarType::MaxTemp &&
    1072            0 :                     spmFNT->ctrlVar != HVAC::CtrlVarType::MinTemp) {
    1073            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1074            0 :                     ErrorsFound = true;
    1075              :                 }
    1076              : 
    1077            0 :                 spmFNT->refNodeNum = GetOnlySingleNode(state,
    1078            0 :                                                        ip->getAlphaFieldValue(fields, props, "reference_node_name"),
    1079              :                                                        ErrorsFound,
    1080            0 :                                                        spmNodeObjectTypes[(int)spm->type],
    1081            0 :                                                        spmFNT->Name,
    1082              :                                                        DataLoopNode::NodeFluidType::Blank,
    1083              :                                                        DataLoopNode::ConnectionType::Sensor,
    1084              :                                                        NodeInputManager::CompFluidStream::Primary,
    1085              :                                                        ObjectIsNotParent);
    1086              : 
    1087            0 :                 spmFNT->refTempType =
    1088            0 :                     static_cast<AirTempType>(getEnumValue(nodeTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_temperature_type")));
    1089              : 
    1090            0 :                 spmFNT->offset = ip->getRealFieldValue(fields, props, "offset_temperature_difference");
    1091            0 :             } break;
    1092              : 
    1093              :             // SetpointManager:FollowGroundTemperature
    1094            3 :             case SPMType::FollowGroundTemp: {
    1095            3 :                 auto *spmFGT = dynamic_cast<SPMFollowGroundTemp *>(spm);
    1096            3 :                 assert(spmFGT != nullptr);
    1097              : 
    1098            3 :                 if (spmFGT->ctrlVar != HVAC::CtrlVarType::Temp && spmFGT->ctrlVar != HVAC::CtrlVarType::MaxTemp &&
    1099            0 :                     spmFGT->ctrlVar != HVAC::CtrlVarType::MinTemp) {
    1100              :                     // should not come here if idd type choice and key list is working
    1101            0 :                     ShowSevereItemNotFound(state, eoh, "control_variable", ctrlVarName);
    1102            0 :                     ErrorsFound = true;
    1103              :                 }
    1104              : 
    1105            3 :                 spmFGT->refTempType = static_cast<DataEnvironment::GroundTempType>(
    1106            6 :                     getEnumValue(groundTempObjectTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_ground_temperature_object_type")));
    1107              : 
    1108            3 :                 if (state.dataSetPointManager->NoGroundTempObjWarning[(int)spmFGT->refTempType]) {
    1109            3 :                     if (!state.dataEnvrn->GroundTempInputs[(int)spmFGT->refTempType]) {
    1110            4 :                         ShowWarningError(state,
    1111            4 :                                          format("{}: {}=\"{}\" requires \"Site:GroundTemperature:BuildingSurface\" in the input..",
    1112              :                                                 routineName,
    1113              :                                                 cCurrentModuleObject,
    1114            2 :                                                 spmFGT->Name));
    1115            4 :                         ShowContinueError(state,
    1116            4 :                                           format("Defaults, constant throughout the year of ({:.1R}) will be used.",
    1117            2 :                                                  state.dataEnvrn->GroundTemp[(int)spmFGT->refTempType]));
    1118              :                     }
    1119            3 :                     state.dataSetPointManager->NoGroundTempObjWarning[(int)spmFGT->refTempType] = false;
    1120              :                 }
    1121              : 
    1122            6 :                 spmFGT->offset = ip->getRealFieldValue(fields, props, "offset_temperature_difference");
    1123            3 :             } break;
    1124              : 
    1125              :             // SetpointManager:CondenserEnteringReset
    1126            0 :             case SPMType::CondenserEnteringTemp: {
    1127            0 :                 auto *spmCET = dynamic_cast<SPMCondenserEnteringTemp *>(spm);
    1128            0 :                 assert(spmCET != nullptr);
    1129              : 
    1130            0 :                 if (spmCET->ctrlVar != HVAC::CtrlVarType::Temp) {
    1131            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1132            0 :                     ErrorsFound = true;
    1133              :                 }
    1134              : 
    1135              :                 std::string condenserEnteringTempSchedName =
    1136            0 :                     ip->getAlphaFieldValue(fields, props, "default_condenser_entering_water_temperature_schedule_name");
    1137            0 :                 if ((spmCET->condenserEnteringTempSched = Sched::GetSchedule(state, Util::makeUPPER(condenserEnteringTempSchedName))) == nullptr) {
    1138            0 :                     ShowSevereItemNotFound(state, eoh, "default_condenser_entering_water_temperature_schedule_name", condenserEnteringTempSchedName);
    1139            0 :                     ErrorsFound = true;
    1140              :                 }
    1141              : 
    1142            0 :                 std::string minDesignWetBulbCurveName = ip->getAlphaFieldValue(fields, props, "minimum_design_wetbulb_temperature_curve_name");
    1143            0 :                 spmCET->minTowerDesignWetBulbCurveNum = GetCurveIndex(state, minDesignWetBulbCurveName);
    1144              : 
    1145            0 :                 std::string minOAWetBulbCurveName = ip->getAlphaFieldValue(fields, props, "minimum_outside_air_wetbulb_temperature_curve_name");
    1146            0 :                 spmCET->minOAWetBulbCurveNum = GetCurveIndex(state, minOAWetBulbCurveName);
    1147              : 
    1148              :                 std::string optCondenserEnteringTempCurveName =
    1149            0 :                     ip->getAlphaFieldValue(fields, props, "optimized_cond_entering_water_temperature_curve_name");
    1150              : 
    1151            0 :                 spmCET->optCondenserEnteringTempCurveNum = GetCurveIndex(state, optCondenserEnteringTempCurveName);
    1152            0 :                 spmCET->minLift = ip->getRealFieldValue(fields, props, "minimum_lift");
    1153              : 
    1154            0 :                 spmCET->maxCondenserEnteringTemp = ip->getRealFieldValue(fields, props, "maximum_condenser_entering_water_temperature");
    1155            0 :                 spmCET->towerDesignInletAirWetBulbTemp = ip->getRealFieldValue(fields, props, "cooling_tower_design_inlet_air_wet_bulb_temperature");
    1156              : 
    1157            0 :                 if (spmCET->maxCondenserEnteringTemp < spmCET->towerDesignInletAirWetBulbTemp) {
    1158            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spmCET->Name));
    1159            0 :                     ShowContinueError(state,
    1160            0 :                                       format("...maximum_condenser_entering_water_temperature=[{:.1R}] is less than "
    1161              :                                              "cooling_tower_design_inlet_air_wet-bulb_temperature=[{:.1R}].",
    1162            0 :                                              spmCET->maxCondenserEnteringTemp,
    1163            0 :                                              spmCET->towerDesignInletAirWetBulbTemp));
    1164              :                 }
    1165              : 
    1166            0 :             } break;
    1167              : 
    1168              :             // SetpointManager:CondenserEnteringReset:Ideal
    1169            0 :             case SPMType::IdealCondenserEnteringTemp: {
    1170            0 :                 auto *spmIdealCET = dynamic_cast<SPMIdealCondenserEnteringTemp *>(spm);
    1171            0 :                 assert(spmIdealCET != nullptr);
    1172              : 
    1173            0 :                 if (spmIdealCET->ctrlVar != HVAC::CtrlVarType::Temp) {
    1174            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1175            0 :                     ErrorsFound = true;
    1176              :                 }
    1177              : 
    1178            0 :                 spmIdealCET->minLift = ip->getRealFieldValue(fields, props, "minimum_lift");
    1179            0 :                 spmIdealCET->maxCondenserEnteringTemp = ip->getRealFieldValue(fields, props, "maximum_condenser_entering_water_temperature");
    1180              : 
    1181            0 :             } break;
    1182              : 
    1183              :             // SetpointManager:SingleZone:OneStageCooling
    1184            0 :             case SPMType::SZOneStageCooling: {
    1185            0 :                 auto *spmSZOSC = dynamic_cast<SPMSingleZoneOneStageCooling *>(spm);
    1186            0 :                 assert(spmSZOSC != nullptr);
    1187              : 
    1188            0 :                 spmSZOSC->coolingOnSetPt = ip->getRealFieldValue(fields, props, "cooling_stage_on_supply_air_setpoint_temperature");
    1189            0 :                 spmSZOSC->coolingOffSetPt = ip->getRealFieldValue(fields, props, "cooling_stage_off_supply_air_setpoint_temperature");
    1190              : 
    1191            0 :                 if (spmSZOSC->coolingOffSetPt < spmSZOSC->coolingOnSetPt) {
    1192              :                     // throw warning, off must be warmer than on
    1193            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spmSZOSC->Name));
    1194            0 :                     ShowContinueError(state,
    1195            0 :                                       format("...cooling_stage_off_supply_air_setpoint_temperature=[{:.1R}] is less than "
    1196              :                                              "cooling_stage_on_supply_air_setpoint_temperature=[{:.1R}].",
    1197            0 :                                              spmSZOSC->coolingOffSetPt,
    1198            0 :                                              spmSZOSC->coolingOnSetPt));
    1199              :                 }
    1200              : 
    1201            0 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
    1202              :                 // get the actual zone number of the control zone
    1203            0 :                 spmSZOSC->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
    1204            0 :                 if (spmSZOSC->ctrlZoneNum == 0) {
    1205            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
    1206            0 :                     ErrorsFound = true;
    1207              :                 } else {
    1208            0 :                     spmSZOSC->zoneNodeNum = GetSystemNodeNumberForZone(state, spmSZOSC->ctrlZoneNum);
    1209            0 :                     if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
    1210            0 :                         if (!state.dataZoneCtrls->StageZoneLogic(spmSZOSC->ctrlZoneNum)) {
    1211            0 :                             ShowSevereError(state, format("{}: {}=\"{}\", invalid field.", routineName, cCurrentModuleObject, spmSZOSC->Name));
    1212            0 :                             ShowContinueError(state, format("..invalid control_zone_name=\"{}\".", ctrlZoneName));
    1213            0 :                             ShowContinueError(state, "Zone thermostat must use ZoneControl:Thermostat:StagedDualSetpoint.");
    1214            0 :                             ErrorsFound = true;
    1215              :                         }
    1216              :                     }
    1217              :                 }
    1218            0 :             } break;
    1219              : 
    1220              :             // SetpointManager:SingleZone:OneStageHeating
    1221            0 :             case SPMType::SZOneStageHeating: {
    1222            0 :                 auto *spmSZOSH = dynamic_cast<SPMSingleZoneOneStageHeating *>(spm);
    1223            0 :                 assert(spmSZOSH != nullptr);
    1224              : 
    1225            0 :                 spmSZOSH->heatingOnSetPt = ip->getRealFieldValue(fields, props, "heating_stage_on_supply_air_setpoint_temperature");
    1226            0 :                 spmSZOSH->heatingOffSetPt = ip->getRealFieldValue(fields, props, "heating_stage_off_supply_air_setpoint_temperature");
    1227              : 
    1228            0 :                 if (spmSZOSH->heatingOffSetPt > spmSZOSH->heatingOnSetPt) {
    1229              :                     // throw warning, off must be warmer than on
    1230            0 :                     ShowWarningError(state, format("{}: {}=\"{}\",", routineName, cCurrentModuleObject, spmSZOSH->Name));
    1231            0 :                     ShowContinueError(state,
    1232            0 :                                       format("...heating_stage_off_supply_air_setpoint_temperature=[{:.1R}] is less than "
    1233              :                                              "heating_stage_on_supply_air_setpoint_temperature=[{:.1R}].",
    1234            0 :                                              spmSZOSH->heatingOffSetPt,
    1235            0 :                                              spmSZOSH->heatingOnSetPt));
    1236              :                 }
    1237              : 
    1238            0 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
    1239              :                 // get the actual zone number of the control zone
    1240            0 :                 spmSZOSH->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
    1241            0 :                 if (spmSZOSH->ctrlZoneNum == 0) {
    1242            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
    1243            0 :                     ErrorsFound = true;
    1244              :                 } else {
    1245            0 :                     spmSZOSH->zoneNodeNum = GetSystemNodeNumberForZone(state, spmSZOSH->ctrlZoneNum);
    1246            0 :                     if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
    1247            0 :                         if (!state.dataZoneCtrls->StageZoneLogic(spmSZOSH->ctrlZoneNum)) {
    1248            0 :                             ShowSevereError(state, format("{}: {}=\"{}\", invalid field.", routineName, cCurrentModuleObject, spmSZOSH->Name));
    1249            0 :                             ShowContinueError(state, format("..invalid control_zone_name=\"{}\".", ctrlZoneName));
    1250            0 :                             ShowContinueError(state, "Zone thermostat must use ZoneControl:Thermostat:StagedDualSetpoint.");
    1251            0 :                             ErrorsFound = true;
    1252              :                         }
    1253              :                     }
    1254              :                 }
    1255            0 :             } break;
    1256              : 
    1257              :             // SetpointManager:ReturnTemperature:ChilledWater
    1258              :             // SetpointManager:ReturnTemperature:HotWater
    1259            0 :             case SPMType::ChilledWaterReturnTemp:
    1260              :             case SPMType::HotWaterReturnTemp: {
    1261            0 :                 auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    1262            0 :                 assert(spmRWT != nullptr);
    1263              : 
    1264            0 :                 bool errFlag = false;
    1265            0 :                 spmRWT->supplyNodeNum = GetOnlySingleNode(state,
    1266            0 :                                                           ip->getAlphaFieldValue(fields, props, "plant_loop_supply_outlet_node"),
    1267              :                                                           errFlag,
    1268            0 :                                                           spmNodeObjectTypes[(int)spm->type],
    1269            0 :                                                           spmRWT->Name,
    1270              :                                                           DataLoopNode::NodeFluidType::Blank,
    1271              :                                                           DataLoopNode::ConnectionType::SetPoint,
    1272              :                                                           NodeInputManager::CompFluidStream::Primary,
    1273              :                                                           ObjectIsNotParent,
    1274              :                                                           "plant_loop_supply_outlet_node"); // setpoint nodes
    1275            0 :                 spmRWT->returnNodeNum = GetOnlySingleNode(state,
    1276            0 :                                                           ip->getAlphaFieldValue(fields, props, "plant_loop_supply_inlet_node"),
    1277              :                                                           errFlag,
    1278            0 :                                                           spmNodeObjectTypes[(int)spm->type],
    1279            0 :                                                           spmRWT->Name,
    1280              :                                                           DataLoopNode::NodeFluidType::Blank,
    1281              :                                                           DataLoopNode::ConnectionType::Sensor,
    1282              :                                                           NodeInputManager::CompFluidStream::Primary,
    1283              :                                                           ObjectIsNotParent,
    1284              :                                                           "plant_loop_supply_inlet_node"); // setpoint nodes
    1285              : 
    1286              :                 // process the setpoint inputs
    1287            0 :                 spmRWT->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_supply_temperature_setpoint");
    1288            0 :                 spmRWT->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_supply_temperature_setpoint");
    1289              : 
    1290            0 :                 spmRWT->returnTempType = static_cast<ReturnTempType>(
    1291            0 :                     getEnumValue(returnTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "return_temperature_setpoint_input_type")));
    1292              : 
    1293            0 :                 if (spmRWT->returnTempType == ReturnTempType::Scheduled) {
    1294            0 :                     std::string schedName = ip->getAlphaFieldValue(fields, props, "return_temperature_setpoint_scheduled_name");
    1295            0 :                     if ((spmRWT->returnTempSched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
    1296            0 :                         ShowSevereItemNotFound(state, eoh, "return_temperature_setpoint_scheduled_name", schedName);
    1297            0 :                         ErrorsFound = true;
    1298              :                     }
    1299            0 :                 } else if (spmRWT->returnTempType == ReturnTempType::Constant) {
    1300            0 :                     spmRWT->returnTempConstantTarget = ip->getRealFieldValue(fields, props, "return_temperature_setpoint_constant_value");
    1301              :                 }
    1302            0 :             } break;
    1303              : 
    1304              :             // SetpointManager:SystemNodeReset:Temperature
    1305            1 :             case SPMType::SystemNodeTemp: {
    1306            1 :                 auto *spmSNRTemp = dynamic_cast<SPMSystemNode *>(spm);
    1307            1 :                 assert(spmSNRTemp != nullptr);
    1308              : 
    1309            1 :                 if (spmSNRTemp->ctrlVar != HVAC::CtrlVarType::Temp && spmSNRTemp->ctrlVar != HVAC::CtrlVarType::MaxTemp &&
    1310            0 :                     spmSNRTemp->ctrlVar != HVAC::CtrlVarType::MinTemp) {
    1311            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1312            0 :                     ErrorsFound = true;
    1313              :                 }
    1314              : 
    1315            2 :                 spmSNRTemp->lowRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_low_reference_temperature");
    1316            2 :                 spmSNRTemp->highRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_high_reference_temperature");
    1317            2 :                 spmSNRTemp->lowRef = ip->getRealFieldValue(fields, props, "low_reference_temperature");
    1318            2 :                 spmSNRTemp->highRef = ip->getRealFieldValue(fields, props, "high_reference_temperature");
    1319              : 
    1320            2 :                 spmSNRTemp->refNodeNum = GetOnlySingleNode(state,
    1321            3 :                                                            ip->getAlphaFieldValue(fields, props, "reference_node_name"),
    1322              :                                                            ErrorsFound,
    1323            1 :                                                            spmNodeObjectTypes[(int)spm->type],
    1324            1 :                                                            spmSNRTemp->Name,
    1325              :                                                            DataLoopNode::NodeFluidType::Blank,
    1326              :                                                            DataLoopNode::ConnectionType::Sensor,
    1327              :                                                            NodeInputManager::CompFluidStream::Primary,
    1328              :                                                            ObjectIsNotParent);
    1329            1 :             } break;
    1330              : 
    1331              :             // SetpointManager:SystemNodeReset:Humidity
    1332            1 :             case SPMType::SystemNodeHum: {
    1333            1 :                 auto *spmSNRHum = dynamic_cast<SPMSystemNode *>(spm);
    1334            1 :                 assert(spmSNRHum != nullptr);
    1335              : 
    1336            1 :                 if (spmSNRHum->ctrlVar != HVAC::CtrlVarType::HumRat && spmSNRHum->ctrlVar != HVAC::CtrlVarType::MaxHumRat &&
    1337            0 :                     spmSNRHum->ctrlVar != HVAC::CtrlVarType::MinHumRat) {
    1338            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1339            0 :                     ErrorsFound = true;
    1340              :                 }
    1341              : 
    1342            2 :                 spmSNRHum->lowRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_low_reference_humidity_ratio");
    1343            2 :                 spmSNRHum->highRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_high_reference_humidity_ratio");
    1344            2 :                 spmSNRHum->lowRef = ip->getRealFieldValue(fields, props, "low_reference_humidity_ratio");
    1345            2 :                 spmSNRHum->highRef = ip->getRealFieldValue(fields, props, "high_reference_humidity_ratio");
    1346              : 
    1347            2 :                 spmSNRHum->refNodeNum = GetOnlySingleNode(state,
    1348            3 :                                                           ip->getAlphaFieldValue(fields, props, "reference_node_name"),
    1349              :                                                           ErrorsFound,
    1350            1 :                                                           spmNodeObjectTypes[(int)spm->type],
    1351            1 :                                                           spmSNRHum->Name,
    1352              :                                                           DataLoopNode::NodeFluidType::Blank,
    1353              :                                                           DataLoopNode::ConnectionType::Sensor,
    1354              :                                                           NodeInputManager::CompFluidStream::Primary,
    1355              :                                                           ObjectIsNotParent);
    1356            1 :             } break;
    1357              : 
    1358              :                 // SetpointManager:MultiZone:Cooling:Average
    1359              :                 // SetpointManager:MultiZone:Heating:Average
    1360              :                 // SetpointManager:MultiZone:MinimumHumidity:Average
    1361              :                 // SetpointManager:MultiZone:MaximumHumidity:Average
    1362              :                 // SetpointManager:MultiZone:Humidity:Minimum
    1363              :                 // SetpointManager:MultiZone:Humidity:Maximum
    1364              : 
    1365            0 :             default:
    1366            0 :                 break;
    1367              :             } // switch (spm->type)
    1368              : 
    1369              :             // Load control node list
    1370              :             // Do this at the end to preserve node order
    1371          221 :             if (spm->type != SPMType::ReturnAirBypass && spm->type != SPMType::ChilledWaterReturnTemp && spm->type != SPMType::HotWaterReturnTemp) {
    1372          442 :                 std::string ctrlNodeListName = ip->getAlphaFieldValue(fields, props, "setpoint_node_or_nodelist_name");
    1373          221 :                 NodeListError = false;
    1374          442 :                 GetNodeNums(state,
    1375              :                             ctrlNodeListName,
    1376              :                             NumNodes,
    1377              :                             NodeNums,
    1378              :                             NodeListError,
    1379              :                             DataLoopNode::NodeFluidType::Blank,
    1380          221 :                             spmNodeObjectTypes[iSPM],
    1381              :                             name,
    1382              :                             DataLoopNode::ConnectionType::SetPoint,
    1383              :                             NodeInputManager::CompFluidStream::Primary,
    1384              :                             ObjectIsNotParent,
    1385              :                             false,
    1386              :                             "setpoint_node_or_nodelist_name");
    1387              : 
    1388          221 :                 if (!NodeListError) {
    1389          480 :                     for (int iNode = 1; iNode <= NumNodes; ++iNode) {
    1390          259 :                         spm->ctrlNodeNums.push_back(NodeNums(iNode));
    1391              :                     }
    1392              :                 } else {
    1393            0 :                     ErrorsFound = true;
    1394              :                 }
    1395          221 :             }
    1396              : 
    1397              :             // Now load all of the optional fields
    1398          221 :             switch (spm->type) {
    1399           58 :             case SPMType::MixedAir: {
    1400           58 :                 auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
    1401           58 :                 assert(spmMA != nullptr);
    1402          116 :                 if (auto found = fields.find("cooling_coil_inlet_node_name"); found != fields.end()) {
    1403            0 :                     spmMA->coolCoilInNodeNum = GetOnlySingleNode(state,
    1404            0 :                                                                  Util::makeUPPER(found.value().get<std::string>()),
    1405              :                                                                  ErrorsFound,
    1406            0 :                                                                  spmNodeObjectTypes[(int)spm->type],
    1407            0 :                                                                  spmMA->Name,
    1408              :                                                                  DataLoopNode::NodeFluidType::Air,
    1409              :                                                                  DataLoopNode::ConnectionType::Sensor,
    1410              :                                                                  NodeInputManager::CompFluidStream::Primary,
    1411              :                                                                  ObjectIsNotParent);
    1412              :                 }
    1413              : 
    1414          116 :                 if (auto found = fields.find("cooling_coil_outlet_node_name"); found != fields.end()) {
    1415            0 :                     spmMA->coolCoilOutNodeNum = GetOnlySingleNode(state,
    1416            0 :                                                                   Util::makeUPPER(found.value().get<std::string>()),
    1417              :                                                                   ErrorsFound,
    1418            0 :                                                                   spmNodeObjectTypes[(int)spm->type],
    1419            0 :                                                                   spmMA->Name,
    1420              :                                                                   DataLoopNode::NodeFluidType::Air,
    1421              :                                                                   DataLoopNode::ConnectionType::Sensor,
    1422              :                                                                   NodeInputManager::CompFluidStream::Primary,
    1423              :                                                                   ObjectIsNotParent);
    1424              :                 }
    1425              : 
    1426          116 :                 if (auto found = fields.find("minimum_temperature_at_cooling_coil_outlet_node"); found != fields.end()) {
    1427            0 :                     spmMA->minCoolCoilOutTemp = found.value().get<Real64>();
    1428              :                 }
    1429              : 
    1430              :                 // Also, do this check now that we have both RefNodeNum and ctrlNodeNums
    1431           58 :                 if (std::find(spmMA->ctrlNodeNums.begin(), spmMA->ctrlNodeNums.end(), spmMA->refNodeNum) != spmMA->ctrlNodeNums.end()) {
    1432            1 :                     ShowSevereError(state, format("{}: {}=\"{}\", reference node.", routineName, cCurrentModuleObject, spmMA->Name));
    1433            1 :                     if (spmMA->ctrlNodeNums.size() > 1) {
    1434            0 :                         ShowContinueError(state, "..Reference Node is the same as one of the nodes in SetPoint NodeList");
    1435              :                     } else {
    1436            3 :                         ShowContinueError(state, "..Reference Node is the same as the SetPoint Node");
    1437              :                     }
    1438            1 :                     ShowContinueError(state, format("Reference Node Name=\"{}\".", state.dataLoopNodes->NodeID(spmMA->refNodeNum)));
    1439            1 :                     ErrorsFound = true;
    1440              :                 }
    1441           58 :             } break;
    1442              : 
    1443          163 :             default:
    1444          163 :                 break;
    1445              :             } // switch (spm->type)
    1446              : 
    1447          221 :         } // for (instance)
    1448          159 :     }     // for (iSPM)
    1449              : 
    1450          248 : } // GetSetPointManagerInputData()
    1451              : 
    1452           96 : void VerifySetPointManagers(EnergyPlusData &state, [[maybe_unused]] bool &ErrorsFound) // flag to denote node conflicts in input. !unused1208
    1453              : {
    1454              :     // SUBROUTINE INFORMATION:
    1455              :     //       AUTHOR         Richard Raustad, FSEC
    1456              :     //       DATE WRITTEN   July 2008
    1457              :     //       MODIFIED       Rick Strand, Aug 2014 (removed deallocation of AllSetPtMgrs so ScheduledTES could also verify control nodes)
    1458              : 
    1459              :     // PURPOSE OF THIS SUBROUTINE
    1460              :     // Check the SetPointManager data to eliminate conflicts.
    1461              : 
    1462              :     // METHODOLOGY EMPLOYED:
    1463              :     // 1) Check for duplicate names in individual setpoint managers.
    1464              :     // Control nodes = A B C D
    1465              :     // Check A with B, C, and D
    1466              :     // Check B with C and D
    1467              :     // Check C with D
    1468              :     // 2) Check for duplicate names in all other setpoint managers
    1469              :     //    Verify setpoint managers use same control type (e.g. TEMP) and then check for duplicate nodes
    1470              :     // SPM 1 - Control nodes A - D, SPM 2 - Control nodes E - H, SPM 3 - Control nodes I - L
    1471              :     // If SPM 1 has same control type as SPM 2 and SPM 3 (e.g. all use SPM%CtrlTypeMode = HVAC::CtrlVarType::Temp) then:
    1472              :     // Check A with E-H and I-L
    1473              :     // Check B with E-H and I-L
    1474              :     // Check C with E-H and I-L
    1475              :     // Check D with E-H and I-L
    1476              :     // Then check SPM 2 nodes with SPM 3. Check E with I-L, F with I-L, etc.
    1477              :     // 3) For SET POINT MANAGER:RETURN AIR BYPASS FLOW
    1478              :     //    check for duplicate air loop names.
    1479              : 
    1480          211 :     for (int iSPM = 1; iSPM <= state.dataSetPointManager->spms.isize(); ++iSPM) {
    1481          115 :         auto const *spm = state.dataSetPointManager->spms(iSPM);
    1482              : 
    1483              :         // check for duplicate nodes in each setpoint managers control node list (node lists of size 1 do not need verification)
    1484              :         // issue warning only since duplicate node names within a setpoint manager does not cause a conflict (i.e., same
    1485              :         // value written to node) but may indicate an error in the node name.
    1486          133 :         for (int iNode = 0; iNode < (int)spm->ctrlNodeNums.size() - 1; ++iNode) {
    1487           40 :             for (int jNode = iNode + 1; jNode < (int)spm->ctrlNodeNums.size(); ++jNode) {
    1488           22 :                 if (spm->ctrlNodeNums[iNode] != spm->ctrlNodeNums[jNode]) continue;
    1489            0 :                 ShowWarningError(state, format("{} =\"{}\"", spmTypeNames[(int)spm->type], spm->Name));
    1490            0 :                 ShowContinueError(state, format("...duplicate node specified = {}", state.dataLoopNodes->NodeID(spm->ctrlNodeNums[iNode])));
    1491            0 :                 ShowContinueError(state, format("...control type variable    = {}", ctrlVarTypeNamesUC[(int)spm->ctrlVar]));
    1492              :             }
    1493              :         }
    1494              : 
    1495              :         // check for node conflicts in all other setpoint managers
    1496          298 :         for (int jSPM = iSPM + 1; jSPM <= (int)state.dataSetPointManager->spms.size(); ++jSPM) {
    1497          183 :             auto const *spm2 = state.dataSetPointManager->spms(jSPM);
    1498              : 
    1499          183 :             if (spm == spm2) continue;
    1500              : 
    1501          183 :             if (spm->type == SPMType::ReturnAirBypass && spm2->type == SPMType::ReturnAirBypass) {
    1502              : 
    1503              :                 //     check the air loop name for duplicates in this SP manager type
    1504            0 :                 if (spm->airLoopNum == spm2->airLoopNum) {
    1505            0 :                     ShowWarningError(state, format("{}=\"{}\"", spmTypeNames[(int)spm->type], spm->Name));
    1506            0 :                     ShowContinueError(state, "...air loop name conflicts with another setpoint manager.");
    1507            0 :                     ShowContinueError(state, format("...conflicting setpoint manager = {} \"{}\"", spmTypeNames[(int)spm2->type], spm2->Name));
    1508            0 :                     ShowContinueError(state, format("...conflicting air loop name = {}", spm->airLoopName));
    1509              :                     //        ErrorsFound=.TRUE.
    1510              :                 }
    1511              : 
    1512              :                 //     check for duplicate control nodes
    1513            0 :                 if (spm->ctrlVar != spm2->ctrlVar) continue;
    1514              : 
    1515            0 :                 for (int iNode = 0; iNode < (int)spm->ctrlNodeNums.size(); ++iNode) {
    1516            0 :                     for (int jNode = 0; jNode < (int)spm2->ctrlNodeNums.size(); ++jNode) {
    1517            0 :                         if ((spm->ctrlNodeNums[iNode] == spm2->ctrlNodeNums[jNode]) && spm->ctrlNodeNums[iNode] != 0) {
    1518            0 :                             ShowWarningError(state, format("{}=\"{}\"", spmTypeNames[(int)spm->type], spm->Name));
    1519            0 :                             ShowContinueError(state, "...setpoint node conflicts with another setpoint manager.");
    1520            0 :                             ShowContinueError(state,
    1521            0 :                                               format("...conflicting setpoint manager = {} \"{}\"", spmTypeNames[(int)spm2->type], spm2->Name));
    1522            0 :                             ShowContinueError(state, format("...conflicting node name = {}", state.dataLoopNodes->NodeID(spm->ctrlNodeNums[iNode])));
    1523            0 :                             ShowContinueError(state, format("...control type variable = {}", ctrlVarTypeNames[(int)spm->ctrlVar]));
    1524              :                             //            ErrorsFound=.TRUE.
    1525              :                         }
    1526              :                     }
    1527              :                 }
    1528              : 
    1529            0 :             } else { // not a RAB setpoint manager
    1530              : 
    1531              :                 //     check just the control nodes for other types of SP managers
    1532          183 :                 if (spm->ctrlVar != spm2->ctrlVar) continue;
    1533              : 
    1534          382 :                 for (int iNode = 0; iNode < (int)spm->ctrlNodeNums.size(); ++iNode) {
    1535          428 :                     for (int jNode = 0; jNode < (int)spm2->ctrlNodeNums.size(); ++jNode) {
    1536              : 
    1537          229 :                         if (spm->ctrlNodeNums[iNode] != spm2->ctrlNodeNums[jNode]) continue;
    1538              : 
    1539              :                         //         only warn if scheduled setpoint manager is setting mass flow rate on the same node used by RAB
    1540            0 :                         if (spm->type == SPMType::ReturnAirBypass || spm2->type == SPMType::ReturnAirBypass) {
    1541            0 :                             ShowWarningError(state, format("{}=\"{}\"", spmTypeNames[(int)spm->type], spm->Name));
    1542            0 :                             ShowContinueError(state, "...setpoint node conflicts with another setpoint manager.");
    1543            0 :                             ShowContinueError(state, format("...conflicting setpoint manager ={}:\"{}\"", spmTypeNames[(int)spm2->type], spm2->Name));
    1544            0 :                             ShowContinueError(state, format("...conflicting node name = {}", state.dataLoopNodes->NodeID(spm->ctrlNodeNums[iNode])));
    1545            0 :                             ShowContinueError(state, format("...control type variable = {}", ctrlVarTypeNames[(int)spm->ctrlVar]));
    1546            0 :                             ShowContinueError(state,
    1547              :                                               "...return air bypass flow setpoint manager will have priority setting mass flow rate on this node.");
    1548              :                         } else { // severe error for other SP manager types
    1549            0 :                             ShowWarningError(state, format("{}=\"{}\"", spmTypeNames[(int)spm->type], spm->Name));
    1550            0 :                             ShowContinueError(state, "...setpoint node conflicts with another setpoint manager.");
    1551            0 :                             ShowContinueError(state,
    1552            0 :                                               format("...conflicting setpoint manager = {}:\"{}\"", spmTypeNames[(int)spm2->type], spm2->Name));
    1553            0 :                             ShowContinueError(state, format("...conflicting node name = {}", state.dataLoopNodes->NodeID(spm->ctrlNodeNums[iNode])));
    1554            0 :                             ShowContinueError(state, format("...control type variable = {}", ctrlVarTypeNames[(int)spm->ctrlVar]));
    1555              :                             //            ErrorsFound=.TRUE.
    1556              :                         }
    1557              :                     }
    1558              :                 }
    1559              :             }
    1560              : 
    1561              :         } // for (jSPM)
    1562              : 
    1563              :     } // for (iSPM)
    1564              : 
    1565              :     // Removed the following line for ScheduledTES control implementation
    1566              :     // if ( allocated( AllSetPtMgr ) ) AllSetPtMgr.deallocate();
    1567           96 : } // VerifySetPointManager()
    1568              : 
    1569       208583 : void InitSetPointManagers(EnergyPlusData &state)
    1570              : {
    1571              :     // SUBROUTINE INFORMATION:
    1572              :     //       AUTHOR         Fred Buhl
    1573              :     //       DATE WRITTEN   October 2000
    1574              :     //       MODIFIED       Shirey/Raustad (FSEC), Jan 2004
    1575              :     //                      Nov 2004 - Jan 2005 M. J. Witte, GARD Analytics, Inc.
    1576              :     //                        Add new setpoint managers:
    1577              :     //                          SET POINT MANAGER:SINGLE ZONE HEATING and
    1578              :     //                          SET POINT MANAGER:SINGLE ZONE COOLING
    1579              :     //                          SET POINT MANAGER:OUTSIDE AIR PRETREAT
    1580              :     //                        Work supported by ASHRAE research project 1254-RP
    1581              :     //                      Haves Oct 2004
    1582              :     //                      July 2010 B.A. Nigusse, FSEC/UCF
    1583              :     //                        Added new setpoint managers:
    1584              :     //                          SetpointManager:MultiZone:Heating:Average
    1585              :     //                          SetpointManager:MultiZone:Cooling:Average
    1586              :     //                          SetpointManager:MultiZone:MinimumHumidity:Average
    1587              :     //                          SetpointManager:MultiZone:MaximumHumidity:Average
    1588              :     //                      Aug 2010 B.A. Nigusse, FSEC/UCF
    1589              :     //                        Added new setpoint managers:
    1590              :     //                          SetpointManager:MultiZone:Humidity:Minimum
    1591              :     //                          SetpointManager:MultiZone:Humidity:Maximum
    1592              :     //                      Sep 2010 B.A. Nigusse, FSEC/UCF
    1593              :     //                         Added control variables for SetpointManage:Scheduled
    1594              :     //                      Jan 2022 Wooyoung Jung, Jeremy Lerond and Jian Zhang, PNNL
    1595              :     //                         Added new setpoint managers:
    1596              :     //                          SetpointManager:SystemNodeReset:Temperature
    1597              :     //                          SetpointManager:SystemNodeReset:Humidity
    1598              : 
    1599              :     // PURPOSE OF THIS SUBROUTINE:
    1600              :     // This subroutine is for initializations of the Setpoint Manager objects.
    1601              : 
    1602              :     // METHODOLOGY EMPLOYED:
    1603              :     // Uses the status flags to trigger initializations.
    1604              : 
    1605              :     // Using/Aliasing
    1606              :     using namespace DataPlant;
    1607              :     using OutAirNodeManager::CheckOutAirNodeNumber;
    1608              : 
    1609              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1610       208583 :     constexpr std::string_view routineName = "InitSetPointManagers";
    1611              : 
    1612       208583 :     bool ErrorsFound(false);
    1613              : 
    1614       208583 :     state.dataSetPointManager->ManagerOn = true;
    1615              : 
    1616              :     // One time initializations
    1617              : 
    1618       417161 :     if (state.dataZoneEquip->ZoneEquipInputsFilled &&
    1619       208578 :         state.dataAirLoop->AirLoopInputsFilled) { // check that the zone equipment and air loop data has been read in
    1620              : 
    1621       208371 :         if (state.dataSetPointManager->InitSetPointManagersOneTimeFlag) {
    1622              : 
    1623          206 :             for (auto *spm : state.dataSetPointManager->spms) {
    1624          112 :                 std::string_view spmName = spm->Name;
    1625          112 :                 std::string_view spmTypeName = spmTypeNames[(int)spm->type];
    1626              : 
    1627          112 :                 ErrorObjectHeader eoh{routineName, spmTypeName, spmName};
    1628              : 
    1629          112 :                 switch (spm->type) {
    1630              : 
    1631            4 :                 case SPMType::SZHeating:
    1632              :                 case SPMType::SZCooling: {
    1633            4 :                     auto *spmSZT = dynamic_cast<SPMSingleZoneTemp *>(spm);
    1634            4 :                     assert(spmSZT != nullptr);
    1635              :                     // find the index in the ZoneEquipConfig array of the control zone (the one with the main or only thermostat)
    1636            4 :                     int ConZoneNum = 0;
    1637            8 :                     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1638            4 :                         if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode == spmSZT->zoneNodeNum) {
    1639            4 :                             ConZoneNum = ZoneNum;
    1640              :                         }
    1641              :                     }
    1642            4 :                     if (ConZoneNum == 0) {
    1643            0 :                         ShowSevereError(state, format("{}=\"{}\", Zone Node not found:", spmTypeName, spmName));
    1644            0 :                         ShowContinueError(state,
    1645            0 :                                           format("Node=\"{}\", not found in any controlled Zone", state.dataLoopNodes->NodeID(spmSZT->zoneNodeNum)));
    1646            0 :                         ErrorsFound = true;
    1647              :                     } else {
    1648            4 :                         auto &zoneEquip = state.dataZoneEquip->ZoneEquipConfig(ConZoneNum);
    1649            4 :                         bool found = false;
    1650            8 :                         for (int zoneInNode = 1; zoneInNode <= zoneEquip.NumInletNodes; ++zoneInNode) {
    1651            4 :                             if (spmSZT->zoneInletNodeNum == zoneEquip.InletNode(zoneInNode)) {
    1652            2 :                                 found = true;
    1653              :                             }
    1654              :                         }
    1655            4 :                         if (!found) {
    1656            4 :                             ShowSevereError(state,
    1657            4 :                                             format("{}=\"{}\", The zone inlet node of {}",
    1658              :                                                    spmTypeName,
    1659              :                                                    spmName,
    1660            2 :                                                    state.dataLoopNodes->NodeID(spmSZT->zoneInletNodeNum)));
    1661            2 :                             ShowContinueError(state, format("is not found in Zone = {}. Please check inputs.", zoneEquip.ZoneName));
    1662            2 :                             ErrorsFound = true;
    1663              :                         }
    1664              :                     }
    1665            4 :                 } break;
    1666              : 
    1667            0 :                 case SPMType::SZMinHum:
    1668              :                 case SPMType::SZMaxHum: {
    1669            0 :                     auto *spmSZH = dynamic_cast<SPMSingleZoneHum *>(spm);
    1670            0 :                     assert(spmSZH != nullptr);
    1671              : 
    1672              :                     // set the actual and controlled zone numbers
    1673            0 :                     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1674            0 :                         if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode == spmSZH->zoneNodeNum) {
    1675            0 :                             spmSZH->ctrlZoneNum = ZoneNum;
    1676            0 :                             break;
    1677              :                         }
    1678              :                     }
    1679              :                     // still need to validate...
    1680            0 :                     if (spmSZH->ctrlZoneNum == 0) { // didn't find
    1681            0 :                         ShowSevereCustom(state, eoh, format("could not find Controlled Zone={}", state.dataHeatBal->Zone(spmSZH->ctrlZoneNum).Name));
    1682            0 :                         ErrorsFound = true;
    1683              :                     } else {
    1684              :                         // make sure humidity controlled zone
    1685            0 :                         bool HstatZoneFound = false;
    1686            0 :                         for (int iZone = 1; iZone <= state.dataZoneCtrls->NumHumidityControlZones; ++iZone) {
    1687            0 :                             if (state.dataZoneCtrls->HumidityControlZone(iZone).ActualZoneNum == spmSZH->ctrlZoneNum) {
    1688            0 :                                 HstatZoneFound = true;
    1689            0 :                                 break;
    1690              :                             }
    1691              :                         }
    1692            0 :                         if (!HstatZoneFound) {
    1693            0 :                             ShowSevereError(state, format("{}=\"{}\", invalid humidistat specification", spmTypeName, spmName));
    1694            0 :                             ShowContinueError(state,
    1695            0 :                                               format("could not locate Humidistat in Zone={}", state.dataHeatBal->Zone(spmSZH->ctrlZoneNum).Name));
    1696            0 :                             ErrorsFound = true;
    1697              :                         }
    1698              :                     }
    1699            0 :                 } break;
    1700              : 
    1701            6 :                 case SPMType::SZReheat: {
    1702            6 :                     auto *spmSZR = dynamic_cast<SPMSingleZoneReheat *>(spm);
    1703            6 :                     assert(spmSZR != nullptr);
    1704              : 
    1705            6 :                     int FanNodeIn = 0;
    1706            6 :                     int FanNodeOut = 0;
    1707            6 :                     int MixedAirNode = 0;
    1708            6 :                     int InletBranchNum = 0;
    1709            6 :                     int LoopInNode = 0;
    1710              : 
    1711              :                     // find the index in the ZoneEquipConfig array of the control zone (the one with the main or only thermostat)
    1712            6 :                     int ConZoneNum = 0;
    1713           12 :                     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1714            6 :                         if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode == spmSZR->zoneNodeNum) {
    1715            6 :                             ConZoneNum = ZoneNum;
    1716              :                         }
    1717              :                     }
    1718              : 
    1719            6 :                     if (ConZoneNum == 0) {
    1720            0 :                         ShowSevereError(state, format("{}=\"{}\", Zone Node not found:", spmTypeName, spmName));
    1721            0 :                         ShowContinueError(state,
    1722            0 :                                           format("Node=\"{}\", not found in any controlled Zone", state.dataLoopNodes->NodeID(spmSZR->zoneNodeNum)));
    1723            0 :                         ErrorsFound = true;
    1724              :                     } else {
    1725            6 :                         bool found = false;
    1726            6 :                         auto const &zoneEquip = state.dataZoneEquip->ZoneEquipConfig(ConZoneNum);
    1727           12 :                         for (int zoneInNode = 1; zoneInNode <= zoneEquip.NumInletNodes; ++zoneInNode) {
    1728            6 :                             if (spmSZR->zoneInletNodeNum == zoneEquip.InletNode(zoneInNode)) {
    1729            5 :                                 spmSZR->airLoopNum = zoneEquip.InletNodeAirLoopNum(zoneInNode);
    1730            5 :                                 found = true;
    1731              :                             }
    1732              :                         }
    1733            6 :                         if (!found) {
    1734            2 :                             ShowSevereError(state,
    1735            2 :                                             format("{}=\"{}\", The zone inlet node of {}",
    1736              :                                                    spmTypeName,
    1737              :                                                    spmName,
    1738            1 :                                                    state.dataLoopNodes->NodeID(spmSZR->zoneInletNodeNum)));
    1739            1 :                             ShowContinueError(state, format("is not found in Zone = {}. Please check inputs.", zoneEquip.ZoneName));
    1740            1 :                             ErrorsFound = true;
    1741              :                         }
    1742            6 :                         if (spmSZR->airLoopNum == 0) {
    1743            1 :                             ShowSevereError(state, format("{}=\"{}\", The zone inlet node is not connected to an air loop.", spmTypeName, spmName));
    1744            1 :                             ErrorsFound = true;
    1745            1 :                             continue;
    1746              :                         }
    1747              :                     }
    1748              : 
    1749            5 :                     auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmSZR->airLoopNum);
    1750            5 :                     MixedAirNode = primaryAirSystem.OASysOutletNodeNum;
    1751            5 :                     InletBranchNum = primaryAirSystem.InletBranchNum[0];
    1752            5 :                     LoopInNode = primaryAirSystem.Branch(InletBranchNum).NodeNumIn;
    1753              :                     // get the supply fan inlet and outlet nodes
    1754            5 :                     if (MixedAirNode > 0) {
    1755            5 :                         bool LookForFan = false;
    1756           10 :                         for (auto const &branch : primaryAirSystem.Branch) {
    1757           15 :                             for (auto const &comp : branch.Comp) {
    1758           13 :                                 if (MixedAirNode == comp.NodeNumIn) {
    1759            5 :                                     LookForFan = true;
    1760              :                                 }
    1761           13 :                                 if (LookForFan) {
    1762           21 :                                     if (Util::SameString(comp.TypeOf, "Fan:ConstantVolume") || Util::SameString(comp.TypeOf, "Fan:VariableVolume") ||
    1763           21 :                                         Util::SameString(comp.TypeOf, "Fan:OnOff") || Util::SameString(comp.TypeOf, "Fan:ComponentModel")) {
    1764            3 :                                         FanNodeIn = comp.NodeNumIn;
    1765            3 :                                         FanNodeOut = comp.NodeNumOut;
    1766            3 :                                         break;
    1767              :                                     }
    1768              :                                 }
    1769              :                             }
    1770              :                         } // for (BranchNum)
    1771              :                     } else {
    1772            0 :                         for (auto const &branch : primaryAirSystem.Branch) {
    1773            0 :                             for (auto const &comp : branch.Comp) {
    1774            0 :                                 if (Util::SameString(comp.TypeOf, "Fan:ConstantVolume") || Util::SameString(comp.TypeOf, "Fan:VariableVolume") ||
    1775            0 :                                     Util::SameString(comp.TypeOf, "Fan:OnOff") || Util::SameString(comp.TypeOf, "Fan:ComponentModel")) {
    1776            0 :                                     FanNodeIn = comp.NodeNumIn;
    1777            0 :                                     FanNodeOut = comp.NodeNumOut;
    1778              :                                 }
    1779              :                             }
    1780              :                         }
    1781              :                     }
    1782              : 
    1783            5 :                     spmSZR->fanInNodeNum = FanNodeIn;
    1784            5 :                     spmSZR->fanOutNodeNum = FanNodeOut;
    1785            5 :                     spmSZR->mixedAirNodeNum = MixedAirNode;
    1786            5 :                     spmSZR->oaInNodeNum = primaryAirSystem.OAMixOAInNodeNum;
    1787              :                     // this next line assumes that OA system is the first thing on the branch, what if there is a relief fan or heat recovery coil
    1788              :                     // or other component in there first? does it matter?
    1789            5 :                     spmSZR->retNodeNum = primaryAirSystem.OASysInletNodeNum;
    1790            5 :                     spmSZR->loopInNodeNum = LoopInNode;
    1791              : 
    1792            5 :                 } break;
    1793              : 
    1794            4 :                 case SPMType::Warmest:
    1795              :                 case SPMType::Coldest: {
    1796            4 :                     auto *spmT = dynamic_cast<SPMTempest *>(spm);
    1797            4 :                     assert(spmT != nullptr);
    1798            4 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1799            4 :                         spmT->airLoopNum =
    1800            4 :                             Util::FindItemInList(spmT->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1801            4 :                         if (spmT->airLoopNum == 0) {
    1802            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmT->airLoopName);
    1803            0 :                             ErrorsFound = true;
    1804            4 :                         } else if (state.dataAirLoop->AirToZoneNodeInfo(spmT->airLoopNum).NumZonesCooled == 0) {
    1805            0 :                             ShowSevereError(state, format("{}=\"{}\", no zones with cooling found:", spmTypeName, spmName));
    1806            0 :                             ShowContinueError(state, format("Air Loop provides no cooling, Air Loop=\"{}\".", spmT->airLoopName));
    1807            0 :                             ErrorsFound = true;
    1808              :                         }
    1809              :                     } else {
    1810            0 :                         ShowSevereError(state, format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName));
    1811            0 :                         ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate.");
    1812            0 :                         ErrorsFound = true;
    1813              :                     }
    1814            4 :                 } break;
    1815              : 
    1816            0 :                 case SPMType::WarmestTempFlow: {
    1817            0 :                     auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    1818            0 :                     assert(spmWTF != nullptr);
    1819              : 
    1820            0 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1821            0 :                         spmWTF->airLoopNum = Util::FindItemInList(
    1822            0 :                             spmWTF->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1823            0 :                         if (spmWTF->airLoopNum == 0) {
    1824            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmWTF->airLoopName);
    1825            0 :                             ErrorsFound = true;
    1826              :                         } else {
    1827            0 :                             spmWTF->simReady = true;
    1828              :                         }
    1829            0 :                         if (state.dataAirLoop->AirToZoneNodeInfo(spmWTF->airLoopNum).NumZonesCooled == 0) {
    1830            0 :                             ShowSevereError(state, format("{}=\"{}\", no zones with cooling found:", spmTypeName, spmName));
    1831            0 :                             ShowContinueError(state, format("Air Loop provides no cooling, Air Loop=\"{}\".", spmWTF->airLoopName));
    1832            0 :                             ErrorsFound = true;
    1833              :                         }
    1834              :                     } else {
    1835            0 :                         ShowSevereError(state, format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName));
    1836            0 :                         ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate.");
    1837            0 :                         ErrorsFound = true;
    1838              :                     }
    1839            0 :                 } break;
    1840              : 
    1841            0 :                 case SPMType::ReturnAirBypass: {
    1842            0 :                     auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    1843            0 :                     assert(spmRAB != nullptr);
    1844              : 
    1845            0 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1846            0 :                         spmRAB->airLoopNum = Util::FindItemInList(
    1847            0 :                             spmRAB->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1848            0 :                         if (spmRAB->airLoopNum == 0) {
    1849            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmRAB->airLoopName);
    1850            0 :                             ErrorsFound = true;
    1851              :                         }
    1852              : 
    1853            0 :                         auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmRAB->airLoopNum);
    1854            0 :                         if (primaryAirSystem.RABExists) {
    1855            0 :                             spmRAB->rabMixInNodeNum = primaryAirSystem.RABMixInNode;
    1856            0 :                             spmRAB->supMixInNodeNum = primaryAirSystem.SupMixInNode;
    1857            0 :                             spmRAB->mixOutNodeNum = primaryAirSystem.MixOutNode;
    1858            0 :                             spmRAB->rabSplitOutNodeNum = primaryAirSystem.RABSplitOutNode;
    1859            0 :                             spmRAB->sysOutNodeNum = state.dataAirLoop->AirToZoneNodeInfo(spmRAB->airLoopNum).AirLoopSupplyNodeNum(1);
    1860            0 :                             spmRAB->ctrlNodeNums.push_back(spmRAB->rabSplitOutNodeNum);
    1861              :                         } else {
    1862            0 :                             ShowSevereError(state, format("{}=\"{}\", no RAB in air loop found:", spmTypeName, spmName));
    1863            0 :                             ShowContinueError(state, format("Air Loop=\"{}\".", spmRAB->airLoopName));
    1864            0 :                             ErrorsFound = true;
    1865              :                         }
    1866              :                     } else {
    1867            0 :                         ShowSevereError(state, format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName));
    1868            0 :                         ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate.");
    1869            0 :                         ErrorsFound = true;
    1870              :                     }
    1871            0 :                 } break;
    1872              : 
    1873            0 :                 case SPMType::MZCoolingAverage:
    1874              :                 case SPMType::MZHeatingAverage: {
    1875            0 :                     auto *spmMZTemp = dynamic_cast<SPMMultiZoneTemp *>(spm);
    1876            0 :                     assert(spmMZTemp != nullptr);
    1877              : 
    1878            0 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1879            0 :                         spmMZTemp->airLoopNum = Util::FindItemInList(
    1880            0 :                             spmMZTemp->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1881            0 :                         if (spmMZTemp->airLoopNum == 0) {
    1882            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmMZTemp->airLoopName);
    1883            0 :                             ErrorsFound = true;
    1884              :                         }
    1885              : 
    1886            0 :                         if (state.dataAirLoop->AirToZoneNodeInfo(spmMZTemp->airLoopNum).NumZonesCooled == 0) {
    1887            0 :                             ShowSevereError(state, format("{}=\"{}\", no zones with cooling found:", spmTypeName, spmName));
    1888            0 :                             ShowContinueError(state, format("Air Loop provides no cooling, Air Loop=\"{}\".", spmMZTemp->airLoopName));
    1889            0 :                             ErrorsFound = true;
    1890              :                         }
    1891              :                     } else {
    1892            0 :                         ShowSevereError(state, format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName));
    1893            0 :                         ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate.");
    1894            0 :                         ErrorsFound = true;
    1895              :                     }
    1896            0 :                 } break;
    1897              : 
    1898            0 :                 case SPMType::MZMinHumAverage:
    1899              :                 case SPMType::MZMaxHumAverage:
    1900              :                 case SPMType::MZMinHum:
    1901              :                 case SPMType::MZMaxHum: {
    1902            0 :                     auto *spmMZHum = dynamic_cast<SPMMultiZoneHum *>(spm);
    1903            0 :                     assert(spmMZHum != nullptr);
    1904              : 
    1905            0 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1906            0 :                         spmMZHum->airLoopNum = Util::FindItemInList(
    1907            0 :                             spmMZHum->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1908            0 :                         if (spmMZHum->airLoopNum == 0) {
    1909            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmMZHum->airLoopName);
    1910            0 :                             ErrorsFound = true;
    1911              :                         } else {
    1912              :                             // make sure humidity controlled zone
    1913            0 :                             auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmMZHum->airLoopNum);
    1914            0 :                             auto const &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(spmMZHum->airLoopNum);
    1915            0 :                             bool HstatZoneFound = false;
    1916            0 :                             for (int iZone = 1; iZone <= state.dataZoneCtrls->NumHumidityControlZones; ++iZone) {
    1917            0 :                                 for (int jZone = 1; jZone <= airToZoneNode.NumZonesCooled; ++jZone) {
    1918            0 :                                     if (state.dataZoneCtrls->HumidityControlZone(iZone).ActualZoneNum == airToZoneNode.CoolCtrlZoneNums(jZone)) {
    1919            0 :                                         HstatZoneFound = true;
    1920            0 :                                         break;
    1921              :                                     }
    1922              :                                 }
    1923              :                             }
    1924              : 
    1925            0 :                             if (!HstatZoneFound) {
    1926            0 :                                 ShowSevereError(state, format("{}=\"{}\", invalid humidistat specification", spmTypeName, spmName));
    1927            0 :                                 ShowContinueError(
    1928              :                                     state,
    1929            0 :                                     format("could not locate Humidistat in any of the zones served by the Air loop={}", primaryAirSystem.Name));
    1930            0 :                                 ErrorsFound = true;
    1931              :                             }
    1932              :                         }
    1933              :                     } else {
    1934            0 :                         ShowSevereError(state, format("{}=\"{}\", no AirLoopHVAC objects found:", spmTypeName, spmName));
    1935            0 :                         ShowContinueError(state, "Setpoint Manager needs an AirLoopHVAC to operate.");
    1936            0 :                         ErrorsFound = true;
    1937              :                     }
    1938            0 :                 } break;
    1939              : 
    1940            0 :                 case SPMType::CondenserEnteringTemp: {
    1941            0 :                     auto *spmCET = dynamic_cast<SPMCondenserEnteringTemp *>(spm);
    1942            0 :                     assert(spmCET != nullptr);
    1943              : 
    1944              :                     // Scan loops and find the loop index that includes the condenser cooling tower node used as setpoint
    1945              :                     // Begin demand side loops ... When condenser is added becomes NumLoops
    1946            0 :                     for (int LoopNum = 1; LoopNum <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops; ++LoopNum) {
    1947            0 :                         auto &plantLoop = state.dataPlnt->PlantLoop(LoopNum);
    1948            0 :                         for (int ctrlNodeNum : spmCET->ctrlNodeNums) {
    1949            0 :                             if (plantLoop.TempSetPointNodeNum != ctrlNodeNum) continue;
    1950              : 
    1951            0 :                             for (auto const &branch : plantLoop.LoopSide(LoopSideLocation::Supply).Branch) {
    1952            0 :                                 for (auto const &comp : branch.Comp) {
    1953            0 :                                     if (comp.Type == PlantEquipmentType::CoolingTower_SingleSpd) {
    1954            0 :                                         ShowSevereError(state, format("{}=\"{}\", invalid tower found", spmTypeName, spmName));
    1955            0 :                                         ShowContinueError(state, format("Found SingleSpeed Cooling Tower, Cooling Tower={}", comp.Name));
    1956            0 :                                         ShowContinueError(state, "SingleSpeed cooling towers cannot be used with this setpoint manager.");
    1957            0 :                                         ErrorsFound = true;
    1958              :                                     }
    1959              :                                 }
    1960              :                             }
    1961              : 
    1962              :                             // Scan all attached chillers in the condenser loop index found to find the chiller index
    1963            0 :                             for (int BranchNum = 1; BranchNum <= plantLoop.LoopSide(LoopSideLocation::Demand).TotalBranches; ++BranchNum) {
    1964            0 :                                 auto &branch = plantLoop.LoopSide(LoopSideLocation::Demand).Branch(BranchNum);
    1965              : 
    1966            0 :                                 for (int CompNum = 1; CompNum <= branch.TotalComponents; ++CompNum) {
    1967            0 :                                     auto const &comp = branch.Comp(CompNum);
    1968            0 :                                     switch (comp.Type) {
    1969              : 
    1970            0 :                                     case PlantEquipmentType::Chiller_Absorption:
    1971              :                                     case PlantEquipmentType::Chiller_Indirect_Absorption:
    1972              :                                     case PlantEquipmentType::Chiller_CombTurbine:
    1973              :                                     case PlantEquipmentType::Chiller_ConstCOP:
    1974              :                                     case PlantEquipmentType::Chiller_Electric:
    1975              :                                     case PlantEquipmentType::Chiller_ElectricEIR:
    1976              :                                     case PlantEquipmentType::Chiller_DFAbsorption:
    1977              :                                     case PlantEquipmentType::Chiller_ElectricReformEIR:
    1978              :                                     case PlantEquipmentType::Chiller_EngineDriven: {
    1979              :                                         // Scan the supply side to find the chiller index and branch index on plantloop
    1980            0 :                                         DataPlant::PlantEquipmentType ChillerType = comp.Type;
    1981            0 :                                         for (int LoopNum2 = 1; LoopNum2 <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops;
    1982              :                                              ++LoopNum2) {
    1983            0 :                                             auto &plantLoop2 = state.dataPlnt->PlantLoop(LoopNum2);
    1984            0 :                                             auto &loopSide2 = plantLoop2.LoopSide(LoopSideLocation::Supply);
    1985            0 :                                             for (int BranchNum2 = 1; BranchNum2 <= loopSide2.TotalBranches; ++BranchNum2) {
    1986            0 :                                                 auto const &branch2 = loopSide2.Branch(BranchNum2);
    1987              : 
    1988            0 :                                                 for (int CompNum2 = 1; CompNum2 <= branch2.TotalComponents; ++CompNum2) {
    1989            0 :                                                     auto const &comp2 = branch2.Comp(CompNum2);
    1990            0 :                                                     if (comp2.Type == ChillerType) {
    1991            0 :                                                         spmCET->plantPloc = {LoopNum2, LoopSideLocation::Supply, BranchNum2, CompNum2};
    1992            0 :                                                         break;
    1993              :                                                     }
    1994              :                                                 }
    1995              :                                             }
    1996              :                                         }
    1997            0 :                                         spmCET->chillerType = ChillerType;
    1998            0 :                                         spmCET->demandPloc = {LoopNum, LoopSideLocation::Demand, BranchNum, CompNum};
    1999            0 :                                     } break;
    2000              : 
    2001            0 :                                     default:
    2002            0 :                                         break;
    2003              :                                     }
    2004              :                                 } // for (comp)
    2005              :                             }     // for (branch)
    2006              :                         }         // if (
    2007              :                     }             // for (LoopNum)
    2008            0 :                 } break;
    2009              : 
    2010            0 :                 case SPMType::IdealCondenserEnteringTemp: {
    2011            0 :                     auto *spmIdealCET = dynamic_cast<SPMIdealCondenserEnteringTemp *>(spm);
    2012            0 :                     assert(spmIdealCET != nullptr);
    2013              : 
    2014            0 :                     PlantEquipmentType InitType = PlantEquipmentType::Invalid;
    2015            0 :                     int NumChiller = 0;
    2016              : 
    2017              :                     // Scan loops and find the loop index that includes the condenser cooling tower node used as setpoint
    2018              :                     // Begin demand side loops ... When condenser is added becomes NumLoops
    2019            0 :                     for (int LoopNum = 1; LoopNum <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops; ++LoopNum) {
    2020            0 :                         auto &plantLoop = state.dataPlnt->PlantLoop(LoopNum);
    2021            0 :                         auto &supplySide = plantLoop.LoopSide(LoopSideLocation::Supply);
    2022            0 :                         for (int ctrlNodeNum : spmIdealCET->ctrlNodeNums) {
    2023            0 :                             if (plantLoop.TempSetPointNodeNum != ctrlNodeNum) continue;
    2024              : 
    2025            0 :                             for (int BranchNum = 1; BranchNum <= supplySide.TotalBranches; ++BranchNum) {
    2026            0 :                                 auto &branch = supplySide.Branch(BranchNum);
    2027            0 :                                 for (int CompNum = 1; CompNum <= branch.TotalComponents; ++CompNum) {
    2028            0 :                                     auto &comp = branch.Comp(CompNum);
    2029              :                                     // Check if cooling tower is single speed and generate and error
    2030            0 :                                     InitType = comp.Type;
    2031            0 :                                     if (InitType == PlantEquipmentType::CoolingTower_SingleSpd) {
    2032            0 :                                         ShowSevereError(state, format("{}=\"{}\", invalid cooling tower found", spmTypeName, spmName));
    2033            0 :                                         ShowContinueError(state, format("Found Single Speed Cooling Tower, Cooling Tower={}", comp.Name));
    2034            0 :                                         ShowContinueError(state, "SingleSpeed cooling towers cannot be used with this setpoint manager on each loop");
    2035            0 :                                         ErrorsFound = true;
    2036            0 :                                     } else if (InitType == PlantEquipmentType::CoolingTower_TwoSpd ||
    2037              :                                                InitType == PlantEquipmentType::CoolingTower_VarSpd) {
    2038            0 :                                         spmIdealCET->towerPlocs.push_back(PlantLocation(LoopNum, LoopSideLocation::Supply, BranchNum, CompNum));
    2039            0 :                                         spmIdealCET->numTowers++;
    2040              :                                     }
    2041              :                                     // Scan the pump on the condenser water loop
    2042            0 :                                     if (InitType == PlantEquipmentType::PumpVariableSpeed || InitType == PlantEquipmentType::PumpConstantSpeed) {
    2043            0 :                                         spmIdealCET->condenserPumpPloc = {LoopNum, LoopSideLocation::Supply, BranchNum, CompNum};
    2044              :                                     }
    2045              :                                 }
    2046              :                             }
    2047              : 
    2048            0 :                             auto &demandSide = plantLoop.LoopSide(LoopSideLocation::Demand);
    2049              :                             // Scan all attached chillers in the condenser loop index found to find the chiller index
    2050            0 :                             for (int BranchNum = 1; BranchNum <= demandSide.TotalBranches; ++BranchNum) {
    2051            0 :                                 auto &branch = demandSide.Branch(BranchNum);
    2052            0 :                                 for (int CompNum = 1; CompNum <= branch.TotalComponents; ++CompNum) {
    2053            0 :                                     auto &comp = branch.Comp(CompNum);
    2054            0 :                                     InitType = comp.Type;
    2055              : 
    2056            0 :                                     switch (InitType) {
    2057            0 :                                     case PlantEquipmentType::Chiller_Absorption:
    2058              :                                     case PlantEquipmentType::Chiller_Indirect_Absorption:
    2059              :                                     case PlantEquipmentType::Chiller_CombTurbine:
    2060              :                                     case PlantEquipmentType::Chiller_ConstCOP:
    2061              :                                     case PlantEquipmentType::Chiller_Electric:
    2062              :                                     case PlantEquipmentType::Chiller_ElectricEIR:
    2063              :                                     case PlantEquipmentType::Chiller_DFAbsorption:
    2064              :                                     case PlantEquipmentType::Chiller_ElectricReformEIR:
    2065              :                                     case PlantEquipmentType::Chiller_EngineDriven: {
    2066              :                                         // Scan the supply side to find the chiller index and branch index on plantloop
    2067            0 :                                         DataPlant::PlantEquipmentType ChillerType = comp.Type;
    2068            0 :                                         for (int LoopNum2 = 1; LoopNum2 <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops;
    2069              :                                              ++LoopNum2) {
    2070            0 :                                             auto &plantLoop2 = state.dataPlnt->PlantLoop(LoopNum2);
    2071            0 :                                             auto &supplySide2 = plantLoop2.LoopSide(LoopSideLocation::Supply);
    2072            0 :                                             for (int BranchNum2 = 1; BranchNum2 <= supplySide2.TotalBranches; ++BranchNum2) {
    2073            0 :                                                 auto &branch2 = supplySide2.Branch(BranchNum2);
    2074            0 :                                                 for (int CompNum2 = 1; CompNum2 <= branch2.TotalComponents; ++CompNum2) {
    2075            0 :                                                     auto const &comp2 = branch2.Comp(CompNum2);
    2076            0 :                                                     InitType = comp2.Type;
    2077            0 :                                                     if (InitType == ChillerType) {
    2078            0 :                                                         ++NumChiller;
    2079            0 :                                                         spmIdealCET->chillerPloc = {LoopNum2, LoopSideLocation::Supply, BranchNum2, CompNum2};
    2080              :                                                         // Scan the pump on the chilled water loop
    2081            0 :                                                         for (int BranchNum3 = 1; BranchNum3 <= supplySide2.TotalBranches; ++BranchNum3) {
    2082            0 :                                                             auto &branch3 = supplySide2.Branch(BranchNum3);
    2083            0 :                                                             for (int CompNum3 = 1; CompNum3 <= branch3.TotalComponents; ++CompNum3) {
    2084            0 :                                                                 auto const &comp3 = branch3.Comp(CompNum3);
    2085            0 :                                                                 InitType = comp3.Type;
    2086            0 :                                                                 if (InitType == PlantEquipmentType::PumpVariableSpeed ||
    2087              :                                                                     InitType == PlantEquipmentType::PumpConstantSpeed) {
    2088            0 :                                                                     spmIdealCET->chilledWaterPumpPloc = {
    2089              :                                                                         LoopNum2, LoopSideLocation::Supply, BranchNum3, CompNum3};
    2090              :                                                                 }
    2091              :                                                             }
    2092              :                                                         }
    2093              :                                                     }
    2094              :                                                 }
    2095              :                                             }
    2096              :                                         }
    2097            0 :                                         if (NumChiller > 1) {
    2098            0 :                                             ShowSevereError(state, format("{}=\"{}\", too many chillers found", spmTypeName, spmName));
    2099            0 :                                             ShowContinueError(state, "only one chiller can be used with this setpoint manager on each loop");
    2100            0 :                                             ShowContinueError(state, format("Found more than one chiller, chiller ={}", comp.Name));
    2101            0 :                                             ErrorsFound = true;
    2102              :                                         }
    2103            0 :                                         spmIdealCET->chillerType = ChillerType;
    2104            0 :                                         spmIdealCET->condenserPumpPloc.loopNum = LoopNum;
    2105            0 :                                     } break;
    2106              : 
    2107            0 :                                     default:
    2108            0 :                                         break;
    2109              :                                     } // switch (InitType)
    2110              :                                 }     // for (CompNum)
    2111              :                             }         // for (BranchNum)
    2112            0 :                             NumChiller = 0;
    2113              :                         } // for (iNode)
    2114              :                     }     // for (LoopNum)
    2115            0 :                 } break;
    2116              : 
    2117           98 :                 default:
    2118           98 :                     break;
    2119              :                 } // switch (spm->type)
    2120              :             }     // for (spm)
    2121              : 
    2122           94 :             VerifySetPointManagers(state, ErrorsFound);
    2123              : 
    2124           94 :             state.dataSetPointManager->InitSetPointManagersOneTimeFlag = false;
    2125              :         } // if (InitSetPointManagersOneTimeFlag)
    2126              : 
    2127       208371 :         if (ErrorsFound) {
    2128            6 :             ShowFatalError(state, "InitSetPointManagers: Errors found in getting SetPointManager input.");
    2129              :         }
    2130              :     } // if (AirLoopInputsFilled)
    2131              : 
    2132       416865 :     if ((state.dataGlobal->BeginEnvrnFlag && state.dataSetPointManager->InitSetPointManagersMyEnvrnFlag) ||
    2133       208284 :         state.dataSetPointManager->InitSetPointManagersOneTimeFlag2) {
    2134              : 
    2135          499 :         state.dataSetPointManager->ManagerOn = false;
    2136              : 
    2137         1110 :         for (auto *spm : state.dataSetPointManager->spms) {
    2138              : 
    2139          611 :             switch (spm->type) {
    2140          281 :             case SPMType::Scheduled: {
    2141          281 :                 auto *spmS = dynamic_cast<SPMScheduled *>(spm);
    2142          281 :                 assert(spmS != nullptr);
    2143              : 
    2144          582 :                 for (int ctrlNodeNum : spmS->ctrlNodeNums) {
    2145          301 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2146          301 :                     Real64 SchedValue = spmS->sched->getCurrentVal();
    2147              :                     // Initialize scheduled setpoints
    2148          301 :                     switch (spmS->ctrlVar) {
    2149          300 :                     case HVAC::CtrlVarType::Temp: {
    2150          300 :                         node.TempSetPoint = SchedValue;
    2151          300 :                     } break;
    2152            0 :                     case HVAC::CtrlVarType::MaxTemp: {
    2153            0 :                         node.TempSetPointHi = SchedValue;
    2154            0 :                     } break;
    2155            0 :                     case HVAC::CtrlVarType::MinTemp: {
    2156            0 :                         node.TempSetPointLo = SchedValue;
    2157            0 :                     } break;
    2158            0 :                     case HVAC::CtrlVarType::HumRat: {
    2159            0 :                         node.HumRatSetPoint = SchedValue;
    2160            0 :                     } break;
    2161            1 :                     case HVAC::CtrlVarType::MaxHumRat: {
    2162            1 :                         node.HumRatMax = SchedValue;
    2163            1 :                     } break;
    2164            0 :                     case HVAC::CtrlVarType::MinHumRat: {
    2165            0 :                         node.HumRatMin = SchedValue;
    2166            0 :                     } break;
    2167            0 :                     case HVAC::CtrlVarType::MassFlowRate: {
    2168            0 :                         node.MassFlowRateSetPoint = SchedValue;
    2169            0 :                     } break;
    2170            0 :                     case HVAC::CtrlVarType::MaxMassFlowRate: {
    2171            0 :                         node.MassFlowRateMax = SchedValue;
    2172            0 :                     } break;
    2173            0 :                     case HVAC::CtrlVarType::MinMassFlowRate: {
    2174            0 :                         node.MassFlowRateMin = SchedValue;
    2175            0 :                     } break;
    2176            0 :                     default:
    2177            0 :                         break;
    2178              :                     }
    2179              :                 }
    2180          281 :             } break;
    2181              : 
    2182            8 :             case SPMType::ScheduledDual: {
    2183            8 :                 auto *spmSD = dynamic_cast<SPMScheduledDual *>(spm);
    2184            8 :                 assert(spmSD != nullptr);
    2185           16 :                 for (int ctrlNodeNum : spmSD->ctrlNodeNums) {
    2186            8 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2187            8 :                     if (spmSD->ctrlVar == HVAC::CtrlVarType::Temp) {
    2188            8 :                         node.TempSetPointHi = spmSD->hiSched->getCurrentVal();
    2189            8 :                         node.TempSetPointLo = spmSD->loSched->getCurrentVal();
    2190            8 :                         node.TempSetPoint = (node.TempSetPointHi + node.TempSetPointLo) / 2.0;
    2191              :                     }
    2192              :                 }
    2193            8 :             } break;
    2194              : 
    2195           20 :             case SPMType::OutsideAir: {
    2196           20 :                 auto *spmOA = dynamic_cast<SPMOutsideAir *>(spm);
    2197           20 :                 assert(spmOA != nullptr);
    2198              : 
    2199           52 :                 for (int NodeNum : spmOA->ctrlNodeNums) {
    2200           32 :                     spmOA->calculate(state); // Why is this calculated for every node?
    2201              : 
    2202           32 :                     auto &node = state.dataLoopNodes->Node(NodeNum);
    2203           32 :                     if (spmOA->ctrlVar == HVAC::CtrlVarType::Temp) {
    2204           30 :                         node.TempSetPoint = spmOA->setPt;
    2205            2 :                     } else if (spmOA->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    2206            1 :                         node.TempSetPointHi = spmOA->setPt;
    2207            1 :                     } else if (spmOA->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    2208            1 :                         node.TempSetPointLo = spmOA->setPt;
    2209              :                     }
    2210              :                 }
    2211           20 :             } break;
    2212              : 
    2213            0 :             case SPMType::SZMinHum: {
    2214            0 :                 auto *spmSZH = dynamic_cast<SPMSingleZoneHum *>(spm);
    2215            0 :                 assert(spmSZH != nullptr);
    2216              : 
    2217            0 :                 state.dataLoopNodes->Node(spmSZH->zoneNodeNum).MassFlowRate = 0.0;
    2218            0 :                 for (int ctrlNodeNum : spmSZH->ctrlNodeNums) {
    2219            0 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMin = 0.007;
    2220              :                 }
    2221            0 :             } break;
    2222              : 
    2223            4 :             case SPMType::SZMaxHum: {
    2224            4 :                 auto *spmSZH = dynamic_cast<SPMSingleZoneHum *>(spm);
    2225            4 :                 assert(spmSZH != nullptr);
    2226              : 
    2227            4 :                 state.dataLoopNodes->Node(spmSZH->zoneNodeNum).MassFlowRate = 0.0;
    2228            8 :                 for (int ctrlNodeNum : spmSZH->ctrlNodeNums) {
    2229            4 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMax = 0.011;
    2230              :                 }
    2231            4 :             } break;
    2232              : 
    2233           21 :             case SPMType::SZReheat: {
    2234           21 :                 auto *spmSZR = dynamic_cast<SPMSingleZoneReheat *>(spm);
    2235           21 :                 assert(spmSZR != nullptr);
    2236              : 
    2237           21 :                 state.dataLoopNodes->Node(spmSZR->zoneInletNodeNum).MassFlowRate = 0.0;
    2238           21 :                 state.dataLoopNodes->Node(spmSZR->zoneNodeNum).MassFlowRate = 0.0;
    2239           21 :                 if (spmSZR->ctrlVar == HVAC::CtrlVarType::Temp) {
    2240           42 :                     for (int ctrlNodeNum : spmSZR->ctrlNodeNums) {
    2241           21 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2242              :                     }
    2243              :                 }
    2244              : 
    2245           21 :             } break;
    2246              : 
    2247            8 :             case SPMType::SZHeating:
    2248              :             case SPMType::SZCooling: {
    2249            8 :                 auto *spmSZT = dynamic_cast<SPMSingleZoneTemp *>(spm);
    2250            8 :                 assert(spmSZT != nullptr);
    2251              : 
    2252            8 :                 state.dataLoopNodes->Node(spmSZT->zoneInletNodeNum).MassFlowRate = 0.0;
    2253            8 :                 state.dataLoopNodes->Node(spmSZT->zoneNodeNum).MassFlowRate = 0.0;
    2254              : 
    2255            8 :                 if (spmSZT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2256           16 :                     for (int ctrlNodeNum : spmSZT->ctrlNodeNums) {
    2257            8 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2258              :                     }
    2259              :                 }
    2260            8 :             } break;
    2261              : 
    2262          223 :             case SPMType::MixedAir: {
    2263          223 :                 auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
    2264          223 :                 assert(spmMA != nullptr);
    2265              : 
    2266          223 :                 auto &refNode = state.dataLoopNodes->Node(spmMA->refNodeNum);
    2267          223 :                 auto &fanInNode = state.dataLoopNodes->Node(spmMA->fanInNodeNum);
    2268          223 :                 auto &fanOutNode = state.dataLoopNodes->Node(spmMA->fanOutNodeNum);
    2269              : 
    2270          223 :                 refNode.MassFlowRate = fanInNode.MassFlowRate = fanOutNode.MassFlowRate = 0.0;
    2271          223 :                 refNode.Temp = fanInNode.Temp = fanOutNode.Temp = 20.0;
    2272          223 :                 refNode.HumRat = fanInNode.HumRat = fanOutNode.HumRat = state.dataEnvrn->OutHumRat;
    2273          223 :                 refNode.Quality = fanInNode.Quality = fanOutNode.Quality = 1.0;
    2274          223 :                 refNode.Press = fanInNode.Press = fanOutNode.Press = state.dataEnvrn->OutBaroPress;
    2275          223 :                 refNode.Enthalpy = fanInNode.Enthalpy = fanOutNode.Enthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
    2276              : 
    2277          223 :                 if (spmMA->ctrlVar == HVAC::CtrlVarType::Temp) {
    2278          515 :                     for (int ctrlNodeNum : spmMA->ctrlNodeNums) {
    2279          292 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2280              :                     }
    2281              :                 }
    2282              : 
    2283          223 :             } break;
    2284              : 
    2285            1 :             case SPMType::OutsideAirPretreat: {
    2286            1 :                 auto *spmOAP = dynamic_cast<SPMOutsideAirPretreat *>(spm);
    2287            1 :                 assert(spmOAP != nullptr);
    2288              : 
    2289            1 :                 auto &refNode = state.dataLoopNodes->Node(spmOAP->refNodeNum);
    2290            1 :                 auto &mixedOutNode = state.dataLoopNodes->Node(spmOAP->mixedOutNodeNum);
    2291            1 :                 auto &oaInNode = state.dataLoopNodes->Node(spmOAP->oaInNodeNum);
    2292            1 :                 auto &returnInNode = state.dataLoopNodes->Node(spmOAP->returnInNodeNum);
    2293              : 
    2294            1 :                 refNode.MassFlowRate = mixedOutNode.MassFlowRate = oaInNode.MassFlowRate = returnInNode.MassFlowRate = 0.0;
    2295            1 :                 refNode.Temp = mixedOutNode.Temp = oaInNode.Temp = returnInNode.Temp = 20.0;
    2296            1 :                 refNode.HumRat = mixedOutNode.HumRat = oaInNode.HumRat = returnInNode.HumRat = state.dataEnvrn->OutHumRat;
    2297            1 :                 refNode.Quality = mixedOutNode.Quality = oaInNode.Quality = returnInNode.Quality = 1.0;
    2298            1 :                 refNode.Press = mixedOutNode.Press = oaInNode.Press = returnInNode.Press = state.dataEnvrn->OutBaroPress;
    2299            1 :                 refNode.Enthalpy = mixedOutNode.Enthalpy = oaInNode.Enthalpy = returnInNode.Enthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
    2300              : 
    2301            2 :                 for (int ctrlNodeNum : spmOAP->ctrlNodeNums) {
    2302            1 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2303            1 :                     if (spmOAP->ctrlVar == HVAC::CtrlVarType::Temp) {
    2304            0 :                         node.TempSetPoint = 20.0; // Set the setpoint
    2305            1 :                     } else if (spmOAP->ctrlVar == HVAC::CtrlVarType::MaxHumRat) {
    2306            1 :                         node.HumRatMax = state.dataEnvrn->OutHumRat; // Set the setpoint
    2307            0 :                     } else if (spmOAP->ctrlVar == HVAC::CtrlVarType::MinHumRat) {
    2308            0 :                         node.HumRatMin = state.dataEnvrn->OutHumRat; // Set the setpoint
    2309            0 :                     } else if (spmOAP->ctrlVar == HVAC::CtrlVarType::HumRat) {
    2310            0 :                         node.HumRatSetPoint = state.dataEnvrn->OutHumRat; // Set the setpoint
    2311              :                     }
    2312              :                 }
    2313            1 :             } break;
    2314              : 
    2315           24 :             case SPMType::Warmest:
    2316              :             case SPMType::Coldest: {
    2317              : 
    2318           48 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2319           24 :                     if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    2320           24 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2321              :                     }
    2322              :                 }
    2323              : 
    2324           24 :             } break;
    2325              : 
    2326            0 :             case SPMType::WarmestTempFlow: {
    2327            0 :                 auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    2328            0 :                 assert(spmWTF != nullptr);
    2329              : 
    2330            0 :                 if (spmWTF->ctrlVar == HVAC::CtrlVarType::Temp) {
    2331            0 :                     for (int ctrlNodeNum : spmWTF->ctrlNodeNums) {
    2332            0 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the temperature setpoint
    2333            0 :                         if (spmWTF->airLoopNum != 0) {
    2334            0 :                             state.dataAirLoop->AirLoopFlow(spmWTF->airLoopNum).ReqSupplyFrac = 1.0;           // PH 10/09/04 Set the flow
    2335            0 :                             state.dataAirLoop->AirLoopControlInfo(spmWTF->airLoopNum).LoopFlowRateSet = true; // PH 10/09/04 Set the flag
    2336              :                         }
    2337              :                     }
    2338              :                 }
    2339            0 :             } break;
    2340              : 
    2341            0 :             case SPMType::ReturnAirBypass: {
    2342            0 :                 if (state.dataZoneEquip->ZoneEquipInputsFilled && state.dataAirLoop->AirLoopInputsFilled) {
    2343              : 
    2344            0 :                     auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    2345            0 :                     assert(spmRAB != nullptr);
    2346              : 
    2347            0 :                     if (spmRAB->ctrlVar == HVAC::CtrlVarType::MassFlowRate) {
    2348            0 :                         state.dataLoopNodes->Node(spmRAB->rabSplitOutNodeNum).MassFlowRateSetPoint = 0.0;
    2349              :                     }
    2350              :                 }
    2351            0 :             } break;
    2352              : 
    2353            0 :             case SPMType::MZCoolingAverage:
    2354              :             case SPMType::MZHeatingAverage: {
    2355            0 :                 if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    2356            0 :                     for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2357            0 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2358              :                     }
    2359              :                 }
    2360            0 :             } break;
    2361              : 
    2362            0 :             case SPMType::MZMinHumAverage:
    2363              :             case SPMType::MZMinHum: {
    2364            0 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2365            0 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMin = 0.007; // Set the setpoint
    2366              :                 }
    2367            0 :             } break;
    2368              : 
    2369            0 :             case SPMType::MZMaxHumAverage:
    2370              :             case SPMType::MZMaxHum: {
    2371            0 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2372            0 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMax = 0.011; // Set the setpoint
    2373              :                 }
    2374            0 :             } break;
    2375              : 
    2376            6 :             case SPMType::FollowOutsideAirTemp: {
    2377            6 :                 auto *spmFOAT = dynamic_cast<SPMFollowOutsideAirTemp *>(spm);
    2378            6 :                 assert(spmFOAT != nullptr);
    2379            6 :                 bool isWetBulb = spmFOAT->refTempType == AirTempType::WetBulb;
    2380              : 
    2381           12 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2382            6 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2383            6 :                     if (spmFOAT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2384            6 :                         node.TempSetPoint = isWetBulb ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp;
    2385            0 :                     } else if (spmFOAT->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    2386            0 :                         node.TempSetPointHi = isWetBulb ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp;
    2387            0 :                     } else if (spmFOAT->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    2388            0 :                         node.TempSetPointLo = isWetBulb ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp;
    2389              :                     }
    2390              :                 }
    2391            6 :             } break;
    2392              : 
    2393            0 :             case SPMType::FollowSystemNodeTemp: {
    2394            0 :                 auto *spmFSNT = dynamic_cast<SPMFollowSysNodeTemp *>(spm);
    2395            0 :                 assert(spmFSNT != nullptr);
    2396              : 
    2397            0 :                 bool isWetBulb = spmFSNT->refTempType == AirTempType::WetBulb;
    2398            0 :                 auto &refNode = state.dataLoopNodes->Node(spmFSNT->refNodeNum);
    2399            0 :                 for (int ctrlNodeNum : spmFSNT->ctrlNodeNums) {
    2400            0 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2401            0 :                     if (CheckOutAirNodeNumber(state, spmFSNT->refNodeNum)) {
    2402            0 :                         refNode.SPMNodeWetBulbRepReq = isWetBulb;
    2403            0 :                         if (spmFSNT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2404            0 :                             node.TempSetPoint = isWetBulb ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp;
    2405            0 :                         } else if (spmFSNT->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    2406            0 :                             node.TempSetPointHi = isWetBulb ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp;
    2407            0 :                         } else if (spmFSNT->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    2408            0 :                             node.TempSetPointLo = isWetBulb ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp;
    2409              :                         }
    2410              :                     } else { // If reference node is a water node, then set RefTypeMode to NodeDryBulb
    2411              : 
    2412            0 :                         if (refNode.FluidType == DataLoopNode::NodeFluidType::Water) {
    2413            0 :                             spmFSNT->refTempType = AirTempType::DryBulb;
    2414            0 :                         } else if (refNode.FluidType == DataLoopNode::NodeFluidType::Air) {
    2415            0 :                             if (spmFSNT->refTempType == AirTempType::WetBulb) {
    2416            0 :                                 refNode.SPMNodeWetBulbRepReq = true;
    2417              :                             }
    2418              :                         }
    2419            0 :                         if (spmFSNT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2420            0 :                             node.TempSetPoint = 20.0; // Set the setpoint
    2421            0 :                         } else if (spmFSNT->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    2422            0 :                             node.TempSetPointHi = 20.0; // Set the setpoint
    2423            0 :                         } else if (spmFSNT->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    2424            0 :                             node.TempSetPointLo = 20.0; // Set the setpoint
    2425              :                         }
    2426              :                     }
    2427              :                 }
    2428            0 :             } break;
    2429              : 
    2430           13 :             case SPMType::FollowGroundTemp: {
    2431           13 :                 auto *spmFGT = dynamic_cast<SPMFollowGroundTemp *>(spm);
    2432           13 :                 assert(spmFGT != nullptr);
    2433              : 
    2434           13 :                 Real64 GroundTemp = state.dataEnvrn->GroundTemp[(int)spmFGT->refTempType];
    2435              : 
    2436           26 :                 for (int ctrlNodeNum : spmFGT->ctrlNodeNums) {
    2437           13 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2438           13 :                     if (spmFGT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2439           13 :                         node.TempSetPoint = GroundTemp;
    2440            0 :                     } else if (spmFGT->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    2441            0 :                         node.TempSetPointHi = GroundTemp;
    2442            0 :                     } else if (spmFGT->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    2443            0 :                         node.TempSetPointLo = GroundTemp;
    2444              :                     }
    2445              :                 }
    2446           13 :             } break;
    2447              : 
    2448            0 :             case SPMType::CondenserEnteringTemp: {
    2449            0 :                 auto *spmCER = dynamic_cast<SPMCondenserEnteringTemp *>(spm);
    2450            0 :                 assert(spmCER != nullptr);
    2451            0 :                 Real64 SchedValue = spmCER->condenserEnteringTempSched->getCurrentVal();
    2452            0 :                 for (int ctrlNodeNum : spmCER->ctrlNodeNums) {
    2453            0 :                     if (spmCER->ctrlVar == HVAC::CtrlVarType::Temp) {
    2454            0 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = SchedValue;
    2455              :                     }
    2456              :                 }
    2457            0 :             } break;
    2458              : 
    2459            0 :             case SPMType::IdealCondenserEnteringTemp: {
    2460            0 :                 auto const *spmICER = dynamic_cast<SPMIdealCondenserEnteringTemp *>(spm);
    2461            0 :                 assert(spmICER != nullptr);
    2462              : 
    2463            0 :                 if (spmICER->ctrlVar == HVAC::CtrlVarType::Temp) {
    2464            0 :                     for (int ctrlNodeNum : spmICER->ctrlNodeNums) {
    2465            0 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmICER->maxCondenserEnteringTemp;
    2466              :                     }
    2467              :                 }
    2468            0 :             } break;
    2469              : 
    2470            0 :             case SPMType::SZOneStageCooling: {
    2471            0 :                 auto const *spmSZOSC = dynamic_cast<SPMSingleZoneOneStageCooling *>(spm);
    2472            0 :                 assert(spmSZOSC != nullptr);
    2473              : 
    2474            0 :                 if (spmSZOSC->ctrlVar == HVAC::CtrlVarType::Temp) {
    2475            0 :                     for (int ctrlNodeNum : spmSZOSC->ctrlNodeNums) {
    2476            0 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmSZOSC->coolingOffSetPt;
    2477              :                     }
    2478              :                 }
    2479            0 :             } break;
    2480              : 
    2481            0 :             case SPMType::SZOneStageHeating: {
    2482            0 :                 auto const *spmSZOSH = dynamic_cast<SPMSingleZoneOneStageHeating *>(spm);
    2483            0 :                 assert(spmSZOSH != nullptr);
    2484              : 
    2485            0 :                 if (spmSZOSH->ctrlVar == HVAC::CtrlVarType::Temp) {
    2486            0 :                     for (int ctrlNodeNum : spmSZOSH->ctrlNodeNums) {
    2487            0 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmSZOSH->heatingOffSetPt;
    2488              :                     }
    2489              :                 }
    2490              : 
    2491            0 :             } break;
    2492              : 
    2493            0 :             case SPMType::ChilledWaterReturnTemp: {
    2494            0 :                 auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    2495            0 :                 assert(spmRWT != nullptr);
    2496              : 
    2497            0 :                 state.dataLoopNodes->Node(spmRWT->supplyNodeNum).TempSetPoint = spmRWT->minSetTemp;
    2498              : 
    2499            0 :             } break;
    2500              : 
    2501            0 :             case SPMType::HotWaterReturnTemp: {
    2502            0 :                 auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    2503            0 :                 assert(spmRWT != nullptr);
    2504              : 
    2505            0 :                 state.dataLoopNodes->Node(spmRWT->supplyNodeNum).TempSetPoint = spmRWT->maxSetTemp;
    2506            0 :             } break;
    2507              : 
    2508            2 :             case SPMType::SystemNodeTemp:
    2509              :             case SPMType::SystemNodeHum: {
    2510            4 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2511            2 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2512            2 :                     spm->calculate(state);
    2513            2 :                     switch (spm->ctrlVar) {
    2514            1 :                     case HVAC::CtrlVarType::Temp: {
    2515            1 :                         node.TempSetPoint = spm->setPt;
    2516            1 :                     } break;
    2517            0 :                     case HVAC::CtrlVarType::MaxTemp: {
    2518            0 :                         node.TempSetPointHi = spm->setPt;
    2519            0 :                     } break;
    2520            0 :                     case HVAC::CtrlVarType::MinTemp: {
    2521            0 :                         node.TempSetPointLo = spm->setPt;
    2522            0 :                     } break;
    2523            1 :                     case HVAC::CtrlVarType::HumRat: {
    2524            1 :                         node.HumRatSetPoint = spm->setPt;
    2525            1 :                     } break;
    2526            0 :                     case HVAC::CtrlVarType::MaxHumRat: {
    2527            0 :                         node.HumRatMax = spm->setPt;
    2528            0 :                     } break;
    2529            0 :                     case HVAC::CtrlVarType::MinHumRat: {
    2530            0 :                         node.HumRatMin = spm->setPt;
    2531            0 :                     } break;
    2532            0 :                     default:
    2533            0 :                         break;
    2534              :                     }
    2535              :                 }
    2536            2 :             } break;
    2537              : 
    2538            0 :             default:
    2539            0 :                 break;
    2540              :             } // switch (spm->type)
    2541              :         }     // for (spm)
    2542              : 
    2543          499 :         state.dataSetPointManager->InitSetPointManagersMyEnvrnFlag = false;
    2544          499 :         if (!state.dataSetPointManager->InitSetPointManagersOneTimeFlag) state.dataSetPointManager->InitSetPointManagersOneTimeFlag2 = false;
    2545              : 
    2546          499 :         if (ErrorsFound) {
    2547            0 :             ShowFatalError(state, "InitSetPointManagers: Errors found. Program Terminates.");
    2548              :         }
    2549              : 
    2550              :     } // end begin environment inits
    2551              : 
    2552       208581 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    2553       207843 :         state.dataSetPointManager->InitSetPointManagersMyEnvrnFlag = true;
    2554              :     }
    2555       208581 : } // InitSetPointManagers()
    2556              : 
    2557       208099 : void SimSetPointManagers(EnergyPlusData &state)
    2558              : {
    2559              :     // SUBROUTINE INFORMATION:
    2560              :     //       AUTHOR         Fred Buhl
    2561              :     //       DATE WRITTEN   July 1998
    2562              :     //       MODIFIED       Shirey/Raustad (FSEC), Jan 2004
    2563              :     //                      Nov 2004 M. J. Witte, GARD Analytics, Inc.
    2564              :     //                        Add new setpoint managers:
    2565              :     //                          SET POINT MANAGER:SINGLE ZONE HEATING and
    2566              :     //                          SET POINT MANAGER:SINGLE ZONE COOLING
    2567              :     //                        Work supported by ASHRAE research project 1254-RP
    2568              :     //                      Haves Oct 2004
    2569              :     //                      July 2010 B.A. Nigusse, FSEC/UCF
    2570              :     //                        Added new setpoint managers
    2571              :     //                          SetpointManager:MultiZone:Heating:Average
    2572              :     //                          SetpointManager:MultiZone:Cooling:Average
    2573              :     //                          SetpointManager:MultiZone:MinimumHumidity:Average
    2574              :     //                          SetpointManager:MultiZone:MaximumHumidity:Average
    2575              :     //                      Aug 2010 B.A. Nigusse, FSEC/UCF
    2576              :     //                        Added new setpoint managers:
    2577              :     //                          SetpointManager:MultiZone:Humidity:Minimum
    2578              :     //                          SetpointManager:MultiZone:Humidity:Maximum
    2579              :     //                      Aug 2014 Rick Strand, UIUC
    2580              :     //                         SetpointManager:ScheduleTES (internally defined)
    2581              :     //                      Jan 2022 Wooyoung Jung, Jeremy Lerond and Jian Zhang, PNNL
    2582              :     //                        Added new setpoint managers:
    2583              :     //                          SetpointManager:SystemNodeReset:Temperature
    2584              :     //                          SetpointManager:SystemNodeReset:Humidity
    2585              : 
    2586              :     // PURPOSE OF THIS SUBROUTINE
    2587              :     // Loop over all the Setpoint Managers and invoke the correct
    2588              :     // Setpoint Manager algorithm.
    2589              : 
    2590       340424 :     for (auto *spm : state.dataSetPointManager->spms) {
    2591       132325 :         if (spm->type != SPMType::MixedAir && spm->type != SPMType::OutsideAirPretreat) {
    2592        76744 :             spm->calculate(state);
    2593              :         }
    2594              :     }
    2595       208099 : } // SimSetPointManagers()
    2596              : 
    2597        53919 : void SPMScheduled::calculate([[maybe_unused]] EnergyPlusData &state)
    2598              : {
    2599              :     // SUBROUTINE INFORMATION:
    2600              :     //       AUTHOR         Fred Buhl
    2601              :     //       DATE WRITTEN   July 1998
    2602              : 
    2603              :     // PURPOSE OF THIS SUBROUTINE:
    2604              :     // Set the setpoint using a simple schedule.
    2605        53919 :     this->setPt = this->sched->getCurrentVal();
    2606        53919 : } // SPMScheduled::calculate()
    2607              : 
    2608            6 : void SPMTESScheduled::calculate([[maybe_unused]] EnergyPlusData &state)
    2609              : {
    2610              :     // SUBROUTINE INFORMATION:
    2611              :     //       AUTHOR         Rick Strand
    2612              :     //       DATE WRITTEN   Aug 2014
    2613              : 
    2614              :     // PURPOSE OF THIS SUBROUTINE:
    2615              :     // Set the setpoint using a simple schedule, then modify the value based on TES simple controls logic
    2616              : 
    2617              :     // METHODOLOGY EMPLOYED:
    2618              :     // Modified schedule setpoint manager logic
    2619              : 
    2620              :     // Locals
    2621            6 :     Real64 constexpr OnVal(0.5);
    2622              : 
    2623            6 :     Real64 CurSchValOnPeak = this->sched->getCurrentVal();
    2624            6 :     Real64 CurSchValCharge = this->chargeSched->getCurrentVal();
    2625              : 
    2626              :     // CtrlType bug
    2627              :     //        if (this->CompOpType == DataPlant::CtrlType::CoolingOp) { // this is some sort of chiller
    2628            6 :     if (this->compOpType == DataPlant::CtrlType::HeatingOp) { // this is some sort of chiller
    2629            4 :         if (CurSchValOnPeak >= OnVal) {
    2630            1 :             this->setPt = this->nonChargeCHWTemp;
    2631            3 :         } else if (CurSchValCharge < OnVal) {
    2632            2 :             this->setPt = this->nonChargeCHWTemp;
    2633              :         } else {
    2634            1 :             this->setPt = this->chargeCHWTemp;
    2635              :         }
    2636              :         // CtrlType Bug
    2637              :         //        } else if (this->CompOpType == DataPlant::CtrlType::DualOp) { // this is some sort of ice storage system
    2638            2 :     } else if (this->compOpType == DataPlant::CtrlType::CoolingOp) { // this is some sort of ice storage system
    2639            2 :         this->setPt = this->nonChargeCHWTemp;
    2640              :     }
    2641            6 : } // SPMTESSScheduled::calculate()
    2642              : 
    2643          576 : void SPMScheduledDual::calculate([[maybe_unused]] EnergyPlusData &state)
    2644              : {
    2645              :     // SUBROUTINE INFORMATION:
    2646              :     //       AUTHOR         Richard Liesen
    2647              :     //       DATE WRITTEN   May 2004
    2648              : 
    2649              :     // PURPOSE OF THIS SUBROUTINE:
    2650              :     // Set the both setpoint using a simple schedule.
    2651          576 :     this->setPtHi = this->hiSched->getCurrentVal();
    2652          576 :     this->setPtLo = this->loSched->getCurrentVal();
    2653          576 : } // SPMScheduledDual::calculate()
    2654              : 
    2655         6107 : void SPMOutsideAir::calculate(EnergyPlusData &state)
    2656              : {
    2657         6107 :     Real64 SchedVal = (this->sched != nullptr) ? this->sched->getCurrentVal() : 0.0;
    2658              : 
    2659         6107 :     if (SchedVal == 2.0) {
    2660            1 :         this->setPt = interpSetPoint(this->low2, this->high2, state.dataEnvrn->OutDryBulbTemp, this->lowSetPt2, this->highSetPt2);
    2661              :     } else {
    2662         6106 :         if ((this->sched != nullptr) && (SchedVal != 1.0)) { // Since schedule is optional, only check this if the user entered a schedule
    2663            1 :             ++this->setPtErrorCount;
    2664            1 :             if (this->setPtErrorCount <= 10) {
    2665            2 :                 ShowSevereError(state,
    2666            2 :                                 format("Schedule Values for the Outside Air Setpoint Manager = {} are something other than 1 or 2.", this->Name));
    2667            1 :                 ShowContinueError(state, format("...the value for the schedule currently is {}", SchedVal));
    2668            3 :                 ShowContinueError(state, "...the value is being interpreted as 1 for this run but should be fixed.");
    2669              :             } else {
    2670            0 :                 ShowRecurringSevereErrorAtEnd(
    2671              :                     state,
    2672            0 :                     format("Schedule Values for the Outside Air Setpoint Manager = {} are something other than 1 or 2.", this->Name),
    2673            0 :                     this->invalidSchedValErrorIndex);
    2674              :             }
    2675              :         }
    2676         6106 :         this->setPt = interpSetPoint(this->low1, this->high1, state.dataEnvrn->OutDryBulbTemp, this->lowSetPt1, this->highSetPt1);
    2677              :     }
    2678              : 
    2679         6107 : } // SPMOutsideAir::calculate()
    2680              : 
    2681         8686 : void SPMSingleZoneReheat::calculate(EnergyPlusData &state)
    2682              : {
    2683              :     // SUBROUTINE INFORMATION:
    2684              :     //       AUTHOR         Fred Buhl
    2685              :     //       DATE WRITTEN   May 2000
    2686              : 
    2687              :     // PURPOSE OF THIS SUBROUTINE:
    2688              :     // From the heating or cooling load of the control zone, calculate the supply air setpoint
    2689              :     // needed to meet that zone load
    2690              : 
    2691              :     // Using/Aliasing
    2692              :     using namespace DataZoneEnergyDemands;
    2693              :     using Psychrometrics::PsyTdbFnHW;
    2694              : 
    2695              :     Real64 TSetPt;
    2696              : 
    2697         8686 :     auto const &zoneInletNode = state.dataLoopNodes->Node(this->zoneInletNodeNum);
    2698              : 
    2699              :     // changed from MinOAFrac, now updates to current oa fraction for improve deadband control
    2700         8686 :     Real64 OAFrac = state.dataAirLoop->AirLoopFlow(this->airLoopNum).OAFrac;
    2701         8686 :     Real64 ZoneMassFlow = zoneInletNode.MassFlowRate;
    2702              : 
    2703         8686 :     auto const &zoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum);
    2704         8686 :     Real64 ZoneLoad = zoneSysEnergyDemand.TotalOutputRequired;
    2705         8686 :     Real64 ZoneLoadToCoolSetPt = zoneSysEnergyDemand.OutputRequiredToCoolingSP;
    2706         8686 :     Real64 ZoneLoadToHeatSetPt = zoneSysEnergyDemand.OutputRequiredToHeatingSP;
    2707         8686 :     bool DeadBand = state.dataZoneEnergyDemand->DeadBandOrSetback(this->ctrlZoneNum);
    2708         8686 :     Real64 ZoneTemp = state.dataLoopNodes->Node(this->zoneNodeNum).Temp;
    2709              : 
    2710              :     Real64 TMixAtMinOA;
    2711         8686 :     if (this->oaInNodeNum > 0) {
    2712         8686 :         auto const &oaInNode = state.dataLoopNodes->Node(this->oaInNodeNum);
    2713         8686 :         auto const &retNode = state.dataLoopNodes->Node(this->retNodeNum);
    2714         8686 :         Real64 HumRatMixAtMinOA = (1.0 - OAFrac) * retNode.HumRat + OAFrac * oaInNode.HumRat;
    2715         8686 :         Real64 EnthMixAtMinOA = (1.0 - OAFrac) * retNode.Enthalpy + OAFrac * oaInNode.Enthalpy;
    2716         8686 :         TMixAtMinOA = PsyTdbFnHW(EnthMixAtMinOA, HumRatMixAtMinOA);
    2717              :     } else {
    2718            0 :         TMixAtMinOA = state.dataLoopNodes->Node(this->loopInNodeNum).Temp;
    2719              :     }
    2720              : 
    2721              :     Real64 FanDeltaT;
    2722         8686 :     if (this->fanOutNodeNum > 0 && this->fanInNodeNum > 0) {
    2723         1414 :         FanDeltaT = state.dataLoopNodes->Node(this->fanOutNodeNum).Temp - state.dataLoopNodes->Node(this->fanInNodeNum).Temp;
    2724              :     } else {
    2725         7272 :         FanDeltaT = 0.0;
    2726              :     }
    2727              : 
    2728         8686 :     Real64 TSupNoHC = TMixAtMinOA + FanDeltaT;
    2729         8686 :     Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    2730         8686 :     Real64 ExtrRateNoHC = CpAir * ZoneMassFlow * (TSupNoHC - ZoneTemp);
    2731         8686 :     if (ZoneMassFlow <= HVAC::SmallMassFlow) {
    2732         2212 :         TSetPt = TSupNoHC;
    2733              : 
    2734         6474 :     } else if (DeadBand || std::abs(ZoneLoad) < HVAC::SmallLoad) {
    2735              :         // if air with no active heating or cooling provides cooling
    2736           67 :         if (ExtrRateNoHC < 0.0) {
    2737              :             // if still in deadband, do no active heating or cooling;
    2738              :             // if below heating setpoint, set a supply temp that will cool to the heating setpoint
    2739           63 :             TSetPt = (ExtrRateNoHC >= ZoneLoadToHeatSetPt) ? TSupNoHC : (ZoneTemp + ZoneLoadToHeatSetPt / (CpAir * ZoneMassFlow));
    2740              : 
    2741              :             // if air with no active heating or cooling provides heating
    2742            4 :         } else if (ExtrRateNoHC > 0.0) {
    2743              :             // if still in deadband, do no active heating or cooling;
    2744              :             // if above cooling setpoint, set a supply temp that will heat to the cooling setpoint
    2745            4 :             TSetPt = (ExtrRateNoHC <= ZoneLoadToCoolSetPt) ? TSupNoHC : (ZoneTemp + ZoneLoadToCoolSetPt / (CpAir * ZoneMassFlow));
    2746              : 
    2747              :         } else {
    2748            0 :             TSetPt = TSupNoHC;
    2749              :         }
    2750              : 
    2751         6407 :     } else if (ZoneLoad < (-1.0 * HVAC::SmallLoad)) {
    2752         1322 :         Real64 TSetPt1 = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlow);
    2753         1322 :         Real64 TSetPt2 = ZoneTemp + ZoneLoadToHeatSetPt / (CpAir * ZoneMassFlow);
    2754         1322 :         TSetPt = (TSetPt1 <= TSupNoHC) ? TSetPt1 : ((TSetPt2 > TSupNoHC) ? TSetPt2 : TSupNoHC);
    2755              : 
    2756         5085 :     } else if (ZoneLoad > HVAC::SmallLoad) {
    2757         5085 :         Real64 TSetPt1 = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlow);
    2758         5085 :         Real64 TSetPt2 = ZoneTemp + ZoneLoadToCoolSetPt / (CpAir * ZoneMassFlow);
    2759         5085 :         TSetPt = (TSetPt1 >= TSupNoHC) ? TSetPt1 : ((TSetPt2 < TSupNoHC) ? TSetPt2 : TSupNoHC);
    2760              : 
    2761              :     } else {
    2762            0 :         TSetPt = TSupNoHC;
    2763              :     }
    2764              : 
    2765         8686 :     this->setPt = std::clamp(TSetPt, this->minSetTemp, this->maxSetTemp);
    2766         8686 : } // SPMSZReheat::calculate()
    2767              : 
    2768           10 : void SPMSingleZoneTemp::calculate(EnergyPlusData &state)
    2769              : {
    2770              :     // SUBROUTINE INFORMATION:
    2771              :     //       AUTHOR         M. J. Witte based on CalcSingZoneRhSetPoint by Fred Buhl,
    2772              :     //                        Work supported by ASHRAE research project 1254-RP
    2773              :     //       DATE WRITTEN   November 2004
    2774              : 
    2775              :     // PURPOSE OF THIS SUBROUTINE:
    2776              :     // From the heating load of the control zone, calculate the supply air setpoint
    2777              :     // needed to meet that zone load (based on CalcSingZoneRhSetPoint)
    2778           10 :     auto const &zoneInletNode = state.dataLoopNodes->Node(this->zoneInletNodeNum);
    2779              : 
    2780              :     // This function handles both heating and cooling
    2781           10 :     auto const &zoneEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum);
    2782           10 :     Real64 ZoneLoadToSP =
    2783           10 :         (this->type == SPMType::SZHeating) ? zoneEnergyDemand.OutputRequiredToHeatingSP : zoneEnergyDemand.OutputRequiredToCoolingSP;
    2784              : 
    2785           10 :     Real64 ZoneTemp = state.dataLoopNodes->Node(this->zoneNodeNum).Temp;
    2786           10 :     if (zoneInletNode.MassFlowRate <= HVAC::SmallMassFlow) {
    2787            0 :         this->setPt = (this->type == SPMType::SZHeating) ? this->minSetTemp : this->maxSetTemp;
    2788              :     } else {
    2789           10 :         Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    2790           10 :         this->setPt = ZoneTemp + ZoneLoadToSP / (CpAir * zoneInletNode.MassFlowRate);
    2791           10 :         this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    2792              :     }
    2793           10 : } // SPMSZTemp::calculate()
    2794              : 
    2795            0 : void SPMSingleZoneOneStageCooling::calculate(EnergyPlusData &state)
    2796              : {
    2797              :     // SUBROUTINE INFORMATION:
    2798              :     //       AUTHOR         B. Griffith
    2799              :     //       DATE WRITTEN   August 2013
    2800              : 
    2801              :     // PURPOSE OF THIS SUBROUTINE:
    2802              :     // calculate the setpoint for staged on/off cooling
    2803              : 
    2804              :     // METHODOLOGY EMPLOYED:
    2805              :     // Evaluate stage in zone energy demand structure and choose setpoint accordingly
    2806              : 
    2807            0 :     this->setPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum).StageNum >= 0) ? this->coolingOffSetPt : this->coolingOnSetPt;
    2808              :     // negative so a cooling stage is set
    2809            0 : } // SPMSingleZoneOneStageCooling::calculate()
    2810              : 
    2811            0 : void SPMSingleZoneOneStageHeating::calculate(EnergyPlusData &state)
    2812              : {
    2813              :     // SUBROUTINE INFORMATION:
    2814              :     //       AUTHOR         B. Griffith
    2815              :     //       DATE WRITTEN   August 2013
    2816              : 
    2817              :     // PURPOSE OF THIS SUBROUTINE:
    2818              :     // calculate the setpoint for staged on/off control
    2819              : 
    2820              :     // METHODOLOGY EMPLOYED:
    2821              :     // Evaluate stage in zone energy demand structure and choose setpoint accordingly
    2822              : 
    2823            0 :     this->setPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum).StageNum <= 0) ? this->heatingOffSetPt : this->heatingOnSetPt;
    2824            0 : } // SPMSingleZoneOneStageHeating::calculate()
    2825              : 
    2826            0 : void SPMSingleZoneHum::calculate(EnergyPlusData &state)
    2827              : {
    2828              :     // SUBROUTINE INFORMATION:
    2829              :     //       AUTHOR         Fred Buhl
    2830              :     //       DATE WRITTEN   October 2000
    2831              :     //       MODIFIED       Shirey/Raustad Jan 2002
    2832              :     //                      Gu, Dec 2007
    2833              : 
    2834              :     // PURPOSE OF THIS SUBROUTINE:
    2835              :     // From humidity load of the control zone, calculate the supply air humidity
    2836              :     // needed to meet the minimum humidity setpoint
    2837              : 
    2838              :     // METHODOLOGY EMPLOYED:
    2839              :     // Zone moisture load from ZoneTempPredictorCorrector (via DataZoneEnergyDemands)
    2840              :     // is used to calculate the minimum supply air humidity ratio
    2841              :     // needed to meet minimum zone relative humidity requirement
    2842              : 
    2843              :     // Using/Aliasing
    2844              :     using Psychrometrics::PsyWFnTdbRhPb;
    2845              : 
    2846              :     // Only use one zone for now
    2847            0 :     auto &zoneNode = state.dataLoopNodes->Node(this->zoneNodeNum);
    2848              : 
    2849            0 :     Real64 ZoneMassFlow = zoneNode.MassFlowRate;
    2850            0 :     if (ZoneMassFlow > HVAC::SmallMassFlow) {
    2851            0 :         auto const &zoneMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(this->ctrlZoneNum);
    2852            0 :         Real64 MoistureLoad =
    2853            0 :             (this->type == SPMType::SZMinHum) ? zoneMoistureDemand.OutputRequiredToHumidifyingSP : zoneMoistureDemand.OutputRequiredToDehumidifyingSP;
    2854              : 
    2855              :         // This function handles both SZMinHum and SZMaxHum
    2856              :         // MoistureLoad (negative for dehumidification) may be so large that a negative humrat results, cap at 0.00001
    2857            0 :         Real64 MaxHum = (this->type == SPMType::SZMinHum) ? 0.0 : 0.00001;
    2858              : 
    2859              :         // Positive Humidity Ratio MoistureLoad means a humidification load and only humidifying can raise up to a minimum
    2860              :         //  IF(MoistureLoad .GT. 0.0) SZMinHumSetPtMgr(SetPtMgrNum)%SetPt = SupplyAirHumRat
    2861            0 :         this->setPt = max(MaxHum, zoneNode.HumRat + MoistureLoad / ZoneMassFlow);
    2862              : 
    2863              :         // This hum rat is currently used in Controller:Simple, control variable "TEMPandHUMRAT" (Jan 2004)
    2864              :         // Negative MoistureLoad means a dehumidification load
    2865              :     } else {
    2866            0 :         this->setPt = 0.0;
    2867              :     }
    2868            0 : } // SPMSingleZoneHum::calculate()
    2869              : 
    2870        55583 : void SPMMixedAir::calculate(EnergyPlusData &state)
    2871              : {
    2872              :     // SUBROUTINE INFORMATION:
    2873              :     //       AUTHOR         Fred Buhl
    2874              :     //       DATE WRITTEN   May 2001
    2875              : 
    2876              :     // PURPOSE OF THIS SUBROUTINE:
    2877              :     // Starting with the setpoint at the reference node, subtract the supply fan
    2878              :     // temperature rise and set the resulting temperature at the mixed air node.
    2879              :     // Using/Aliasing
    2880              :     using EMSManager::CheckIfNodeSetPointManagedByEMS;
    2881              : 
    2882              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2883        55583 :     auto &fanInNode = state.dataLoopNodes->Node(this->fanInNodeNum);
    2884        55583 :     auto &fanOutNode = state.dataLoopNodes->Node(this->fanOutNodeNum);
    2885        55583 :     auto &refNode = state.dataLoopNodes->Node(this->refNodeNum);
    2886              : 
    2887        55583 :     this->freezeCheckEnable = false;
    2888              : 
    2889        55583 :     if (!state.dataGlobal->SysSizingCalc && this->mySetPointCheckFlag) {
    2890              : 
    2891           39 :         if (refNode.TempSetPoint == SensedNodeFlagValue) {
    2892            0 :             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    2893            0 :                 ShowSevereError(state,
    2894            0 :                                 format("CalcMixedAirSetPoint: Missing reference temperature setpoint for Mixed Air Setpoint Manager {}", this->Name));
    2895            0 :                 ShowContinueError(state, format("Node Referenced ={}", state.dataLoopNodes->NodeID(this->refNodeNum)));
    2896            0 :                 ShowContinueError(
    2897              :                     state, "  use an additional Setpoint Manager with Control Variable = \"Temperature\" to establish a setpoint at this node.");
    2898            0 :                 state.dataHVACGlobal->SetPointErrorFlag = true;
    2899              :             } else {
    2900              :                 // need call to check if this is the target of an EnergyManagementSystem:Actuator object
    2901            0 :                 CheckIfNodeSetPointManagedByEMS(state, this->refNodeNum, HVAC::CtrlVarType::Temp, state.dataHVACGlobal->SetPointErrorFlag);
    2902            0 :                 if (state.dataHVACGlobal->SetPointErrorFlag) {
    2903            0 :                     ShowSevereError(
    2904            0 :                         state, format("CalcMixedAirSetPoint: Missing reference temperature setpoint for Mixed Air Setpoint Manager {}", this->Name));
    2905            0 :                     ShowContinueError(state, format("Node Referenced ={}", state.dataLoopNodes->NodeID(this->refNodeNum)));
    2906            0 :                     ShowContinueError(
    2907              :                         state, "  use an additional Setpoint Manager with Control Variable = \"Temperature\" to establish a setpoint at this node.");
    2908            0 :                     ShowContinueError(state, "Or add EMS Actuator to provide temperature setpoint at this node");
    2909              :                 }
    2910              :             }
    2911              :         }
    2912              : 
    2913           39 :         this->mySetPointCheckFlag = false;
    2914              :     }
    2915              : 
    2916        55583 :     this->setPt = refNode.TempSetPoint - (fanOutNode.Temp - fanInNode.Temp);
    2917        55583 :     if (this->coolCoilInNodeNum > 0 && this->coolCoilOutNodeNum > 0) {
    2918            2 :         auto const &coolCoilInNode = state.dataLoopNodes->Node(this->coolCoilInNodeNum);
    2919            2 :         auto const &coolCoilOutNode = state.dataLoopNodes->Node(this->coolCoilOutNodeNum);
    2920            2 :         Real64 dtFan = fanOutNode.Temp - fanInNode.Temp;
    2921            2 :         Real64 dtCoolCoil = coolCoilInNode.Temp - coolCoilOutNode.Temp;
    2922            2 :         if (dtCoolCoil > 0.0 && this->minCoolCoilOutTemp > state.dataEnvrn->OutDryBulbTemp) {
    2923            2 :             this->freezeCheckEnable = true;
    2924            2 :             if (refNode.Temp == coolCoilOutNode.Temp) { // blow through
    2925            1 :                 this->setPt = max(refNode.TempSetPoint, this->minCoolCoilOutTemp) - dtFan + dtCoolCoil;
    2926            1 :             } else if (this->refNodeNum != this->coolCoilOutNodeNum) { // // draw through Ref node is outlet node
    2927            1 :                 this->setPt = max(refNode.TempSetPoint - dtFan, this->minCoolCoilOutTemp) + dtCoolCoil;
    2928              :             } else {
    2929            0 :                 this->setPt = max(refNode.TempSetPoint, this->minCoolCoilOutTemp) + dtCoolCoil;
    2930              :             }
    2931              :         }
    2932              :     }
    2933        55583 : } // SPMMixedAir::calculate()
    2934              : 
    2935            0 : void SPMOutsideAirPretreat::calculate(EnergyPlusData &state)
    2936              : {
    2937              :     // SUBROUTINE INFORMATION:
    2938              :     //       AUTHOR         M. J. Witte based on CalcMixedAirSetPoint by Fred Buhl,
    2939              :     //                        Work supported by ASHRAE research project 1254-RP
    2940              :     //       DATE WRITTEN   January 2005
    2941              :     //       MODIFIED       Witte (GARD), Sep 2006
    2942              :     //                      Griffith( NREL), May 2009, added EMS setpoint checks
    2943              : 
    2944              :     // PURPOSE OF THIS SUBROUTINE:
    2945              :     // Starting with the setpoint at the reference node, determine the required
    2946              :     // outside air inlet conditions which when mixed with return air result in
    2947              :     // the reference setpoint at the mixed air node.
    2948              :     // (based on CalcMixedAirSetPoint)
    2949              : 
    2950              :     // Using/Aliasing
    2951              :     using EMSManager::CheckIfNodeSetPointManagedByEMS;
    2952              : 
    2953              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2954            0 :     Real64 ReturnInValue = 0;   // return air inlet node mass flow rate
    2955            0 :     Real64 RefNodeSetPoint = 0; // setpoint at reference node
    2956            0 :     Real64 MinSetPoint = 0;     // minimum allowed setpoint
    2957            0 :     Real64 MaxSetPoint = 0;     // maximum allowed setpoint
    2958              : 
    2959            0 :     auto &refNode = state.dataLoopNodes->Node(this->refNodeNum);
    2960            0 :     auto &mixedOutNode = state.dataLoopNodes->Node(this->mixedOutNodeNum);
    2961            0 :     auto &oaInNode = state.dataLoopNodes->Node(this->oaInNodeNum);
    2962            0 :     auto &returnInNode = state.dataLoopNodes->Node(this->returnInNodeNum);
    2963              : 
    2964            0 :     bool isHumiditySetPoint = false;
    2965              : 
    2966            0 :     switch (this->ctrlVar) {
    2967            0 :     case HVAC::CtrlVarType::Temp: { // 'Temperature'
    2968            0 :         RefNodeSetPoint = refNode.TempSetPoint;
    2969            0 :         ReturnInValue = returnInNode.Temp;
    2970            0 :         MinSetPoint = this->minSetTemp;
    2971            0 :         MaxSetPoint = this->maxSetTemp;
    2972            0 :     } break;
    2973            0 :     case HVAC::CtrlVarType::MaxHumRat: { // 'HUMRATMAX'
    2974            0 :         RefNodeSetPoint = refNode.HumRatMax;
    2975            0 :         ReturnInValue = returnInNode.HumRat;
    2976            0 :         MinSetPoint = this->minSetHum;
    2977            0 :         MaxSetPoint = this->maxSetHum;
    2978            0 :         isHumiditySetPoint = true;
    2979            0 :     } break;
    2980            0 :     case HVAC::CtrlVarType::MinHumRat: { // 'HUMRATMIN'
    2981            0 :         RefNodeSetPoint = refNode.HumRatMin;
    2982            0 :         ReturnInValue = returnInNode.HumRat;
    2983            0 :         MinSetPoint = this->minSetHum;
    2984            0 :         MaxSetPoint = this->maxSetHum;
    2985            0 :         isHumiditySetPoint = true;
    2986            0 :     } break;
    2987            0 :     case HVAC::CtrlVarType::HumRat: { // 'HumidityRatio'
    2988            0 :         RefNodeSetPoint = refNode.HumRatSetPoint;
    2989            0 :         ReturnInValue = returnInNode.HumRat;
    2990            0 :         MinSetPoint = this->minSetHum;
    2991            0 :         MaxSetPoint = this->maxSetHum;
    2992            0 :         isHumiditySetPoint = true;
    2993            0 :     } break;
    2994            0 :     default:
    2995            0 :         break;
    2996              :     }
    2997              : 
    2998            0 :     if (!state.dataGlobal->SysSizingCalc && this->mySetPointCheckFlag) {
    2999            0 :         this->mySetPointCheckFlag = false;
    3000            0 :         if (RefNodeSetPoint == SensedNodeFlagValue) {
    3001            0 :             if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
    3002            0 :                 ShowSevereError(
    3003            0 :                     state, format("CalcOAPretreatSetPoint: Missing reference setpoint for Outdoor Air Pretreat Setpoint Manager {}", this->Name));
    3004            0 :                 ShowContinueError(state, format("Node Referenced ={}", state.dataLoopNodes->NodeID(this->refNodeNum)));
    3005            0 :                 ShowContinueError(state, "use a Setpoint Manager to establish a setpoint at this node.");
    3006            0 :                 ShowFatalError(state, "Missing reference setpoint.");
    3007              :             } else {
    3008            0 :                 bool LocalSetPointCheckFailed = false;
    3009            0 :                 switch (this->ctrlVar) {
    3010            0 :                 case HVAC::CtrlVarType::Temp:      // 'Temperature'
    3011              :                 case HVAC::CtrlVarType::MaxHumRat: // 'HUMRATMAX'
    3012              :                 case HVAC::CtrlVarType::MinHumRat: // 'HUMRATMIN'
    3013              :                 case HVAC::CtrlVarType::HumRat: {  // 'HumidityRatio'
    3014            0 :                     CheckIfNodeSetPointManagedByEMS(state, this->refNodeNum, this->ctrlVar, LocalSetPointCheckFailed);
    3015            0 :                 } break;
    3016            0 :                 default:
    3017            0 :                     break;
    3018              :                 }
    3019            0 :                 if (LocalSetPointCheckFailed) {
    3020            0 :                     ShowSevereError(
    3021            0 :                         state, format("CalcOAPretreatSetPoint: Missing reference setpoint for Outdoor Air Pretreat Setpoint Manager {}", this->Name));
    3022            0 :                     ShowContinueError(state, format("Node Referenced ={}", state.dataLoopNodes->NodeID(this->refNodeNum)));
    3023            0 :                     ShowContinueError(state, "use a Setpoint Manager to establish a setpoint at this node.");
    3024            0 :                     ShowContinueError(state, "Or use an EMS actuator to control a setpoint at this node.");
    3025            0 :                     ShowFatalError(state, "Missing reference setpoint.");
    3026              :                 }
    3027              :             }
    3028              :         }
    3029              :     }
    3030            0 :     if ((mixedOutNode.MassFlowRate <= 0.0) || (oaInNode.MassFlowRate <= 0.0)) {
    3031            0 :         this->setPt = RefNodeSetPoint;
    3032            0 :     } else if (isHumiditySetPoint && (RefNodeSetPoint == 0.0)) {
    3033              :         // For humidity setpoints, zero is special meaning "off" or "no load"
    3034              :         // so pass through zero setpoints without enforcing the max/min setpoint limits
    3035            0 :         this->setPt = 0.0;
    3036              :     } else {
    3037            0 :         Real64 OAFraction = oaInNode.MassFlowRate / mixedOutNode.MassFlowRate;
    3038            0 :         this->setPt = ReturnInValue + (RefNodeSetPoint - ReturnInValue) / OAFraction;
    3039              :         // Apply maximum and minimum values
    3040            0 :         this->setPt = std::clamp(this->setPt, MinSetPoint, MaxSetPoint);
    3041              :     }
    3042            0 : } // SPMOutsideAirPretreat::calculate()
    3043              : 
    3044         3977 : void SPMTempest::calculate(EnergyPlusData &state)
    3045              : {
    3046              :     // SUBROUTINE INFORMATION:
    3047              :     //       AUTHOR         Fred Buhl
    3048              :     //       DATE WRITTEN   May 2002
    3049              : 
    3050              :     // PURPOSE OF THIS SUBROUTINE:
    3051              :     // Calculate the "warmest" supply air setpoint temperature that will satisfy the cooling
    3052              :     // requirements of all the zones served by a central air system.
    3053              : 
    3054              :     // METHODOLOGY EMPLOYED:
    3055              :     // Zone sensible heat balance
    3056              : 
    3057              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3058         3977 :     Real64 SetPointTemp = 0.0;
    3059              : 
    3060         3977 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3061              : 
    3062         3977 :     if (this->type == SPMType::Warmest) {
    3063              : 
    3064         3976 :         Real64 TotCoolLoad = 0.0;
    3065         3976 :         SetPointTemp = this->maxSetTemp;
    3066              : 
    3067         7952 :         for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3068         3976 :             int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3069         3976 :             auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3070         3976 :             auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3071              : 
    3072         3976 :             Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3073         3976 :             Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3074         3976 :             Real64 ZoneTemp = zoneNode.Temp;
    3075         3976 :             Real64 ZoneSetPointTemp = this->maxSetTemp;
    3076         3976 :             if (ZoneLoad < 0.0) {
    3077         2282 :                 TotCoolLoad += std::abs(ZoneLoad);
    3078         2282 :                 Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3079         2282 :                 if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3080         2282 :                     ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3081              :                 }
    3082              :             }
    3083         3976 :             SetPointTemp = min(SetPointTemp, ZoneSetPointTemp);
    3084              :         }
    3085              : 
    3086         3976 :         SetPointTemp = std::clamp(SetPointTemp, this->minSetTemp, this->maxSetTemp);
    3087         3976 :         if (TotCoolLoad < HVAC::SmallLoad) {
    3088         1694 :             SetPointTemp = this->maxSetTemp;
    3089              :         }
    3090              : 
    3091              :     } else { // (spm->type == SPMType::Coldest)
    3092            1 :         Real64 TotHeatLoad = 0.0;
    3093            1 :         SetPointTemp = this->minSetTemp;
    3094              : 
    3095            1 :         if (airToZoneNode.NumZonesHeated > 0) {
    3096              :             // dual-duct heated only zones
    3097            0 :             for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesHeated; ++iZoneNum) {
    3098            0 :                 int CtrlZoneNum = airToZoneNode.HeatCtrlZoneNums(iZoneNum);
    3099            0 :                 auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.HeatZoneInletNodes(iZoneNum));
    3100            0 :                 auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3101            0 :                 Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3102            0 :                 Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3103            0 :                 Real64 ZoneTemp = zoneNode.Temp;
    3104            0 :                 Real64 ZoneSetPointTemp = this->minSetTemp;
    3105            0 :                 if (ZoneLoad > 0.0) {
    3106            0 :                     TotHeatLoad += ZoneLoad;
    3107            0 :                     Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3108            0 :                     if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3109            0 :                         ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3110              :                     }
    3111              :                 }
    3112            0 :                 SetPointTemp = max(SetPointTemp, ZoneSetPointTemp);
    3113              :             }
    3114              :         } else {
    3115              :             // single-duct or central heated and cooled zones
    3116            2 :             for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3117            1 :                 int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3118            1 :                 auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3119            1 :                 auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3120            1 :                 Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3121            1 :                 Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3122            1 :                 Real64 ZoneTemp = zoneNode.Temp;
    3123            1 :                 Real64 ZoneSetPointTemp = this->minSetTemp;
    3124            1 :                 if (ZoneLoad > 0.0) {
    3125            1 :                     TotHeatLoad += ZoneLoad;
    3126            1 :                     Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3127            1 :                     if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3128            1 :                         ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3129              :                     }
    3130              :                 }
    3131            1 :                 SetPointTemp = max(SetPointTemp, ZoneSetPointTemp);
    3132              :             }
    3133              :         }
    3134              : 
    3135            1 :         SetPointTemp = std::clamp(SetPointTemp, this->minSetTemp, this->maxSetTemp);
    3136            1 :         if (TotHeatLoad < HVAC::SmallLoad) {
    3137            0 :             SetPointTemp = this->minSetTemp;
    3138              :         }
    3139              :     }
    3140              : 
    3141         3977 :     this->setPt = SetPointTemp;
    3142         3977 : } // SMPTempest::calculate()
    3143              : 
    3144            0 : void SPMWarmestTempFlow::calculate(EnergyPlusData &state)
    3145              : {
    3146              :     // SUBROUTINE INFORMATION:
    3147              :     //       AUTHOR         Fred Buhl
    3148              :     //       DATE WRITTEN   May 2002
    3149              :     //       MODIFIED       Haves, Oct 2004
    3150              : 
    3151              :     // PURPOSE OF THIS SUBROUTINE:
    3152              :     // Calculate the "warmest" supply air setpoint temperature that will satisfy the cooling
    3153              :     // requirements of all the zones served by a central air system.
    3154              : 
    3155              :     // METHODOLOGY EMPLOYED:
    3156              :     // Zone sensible heat balance
    3157              : 
    3158              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3159              : 
    3160            0 :     if (!this->simReady) return;
    3161            0 :     Real64 TotCoolLoad = 0.0;
    3162            0 :     Real64 MaxSetPointTemp = this->maxSetTemp;
    3163            0 :     Real64 SetPointTemp = MaxSetPointTemp;
    3164            0 :     Real64 MinSetPointTemp = this->minSetTemp;
    3165            0 :     Real64 MinFracFlow = this->minTurndown;
    3166            0 :     Real64 FracFlow = MinFracFlow;
    3167            0 :     int CritZoneNumTemp = 0;
    3168            0 :     int CritZoneNumFlow = 0;
    3169              : 
    3170            0 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3171              : 
    3172            0 :     for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3173            0 :         int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3174            0 :         auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3175            0 :         auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3176              : 
    3177            0 :         Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3178            0 :         Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3179            0 :         Real64 ZoneTemp = zoneNode.Temp;
    3180            0 :         Real64 ZoneSetPointTemp = MaxSetPointTemp;
    3181            0 :         Real64 ZoneFracFlow = MinFracFlow;
    3182              : 
    3183            0 :         if (ZoneLoad < 0.0) {
    3184            0 :             TotCoolLoad += std::abs(ZoneLoad);
    3185            0 :             Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3186            0 :             if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3187            0 :                 if (this->strategy == ControlStrategy::TempFirst) {
    3188              :                     // First find supply air temperature required to meet the load at minimum flow. If this is
    3189              :                     // below the minimum supply air temperature, calculate the fractional flow rate required to meet the
    3190              :                     // load at the minimum supply air temperature.
    3191            0 :                     ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax * MinFracFlow);
    3192            0 :                     if (ZoneSetPointTemp < MinSetPointTemp) {
    3193            0 :                         ZoneFracFlow = (ZoneLoad / (CpAir * (MinSetPointTemp - ZoneTemp))) / ZoneMassFlowMax;
    3194              :                     } else {
    3195            0 :                         ZoneFracFlow = MinFracFlow;
    3196              :                     }
    3197              :                 } else { // ControlStrategy = FlowFirst
    3198              :                     // First find supply air flow rate required to meet the load at maximum supply air temperature. If this
    3199              :                     // is above the maximum supply air flow rate, calculate the supply air temperature required to meet the
    3200              :                     // load at the maximum flow.
    3201            0 :                     ZoneFracFlow = (ZoneLoad / (CpAir * (MaxSetPointTemp - ZoneTemp))) / ZoneMassFlowMax;
    3202            0 :                     if (ZoneFracFlow > 1.0 || ZoneFracFlow < 0.0) {
    3203            0 :                         ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3204              :                     } else {
    3205            0 :                         ZoneSetPointTemp = MaxSetPointTemp;
    3206              :                     }
    3207              :                 }
    3208              :             }
    3209              :         }
    3210            0 :         if (ZoneSetPointTemp < SetPointTemp) {
    3211            0 :             SetPointTemp = ZoneSetPointTemp;
    3212            0 :             CritZoneNumTemp = CtrlZoneNum;
    3213              :         }
    3214            0 :         if (ZoneFracFlow > FracFlow) {
    3215            0 :             FracFlow = ZoneFracFlow;
    3216            0 :             CritZoneNumFlow = CtrlZoneNum;
    3217              :         }
    3218              :     }
    3219              : 
    3220            0 :     SetPointTemp = std::clamp(SetPointTemp, MinSetPointTemp, MaxSetPointTemp);
    3221            0 :     FracFlow = std::clamp(FracFlow, MinFracFlow, 1.0);
    3222            0 :     if (TotCoolLoad < HVAC::SmallLoad) {
    3223            0 :         SetPointTemp = MaxSetPointTemp;
    3224            0 :         FracFlow = MinFracFlow;
    3225              :     }
    3226              : 
    3227            0 :     this->setPt = SetPointTemp;
    3228            0 :     this->turndown = FracFlow;
    3229            0 :     if (this->strategy == ControlStrategy::TempFirst) {
    3230            0 :         this->critZoneNum = (CritZoneNumFlow != 0) ? CritZoneNumFlow : CritZoneNumTemp;
    3231              :     } else { // ControlStrategy = FlowFirst
    3232            0 :         this->critZoneNum = (CritZoneNumTemp != 0) ? CritZoneNumTemp : CritZoneNumFlow;
    3233              :     }
    3234              : } // SPMWarmestTempFlow::calculate()
    3235              : 
    3236            0 : void SPMReturnAirBypassFlow::calculate(EnergyPlusData &state)
    3237              : {
    3238              :     // SUBROUTINE INFORMATION:
    3239              :     //       AUTHOR         Fred Buhl
    3240              :     //       DATE WRITTEN   July 2005
    3241              : 
    3242              :     // PURPOSE OF THIS SUBROUTINE:
    3243              :     // Given the desired setpoint temperature, calculate the flow rate through the
    3244              :     // return air branch that will deliver the desired temperature at the loop outlet
    3245              :     // node.
    3246              : 
    3247            0 :     auto &mixerRABInNode = state.dataLoopNodes->Node(this->rabMixInNodeNum);
    3248            0 :     auto &mixerSupInNode = state.dataLoopNodes->Node(this->supMixInNodeNum);
    3249            0 :     auto &mixerOutNode = state.dataLoopNodes->Node(this->mixOutNodeNum);
    3250            0 :     auto &loopOutNode = state.dataLoopNodes->Node(this->sysOutNodeNum);
    3251              : 
    3252            0 :     Real64 TempSetPt = this->sched->getCurrentVal();
    3253            0 :     Real64 TempSetPtMod = TempSetPt - (loopOutNode.Temp - mixerOutNode.Temp);
    3254            0 :     Real64 SupFlow = mixerSupInNode.MassFlowRate;
    3255            0 :     Real64 TempSup = mixerSupInNode.Temp;
    3256            0 :     Real64 TotSupFlow = mixerOutNode.MassFlowRate;
    3257            0 :     Real64 TempRAB = mixerRABInNode.Temp;
    3258            0 :     Real64 RABFlow = (TotSupFlow * TempSetPtMod - SupFlow * TempSup) / max(TempRAB, 1.0);
    3259            0 :     RABFlow = std::clamp(RABFlow, 0.0, TotSupFlow);
    3260            0 :     this->FlowSetPt = RABFlow;
    3261            0 : }
    3262              : 
    3263            0 : void SPMMultiZoneTemp::calculate(EnergyPlusData &state)
    3264              : {
    3265              :     // SUBROUTINE INFORMATION:
    3266              :     //       AUTHOR         Bereket Nigusse, FSEC
    3267              :     //       DATE WRITTEN   July 2010
    3268              : 
    3269              :     // PURPOSE OF THIS SUBROUTINE:
    3270              :     // Calculates the "Average" supply air setpoint temperature that will satisfy the heating
    3271              :     // requirements of multizones served by a central air system.
    3272              : 
    3273              :     // This function handles both MZAverageHeating and MZAverageCooling
    3274              : 
    3275              :     // METHODOLOGY EMPLOYED:
    3276              :     // Zone sensible (heating load) heat balance around the zones served by a central air system
    3277              : 
    3278              :     // sum of the zone's predicted loads for this air loop [W]
    3279            0 :     Real64 SumLoad = 0.0;
    3280              :     // sum of the product of zone inlet node actual mass flow rate, and
    3281              :     // Cp of air at zone inlet node for all heated zones in the airloop [W/C]
    3282            0 :     Real64 SumProductMdotCp = 0.0;
    3283              :     // sum of the product of zone inlet node actual mass flow rate, and
    3284              :     // Cp of air at zone air node for all zones in the airloop [W/C]
    3285            0 :     Real64 SumProductMdotCpTot = 0.0;
    3286              :     // sum of the product of zone inlet node actual mass flow rate,
    3287              :     // Cp of air at zone air node and zone air node temperature for
    3288              :     // all zones in the air loop [W]
    3289            0 :     Real64 SumProductMdotCpTZoneTot = 0.0;
    3290              : 
    3291            0 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3292            0 :     for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3293              :         // DO ZonesHeatedIndex=1,AirToZoneNodeInfo(AirLoopNum)%NumZonesHeated
    3294              :         // Using AirToZoneNodeInfo(AirLoopNum)%Cool* structure variables since they include heating and cooling.
    3295              : 
    3296              :         // The data for number of zones heated is included in the data structure of the variable
    3297              :         // "AirToZoneNodeInfo(AirLoopNum)%NumZonesCooled" for all systems.  The data structure
    3298              :         // "AirToZoneNodeInfo(AirLoopNum)%NumZonesHeated" applies to Dual Duct System only and
    3299              :         // if used will limit the application of this setpoint manager to other systems.  Thus,
    3300              :         // the "AirToZoneNodeInfo(AirLoopNum)%NumZonesCooled" data is used instead.
    3301              : 
    3302            0 :         int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3303            0 :         auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3304            0 :         auto &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3305            0 :         Real64 ZoneMassFlowRate = zoneInletNode.MassFlowRate;
    3306            0 :         Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3307            0 :         Real64 ZoneTemp = zoneNode.Temp;
    3308            0 :         Real64 CpAir = PsyCpAirFnW(zoneNode.HumRat);
    3309            0 :         SumProductMdotCpTot += ZoneMassFlowRate * CpAir;
    3310            0 :         SumProductMdotCpTZoneTot += ZoneMassFlowRate * CpAir * ZoneTemp;
    3311            0 :         if ((this->type == SPMType::MZHeatingAverage && ZoneLoad > 0.0) || (this->type == SPMType::MZCoolingAverage && ZoneLoad < 0.0)) {
    3312            0 :             CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3313            0 :             SumLoad += ZoneLoad;
    3314            0 :             SumProductMdotCp += ZoneMassFlowRate * CpAir;
    3315              :         }
    3316              :     }
    3317            0 :     Real64 ZoneAverageTemp = (SumProductMdotCpTot > 0.0) ? (SumProductMdotCpTZoneTot / SumProductMdotCpTot) : 0.0;
    3318            0 :     Real64 SetPointTemp = (SumProductMdotCp > 0.0) ? (ZoneAverageTemp + SumLoad / SumProductMdotCp)
    3319            0 :                                                    : ((this->type == SPMType::MZHeatingAverage) ? this->minSetTemp : this->maxSetTemp);
    3320              : 
    3321            0 :     SetPointTemp = std::clamp(SetPointTemp, this->minSetTemp, this->maxSetTemp);
    3322            0 :     if (std::abs(SumLoad) < HVAC::SmallLoad) {
    3323            0 :         SetPointTemp = (this->type == SPMType::MZHeatingAverage) ? this->minSetTemp : this->maxSetTemp;
    3324              :     }
    3325            0 :     this->setPt = SetPointTemp;
    3326            0 : } // SPMMultiZoneTemp::calculate()
    3327              : 
    3328            0 : void SPMMultiZoneHum::calculate(EnergyPlusData &state)
    3329              : {
    3330              :     // SUBROUTINE INFORMATION:
    3331              :     //       AUTHOR         Bereket Nigusse, FSEC
    3332              :     //       DATE WRITTEN   July 2010
    3333              : 
    3334              :     // PURPOSE OF THIS SUBROUTINE:
    3335              :     // Calculate the "Average" supply air minimum humidity setpoint that will satisfy the minimum
    3336              :     // humidity ratio requirements of multiple zones served by a central air system.
    3337              : 
    3338              :     // This function handles both MZMinHumAverage and MZMaxHumAverage
    3339              : 
    3340              :     // METHODOLOGY EMPLOYED:
    3341              :     // Zone latent load balance around the zones served by a central air system
    3342              : 
    3343            0 :     Real64 constexpr SmallMoistureLoad(0.00001); // small moisture load [kgWater/s]
    3344              : 
    3345              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3346            0 :     Real64 SumMdot = 0.0;         // sum of the actual mass flow rate for controlled zones in the air loop [kg/s]
    3347            0 :     Real64 SumMdotTot = 0.0;      // sum of the actual mass flow rate for this air loop [kg/s]
    3348            0 :     Real64 SumMoistureLoad = 0.0; // sum of the zone moisture loads for this air loop [W]
    3349              :     // sum of product of actual mass flow rate at the zone inlet node,
    3350              :     // and humidity ratio at zones air node for all zones in the airloop [kgWater/s]
    3351            0 :     Real64 SumProductMdotHumTot = 0.0;
    3352              : 
    3353            0 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3354              : 
    3355            0 :     Real64 SetPointHum = (this->type == SPMType::MZMinHum || this->type == SPMType::MZMinHumAverage) ? this->minSetHum : this->maxSetHum;
    3356              : 
    3357            0 :     for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3358            0 :         int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3359            0 :         auto const &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3360            0 :         auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3361            0 :         auto const &zoneMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(CtrlZoneNum);
    3362            0 :         Real64 ZoneMassFlowRate = zoneInletNode.MassFlowRate;
    3363            0 :         Real64 MoistureLoad = (this->type == SPMType::MZMinHum || this->type == SPMType::MZMinHumAverage)
    3364            0 :                                   ? zoneMoistureDemand.OutputRequiredToHumidifyingSP
    3365              :                                   : zoneMoistureDemand.OutputRequiredToDehumidifyingSP;
    3366              : 
    3367            0 :         Real64 ZoneHum = zoneNode.HumRat;
    3368              :         // For humidification the moisture load is positive
    3369              : 
    3370            0 :         switch (this->type) {
    3371            0 :         case SPMType::MZMinHumAverage: {
    3372            0 :             SumMdotTot += ZoneMassFlowRate;
    3373            0 :             SumProductMdotHumTot += ZoneMassFlowRate * ZoneHum;
    3374            0 :             if (MoistureLoad > 0.0) {
    3375            0 :                 SumMdot += ZoneMassFlowRate;
    3376            0 :                 SumMoistureLoad += MoistureLoad;
    3377              :             }
    3378            0 :         } break;
    3379              : 
    3380            0 :         case SPMType::MZMaxHumAverage: {
    3381            0 :             SumMdotTot += ZoneMassFlowRate;
    3382            0 :             SumProductMdotHumTot += ZoneMassFlowRate * ZoneHum;
    3383            0 :             if (MoistureLoad < 0.0) {
    3384            0 :                 SumMdot += ZoneMassFlowRate;
    3385            0 :                 SumMoistureLoad += MoistureLoad;
    3386              :             }
    3387            0 :         } break;
    3388              : 
    3389            0 :         case SPMType::MZMinHum: {
    3390            0 :             Real64 ZoneSetPointHum = this->minSetHum;
    3391            0 :             if (MoistureLoad > 0.0) {
    3392            0 :                 SumMoistureLoad += MoistureLoad;
    3393            0 :                 if (ZoneMassFlowRate > HVAC::SmallMassFlow) {
    3394            0 :                     ZoneSetPointHum = max(0.0, ZoneHum + MoistureLoad / ZoneMassFlowRate);
    3395              :                 }
    3396              :             }
    3397            0 :             SetPointHum = max(SetPointHum, ZoneSetPointHum);
    3398            0 :         } break;
    3399              : 
    3400            0 :         case SPMType::MZMaxHum: {
    3401            0 :             Real64 ZoneSetPointHum = this->maxSetHum;
    3402            0 :             if (MoistureLoad < 0.0) {
    3403            0 :                 SumMoistureLoad += MoistureLoad;
    3404            0 :                 if (ZoneMassFlowRate > HVAC::SmallMassFlow) {
    3405            0 :                     ZoneSetPointHum = max(0.0, ZoneHum + MoistureLoad / ZoneMassFlowRate);
    3406              :                 }
    3407              :             }
    3408            0 :             SetPointHum = min(SetPointHum, ZoneSetPointHum);
    3409            0 :         } break;
    3410              : 
    3411            0 :         default:
    3412            0 :             break;
    3413              :         } // switch (this->type)
    3414              :     }
    3415              : 
    3416            0 :     if (this->type == SPMType::MZMinHumAverage || this->type == SPMType::MZMaxHumAverage) {
    3417            0 :         Real64 AverageZoneHum = (SumMdotTot > HVAC::SmallMassFlow) ? (SumProductMdotHumTot / SumMdotTot) : 0.0;
    3418            0 :         if (SumMdot > HVAC::SmallMassFlow) {
    3419            0 :             SetPointHum = max(0.0, AverageZoneHum + SumMoistureLoad / SumMdot);
    3420              :         }
    3421            0 :     } else {
    3422            0 :         if (std::abs(SumMoistureLoad) < SmallMoistureLoad) {
    3423            0 :             SetPointHum = (this->type == SPMType::MZMinHum) ? this->minSetHum : this->maxSetHum;
    3424              :         }
    3425              :     }
    3426              : 
    3427            0 :     this->setPt = std::clamp(SetPointHum, this->minSetHum, this->maxSetHum);
    3428            0 : } // SPMMultiZoneHum::calculate()
    3429              : 
    3430         1729 : void SPMFollowOutsideAirTemp::calculate(EnergyPlusData &state)
    3431              : {
    3432              :     // SUBROUTINE INFORMATION:
    3433              :     //       AUTHOR         Chandan Sharma, FSEC
    3434              :     //       DATE WRITTEN   July 2011
    3435              : 
    3436              :     // PURPOSE OF THIS SUBROUTINE:
    3437              :     // Set the setpoint based on outdoor air dry-bulb/wet-bulb temperature
    3438              : 
    3439              :     // METHODOLOGY EMPLOYED:
    3440              :     // Based on reference temperature type specified in the setpoint manager,
    3441              :     // the setpoint is calculated as OutWetBulbTemp(Or OutDryBulbTemp) + Offset.
    3442              :     // The sign convention is that a positive Offset will increase the resulting setpoint.
    3443              :     // Final value of the setpoint is limited by the Max and Min limit specified in the setpoint manager.
    3444         1729 :     this->setPt = ((this->refTempType == AirTempType::WetBulb) ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp) + this->offset;
    3445              : 
    3446              :     // Apply maximum and minimum values
    3447         1729 :     this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    3448         1729 : } // SPMFollowOutsideAirTemp::calculate()
    3449              : 
    3450            0 : void SPMFollowSysNodeTemp::calculate(EnergyPlusData &state)
    3451              : {
    3452              :     // SUBROUTINE INFORMATION:
    3453              :     //       AUTHOR         Chandan Sharma, FSEC
    3454              :     //       DATE WRITTEN   July 2011
    3455              : 
    3456              :     // PURPOSE OF THIS SUBROUTINE:
    3457              :     // Set the setpoint based on current temperatures at a separate system node.
    3458              : 
    3459              :     // METHODOLOGY EMPLOYED:
    3460              :     // The current value of the temperature at a reference node are obtained and used
    3461              :     // to generate setpoint on a second system node.  If the reference node is also designated
    3462              :     // to be an outdoor air (intake) node, then this setpoint manager can be used to follow
    3463              :     // outdoor air conditions that are adjusted for altitude.
    3464              :     // Also, based on reference temperature type specified in the setpoint manager, the out door air wet-bulb
    3465              :     // or dry-bulb temperature at the reference node could be used.
    3466              :     // A temperature offset will be applied to the value obtained from the reference system node.
    3467              :     // If this value is zero, and the limits are met, then the resulting setpoint will be exactly the same
    3468              :     // as the reference system node temperature.  The sign convention is that a positive offset will increase
    3469              :     // the resulting setpoint.
    3470              : 
    3471              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3472            0 :     Real64 RefNodeTemp = (this->refTempType == AirTempType::DryBulb)
    3473            0 :                              ? state.dataLoopNodes->Node(this->refNodeNum).Temp
    3474            0 :                              : (allocated(state.dataLoopNodes->MoreNodeInfo) ? state.dataLoopNodes->MoreNodeInfo(this->refNodeNum).WetBulbTemp : 0.0);
    3475              : 
    3476            0 :     this->setPt = RefNodeTemp + this->offset;
    3477              : 
    3478              :     // Apply maximum and minimum values
    3479            0 :     this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    3480            0 : } // SPMFollowSysNodeTemp::calculate()
    3481              : 
    3482         1769 : void SPMFollowGroundTemp::calculate(EnergyPlusData &state)
    3483              : {
    3484              :     // SUBROUTINE INFORMATION:
    3485              :     //       AUTHOR         Chandan Sharma, FSEC
    3486              :     //       DATE WRITTEN   July 2011
    3487              : 
    3488              :     // PURPOSE OF THIS SUBROUTINE:
    3489              :     // Set the setpoint based on current ground temperature
    3490              : 
    3491              :     // METHODOLOGY EMPLOYED:
    3492              :     // Based on reference ground temperature object type specified in the setpoint manager,
    3493              :     // the setpoint is calculated as GroundTemperature + Offset.
    3494              :     // The sign convention is that a positive Offset will increase the resulting setpoint.
    3495              :     // Final value of the setpoint is limited by the Max and Min limit specified in the setpoint manager.
    3496         1769 :     this->setPt = state.dataEnvrn->GroundTemp[(int)this->refTempType] + this->offset;
    3497              : 
    3498              :     // Apply maximum and minimum values
    3499         1769 :     this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    3500         1769 : } // SPMFollowGrounTemp::calculate()
    3501              : 
    3502            3 : void SPMCondenserEnteringTemp::calculate(EnergyPlusData &state)
    3503              : {
    3504              :     // SUBROUTINE INFORMATION:
    3505              :     //       AUTHOR         Atefe Makhmalbaf and Heejin Cho, PNNL
    3506              :     //       DATE WRITTEN   March 2012
    3507              : 
    3508              :     // PURPOSE OF THIS SUBROUTINE:
    3509              :     // Calculate the optimal condenser water temperature set point for a chiller plant
    3510              :     // with one or more chillers.  The condenser water leaving the tower should be at this temperature
    3511              :     // for optimal operation of the chiller plant.
    3512              : 
    3513              :     // METHODOLOGY EMPLOYED:
    3514              :     // using one curve to determine the optimum condenser entering water temperature for a given timestep
    3515              :     // and two other curves to place boundary conditions on the optimal setpoint value.
    3516              : 
    3517              :     // Using/Aliasing
    3518              :     using namespace DataPlant;
    3519              : 
    3520            3 :     auto &dspm = state.dataSetPointManager;
    3521              : 
    3522              :     // Current timestep's condenser water entering setpoint
    3523            3 :     Real64 CondenserEnteringTempSetPoint = this->condenserEnteringTempSched->getCurrentVal();
    3524              : 
    3525            3 :     auto &supplyLoop = state.dataPlnt->PlantLoop(this->plantPloc.loopNum).LoopSide(LoopSideLocation::Supply);
    3526            3 :     auto &supplyComp = supplyLoop.Branch(this->plantPloc.branchNum).Comp(this->plantPloc.compNum);
    3527              : 
    3528            3 :     auto &demandLoop = state.dataPlnt->PlantLoop(this->demandPloc.loopNum).LoopSide(LoopSideLocation::Demand);
    3529            3 :     auto &demandComp = demandLoop.Branch(this->demandPloc.branchNum).Comp(this->demandPloc.compNum);
    3530              : 
    3531              :     // If chiller is on
    3532            3 :     Real64 CurLoad = std::abs(supplyComp.MyLoad);
    3533            3 :     if (CurLoad > 0) {
    3534              : 
    3535            3 :         Real64 CondInletTemp = 0.0;
    3536            3 :         Real64 EvapOutletTemp = 0.0;
    3537              : 
    3538            3 :         Real64 DesignLoad = 0.0;            // array of chiller design loads
    3539            3 :         Real64 ActualLoad = 0.0;            // array of chiller actual loads
    3540            3 :         Real64 DesignCondenserInTemp = 0.0; // Design condenser inlet temp. C , or 25.d0
    3541            3 :         Real64 DesignEvapOutTemp = 0.0;     // design evaporator outlet temperature, water side
    3542              : 
    3543              :         // Get from tower design values
    3544            3 :         constexpr Real64 NormDesignCondenserFlow = 5.38e-8; // m3/s per watt (typically 3 gpm/ton)=(Volume of condenser fluid)/(ton of heat rejection)
    3545              : 
    3546            3 :         if (this->chillerType == PlantEquipmentType::Chiller_Absorption || this->chillerType == PlantEquipmentType::Chiller_CombTurbine ||
    3547            3 :             this->chillerType == PlantEquipmentType::Chiller_Electric || this->chillerType == PlantEquipmentType::Chiller_ElectricReformEIR ||
    3548            0 :             this->chillerType == PlantEquipmentType::Chiller_EngineDriven) {
    3549            3 :             DesignCondenserInTemp = supplyComp.TempDesCondIn;
    3550            3 :             CondInletTemp = state.dataLoopNodes->Node(demandComp.NodeNumIn).Temp;
    3551            3 :             EvapOutletTemp = state.dataLoopNodes->Node(supplyComp.NodeNumOut).Temp;
    3552            3 :             DesignEvapOutTemp = supplyComp.TempDesEvapOut;
    3553            3 :             DesignLoad = supplyComp.MaxLoad;
    3554            3 :             ActualLoad = state.dataPlnt->PlantLoop(this->plantPloc.loopNum).CoolingDemand;
    3555            0 :         } else if (this->chillerType == PlantEquipmentType::Chiller_Indirect_Absorption ||
    3556            0 :                    this->chillerType == PlantEquipmentType::Chiller_DFAbsorption) {
    3557            0 :             DesignCondenserInTemp = supplyComp.TempDesCondIn;
    3558            0 :             DesignEvapOutTemp = 6.666;
    3559              :         } else {
    3560            0 :             DesignCondenserInTemp = 25.0;
    3561            0 :             DesignEvapOutTemp = 6.666;
    3562              :         }
    3563              : 
    3564              :         // for attached chillers (that are running this timestep) find their Dsn_MinCondSetpt and Dsn_EntCondTemp
    3565            3 :         dspm->CET_DesignMinCondenserSetPt = 999.0;
    3566            3 :         dspm->CET_DesignEnteringCondenserTemp = 0.0;
    3567              : 
    3568              :         // Design Minimum Condenser Entering as a function of the minimum lift and TEvapLvg
    3569              :         // for chillers operating on current cond loop this timestep
    3570            3 :         Real64 DesignMinCondenserEnteringTempThisChiller = DesignEvapOutTemp + (this->minLift);
    3571            3 :         dspm->CET_DesignMinCondenserSetPt = min(dspm->CET_DesignMinCondenserSetPt, DesignMinCondenserEnteringTempThisChiller);
    3572              : 
    3573              :         // Design entering condenser water temperature for chillers operating
    3574              :         // on current cond loop this timestep
    3575            3 :         dspm->CET_DesignEnteringCondenserTemp = max(dspm->CET_DesignEnteringCondenserTemp, DesignCondenserInTemp);
    3576              : 
    3577              :         // ***** Load Calculations *****
    3578              :         // In this section the sum of the actual load (watts) and design load (watts)
    3579              :         // of the chillers that are on is calculated.
    3580            3 :         dspm->CET_ActualLoadSum += ActualLoad;
    3581            3 :         dspm->CET_DesignLoadSum += DesignLoad;
    3582              : 
    3583              :         // Exit if the chillers are all off this hour
    3584            3 :         if (dspm->CET_ActualLoadSum <= 0) {
    3585            0 :             CondenserEnteringTempSetPoint = dspm->CET_DesignEnteringCondenserTemp;
    3586            0 :             return;
    3587              :         }
    3588              : 
    3589              :         // ***** Weighted Ratio Calculation *****
    3590              :         // This section first calculates the actual (ALW) and design (DLW) individual
    3591              :         // weights. Then the weighted actual and design loads are computed. Finally
    3592              :         // the Weighted Ratio is found.
    3593            3 :         Real64 WeightedActualLoad = 0.0; // Actual load weighting of each chiller, W
    3594            3 :         Real64 WeightedDesignLoad = 0.0; // Design capacity of each chiller, W
    3595            3 :         if (dspm->CET_ActualLoadSum != 0 && dspm->CET_DesignLoadSum != 0) {
    3596            3 :             WeightedActualLoad = ((ActualLoad / dspm->CET_ActualLoadSum) * ActualLoad);
    3597            3 :             WeightedDesignLoad = ((DesignLoad / dspm->CET_DesignLoadSum) * DesignLoad);
    3598              :         }
    3599              : 
    3600            3 :         dspm->CET_WeightedActualLoadSum += WeightedActualLoad;
    3601            3 :         dspm->CET_WeightedDesignLoadSum += WeightedDesignLoad;
    3602            3 :         dspm->CET_WeightedLoadRatio = dspm->CET_WeightedActualLoadSum / dspm->CET_WeightedDesignLoadSum;
    3603              : 
    3604              :         // ***** Optimal Temperature Calculation *****
    3605              :         // In this section the optimal temperature is computed along with the minimum
    3606              :         // design wet bulb temp and the minimum actual wet bulb temp.
    3607              :         // Min_DesignWB = ACoef1 + ACoef2*OaWb + ACoef3*WPLR + ACoef4*TwrDsnWB + ACoef5*NF
    3608            3 :         dspm->CET_DesignMinWetBulbTemp = EnergyPlus::Curve::CurveValue(state,
    3609              :                                                                        this->minTowerDesignWetBulbCurveNum,
    3610            3 :                                                                        state.dataEnvrn->OutWetBulbTemp,
    3611            3 :                                                                        dspm->CET_WeightedLoadRatio,
    3612              :                                                                        this->towerDesignInletAirWetBulbTemp,
    3613              :                                                                        NormDesignCondenserFlow);
    3614              : 
    3615              :         // Min_ActualWb = BCoef1 + BCoef2*MinDsnWB + BCoef3*WPLR + BCoef4*TwrDsnWB + BCoef5*NF
    3616            3 :         dspm->CET_MinActualWetBulbTemp = EnergyPlus::Curve::CurveValue(state,
    3617              :                                                                        this->minOAWetBulbCurveNum,
    3618            3 :                                                                        dspm->CET_DesignMinWetBulbTemp,
    3619            3 :                                                                        dspm->CET_WeightedLoadRatio,
    3620              :                                                                        this->towerDesignInletAirWetBulbTemp,
    3621              :                                                                        NormDesignCondenserFlow);
    3622              : 
    3623              :         // Opt_CondEntTemp = CCoef1 + CCoef2*OaWb + CCoef3*WPLR + CCoef4*TwrDsnWB + CCoef5*NF
    3624            3 :         dspm->CET_OptCondenserEnteringTemp = EnergyPlus::Curve::CurveValue(state,
    3625              :                                                                            this->optCondenserEnteringTempCurveNum,
    3626            3 :                                                                            state.dataEnvrn->OutWetBulbTemp,
    3627            3 :                                                                            dspm->CET_WeightedLoadRatio,
    3628              :                                                                            this->towerDesignInletAirWetBulbTemp,
    3629              :                                                                            NormDesignCondenserFlow);
    3630              : 
    3631              :         // ***** Calculate (Cond ent - Evap lvg) Section *****
    3632              :         // In this section we find the worst case of (Cond ent - Evap lvg) for the
    3633              :         // chillers that are running.
    3634            3 :         dspm->CET_CurMinLift = 9999.0;
    3635              :         // temp_MinLiftTD = 20.0 / 1.8;
    3636            3 :         Real64 TempMinLift = CondInletTemp - EvapOutletTemp;
    3637            3 :         dspm->CET_CurMinLift = min(dspm->CET_CurMinLift, TempMinLift);
    3638              :     }
    3639              : 
    3640            3 :     Real64 SetPoint = 0.0; // Condenser entering water temperature setpoint this timestep, C
    3641              : 
    3642              :     // ***** Limit conditions Section *****
    3643              :     // Check for limit conditions and control to the proper value.
    3644            3 :     if ((dspm->CET_WeightedLoadRatio >= 0.90) && (dspm->CET_OptCondenserEnteringTemp >= (dspm->CET_DesignEnteringCondenserTemp + 1.0))) {
    3645              :         // Optimized value exceeds the design condenser entering condition or chillers
    3646              :         // near full load condition; reset condenser entering setpoint to its design value
    3647            1 :         SetPoint = dspm->CET_DesignEnteringCondenserTemp + 1.0;
    3648            2 :     } else if ((state.dataEnvrn->OutWetBulbTemp >= dspm->CET_MinActualWetBulbTemp) &&
    3649            2 :                (this->towerDesignInletAirWetBulbTemp >= dspm->CET_DesignMinWetBulbTemp) && (dspm->CET_CurMinLift > this->minLift)) {
    3650              :         // Boundaries are satisfied; use optimized condenser entering water temp
    3651            1 :         SetPoint = dspm->CET_OptCondenserEnteringTemp;
    3652              :     } else {
    3653              :         // Boundaries violated; Reset to scheduled value of condenser water entering setpoint
    3654            1 :         SetPoint = CondenserEnteringTempSetPoint;
    3655              :     }
    3656              : 
    3657              :     // Do not allow new setpoint to be less than the design condenser minimum entering condition,
    3658              :     // i.e., TCondWaterEnt not allowed to be less than DsnEvapWaterLvg + MinimumLiftTD
    3659            3 :     this->setPt = max(SetPoint, dspm->CET_DesignMinCondenserSetPt);
    3660              : } // SPMCondenserEneteringTemp::calculate()
    3661              : 
    3662            0 : void SPMIdealCondenserEnteringTemp::calculate(EnergyPlusData &state)
    3663              : {
    3664              :     // SUBROUTINE INFORMATION:
    3665              :     //       AUTHOR         Heejin Cho, PNNL
    3666              :     //       DATE WRITTEN   March 2012
    3667              : 
    3668              :     // PURPOSE OF THIS SUBROUTINE:
    3669              :     // Calculate the optimal condenser water entering temperature set point for a chiller plant.
    3670              : 
    3671              :     // METHODOLOGY EMPLOYED:
    3672              :     // The "ideal" chiller-tower optimization scheme uses a search algorithm to find the ideal optimal setpoint
    3673              :     // at a given timestep. This requires resimulating HVAC systems at each timestep until finding
    3674              :     // an "optimal" condenser water entering setpoint (OptSetpoint) which gives the minimum total chiller,
    3675              :     // cooling tower, chilled water pump and condenser water pump power consumption.
    3676              :     // The OptSetpoint falls between realistic minimum and maximum boundaries, which are set by the user.
    3677              :     // The minimum boundary is determined based on the minimum lift (user input)
    3678              :     // and evaporator leaving water temperature. The maximum boundary is specified by the user.
    3679              :     // It is assumed that a single minimum point exists between these boundaries.
    3680              : 
    3681              :     // Using/Aliasing
    3682              :     using namespace DataPlant;
    3683              : 
    3684            0 :     auto &dspm = state.dataSetPointManager;
    3685              : 
    3686              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3687            0 :     auto &supplyLoop = state.dataPlnt->PlantLoop(this->chillerPloc.loopNum).LoopSide(LoopSideLocation::Supply);
    3688            0 :     auto &supplyComp = supplyLoop.Branch(this->chillerPloc.branchNum).Comp(this->chillerPloc.compNum);
    3689              : 
    3690            0 :     if (state.dataGlobal->MetersHaveBeenInitialized) {
    3691              :         // Setup meter vars
    3692            0 :         if (this->setupIdealCondEntSetPtVars) {
    3693            0 :             this->SetupMeteredVarsForSetPt(state);
    3694            0 :             this->setupIdealCondEntSetPtVars = false;
    3695              :         }
    3696              :     }
    3697              : 
    3698            0 :     if (state.dataGlobal->MetersHaveBeenInitialized && state.dataGlobal->RunOptCondEntTemp) {
    3699              : 
    3700              :         // If chiller is on
    3701            0 :         Real64 CurLoad = std::abs(supplyComp.MyLoad);
    3702              : 
    3703            0 :         if (CurLoad > 0) {
    3704              : 
    3705              :             Real64 EvapOutletTemp =
    3706            0 :                 (this->chillerType == PlantEquipmentType::Chiller_Absorption || this->chillerType == PlantEquipmentType::Chiller_CombTurbine ||
    3707            0 :                  this->chillerType == PlantEquipmentType::Chiller_Electric || this->chillerType == PlantEquipmentType::Chiller_ElectricReformEIR ||
    3708            0 :                  this->chillerType == PlantEquipmentType::Chiller_EngineDriven)
    3709            0 :                     ? state.dataLoopNodes->Node(supplyComp.NodeNumOut).Temp
    3710            0 :                     : 6.666;
    3711              : 
    3712            0 :             Real64 CondTempLimit = this->minLift + EvapOutletTemp;
    3713              : 
    3714            0 :             Real64 TotEnergy = this->calculateCurrentEnergyUsage(state);
    3715              : 
    3716            0 :             this->setupSetPointAndFlags(TotEnergy,
    3717            0 :                                         dspm->ICET_TotEnergyPre,
    3718            0 :                                         dspm->ICET_CondenserWaterSetPt,
    3719              :                                         CondTempLimit,
    3720            0 :                                         state.dataGlobal->RunOptCondEntTemp,
    3721            0 :                                         dspm->ICET_RunSubOptCondEntTemp,
    3722            0 :                                         dspm->ICET_RunFinalOptCondEntTemp);
    3723              : 
    3724              :         } else {
    3725            0 :             dspm->ICET_CondenserWaterSetPt = this->maxCondenserEnteringTemp;
    3726            0 :             dspm->ICET_TotEnergyPre = 0.0;
    3727            0 :             state.dataGlobal->RunOptCondEntTemp = false;
    3728            0 :             dspm->ICET_RunSubOptCondEntTemp = false;
    3729              :         }
    3730              :     } else {
    3731            0 :         dspm->ICET_CondenserWaterSetPt = this->maxCondenserEnteringTemp;
    3732            0 :         state.dataGlobal->RunOptCondEntTemp = false;
    3733            0 :         dspm->ICET_RunSubOptCondEntTemp = false;
    3734              :     }
    3735              : 
    3736            0 :     this->setPt = dspm->ICET_CondenserWaterSetPt;
    3737            0 : } // SPMIdealCondenserEnteringTemp::calculate()
    3738              : 
    3739            6 : void SPMIdealCondenserEnteringTemp::setupSetPointAndFlags(Real64 &TotEnergy,
    3740              :                                                           Real64 &TotEnergyPre,
    3741              :                                                           Real64 &CondWaterSetPoint,
    3742              :                                                           Real64 &CondTempLimit,
    3743              :                                                           bool &RunOptCondEntTemp,
    3744              :                                                           bool &RunSubOptCondEntTemp,
    3745              :                                                           bool &RunFinalOptCondEntTemp) const
    3746              : {
    3747              :     Real64 DeltaTotEnergy;
    3748            6 :     if (TotEnergyPre != 0.0) {
    3749              :         // Calculate the total energy consumption difference
    3750            5 :         DeltaTotEnergy = TotEnergyPre - TotEnergy;
    3751              :         // Search for the minimum total energy consumption
    3752            5 :         if ((DeltaTotEnergy > 0) && (CondWaterSetPoint >= CondTempLimit) && (!RunFinalOptCondEntTemp)) {
    3753            2 :             if (!RunSubOptCondEntTemp) {
    3754            1 :                 --CondWaterSetPoint;
    3755            1 :                 RunOptCondEntTemp = true;
    3756              :             } else {
    3757            1 :                 CondWaterSetPoint -= 0.2;
    3758            1 :                 RunOptCondEntTemp = true;
    3759              :             }
    3760            2 :             TotEnergyPre = TotEnergy;
    3761              :             // Set smaller set point (0.2 degC) decrease
    3762            3 :         } else if ((DeltaTotEnergy < 0) && (!RunSubOptCondEntTemp) && (CondWaterSetPoint > CondTempLimit) && (!RunFinalOptCondEntTemp)) {
    3763            1 :             CondWaterSetPoint += 0.8;
    3764            1 :             RunOptCondEntTemp = true;
    3765            1 :             RunSubOptCondEntTemp = true;
    3766              :         } else {
    3767            2 :             if (!RunFinalOptCondEntTemp) {
    3768            1 :                 CondWaterSetPoint += 0.2;
    3769            1 :                 RunOptCondEntTemp = true;
    3770            1 :                 RunSubOptCondEntTemp = false;
    3771            1 :                 RunFinalOptCondEntTemp = true;
    3772              :             } else {
    3773              :                 // CondWaterSetPoint = CondWaterSetPoint; // Self-assignment commented out
    3774            1 :                 TotEnergyPre = 0.0;
    3775            1 :                 RunOptCondEntTemp = false;
    3776            1 :                 RunSubOptCondEntTemp = false;
    3777            1 :                 RunFinalOptCondEntTemp = false;
    3778              :             }
    3779              :         }
    3780              :     } else {
    3781            1 :         CondWaterSetPoint = this->maxCondenserEnteringTemp - 1.0;
    3782            1 :         TotEnergyPre = TotEnergy;
    3783            1 :         RunOptCondEntTemp = true;
    3784            1 :         RunSubOptCondEntTemp = false;
    3785              :     }
    3786            6 : } // SPMIdealCondenserEneteringTemp::()
    3787              : 
    3788            0 : Real64 SPMIdealCondenserEnteringTemp::calculateCurrentEnergyUsage(EnergyPlusData &state)
    3789              : {
    3790            0 :     Real64 ChillerEnergy = GetInternalVariableValue(state, this->chillerVar.Type, this->chillerVar.Num);
    3791            0 :     Real64 ChilledPumpEnergy = GetInternalVariableValue(state, this->chilledWaterPumpVar.Type, this->chilledWaterPumpVar.Num);
    3792            0 :     Real64 TowerFanEnergy = 0;
    3793            0 :     for (int i = 1; i <= this->numTowers; i++) {
    3794            0 :         TowerFanEnergy += GetInternalVariableValue(state, this->towerVars(i).Type, this->towerVars(i).Num);
    3795              :     }
    3796            0 :     Real64 CondPumpEnergy = GetInternalVariableValue(state, this->condenserPumpVar.Type, this->condenserPumpVar.Num);
    3797            0 :     return (ChillerEnergy + ChilledPumpEnergy + TowerFanEnergy + CondPumpEnergy);
    3798              : } // SPMIdealCondenserEnteringTemp::calculateCurrentEnergyUsage()
    3799              : 
    3800           10 : void SPMReturnWaterTemp::calculate(EnergyPlusData &state)
    3801              : {
    3802              :     // SUBROUTINE INFORMATION:
    3803              :     //       AUTHOR         Edwin Lee, NREL
    3804              :     //       DATE WRITTEN   May 2015
    3805              : 
    3806              :     // PURPOSE OF THIS SUBROUTINE:
    3807              :     // Calculate the plant supply temperature reset required to achieve a target plant return temperature
    3808              : 
    3809              :     // METHODOLOGY EMPLOYED:
    3810              :     // The setpoint manager follows this procedure:
    3811              :     //  1. Calculate the current demand
    3812              :     //    a. Sense the current return temperature
    3813              :     //    b. Sense the current supply temperature
    3814              :     //    c. Sense the current flow rate
    3815              :     //    d. Approximate the fluid properties (rho, Cp) from the temperatures
    3816              :     //    ---> Use these to calculate the demand with Q_demand = V_dot * rho * C_p * (T_return_sensed - T_supply_sensed)
    3817              :     //  2. Calculate a new value of supply setpoint that will reject this much Q_demand, while providing a target return temperature
    3818              :     //    * this assumes that the demand will be the same value on the next time around
    3819              :     //    * at any time step, the value of target return temperature may vary if it is scheduled (or actuated with EMS)
    3820              :     //    a. T_supply_setpoint = T_return_target - Q_demand / ( V_dot * rho * C_p )
    3821              :     //  3. Constrain this value to limits
    3822              :     //    a. T_supply_setpoint will be within: [ Design Chilled Water Supply Temperature, Maximum Supply Water Reset Temperature ]
    3823              : 
    3824              :     // NOTES:
    3825              :     // The assumptions related to lagging of setpoint are most suited for smaller timesteps and/or plants that don't vary wildly from one time
    3826              :     // step to another The assumptions also become affected by variable flow plants more-so than constant-flow plants
    3827              : 
    3828              :     // Using/Aliasing
    3829              :     using namespace DataPlant;
    3830              : 
    3831           10 :     auto &supplyNode = state.dataLoopNodes->Node(this->supplyNodeNum);
    3832           10 :     auto &returnNode = state.dataLoopNodes->Node(this->returnNodeNum);
    3833              : 
    3834              :     // we need to know the plant to get the fluid ID in case it is glycol
    3835              :     // but we have to wait in case plant isn't initialized yet
    3836              :     // if plant isn't initialized, assume index=1 (water)
    3837           10 :     if (this->plantLoopNum == 0) {
    3838           10 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    3839            5 :             auto &plantLoop = state.dataPlnt->PlantLoop(LoopNum);
    3840            5 :             if (this->supplyNodeNum == plantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut) {
    3841            3 :                 this->plantLoopNum = LoopNum;
    3842            3 :                 this->plantSetPtNodeNum = plantLoop.TempSetPointNodeNum;
    3843              :                 // now that we've found the plant populated, let's verify that the nodes match
    3844            3 :                 if (!PlantUtilities::verifyTwoNodeNumsOnSamePlantLoop(state, this->supplyNodeNum, this->returnNodeNum)) {
    3845            0 :                     ShowSevereError(state, "Node problem for SetpointManager:ReturnTemperature:ChilledWater.");
    3846            0 :                     ShowContinueError(state, "Return and Supply nodes were not found on the same plant loop.  Verify node names.");
    3847            0 :                     ShowFatalError(state, "Simulation aborts due to setpoint node problem");
    3848              :                 }
    3849              :             }
    3850              :         }
    3851              :     }
    3852              : 
    3853              :     // get the operating flow rate
    3854           10 :     Real64 const mdot = supplyNode.MassFlowRate;
    3855           10 :     Real64 const deltaT = (this->type == SPMType::ChilledWaterReturnTemp) ? (returnNode.Temp - supplyNode.Temp) : (supplyNode.Temp - returnNode.Temp);
    3856              : 
    3857              :     // // calculate the current demand
    3858              :     // fluidIndex = state.dataPlnt->PlantLoop(this->plantLoopNum).FluidIndex;
    3859              :     // // we don't need fluid names since we have a real index, so just pass in the temperature and get properties
    3860              :     // Real64 const avgTemp = (returnNode.Temp + supplyNode.Temp) / 2;
    3861              :     // Real64 const cp = Fluid::GetSpecificHeatGlycol(state, "", avgTemp, fluidIndex, "ReturnWaterChWSetPointManager::calculate");
    3862              :     // Real64 const Qdemand = mdot * cp * deltaT;
    3863              : 
    3864              :     // check for strange conditions
    3865           10 :     if (deltaT < 0) {
    3866            0 :         this->currentSupplySetPt = (this->type == SPMType::ChilledWaterReturnTemp) ? this->minSetTemp : this->maxSetTemp;
    3867            0 :         return;
    3868              :     }
    3869              : 
    3870              :     // Determine a return target, default is to use the constant value, but scheduled or externally
    3871              :     //  set on the return node TempSetPoint will overwrite it.  Note that the schedule index is only
    3872              :     //  greater than zero if the input type is scheduled, and the useReturnTempSetpoint flag is only
    3873              :     //  true if the input type is specified as such
    3874           10 :     Real64 T_return_target = this->returnTempConstantTarget;
    3875           10 :     if (this->returnTempSched != nullptr) {
    3876            0 :         T_return_target = this->returnTempSched->getCurrentVal();
    3877           10 :     } else if (this->returnTempType == ReturnTempType::Setpoint) {
    3878            0 :         if (returnNode.TempSetPoint != SensedNodeFlagValue) {
    3879            0 :             T_return_target = returnNode.TempSetPoint;
    3880              :         } else {
    3881            0 :             ShowSevereError(state, "Return temperature reset setpoint manager encountered an error.");
    3882            0 :             ShowContinueError(state,
    3883              :                               "The manager is specified to look to the return node setpoint to find a target return temperature, but the node "
    3884              :                               "setpoint was invalid");
    3885            0 :             ShowContinueError(state,
    3886            0 :                               format("Verify that a separate setpoint manager is specified to set the setpoint on the return node named \"{}\"",
    3887            0 :                                      state.dataLoopNodes->NodeID(this->returnNodeNum)));
    3888            0 :             ShowContinueError(state, "Or change the target return temperature input type to constant or scheduled");
    3889            0 :             ShowFatalError(state, "Missing reference setpoint");
    3890              :         }
    3891              :     }
    3892              : 
    3893              :     // calculate the supply setpoint to use, default to the design value if flow is zero
    3894           10 :     Real64 T_supply_setpoint = (this->type == SPMType::ChilledWaterReturnTemp) ? this->minSetTemp : this->maxSetTemp;
    3895           10 :     if (mdot > DataConvergParams::PlantFlowRateToler) {
    3896           10 :         T_supply_setpoint = T_return_target + ((this->type == SPMType::ChilledWaterReturnTemp) ? -deltaT : deltaT);
    3897              :     }
    3898              : 
    3899           10 :     this->currentSupplySetPt = std::clamp(T_supply_setpoint, this->minSetTemp, this->maxSetTemp);
    3900              : } // SPMReturnWaterTemp::calculate()
    3901              : 
    3902            0 : void SPMIdealCondenserEnteringTemp::SetupMeteredVarsForSetPt(EnergyPlusData &state)
    3903              : {
    3904              :     // SUBROUTINE INFORMATION:
    3905              :     //       AUTHOR         Linda Lawrie
    3906              :     //       DATE WRITTEN   Sep 2013
    3907              : 
    3908              :     // PURPOSE OF THIS SUBROUTINE:
    3909              :     // For the Ideal Cond reset setpoint manager, this sets up the
    3910              :     // report variables used during the calculation.
    3911              : 
    3912              :     // Using/Aliasing
    3913              :     using namespace DataPlant;
    3914              : 
    3915              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3916            0 :     Array1D<OutputProcessor::MeteredVar> meteredVars;
    3917              : 
    3918            0 :     auto &plantLoop = state.dataPlnt->PlantLoop(this->chillerPloc.loopNum);
    3919            0 :     auto &supplySide = plantLoop.LoopSide(this->chillerPloc.loopSideNum);
    3920            0 :     auto &chillerBranch = supplySide.Branch(this->chillerPloc.branchNum);
    3921            0 :     auto &chillerComp = chillerBranch.Comp(this->chillerPloc.compNum);
    3922              : 
    3923            0 :     int NumVariables = GetNumMeteredVariables(state, chillerComp.TypeOf, chillerComp.Name);
    3924            0 :     meteredVars.allocate(NumVariables);
    3925              : 
    3926            0 :     GetMeteredVariables(state, chillerComp.Name, meteredVars);
    3927            0 :     this->chillerVar.Type = meteredVars(1).varType;
    3928            0 :     this->chillerVar.Num = meteredVars(1).num;
    3929              : 
    3930            0 :     auto &chilledWaterPumpBranch = supplySide.Branch(this->chilledWaterPumpPloc.branchNum);
    3931            0 :     auto &chilledWaterPumpComp = chilledWaterPumpBranch.Comp(this->chilledWaterPumpPloc.compNum);
    3932              : 
    3933            0 :     NumVariables = GetNumMeteredVariables(state, chilledWaterPumpComp.TypeOf, chilledWaterPumpComp.Name);
    3934            0 :     meteredVars.allocate(NumVariables);
    3935              : 
    3936            0 :     GetMeteredVariables(state, chilledWaterPumpComp.Name, meteredVars);
    3937            0 :     this->chilledWaterPumpVar.Type = meteredVars(1).varType;
    3938            0 :     this->chilledWaterPumpVar.Num = meteredVars(1).num;
    3939              : 
    3940            0 :     auto &towerLoopSide = state.dataPlnt->PlantLoop(this->towerPlocs(1).loopNum).LoopSide(this->towerPlocs(1).loopSideNum);
    3941              : 
    3942            0 :     for (int i = 1; i <= this->numTowers; i++) {
    3943            0 :         auto &towerComp = towerLoopSide.Branch(this->towerPlocs(i).branchNum).Comp(this->towerPlocs(i).compNum);
    3944            0 :         NumVariables = GetNumMeteredVariables(state, towerComp.TypeOf, towerComp.Name);
    3945            0 :         meteredVars.allocate(NumVariables);
    3946              : 
    3947            0 :         GetMeteredVariables(state, towerComp.Name, meteredVars);
    3948            0 :         this->towerVars.push_back({meteredVars(1).varType, meteredVars(1).num});
    3949              :     }
    3950              : 
    3951            0 :     auto &condenserPumpComp = towerLoopSide.Branch(this->condenserPumpPloc.branchNum).Comp(this->condenserPumpPloc.compNum);
    3952            0 :     NumVariables = GetNumMeteredVariables(state, condenserPumpComp.TypeOf, condenserPumpComp.Name);
    3953            0 :     meteredVars.allocate(NumVariables);
    3954              : 
    3955            0 :     GetMeteredVariables(state, condenserPumpComp.Name, meteredVars);
    3956            0 :     this->condenserPumpVar = {meteredVars(1).varType, meteredVars(1).num};
    3957            0 : } // SPMIdealCondenserEnteringTemp::SetupMeteredVarsForSetPt()
    3958              : 
    3959            8 : void SPMSystemNode::calculate(EnergyPlusData &state)
    3960              : {
    3961            8 :     Real64 RefValue = 0; // Reference value from the Reference node
    3962              : 
    3963            8 :     auto &refNode = state.dataLoopNodes->Node(this->refNodeNum);
    3964              : 
    3965            8 :     switch (this->ctrlVar) {
    3966            4 :     case HVAC::CtrlVarType::Temp:
    3967              :     case HVAC::CtrlVarType::MaxTemp:
    3968              :     case HVAC::CtrlVarType::MinTemp: {
    3969            4 :         RefValue = refNode.Temp;
    3970            4 :     } break;
    3971            4 :     case HVAC::CtrlVarType::HumRat:
    3972              :     case HVAC::CtrlVarType::MaxHumRat:
    3973              :     case HVAC::CtrlVarType::MinHumRat: {
    3974            4 :         RefValue = refNode.HumRat;
    3975            4 :     } break;
    3976            0 :     default:
    3977            0 :         break;
    3978              :     }
    3979              : 
    3980            8 :     this->setPt = interpSetPoint(this->lowRef, this->highRef, RefValue, this->lowRefSetPt, this->highRefSetPt);
    3981            8 : } // SPMSystemNode::calculate()
    3982              : 
    3983         6123 : Real64 interpSetPoint(Real64 const LowVal, Real64 const HighVal, Real64 const RefVal, Real64 const SetptAtLowVal, Real64 const SetptAtHighVal)
    3984              : {
    3985         6123 :     if (LowVal >= HighVal) {
    3986            2 :         return 0.5 * (SetptAtLowVal + SetptAtHighVal);
    3987         6121 :     } else if (RefVal <= LowVal) {
    3988         2139 :         return SetptAtLowVal;
    3989         3982 :     } else if (RefVal >= HighVal) {
    3990         2371 :         return SetptAtHighVal;
    3991              :     } else {
    3992         1611 :         return SetptAtLowVal - ((RefVal - LowVal) / (HighVal - LowVal)) * (SetptAtLowVal - SetptAtHighVal);
    3993              :     }
    3994              : }
    3995              : 
    3996       208099 : void UpdateSetPointManagers(EnergyPlusData &state)
    3997              : {
    3998              :     // SUBROUTINE INFORMATION:
    3999              :     //       AUTHOR         Fred Buhl
    4000              :     //       DATE WRITTEN   July 1998
    4001              :     //       MODIFIED       Shirey/Raustad (FSEC), Jan 2004
    4002              :     //                      P. Haves Oct 2004
    4003              :     //                        Add new setpoint managers:
    4004              :     //                          SET POINT MANAGER:WARMEST TEMP FLOW and
    4005              :     //                          SET POINT MANAGER:COLDEST TEMP FLOW
    4006              :     //                      Nov 2004 M. J. Witte, GARD Analytics, Inc.
    4007              :     //                        Add new setpoint managers:
    4008              :     //                          SET POINT MANAGER:SINGLE ZONE HEATING and
    4009              :     //                          SET POINT MANAGER:SINGLE ZONE COOLING
    4010              :     //                        Work supported by ASHRAE research project 1254-RP
    4011              :     //                      B. Griffith Aug. 2006.  Allow HUMRAT for scheduled setpoint manager
    4012              :     //                      P. Haves Aug 2007
    4013              :     //                        SET POINT MANAGER:WARMEST TEMP FLOW:
    4014              :     //                          Set AirLoopControlInfo()%LoopFlowRateSet every call not just on
    4015              :     //                          initialization (flag now reset in SUBROUTINE ResetHVACControl)
    4016              :     //                        Removed SET POINT MANAGER:COLDEST TEMP FLOW
    4017              :     //                      July 2010 B.A. Nigusse, FSEC/UCF
    4018              :     //                        Added new setpoint managers
    4019              :     //                          SetpointManager:MultiZone:Heating:Average
    4020              :     //                          SetpointManager:MultiZone:Cooling:Average
    4021              :     //                          SetpointManager:MultiZone:MinimumHumidity:Average
    4022              :     //                          SetpointManager:MultiZone:MaximumHumidity:Average
    4023              :     //                      Aug 2010 B.A. Nigusse, FSEC/UCF
    4024              :     //                        Added new setpoint managers:
    4025              :     //                          SetpointManager:MultiZone:Humidity:Minimum
    4026              :     //                          SetpointManager:MultiZone:Humidity:Maximum
    4027              :     //                      Aug 2014 Rick Strand, UIUC
    4028              :     //                          SetpointManager:ScheduledTES (internally defined)
    4029              :     //                      Jan 2022 Wooyoung Jung, Jeremy Lerond and Jian Zhang, PNNL
    4030              :     //                        Added new setpoint managers:
    4031              :     //                          SetpointManager:SystemNodeReset:Temperature
    4032              :     //                          SetpointManager:SystemNodeReset:Humidity
    4033              : 
    4034              :     // PURPOSE OF THIS SUBROUTINE
    4035              :     // Loop over all the Setpoint Managers and use their output arrays
    4036              :     // to set the node setpoints.
    4037              : 
    4038              :     // Using/Aliasing
    4039              :     using EMSManager::CheckIfNodeSetPointManagedByEMS;
    4040              : 
    4041              :     // Loop over all the Scheduled Setpoint Managers
    4042       340424 :     for (auto *spm : state.dataSetPointManager->spms) {
    4043              : 
    4044       132325 :         switch (spm->type) {
    4045              : 
    4046        53925 :         case SPMType::Scheduled:
    4047              :         case SPMType::SystemNodeTemp:
    4048              :         case SPMType::SystemNodeHum: {
    4049       109177 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4050        55252 :                 auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4051        55252 :                 switch (spm->ctrlVar) {
    4052              :                 // set the setpoint depending on the type of variable being controlled
    4053        55249 :                 case HVAC::CtrlVarType::Temp: {
    4054        55249 :                     node.TempSetPoint = spm->setPt;
    4055        55249 :                 } break;
    4056            0 :                 case HVAC::CtrlVarType::MaxTemp: {
    4057            0 :                     node.TempSetPointHi = spm->setPt;
    4058            0 :                 } break;
    4059            0 :                 case HVAC::CtrlVarType::MinTemp: {
    4060            0 :                     node.TempSetPointLo = spm->setPt;
    4061            0 :                 } break;
    4062            3 :                 case HVAC::CtrlVarType::HumRat: {
    4063            3 :                     node.HumRatSetPoint = spm->setPt;
    4064            3 :                 } break;
    4065            0 :                 case HVAC::CtrlVarType::MaxHumRat: {
    4066            0 :                     node.HumRatMax = spm->setPt;
    4067            0 :                 } break;
    4068            0 :                 case HVAC::CtrlVarType::MinHumRat: {
    4069            0 :                     node.HumRatMin = spm->setPt;
    4070            0 :                 } break;
    4071            0 :                 case HVAC::CtrlVarType::MassFlowRate: {
    4072            0 :                     node.MassFlowRateSetPoint = spm->setPt;
    4073            0 :                 } break;
    4074            0 :                 case HVAC::CtrlVarType::MaxMassFlowRate: {
    4075            0 :                     node.MassFlowRateMax = spm->setPt;
    4076            0 :                 } break;
    4077            0 :                 case HVAC::CtrlVarType::MinMassFlowRate: {
    4078            0 :                     node.MassFlowRateMin = spm->setPt;
    4079            0 :                 } break;
    4080            0 :                 default:
    4081            0 :                     break;
    4082              :                 }
    4083              :             } // for (CtrlNodeNum)
    4084        53925 :         } break;
    4085              : 
    4086            0 :         case SPMType::TESScheduled: {
    4087            0 :             auto *spmTESS = dynamic_cast<SPMTESScheduled *>(spm);
    4088            0 :             assert(spmTESS != nullptr);
    4089              : 
    4090            0 :             state.dataLoopNodes->Node(spmTESS->ctrlNodeNum).TempSetPoint = spm->setPt;
    4091            0 :         } break;
    4092              : 
    4093          576 :         case SPMType::ScheduledDual: {
    4094          576 :             auto *spmSD = dynamic_cast<SPMScheduledDual *>(spm);
    4095          576 :             assert(spmSD != nullptr);
    4096              : 
    4097          576 :             if (spmSD->ctrlVar == HVAC::CtrlVarType::Temp) {
    4098         1152 :                 for (int ctrlNodeNum : spmSD->ctrlNodeNums) {
    4099          576 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4100              : 
    4101          576 :                     node.TempSetPointHi = spmSD->setPtHi;                                  // Set the setpoint High
    4102          576 :                     node.TempSetPointLo = spmSD->setPtLo;                                  // Set the setpoint Low
    4103          576 :                     node.TempSetPoint = (node.TempSetPointHi + node.TempSetPointLo) / 2.0; // average of the high and low
    4104              :                 }
    4105              :             }
    4106          576 :         } break;
    4107              : 
    4108         9570 :         case SPMType::OutsideAir:
    4109              :         case SPMType::FollowOutsideAirTemp:
    4110              :         case SPMType::FollowSystemNodeTemp:
    4111              :         case SPMType::FollowGroundTemp: {
    4112        23184 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4113        13614 :                 auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4114        13614 :                 if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    4115        13608 :                     node.TempSetPoint = spm->setPt;
    4116            6 :                 } else if (spm->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    4117            3 :                     node.TempSetPointHi = spm->setPt;
    4118            3 :                 } else if (spm->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    4119            3 :                     node.TempSetPointLo = spm->setPt;
    4120              :                 }
    4121              :             }
    4122              : 
    4123         9570 :         } break;
    4124              : 
    4125        12673 :         case SPMType::SZReheat:
    4126              :         case SPMType::SZHeating:
    4127              :         case SPMType::SZCooling:
    4128              :         case SPMType::Warmest:
    4129              :         case SPMType::Coldest:
    4130              :         case SPMType::MZCoolingAverage:
    4131              :         case SPMType::MZHeatingAverage:
    4132              :         case SPMType::CondenserEnteringTemp:
    4133              :         case SPMType::IdealCondenserEnteringTemp:
    4134              :         case SPMType::SZOneStageCooling:
    4135              :         case SPMType::SZOneStageHeating: {
    4136        12673 :             if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    4137        25346 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4138        12673 :                     state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spm->setPt; // Set the setpoint
    4139              :                 }
    4140              :             }
    4141        12673 :         } break;
    4142              : 
    4143            0 :         case SPMType::SZMinHum:
    4144              :         case SPMType::MZMinHumAverage:
    4145              :         case SPMType::MZMinHum: {
    4146            0 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4147            0 :                 if (spm->type == SPMType::SZMinHum || spm->ctrlVar == HVAC::CtrlVarType::MinHumRat) // Why is SZMinHum not tested for this?
    4148            0 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMin = spm->setPt;
    4149              :             }
    4150            0 :         } break;
    4151              : 
    4152            0 :         case SPMType::SZMaxHum:
    4153              :         case SPMType::MZMaxHumAverage:
    4154              :         case SPMType::MZMaxHum: {
    4155            0 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4156            0 :                 if (spm->type == SPMType::SZMaxHum || spm->ctrlVar == HVAC::CtrlVarType::MaxHumRat) // Why is SZMaxHum not tested for this?
    4157            0 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMax = spm->setPt;
    4158              :             }
    4159            0 :         } break;
    4160              : 
    4161            0 :         case SPMType::WarmestTempFlow: {
    4162            0 :             auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    4163            0 :             assert(spmWTF != nullptr);
    4164              : 
    4165            0 :             if (spmWTF->ctrlVar == HVAC::CtrlVarType::Temp) {
    4166            0 :                 for (int ctrlNodeNum : spmWTF->ctrlNodeNums) {
    4167            0 :                     state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmWTF->setPt; // Set the supply air temperature setpoint
    4168              :                 }
    4169              : 
    4170            0 :                 state.dataAirLoop->AirLoopFlow(spmWTF->airLoopNum).ReqSupplyFrac = spmWTF->turndown; // Set the supply air flow rate
    4171            0 :                 state.dataAirLoop->AirLoopControlInfo(spmWTF->airLoopNum).LoopFlowRateSet = true;    // PH 8/17/07
    4172              :             }
    4173            0 :         } break;
    4174              : 
    4175            0 :         case SPMType::ReturnAirBypass: {
    4176            0 :             auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    4177            0 :             assert(spmRAB != nullptr);
    4178              : 
    4179            0 :             if (spmRAB->ctrlVar == HVAC::CtrlVarType::MassFlowRate) {
    4180            0 :                 state.dataLoopNodes->Node(spmRAB->rabSplitOutNodeNum).MassFlowRateSetPoint = spmRAB->FlowSetPt; // Set the flow setpoint
    4181              :             }
    4182            0 :         } break;
    4183              : 
    4184            0 :         case SPMType::ChilledWaterReturnTemp:
    4185              :         case SPMType::HotWaterReturnTemp: {
    4186            0 :             auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    4187            0 :             assert(spmRWT != nullptr);
    4188            0 :             if (spmRWT->plantSetPtNodeNum > 0) {
    4189            0 :                 state.dataLoopNodes->Node(spmRWT->plantSetPtNodeNum).TempSetPoint = spmRWT->currentSupplySetPt;
    4190              :             }
    4191            0 :         } break;
    4192              : 
    4193              :         // MixedAir and OutsideAirPretreat SPMs have to be handled separately because they depend on other SPMs
    4194        55581 :         case SPMType::MixedAir:
    4195              :         case SPMType::OutsideAirPretreat: {
    4196        55581 :         } break;
    4197              : 
    4198            0 :         default:
    4199            0 :             break;
    4200              :         } // switch (sys->type)
    4201              :     }     // for (spm)
    4202       208099 : } // UpdateSetPointManagers()
    4203              : 
    4204       208082 : void UpdateMixedAirSetPoints(EnergyPlusData &state)
    4205              : {
    4206              :     // SUBROUTINE INFORMATION:
    4207              :     //       AUTHOR         Fred Buhl
    4208              :     //       DATE WRITTEN   May 2001
    4209              : 
    4210              :     // PURPOSE OF THIS SUBROUTINE
    4211              :     // Loop over all the Mixed Air Managers and use their output arrays
    4212              :     // to set the node setpoints.
    4213              : 
    4214       340388 :     for (auto *spm : state.dataSetPointManager->spms) {
    4215       132306 :         if (spm->type != SPMType::MixedAir) continue;
    4216        55580 :         if (spm->ctrlVar != HVAC::CtrlVarType::Temp) continue;
    4217       126531 :         for (int ctrlNodeNum : spm->ctrlNodeNums)
    4218        70951 :             state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spm->setPt; // Set the setpoint
    4219              :     }
    4220       208082 : } // UpdateMixedAirSetPoints()
    4221              : 
    4222       208082 : void UpdateOAPretreatSetPoints(EnergyPlusData &state)
    4223              : {
    4224              :     // SUBROUTINE INFORMATION:
    4225              :     //       AUTHOR         M. J. Witte based on UpdateMixedAirSetPoints by Fred Buhl,
    4226              :     //                        Work supported by ASHRAE research project 1254-RP
    4227              :     //       DATE WRITTEN   January 2005
    4228              : 
    4229              :     // PURPOSE OF THIS SUBROUTINE
    4230              :     // Loop over all the Outside Air Pretreat Managers and use their output arrays
    4231              :     // to set the node setpoints.
    4232              : 
    4233       340388 :     for (auto *spm : state.dataSetPointManager->spms) {
    4234       132306 :         if (spm->type != SPMType::OutsideAirPretreat) continue;
    4235            0 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4236            0 :             auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4237            0 :             switch (spm->ctrlVar) {
    4238            0 :             case HVAC::CtrlVarType::Temp: {
    4239            0 :                 node.TempSetPoint = spm->setPt;
    4240            0 :             } break;
    4241            0 :             case HVAC::CtrlVarType::MaxHumRat: {
    4242            0 :                 node.HumRatMax = spm->setPt;
    4243            0 :             } break;
    4244            0 :             case HVAC::CtrlVarType::MinHumRat: {
    4245            0 :                 node.HumRatMin = spm->setPt;
    4246            0 :             } break;
    4247            0 :             case HVAC::CtrlVarType::HumRat: {
    4248            0 :                 node.HumRatSetPoint = spm->setPt;
    4249            0 :             } break;
    4250            0 :             default:
    4251            0 :                 break;
    4252              :             }
    4253              :         }
    4254              :     }
    4255       208082 : } // UpdateOutsideAirSetPoints()
    4256              : 
    4257            4 : int GetSetPointManagerIndexByNode(EnergyPlusData &state, int const NodeNum, HVAC::CtrlVarType const ctrlVar, SPMType const spmType, bool isRefNode)
    4258              : {
    4259              : 
    4260            4 :     if (state.dataSetPointManager->GetInputFlag) {
    4261            4 :         GetSetPointManagerInputs(state);
    4262            4 :         state.dataSetPointManager->GetInputFlag = false;
    4263              :     }
    4264              : 
    4265            4 :     for (int iSPM = 1; iSPM < (int)state.dataSetPointManager->spms.size(); ++iSPM) {
    4266            0 :         auto *spm = state.dataSetPointManager->spms(iSPM);
    4267            0 :         if (spm->type != spmType) continue;
    4268            0 :         if (spm->ctrlVar != ctrlVar) continue;
    4269              : 
    4270            0 :         if (isRefNode) {
    4271            0 :             if (NodeNum == spm->refNodeNum) return iSPM;
    4272              :         } else {
    4273            0 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4274            0 :                 if (NodeNum == ctrlNodeNum) return iSPM;
    4275              :             }
    4276              :         }
    4277              :     }
    4278              : 
    4279            4 :     return 0;
    4280              : } // getSPMIndexByNode()
    4281              : 
    4282          248 : bool IsNodeOnSetPtManager(EnergyPlusData &state, int const NodeNum, HVAC::CtrlVarType const ctrlVar)
    4283              : {
    4284              :     // FUNCTION INFORMATION:
    4285              :     //       AUTHOR         Sankaranarayanan K P
    4286              :     //       DATE WRITTEN   January 2007
    4287              : 
    4288              :     // PURPOSE OF THIS SUBROUTINE:
    4289              :     // Determines if a particular node is acted upon by a specific setpoint manager
    4290              : 
    4291              :     // METHODOLOGY EMPLOYED:
    4292              :     // Cycle through all setpoint managers and find if the node passed in has a setpoint manager of passed
    4293              :     // in type associated to it.
    4294              :     // Return value
    4295              : 
    4296              :     // First time called, get the input for all the setpoint managers
    4297          248 :     if (state.dataSetPointManager->GetInputFlag) {
    4298           20 :         GetSetPointManagerInputs(state);
    4299           20 :         state.dataSetPointManager->GetInputFlag = false;
    4300              :     }
    4301              : 
    4302          853 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4303          668 :         if (spm->ctrlVar != ctrlVar) continue;
    4304         1399 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4305          797 :             if (NodeNum == ctrlNodeNum) return true;
    4306              :         }
    4307              :     }
    4308              : 
    4309          185 :     return false;
    4310              : } // IsNodeOnSetPointManager()
    4311              : 
    4312          596 : bool NodeHasSPMCtrlVarType(EnergyPlusData &state, int const NodeNum, HVAC::CtrlVarType const ctrlVar)
    4313              : {
    4314              :     // FUNCTION INFORMATION:
    4315              :     //       AUTHOR         Chandan Sharma
    4316              :     //       DATE WRITTEN   March 2013
    4317              : 
    4318              :     // PURPOSE OF THIS SUBROUTINE:
    4319              :     // Determines if a particular node is acted upon by a specific setpoint manager
    4320              : 
    4321              :     // METHODOLOGY EMPLOYED:
    4322              :     // Cycle through all setpoint managers and find if the node has a specific control type
    4323              : 
    4324              :     // First time called, get the input for all the setpoint managers
    4325          596 :     if (state.dataSetPointManager->GetInputFlag) {
    4326           73 :         GetSetPointManagerInputs(state);
    4327           73 :         state.dataSetPointManager->GetInputFlag = false;
    4328              :     }
    4329              : 
    4330          924 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4331          465 :         if (spm->ctrlVar != ctrlVar) continue;
    4332          807 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4333          490 :             if (NodeNum == ctrlNodeNum) return true;
    4334              :         }
    4335              :     }
    4336              : 
    4337          459 :     return false;
    4338              : } // NodeHasSPMCtrlVarType()
    4339              : 
    4340           13 : void ResetHumidityRatioCtrlVarType(EnergyPlusData &state, int const NodeNum)
    4341              : {
    4342              :     // FUNCTION INFORMATION:
    4343              :     //       AUTHOR         Bereket Nigusse
    4344              :     //       DATE WRITTEN   August 2015
    4345              : 
    4346              :     // PURPOSE OF THIS SUBROUTINE:
    4347              :     // Resets setpoint control variable type to "Maximum Humidity Ratio" if control variable type
    4348              :     // is "Humidity Ratio".
    4349              : 
    4350              :     // METHODOLOGY EMPLOYED:
    4351              :     // Cycle through all setpoint managers and find if the node has a "Humidity Ratio" control
    4352              :     // variable type. This routine is called from "GetControllerInput" routine.  This reset is
    4353              :     // just to stop false warning message due to control variable type mismatch.
    4354              : 
    4355              :     // First time called, get the input for all the setpoint managers
    4356           13 :     if (state.dataSetPointManager->GetInputFlag) {
    4357            4 :         GetSetPointManagerInputs(state);
    4358            4 :         state.dataSetPointManager->GetInputFlag = false;
    4359              :     }
    4360              : 
    4361           20 :     for (auto *spm : state.dataSetPointManager->spms) {
    4362           10 :         if (spm->ctrlVar != HVAC::CtrlVarType::HumRat) continue;
    4363            3 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4364            3 :             if (NodeNum != ctrlNodeNum) continue;
    4365              : 
    4366            3 :             spm->ctrlVar = HVAC::CtrlVarType::MaxHumRat;
    4367            3 :             ShowWarningError(state, format("ResetHumidityRatioCtrlVarType: {}=\"{}\". ", spmTypeNames[(int)spm->type], spm->Name));
    4368            6 :             ShowContinueError(state, " ..Humidity ratio control variable type specified is = HumidityRatio");
    4369            6 :             ShowContinueError(state, " ..Humidity ratio control variable type allowed with water coils is = MaximumHumidityRatio");
    4370            6 :             ShowContinueError(state, " ..Setpointmanager control variable type is reset to = MaximumHumidityRatio");
    4371            6 :             ShowContinueError(state, " ..Simulation continues. ");
    4372            3 :             return;
    4373              :         }
    4374              :     }
    4375              : } // ResetHumidityRatioCtrlVarType()
    4376              : 
    4377           75 : void CheckIfAnyIdealCondEntSetPoint(EnergyPlusData &state)
    4378              : {
    4379              :     // SUBROUTINE INFORMATION:
    4380              :     //       AUTHOR         Heejin Cho, PNNL
    4381              :     //       DATE WRITTEN   March 2012
    4382              : 
    4383              :     // PURPOSE OF THIS SUBROUTINE:
    4384              :     // Determine if ideal condenser entering set point manager is used in model and set flag
    4385              : 
    4386          150 :     state.dataGlobal->AnyIdealCondEntSetPointInModel =
    4387           75 :         (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SetpointManager:CondenserEnteringReset:Ideal") > 0);
    4388           75 : } // CheckIfAnyIdealCondEntSetPoint()
    4389              : 
    4390            3 : HVAC::CtrlVarType GetHumidityRatioVariableType(EnergyPlusData &state, int const NodeNum)
    4391              : {
    4392              :     // SUBROUTINE INFORMATION:
    4393              :     //       AUTHOR         B. A. Nigusse
    4394              :     //       DATE WRITTEN   December 2013
    4395              : 
    4396              :     // PURPOSE OF THIS SUBROUTINE
    4397              :     // Loop over all the humidity setpoint Managers to determine the
    4398              :     // humidity ratio setpoint type
    4399              : 
    4400            3 :     if (state.dataSetPointManager->GetInputFlag) {
    4401            0 :         GetSetPointManagerInputs(state);
    4402            0 :         state.dataSetPointManager->GetInputFlag = false;
    4403              :     }
    4404              : 
    4405            7 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4406            4 :         if (spm->type != SPMType::SZMaxHum && spm->type != SPMType::MZMaxHum && spm->type != SPMType::MZMaxHumAverage) continue;
    4407            0 :         if (std::find(spm->ctrlNodeNums.begin(), spm->ctrlNodeNums.end(), NodeNum) != spm->ctrlNodeNums.end()) {
    4408            0 :             return HVAC::CtrlVarType::MaxHumRat;
    4409              :         }
    4410              :     }
    4411              : 
    4412            7 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4413            4 :         if (spm->type != SPMType::SZMinHum && spm->type != SPMType::MZMinHum && spm->type != SPMType::MZMinHumAverage) continue;
    4414            0 :         if (std::find(spm->ctrlNodeNums.begin(), spm->ctrlNodeNums.end(), NodeNum) != spm->ctrlNodeNums.end()) {
    4415            0 :             return HVAC::CtrlVarType::MaxHumRat;
    4416              :         }
    4417              :     }
    4418              : 
    4419            4 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4420            4 :         if (spm->type != SPMType::Scheduled) continue;
    4421            4 :         if (std::find(spm->ctrlNodeNums.begin(), spm->ctrlNodeNums.end(), NodeNum) != spm->ctrlNodeNums.end()) {
    4422            4 :             if (spm->ctrlVar == HVAC::CtrlVarType::HumRat || spm->ctrlVar == HVAC::CtrlVarType::MaxHumRat) return spm->ctrlVar;
    4423              :         }
    4424              :     }
    4425              : 
    4426            0 :     return HVAC::CtrlVarType::HumRat;
    4427              : } // GetHumidityRatioVariableType()
    4428              : 
    4429            2 : void SetUpNewScheduledTESSetPtMgr(EnergyPlusData &state,
    4430              :                                   Sched::Schedule *sched,
    4431              :                                   Sched::Schedule *chargeSched,
    4432              :                                   Real64 NonChargeCHWTemp,
    4433              :                                   Real64 ChargeCHWTemp,
    4434              :                                   DataPlant::CtrlType CompOpType,
    4435              :                                   int const ControlNodeNum)
    4436              : {
    4437              :     // SUBROUTINE INFORMATION:
    4438              :     //       AUTHOR         Rick Strand
    4439              :     //       DATE WRITTEN   August 2014
    4440              : 
    4441              :     // PURPOSE OF THIS SUBROUTINE
    4442              :     // Set up new scheduled TES setpoint managers based on plant control Simple TES
    4443              : 
    4444              :     // METHODOLOGY EMPLOYED:
    4445              :     // Set up internally created scheduled setpoint managers to control the setpoints
    4446              :     // of various ice storage equipment with the user having to do this manually.  The
    4447              :     // point is to provide a simpler input description and take care of logic internally.
    4448              : 
    4449            2 :     auto *spm = new SPMTESScheduled;
    4450              : 
    4451              :     // Set up the scheduled TES setpoint manager information
    4452            2 :     spm->Name = format("TES Scheduled {}", state.dataSetPointManager->spms.size());
    4453            2 :     state.dataSetPointManager->spms.push_back(spm);
    4454            2 :     state.dataSetPointManager->spmMap.insert_or_assign(spm->Name, state.dataSetPointManager->spms.size());
    4455              : 
    4456            2 :     spm->sched = sched;
    4457            2 :     spm->chargeSched = chargeSched;
    4458            2 :     spm->nonChargeCHWTemp = NonChargeCHWTemp;
    4459            2 :     spm->chargeCHWTemp = ChargeCHWTemp;
    4460            2 :     spm->compOpType = CompOpType;
    4461            2 :     spm->ctrlNodeNum = ControlNodeNum;
    4462              : 
    4463              :     // Set up the all setpoint manager information for "verification" that no other setpoint manager controls the node that this new ones does
    4464            2 :     spm->ctrlNodeNums.push_back(spm->ctrlNodeNum);
    4465            2 :     spm->type = SPMType::TESScheduled;
    4466            2 :     spm->ctrlVar = HVAC::CtrlVarType::Temp;
    4467              : 
    4468              :     // Now verify that there is no overlap (no other SPM uses the node of the new setpoint manager)
    4469            2 :     bool ErrorsFoundinTESSchSetup = false;
    4470            2 :     VerifySetPointManagers(state, ErrorsFoundinTESSchSetup);
    4471            2 :     if (ErrorsFoundinTESSchSetup) {
    4472            0 :         ShowFatalError(state, "Errors found in verification step of SetUpNewScheduledTESSetPtMgr.  Program terminates.");
    4473              :     }
    4474              :     // Since all of the other setpoint managers not only been read and verified but also initialized, simulated, and updated,
    4475              :     // we must now also initialize, simulate, and update the current SchTESStPtMgr that was just added.  But the init and simulate
    4476              :     // steps are the same so we can call the simulate first.
    4477              : 
    4478            2 :     spm->calculate(state);
    4479              : 
    4480              :     // Now update reusing code from Update routine specialized to only doing the current (new) setpoint manager and then we are done
    4481            2 :     state.dataLoopNodes->Node(spm->ctrlNodeNum).TempSetPoint = spm->setPt;
    4482            2 : } // end of SetUpNewScheduledTESSetPtMgr
    4483              : 
    4484            0 : bool GetCoilFreezingCheckFlag(EnergyPlusData &state, int const spmNum)
    4485              : {
    4486              :     // SUBROUTINE INFORMATION:
    4487              :     //       AUTHOR         L. Gu
    4488              :     //       DATE WRITTEN   Nov. 2015
    4489              : 
    4490              :     // PURPOSE OF THIS SUBROUTINE
    4491              :     // Get freezing check status
    4492            0 :     if (state.dataSetPointManager->GetInputFlag) {
    4493            0 :         GetSetPointManagerInputs(state);
    4494            0 :         state.dataSetPointManager->GetInputFlag = false;
    4495              :     }
    4496              : 
    4497            0 :     auto const *spmMA = dynamic_cast<SPMMixedAir *>(state.dataSetPointManager->spms(spmNum));
    4498            0 :     assert(spmMA != nullptr);
    4499            0 :     return spmMA->freezeCheckEnable;
    4500              : } // GetCoilFreezingCheckFlag()
    4501              : 
    4502           56 : int GetMixedAirNumWithCoilFreezingCheck(EnergyPlusData &state, int const MixedAirNode)
    4503              : {
    4504              :     // SUBROUTINE INFORMATION:
    4505              :     //       AUTHOR         L. Gu
    4506              :     //       DATE WRITTEN   Nov. 2015
    4507              : 
    4508              :     // PURPOSE OF THIS SUBROUTINE
    4509              :     // Loop over all the MixedAir setpoint Managers to find coil freezing check flag
    4510              : 
    4511           56 :     if (state.dataSetPointManager->GetInputFlag) {
    4512           26 :         GetSetPointManagerInputs(state);
    4513           26 :         state.dataSetPointManager->GetInputFlag = false;
    4514              :     }
    4515              : 
    4516          144 :     for (int iSPM = 1; iSPM <= state.dataSetPointManager->spms.isize(); ++iSPM) {
    4517           88 :         auto *const spm = state.dataSetPointManager->spms(iSPM);
    4518           88 :         if (spm->type != SPMType::MixedAir) continue;
    4519              : 
    4520           42 :         auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
    4521           42 :         assert(spmMA != nullptr);
    4522              : 
    4523           42 :         if (std::find(spmMA->ctrlNodeNums.begin(), spmMA->ctrlNodeNums.end(), MixedAirNode) != spmMA->ctrlNodeNums.end() &&
    4524           42 :             spmMA->coolCoilInNodeNum > 0 && spmMA->coolCoilOutNodeNum > 0) {
    4525            0 :             return iSPM; // Is this really thing we are returning? Not the number of the SPM?  Why?
    4526              :         }
    4527              :     }
    4528              : 
    4529           56 :     return 0;
    4530              : } // End of GetMixedAirNumWithCoilFreezingCheck()
    4531              : 
    4532              : } // namespace EnergyPlus::SetPointManager
        

Generated by: LCOV version 2.0-1