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

Generated by: LCOV version 2.0-1