LCOV - code coverage report
Current view: top level - EnergyPlus - SetPointManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 76.2 % 2328 1774
Test Date: 2025-06-02 07:23:51 Functions: 95.7 % 46 44

            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      2855467 : 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      2855467 :     if (state.dataSetPointManager->GetInputFlag) {
     261          797 :         GetSetPointManagerInputs(state);
     262          797 :         state.dataSetPointManager->GetInputFlag = false;
     263              :     }
     264              : 
     265      2855467 :     InitSetPointManagers(state);
     266              : 
     267      2855467 :     if (state.dataSetPointManager->ManagerOn) {
     268      2849196 :         SimSetPointManagers(state);
     269      2849196 :         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     21297181 :         for (auto *spm : state.dataSetPointManager->spms) {
     273     18447985 :             if (spm->type == SPMType::MixedAir) {
     274      7388026 :                 spm->calculate(state);
     275              :             }
     276              :         }
     277      2849196 :         UpdateMixedAirSetPoints(state);
     278              :         // The Outside Air Pretreat Setpoint Managers (since they depend on other setpoints, they must be calculated
     279              :         // and updated last).
     280     21297181 :         for (auto *spm : state.dataSetPointManager->spms) {
     281     18447985 :             if (spm->type == SPMType::OutsideAirPretreat) {
     282        21275 :                 spm->calculate(state);
     283              :             }
     284              :         }
     285              : 
     286      2849196 :         UpdateOAPretreatSetPoints(state);
     287              :     }
     288      2855467 : } // ManageSetPoints()
     289              : 
     290            0 : int GetSetPointManagerIndex(EnergyPlusData const &state, std::string const &Name)
     291              : {
     292            0 :     auto found = state.dataSetPointManager->spmMap.find(Name);
     293            0 :     return (found != state.dataSetPointManager->spmMap.end()) ? found->second : 0;
     294            0 : } // GetSetPointManagerIndex()
     295              : 
     296          801 : void GetSetPointManagerInputs(EnergyPlusData &state)
     297              : {
     298              :     // wrapper for GetInput to allow unit testing when fatal inputs are detected
     299          801 :     constexpr std::string_view routineName = "GetSetPointManagerInputs"; // include trailing blank space
     300              : 
     301          801 :     if (state.dataSetPointManager->GetInputFlag) {
     302          801 :         bool ErrorsFound(false);
     303          801 :         GetSetPointManagerInputData(state, ErrorsFound);
     304              : 
     305          801 :         if (ErrorsFound) {
     306            0 :             ShowFatalError(state, format("{}: Errors found in input.  Program terminates.", routineName));
     307              :         }
     308          801 :         state.dataSetPointManager->GetInputFlag = false;
     309              :     }
     310          801 : } // GetSetPointManagerInputs()
     311              : 
     312          801 : 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          801 :     std::string cCurrentModuleObject;
     361              : 
     362              :     int NumNodes;
     363          801 :     Array1D_int NodeNums;
     364          801 :     bool NodeListError(false);
     365              :     bool ErrInList;
     366              : 
     367          801 :     auto &ip = state.dataInputProcessing->inputProcessor;
     368              : 
     369          801 :     int NumNums = 0;
     370          801 :     int NumAlphas = 0;
     371          801 :     int NumParams = 0;
     372              : 
     373          801 :     state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, "NodeList", NumParams, NumAlphas, NumNums);
     374          801 :     NodeNums.dimension(NumParams, 0);
     375              : 
     376              :     // Input the data for each Setpoint Manager
     377              : 
     378        26433 :     for (int iSPM = 0; iSPM < (int)SPMType::Num; ++iSPM) {
     379        25632 :         SPMType type = static_cast<SPMType>(iSPM);
     380        25632 :         cCurrentModuleObject = spmTypeNames[iSPM];
     381              : 
     382        25632 :         auto const instances = ip->epJSON.find(cCurrentModuleObject);
     383        25632 :         if (instances == ip->epJSON.end()) {
     384        24314 :             continue; // No SetPointManagers of this type
     385              :         }
     386              : 
     387         1318 :         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         1318 :         std::vector<int> idfNums;
     400         1318 :         std::vector<std::string> idfKeys;
     401         1318 :         int idfFakeNum = 0;
     402         6097 :         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         4779 :             if (state.dataGlobal->isEpJSON || !state.dataGlobal->preserveIDFOrder) {
     405           13 :                 idfNums.push_back(++idfFakeNum);
     406              :             } else {
     407        14298 :                 idfNums.push_back(instance.value().at("idf_order").get<int>());
     408              :             }
     409         4779 :             idfKeys.push_back(instance.key());
     410         1318 :         }
     411              : 
     412              :         // Now sort the IDF numbers
     413         1318 :         std::vector<int> idfSortedNums = idfNums;
     414         1318 :         std::sort(idfSortedNums.begin(), idfSortedNums.end());
     415              : 
     416              :         // Iterate through the sorted IDF numbers
     417         6097 :         for (int idfSortedNum : idfSortedNums) {
     418              :             // Find that number's position in the epJSON order
     419         4779 :             int epJsonNum = std::find(idfNums.begin(), idfNums.end(), idfSortedNum) - idfNums.begin();
     420              :             // Grab the corresponding name
     421         4779 :             std::string const &key = idfKeys[epJsonNum];
     422         4779 :             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         4779 :             ip->markObjectAsUsed(cCurrentModuleObject, key);
     434         4779 :             std::string name = Util::makeUPPER(key);
     435              : 
     436         4779 :             ErrorObjectHeader eoh{routineName, cCurrentModuleObject, name};
     437              : 
     438         4779 :             if (state.dataSetPointManager->spmMap.find(name) != state.dataSetPointManager->spmMap.end()) {
     439            0 :                 ShowSevereDuplicateName(state, eoh);
     440            0 :                 ErrorsFound = true;
     441              :             }
     442              : 
     443         4779 :             SPMBase *spm = nullptr;
     444              : 
     445              :             // Create a SetPointManagerObject of the right child type
     446         4779 :             switch (type) {
     447         1961 :             case SPMType::Scheduled: {
     448         1961 :                 spm = new SPMScheduled;
     449         1961 :             } break;
     450           22 :             case SPMType::ScheduledDual: {
     451           22 :                 spm = new SPMScheduledDual;
     452           22 :             } break;
     453          103 :             case SPMType::OutsideAir: {
     454          103 :                 spm = new SPMOutsideAir;
     455          103 :             } break;
     456          291 :             case SPMType::SZReheat: {
     457          291 :                 spm = new SPMSingleZoneReheat;
     458          291 :             } break;
     459          294 :             case SPMType::SZHeating:
     460              :             case SPMType::SZCooling: {
     461          294 :                 spm = new SPMSingleZoneTemp;
     462          294 :             } break;
     463           89 :             case SPMType::SZMinHum:
     464              :             case SPMType::SZMaxHum: {
     465           89 :                 spm = new SPMSingleZoneHum;
     466           89 :             } break;
     467         1710 :             case SPMType::MixedAir: {
     468         1710 :                 spm = new SPMMixedAir;
     469         1710 :             } break;
     470            9 :             case SPMType::OutsideAirPretreat: {
     471            9 :                 spm = new SPMOutsideAirPretreat;
     472            9 :             } break;
     473           23 :             case SPMType::Warmest:
     474              :             case SPMType::Coldest: {
     475           23 :                 spm = new SPMTempest;
     476           23 :             } break;
     477            4 :             case SPMType::WarmestTempFlow: {
     478            4 :                 spm = new SPMWarmestTempFlow;
     479            4 :             } break;
     480            2 :             case SPMType::MZCoolingAverage:
     481              :             case SPMType::MZHeatingAverage: {
     482            2 :                 spm = new SPMMultiZoneTemp;
     483            2 :             } break;
     484           24 :             case SPMType::MZMinHumAverage:
     485              :             case SPMType::MZMaxHumAverage:
     486              :             case SPMType::MZMinHum:
     487              :             case SPMType::MZMaxHum: {
     488           24 :                 spm = new SPMMultiZoneHum;
     489           24 :             } break;
     490            1 :             case SPMType::ReturnAirBypass: {
     491            1 :                 spm = new SPMReturnAirBypassFlow;
     492            1 :             } break;
     493          204 :             case SPMType::FollowOutsideAirTemp: {
     494          204 :                 spm = new SPMFollowOutsideAirTemp;
     495          204 :             } break;
     496            1 :             case SPMType::FollowSystemNodeTemp: {
     497            1 :                 spm = new SPMFollowSysNodeTemp;
     498            1 :             } break;
     499           20 :             case SPMType::FollowGroundTemp: {
     500           20 :                 spm = new SPMFollowGroundTemp;
     501           20 :             } break;
     502            3 :             case SPMType::CondenserEnteringTemp: {
     503            3 :                 spm = new SPMCondenserEnteringTemp;
     504            3 :             } break;
     505            2 :             case SPMType::IdealCondenserEnteringTemp: {
     506            2 :                 spm = new SPMIdealCondenserEnteringTemp;
     507            2 :             } break;
     508            4 :             case SPMType::SZOneStageCooling: {
     509            4 :                 spm = new SPMSingleZoneOneStageCooling;
     510            4 :             } break;
     511            4 :             case SPMType::SZOneStageHeating: {
     512            4 :                 spm = new SPMSingleZoneOneStageHeating;
     513            4 :             } break;
     514            4 :             case SPMType::ChilledWaterReturnTemp:
     515              :             case SPMType::HotWaterReturnTemp: {
     516            4 :                 spm = new SPMReturnWaterTemp;
     517            4 :             } break;
     518            0 :             case SPMType::TESScheduled: {
     519            0 :                 spm = new SPMTESScheduled;
     520            0 :             } break;
     521            4 :             case SPMType::SystemNodeTemp:
     522              :             case SPMType::SystemNodeHum: {
     523            4 :                 spm = new SPMSystemNode;
     524            4 :             } break;
     525            0 :             default: {
     526            0 :                 assert(false);
     527              :             } break;
     528              :             } // switch (type)
     529              : 
     530              :             // Set name and append to array
     531         4779 :             spm->Name = name;
     532         4779 :             spm->type = type;
     533         4779 :             state.dataSetPointManager->spms.push_back(spm);
     534         4779 :             state.dataSetPointManager->spmMap.insert_or_assign(spm->Name, state.dataSetPointManager->spms.size());
     535              : 
     536              :             // control variable type
     537         9558 :             std::string ctrlVarName;
     538         4779 :             switch (spm->type) {
     539           33 :             case SPMType::SZMinHum: {
     540           33 :                 spm->ctrlVar = HVAC::CtrlVarType::MinHumRat;
     541           33 :             } break;
     542           56 :             case SPMType::SZMaxHum: {
     543           56 :                 spm->ctrlVar = HVAC::CtrlVarType::MaxHumRat;
     544           56 :             } break;
     545            2 :             case SPMType::MZHeatingAverage:
     546              :             case SPMType::MZCoolingAverage: {
     547            2 :                 spm->ctrlVar = HVAC::CtrlVarType::Temp;
     548            2 :             } break;
     549            9 :             case SPMType::MZMinHumAverage:
     550              :             case SPMType::MZMinHum: {
     551            9 :                 spm->ctrlVar = HVAC::CtrlVarType::MinHumRat;
     552            9 :             } break;
     553           15 :             case SPMType::MZMaxHumAverage:
     554              :             case SPMType::MZMaxHum: {
     555           15 :                 spm->ctrlVar = HVAC::CtrlVarType::MaxHumRat;
     556           15 :             } break;
     557            8 :             case SPMType::SZOneStageCooling:
     558              :             case SPMType::SZOneStageHeating: {
     559            8 :                 spm->ctrlVar = HVAC::CtrlVarType::Temp;
     560            8 :             } break;
     561            4 :             case SPMType::ChilledWaterReturnTemp:
     562              :             case SPMType::HotWaterReturnTemp: {
     563            4 :                 spm->ctrlVar = HVAC::CtrlVarType::Temp;
     564            4 :             } break;
     565            1 :             case SPMType::ReturnAirBypass: {
     566            1 :                 spm->ctrlVar = HVAC::CtrlVarType::MassFlowRate;
     567            1 :             } break;
     568              : 
     569         4651 :             default: {
     570         9302 :                 ctrlVarName = ip->getAlphaFieldValue(fields, props, "control_variable");
     571         4651 :                 spm->ctrlVar = static_cast<HVAC::CtrlVarType>(getEnumValue(ctrlVarTypeNamesUC, ctrlVarName));
     572         4651 :             } break;
     573              :             } // switch (spm->type)
     574              : 
     575              :             // Load Min and Max Temp setpoints for some SPMs
     576         4779 :             switch (spm->type) {
     577          262 :             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          524 :                 spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_setpoint_temperature");
     586          524 :                 spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_setpoint_temperature");
     587          262 :                 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          262 :             } break;
     595              : 
     596          585 :             case SPMType::SZReheat:
     597              :             case SPMType::SZHeating:
     598              :             case SPMType::SZCooling: {
     599         1170 :                 spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_supply_air_temperature");
     600         1170 :                 spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_supply_air_temperature");
     601          585 :                 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          585 :             } break;
     609              : 
     610            1 :             case SPMType::FollowSystemNodeTemp: {
     611            2 :                 spm->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_limit_setpoint_temperature");
     612            2 :                 spm->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_limit_setpoint_temperature");
     613            1 :                 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            1 :             } break;
     621              : 
     622         3931 :             default:
     623         3931 :                 break;
     624              :             } // switch (spm->type)
     625              : 
     626              :             // Read Min and Max HumRat for some SPMs
     627         4779 :             switch (spm->type) {
     628              : 
     629           33 :             case SPMType::OutsideAirPretreat:
     630              :             case SPMType::MZMinHumAverage:
     631              :             case SPMType::MZMaxHumAverage:
     632              :             case SPMType::MZMinHum:
     633              :             case SPMType::MZMaxHum: {
     634           66 :                 spm->minSetHum = ip->getRealFieldValue(fields, props, "minimum_setpoint_humidity_ratio");
     635           66 :                 spm->maxSetHum = ip->getRealFieldValue(fields, props, "maximum_setpoint_humidity_ratio");
     636           33 :                 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           33 :                 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           33 :                 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           33 :             } break;
     658         4746 :             default:
     659         4746 :                 break;
     660              :             } // switch (spm->type)
     661              : 
     662              :             // Read HVAC Air Loop name
     663         4779 :             switch (spm->type) {
     664           54 :             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          108 :                 spm->airLoopName = ip->getAlphaFieldValue(fields, props, "hvac_air_loop_name");
     675           54 :                 spm->airLoopNum = 0;
     676           54 :             } break;
     677              : 
     678         4725 :             default:
     679         4725 :                 break;
     680              :             } // switch (spm->type)
     681              : 
     682              :             // Read SPM-specific fields
     683         4779 :             switch (spm->type) {
     684              : 
     685              :             // SetpointManager:Scheduled
     686         1961 :             case SPMType::Scheduled: {
     687         1961 :                 auto *spmS = dynamic_cast<SPMScheduled *>(spm);
     688         1961 :                 assert(spmS != nullptr);
     689              : 
     690         3922 :                 std::string schedName = ip->getAlphaFieldValue(fields, props, "schedule_name");
     691         1961 :                 if ((spmS->sched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
     692            0 :                     ShowSevereItemNotFound(state, eoh, "schedule_name", schedName);
     693            0 :                     ErrorsFound = true;
     694              :                 }
     695         1961 :                 spmS->setPt = 0.0;
     696         1961 :             } break;
     697              : 
     698              :             // SetpointManager:Scheduled:DualSetpoint
     699           22 :             case SPMType::ScheduledDual: {
     700           22 :                 auto *spmSD = dynamic_cast<SPMScheduledDual *>(spm);
     701           22 :                 assert(spmSD != nullptr);
     702              : 
     703           22 :                 if (spmSD->ctrlVar != HVAC::CtrlVarType::Temp) {
     704            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     705            0 :                     ErrorsFound = true;
     706              :                 }
     707              : 
     708           44 :                 std::string schedHiName = ip->getAlphaFieldValue(fields, props, "high_setpoint_schedule_name");
     709           22 :                 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           44 :                 std::string schedLoName = ip->getAlphaFieldValue(fields, props, "low_setpoint_schedule_name");
     715           22 :                 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           22 :                 spmSD->setPtHi = 0.0;
     720           22 :                 spmSD->setPtLo = 0.0;
     721              : 
     722           22 :             } break;
     723              : 
     724              :             // SetpointManager:OutdoorAirReset
     725          103 :             case SPMType::OutsideAir: {
     726          103 :                 auto *spmOA = dynamic_cast<SPMOutsideAir *>(spm);
     727          103 :                 assert(spmOA != nullptr);
     728          103 :                 if (spmOA->ctrlVar != HVAC::CtrlVarType::Temp && spmOA->ctrlVar != HVAC::CtrlVarType::MaxTemp &&
     729            0 :                     spmOA->ctrlVar != HVAC::CtrlVarType::MinTemp) {
     730            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     731            0 :                     ErrorsFound = true;
     732              :                 }
     733              : 
     734          206 :                 spmOA->lowSetPt1 = ip->getRealFieldValue(fields, props, "setpoint_at_outdoor_low_temperature");
     735          206 :                 spmOA->low1 = ip->getRealFieldValue(fields, props, "outdoor_low_temperature");
     736          206 :                 spmOA->highSetPt1 = ip->getRealFieldValue(fields, props, "setpoint_at_outdoor_high_temperature");
     737          309 :                 spmOA->high1 = ip->getRealFieldValue(fields, props, "outdoor_high_temperature");
     738              : 
     739              :                 // Get optional input: schedule and 2nd reset rule
     740          206 :                 if (auto foundSched = fields.find("schedule_name"); foundSched != fields.end()) {
     741            0 :                     std::string schedName = Util::makeUPPER(foundSched.value().get<std::string>());
     742            0 :                     if ((spmOA->sched = Sched::GetSchedule(state, Util::makeUPPER(schedName))) == nullptr) {
     743            0 :                         ShowSevereItemNotFound(state, eoh, "schedule_name", schedName);
     744            0 :                         ErrorsFound = true;
     745            0 :                     } 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            0 :                     if (auto found = fields.find("setpoint_at_outdoor_low_temperature_2"); found != fields.end()) {
     751            0 :                         spmOA->lowSetPt2 = found.value().get<Real64>();
     752            0 :                     }
     753            0 :                     if (auto found = fields.find("outdoor_low_temperature_2"); found != fields.end()) {
     754            0 :                         spmOA->low2 = found.value().get<Real64>();
     755            0 :                     }
     756            0 :                     if (auto found = fields.find("setpoint_at_outdoor_high_temperature_2"); found != fields.end()) {
     757            0 :                         spmOA->highSetPt2 = found.value().get<Real64>();
     758            0 :                     }
     759            0 :                     if (auto found = fields.find("outdoor_high_temperature_2"); found != fields.end()) {
     760            0 :                         spmOA->high2 = found.value().get<Real64>();
     761            0 :                     }
     762            0 :                     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            0 :                 } else { // !foundSched
     772          103 :                     spmOA->sched = nullptr;
     773          103 :                     spmOA->lowSetPt2 = 0.0;
     774          103 :                     spmOA->low2 = 0.0;
     775          103 :                     spmOA->highSetPt2 = 0.0;
     776          103 :                     spmOA->high2 = 0.0;
     777          103 :                 }
     778          103 :             } break;
     779              : 
     780              :             //  SetpointManager:SingleZone:Reheat
     781          291 :             case SPMType::SZReheat: {
     782          291 :                 auto *spmSZR = dynamic_cast<SPMSingleZoneReheat *>(spm);
     783          291 :                 assert(spmSZR != nullptr);
     784              : 
     785          291 :                 if (spmSZR->ctrlVar != HVAC::CtrlVarType::Temp) {
     786            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     787            0 :                     ErrorsFound = true;
     788              :                 }
     789              : 
     790          582 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
     791              :                 // get the actual zone number of the control zone
     792          291 :                 spmSZR->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
     793          291 :                 if (spmSZR->ctrlZoneNum == 0) {
     794            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
     795            0 :                     ErrorsFound = true;
     796              :                 }
     797          291 :                 spmSZR->setPt = 0.0;
     798              : 
     799          582 :                 spmSZR->zoneNodeNum = GetOnlySingleNode(state,
     800          873 :                                                         ip->getAlphaFieldValue(fields, props, "zone_node_name"),
     801              :                                                         ErrorsFound,
     802          291 :                                                         spmNodeObjectTypes[(int)spm->type],
     803          291 :                                                         spmSZR->Name,
     804              :                                                         DataLoopNode::NodeFluidType::Air,
     805              :                                                         DataLoopNode::ConnectionType::Sensor,
     806              :                                                         NodeInputManager::CompFluidStream::Primary,
     807              :                                                         ObjectIsNotParent);
     808          582 :                 spmSZR->zoneInletNodeNum = GetOnlySingleNode(state,
     809          873 :                                                              ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"),
     810              :                                                              ErrorsFound,
     811          291 :                                                              spmNodeObjectTypes[(int)spm->type],
     812          291 :                                                              spmSZR->Name,
     813              :                                                              DataLoopNode::NodeFluidType::Air,
     814              :                                                              DataLoopNode::ConnectionType::Sensor,
     815              :                                                              NodeInputManager::CompFluidStream::Primary,
     816              :                                                              ObjectIsNotParent);
     817          291 :             } break;
     818              : 
     819              :             // SetpointManager:SingleZone:Heating
     820              :             // SetpointManager:SingleZone:Cooling
     821          294 :             case SPMType::SZHeating:
     822              :             case SPMType::SZCooling: {
     823          294 :                 auto *spmSZTemp = dynamic_cast<SPMSingleZoneTemp *>(spm);
     824          294 :                 assert(spmSZTemp != nullptr);
     825              : 
     826          294 :                 if (spmSZTemp->ctrlVar != HVAC::CtrlVarType::Temp) {
     827            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     828            0 :                     ErrorsFound = true;
     829              :                 }
     830              : 
     831          588 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
     832          294 :                 spmSZTemp->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
     833          294 :                 if (spmSZTemp->ctrlZoneNum == 0) {
     834            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
     835            0 :                     ErrorsFound = true;
     836              :                 }
     837          294 :                 spmSZTemp->setPt = 0.0;
     838              : 
     839          588 :                 spmSZTemp->zoneNodeNum = GetOnlySingleNode(state,
     840          882 :                                                            ip->getAlphaFieldValue(fields, props, "zone_node_name"),
     841              :                                                            ErrorsFound,
     842          294 :                                                            spmNodeObjectTypes[(int)spm->type],
     843          294 :                                                            spmSZTemp->Name,
     844              :                                                            DataLoopNode::NodeFluidType::Air,
     845              :                                                            DataLoopNode::ConnectionType::Sensor,
     846              :                                                            NodeInputManager::CompFluidStream::Primary,
     847              :                                                            ObjectIsNotParent);
     848          588 :                 spmSZTemp->zoneInletNodeNum = GetOnlySingleNode(state,
     849          882 :                                                                 ip->getAlphaFieldValue(fields, props, "zone_inlet_node_name"),
     850              :                                                                 ErrorsFound,
     851          294 :                                                                 spmNodeObjectTypes[(int)spm->type],
     852          294 :                                                                 spmSZTemp->Name,
     853              :                                                                 DataLoopNode::NodeFluidType::Air,
     854              :                                                                 DataLoopNode::ConnectionType::Sensor,
     855              :                                                                 NodeInputManager::CompFluidStream::Primary,
     856              :                                                                 ObjectIsNotParent);
     857              : 
     858          294 :             } break;
     859              : 
     860              :             // SetpointManager:SingleZone:Humidity:Minimum
     861              :             // SetpointManager:SingleZone:Humidity:Maximum
     862           89 :             case SPMType::SZMinHum:
     863              :             case SPMType::SZMaxHum: {
     864           89 :                 auto *spmSZHum = dynamic_cast<SPMSingleZoneHum *>(spm);
     865           89 :                 assert(spmSZHum != nullptr);
     866              : 
     867           89 :                 ErrInList = false;
     868          178 :                 std::string ctrlZoneNodeName = ip->getAlphaFieldValue(fields, props, "control_zone_air_node_name");
     869          178 :                 GetNodeNums(state,
     870              :                             ctrlZoneNodeName,
     871              :                             NumNodes,
     872              :                             NodeNums,
     873              :                             ErrInList,
     874              :                             DataLoopNode::NodeFluidType::Air,
     875           89 :                             spmNodeObjectTypes[(int)spm->type],
     876           89 :                             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           89 :                 if (ErrInList) {
     884            0 :                     ErrorsFound = true;
     885              :                 }
     886              : 
     887              :                 // only allow one control zone for now
     888           89 :                 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           89 :                 spmSZHum->zoneNodeNum = NodeNums(1);
     896           89 :                 spmSZHum->ctrlZoneNum = 0;
     897           89 :             } break;
     898              : 
     899              :             // SetpointManager:MixedAir
     900         1710 :             case SPMType::MixedAir: {
     901         1710 :                 auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
     902         1710 :                 assert(spmMA != nullptr);
     903              : 
     904         1710 :                 if (spmMA->ctrlVar != HVAC::CtrlVarType::Temp) {
     905            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
     906            0 :                     ErrorsFound = true;
     907              :                 }
     908              : 
     909         3420 :                 spmMA->refNodeNum = GetOnlySingleNode(state,
     910         5130 :                                                       ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"),
     911              :                                                       ErrorsFound,
     912         1710 :                                                       spmNodeObjectTypes[(int)spm->type],
     913         1710 :                                                       spmMA->Name,
     914              :                                                       DataLoopNode::NodeFluidType::Air,
     915              :                                                       DataLoopNode::ConnectionType::Sensor,
     916              :                                                       NodeInputManager::CompFluidStream::Primary,
     917              :                                                       ObjectIsNotParent);
     918         3420 :                 spmMA->fanInNodeNum = GetOnlySingleNode(state,
     919         5130 :                                                         ip->getAlphaFieldValue(fields, props, "fan_inlet_node_name"),
     920              :                                                         ErrorsFound,
     921         1710 :                                                         spmNodeObjectTypes[(int)spm->type],
     922         1710 :                                                         spmMA->Name,
     923              :                                                         DataLoopNode::NodeFluidType::Air,
     924              :                                                         DataLoopNode::ConnectionType::Sensor,
     925              :                                                         NodeInputManager::CompFluidStream::Primary,
     926              :                                                         ObjectIsNotParent);
     927         3420 :                 spmMA->fanOutNodeNum = GetOnlySingleNode(state,
     928         5130 :                                                          ip->getAlphaFieldValue(fields, props, "fan_outlet_node_name"),
     929              :                                                          ErrorsFound,
     930         1710 :                                                          spmNodeObjectTypes[(int)spm->type],
     931         1710 :                                                          spmMA->Name,
     932              :                                                          DataLoopNode::NodeFluidType::Air,
     933              :                                                          DataLoopNode::ConnectionType::Sensor,
     934              :                                                          NodeInputManager::CompFluidStream::Primary,
     935              :                                                          ObjectIsNotParent);
     936         1710 :             } break;
     937              : 
     938              :             // SetpointManager:OutdoorAirPretreat
     939            9 :             case SPMType::OutsideAirPretreat: {
     940            9 :                 auto *spmOAP = dynamic_cast<SPMOutsideAirPretreat *>(spm);
     941            9 :                 assert(spmOAP != nullptr);
     942              : 
     943           18 :                 spmOAP->refNodeNum = GetOnlySingleNode(state,
     944           27 :                                                        ip->getAlphaFieldValue(fields, props, "reference_setpoint_node_name"),
     945              :                                                        ErrorsFound,
     946            9 :                                                        spmNodeObjectTypes[(int)spm->type],
     947            9 :                                                        spmOAP->Name,
     948              :                                                        DataLoopNode::NodeFluidType::Air,
     949              :                                                        DataLoopNode::ConnectionType::Sensor,
     950              :                                                        NodeInputManager::CompFluidStream::Primary,
     951              :                                                        ObjectIsNotParent);
     952           18 :                 spmOAP->mixedOutNodeNum = GetOnlySingleNode(state,
     953           27 :                                                             ip->getAlphaFieldValue(fields, props, "mixed_air_stream_node_name"),
     954              :                                                             ErrorsFound,
     955            9 :                                                             spmNodeObjectTypes[(int)spm->type],
     956            9 :                                                             spmOAP->Name,
     957              :                                                             DataLoopNode::NodeFluidType::Air,
     958              :                                                             DataLoopNode::ConnectionType::Sensor,
     959              :                                                             NodeInputManager::CompFluidStream::Primary,
     960              :                                                             ObjectIsNotParent);
     961           18 :                 spmOAP->oaInNodeNum = GetOnlySingleNode(state,
     962           27 :                                                         ip->getAlphaFieldValue(fields, props, "outdoor_air_stream_node_name"),
     963              :                                                         ErrorsFound,
     964            9 :                                                         spmNodeObjectTypes[(int)spm->type],
     965            9 :                                                         spmOAP->Name,
     966              :                                                         DataLoopNode::NodeFluidType::Air,
     967              :                                                         DataLoopNode::ConnectionType::Sensor,
     968              :                                                         NodeInputManager::CompFluidStream::Primary,
     969              :                                                         ObjectIsNotParent);
     970           18 :                 spmOAP->returnInNodeNum = GetOnlySingleNode(state,
     971           27 :                                                             ip->getAlphaFieldValue(fields, props, "return_air_stream_node_name"),
     972              :                                                             ErrorsFound,
     973            9 :                                                             spmNodeObjectTypes[(int)spm->type],
     974            9 :                                                             spmOAP->Name,
     975              :                                                             DataLoopNode::NodeFluidType::Air,
     976              :                                                             DataLoopNode::ConnectionType::Sensor,
     977              :                                                             NodeInputManager::CompFluidStream::Primary,
     978              :                                                             ObjectIsNotParent);
     979              : 
     980            9 :                 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            9 :             } break;
     991              : 
     992              :             // SetpointManager:Warmest
     993              :             // SetpointManager:Coldest
     994           23 :             case SPMType::Warmest:
     995              :             case SPMType::Coldest: {
     996           23 :                 auto *spmEst = dynamic_cast<SPMTempest *>(spm);
     997           23 :                 assert(spmEst != nullptr);
     998              : 
     999           23 :                 if (spmEst->ctrlVar != HVAC::CtrlVarType::Temp) {
    1000            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1001            0 :                     ErrorsFound = true;
    1002              :                 }
    1003              : 
    1004           46 :                 std::string strategyName = ip->getAlphaFieldValue(fields, props, "strategy");
    1005           23 :                 spmEst->strategy = static_cast<SupplyFlowTempStrategy>(getEnumValue(supplyFlowTempStrategyNamesUC, strategyName));
    1006              : 
    1007           23 :                 if ((spmEst->type == SPMType::Warmest && spmEst->strategy != SupplyFlowTempStrategy::MaxTemp) ||
    1008           23 :                     (spmEst->type == SPMType::Coldest && spmEst->strategy != SupplyFlowTempStrategy::MinTemp)) {
    1009            0 :                     ShowSevereInvalidKey(state, eoh, "strategy", strategyName);
    1010            0 :                     ErrorsFound = true;
    1011              :                 }
    1012           23 :             } break;
    1013              : 
    1014              :             // SetpointManager:WarmestTemperatureFlow
    1015            4 :             case SPMType::WarmestTempFlow: {
    1016            4 :                 auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    1017            4 :                 assert(spmWTF != nullptr);
    1018              : 
    1019            4 :                 if (spmWTF->ctrlVar != HVAC::CtrlVarType::Temp) {
    1020            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1021            0 :                     ErrorsFound = true;
    1022              :                 }
    1023              : 
    1024            8 :                 spmWTF->minTurndown = ip->getRealFieldValue(fields, props, "minimum_turndown_ratio");
    1025            4 :                 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            8 :                 spmWTF->strategy = static_cast<ControlStrategy>(getEnumValue(strategyNamesUC, ip->getAlphaFieldValue(fields, props, "strategy")));
    1032              : 
    1033            4 :                 SetupOutputVariable(state,
    1034              :                                     "Setpoint Manager Warmest Temperature Critical Zone Number",
    1035              :                                     Constant::Units::None,
    1036            4 :                                     spmWTF->critZoneNum,
    1037              :                                     OutputProcessor::TimeStepType::System,
    1038              :                                     OutputProcessor::StoreType::Average,
    1039            4 :                                     spmWTF->Name);
    1040            8 :                 SetupOutputVariable(state,
    1041              :                                     "Setpoint Manager Warmest Temperature Turndown Flow Fraction",
    1042              :                                     Constant::Units::None,
    1043            4 :                                     spmWTF->turndown,
    1044              :                                     OutputProcessor::TimeStepType::System,
    1045              :                                     OutputProcessor::StoreType::Average,
    1046            4 :                                     spmWTF->Name);
    1047            4 :             } break;
    1048              : 
    1049              :             // SetpointManager:ReturnAirBypassFlow
    1050            1 :             case SPMType::ReturnAirBypass: {
    1051            1 :                 auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    1052            1 :                 assert(spmRAB != nullptr);
    1053              : 
    1054            2 :                 std::string schedName = ip->getAlphaFieldValue(fields, props, "temperature_setpoint_schedule_name");
    1055            1 :                 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            1 :             } break;
    1060              : 
    1061              :             // SetpointManager:FollowOutdoorAirTemperature
    1062          204 :             case SPMType::FollowOutsideAirTemp: {
    1063          204 :                 auto *spmFOAT = dynamic_cast<SPMFollowOutsideAirTemp *>(spm);
    1064          204 :                 assert(spmFOAT != nullptr);
    1065              : 
    1066          204 :                 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          204 :                 spmFOAT->refTempType =
    1073          408 :                     static_cast<AirTempType>(getEnumValue(oaTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_temperature_type")));
    1074              : 
    1075          408 :                 spmFOAT->offset = ip->getRealFieldValue(fields, props, "offset_temperature_difference");
    1076          204 :             } break;
    1077              : 
    1078              :             // SetpointManager:FollowSystemNodeTemperature
    1079            1 :             case SPMType::FollowSystemNodeTemp: {
    1080            1 :                 auto *spmFNT = dynamic_cast<SPMFollowSysNodeTemp *>(spm);
    1081            1 :                 assert(spmFNT != nullptr);
    1082              : 
    1083            1 :                 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            2 :                 spmFNT->refNodeNum = GetOnlySingleNode(state,
    1090            3 :                                                        ip->getAlphaFieldValue(fields, props, "reference_node_name"),
    1091              :                                                        ErrorsFound,
    1092            1 :                                                        spmNodeObjectTypes[(int)spm->type],
    1093            1 :                                                        spmFNT->Name,
    1094              :                                                        DataLoopNode::NodeFluidType::Blank,
    1095              :                                                        DataLoopNode::ConnectionType::Sensor,
    1096              :                                                        NodeInputManager::CompFluidStream::Primary,
    1097              :                                                        ObjectIsNotParent);
    1098              : 
    1099            1 :                 spmFNT->refTempType =
    1100            2 :                     static_cast<AirTempType>(getEnumValue(nodeTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_temperature_type")));
    1101              : 
    1102            2 :                 spmFNT->offset = ip->getRealFieldValue(fields, props, "offset_temperature_difference");
    1103            1 :             } break;
    1104              : 
    1105              :             // SetpointManager:FollowGroundTemperature
    1106           20 :             case SPMType::FollowGroundTemp: {
    1107           20 :                 auto *spmFGT = dynamic_cast<SPMFollowGroundTemp *>(spm);
    1108           20 :                 assert(spmFGT != nullptr);
    1109              : 
    1110           20 :                 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           20 :                 spmFGT->refTempType = static_cast<DataEnvironment::GroundTempType>(
    1118           40 :                     getEnumValue(groundTempObjectTypeNamesUC, ip->getAlphaFieldValue(fields, props, "reference_ground_temperature_object_type")));
    1119              : 
    1120           20 :                 if (state.dataSetPointManager->NoGroundTempObjWarning[(int)spmFGT->refTempType]) {
    1121           20 :                     if (!state.dataEnvrn->GroundTempInputs[(int)spmFGT->refTempType]) {
    1122            0 :                         ShowWarningError(state,
    1123            0 :                                          format("{}: {}=\"{}\" requires \"Site:GroundTemperature:BuildingSurface\" in the input..",
    1124              :                                                 routineName,
    1125              :                                                 cCurrentModuleObject,
    1126            0 :                                                 spmFGT->Name));
    1127            0 :                         ShowContinueError(state,
    1128            0 :                                           format("Defaults, constant throughout the year of ({:.1R}) will be used.",
    1129            0 :                                                  state.dataEnvrn->GroundTemp[(int)spmFGT->refTempType]));
    1130              :                     }
    1131           20 :                     state.dataSetPointManager->NoGroundTempObjWarning[(int)spmFGT->refTempType] = false;
    1132              :                 }
    1133              : 
    1134           40 :                 spmFGT->offset = ip->getRealFieldValue(fields, props, "offset_temperature_difference");
    1135           20 :             } break;
    1136              : 
    1137              :             // SetpointManager:CondenserEnteringReset
    1138            3 :             case SPMType::CondenserEnteringTemp: {
    1139            3 :                 auto *spmCET = dynamic_cast<SPMCondenserEnteringTemp *>(spm);
    1140            3 :                 assert(spmCET != nullptr);
    1141              : 
    1142            3 :                 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            6 :                     ip->getAlphaFieldValue(fields, props, "default_condenser_entering_water_temperature_schedule_name");
    1149            3 :                 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            6 :                 std::string minDesignWetBulbCurveName = ip->getAlphaFieldValue(fields, props, "minimum_design_wetbulb_temperature_curve_name");
    1155            3 :                 spmCET->minTowerDesignWetBulbCurveNum = GetCurveIndex(state, minDesignWetBulbCurveName);
    1156              : 
    1157            6 :                 std::string minOAWetBulbCurveName = ip->getAlphaFieldValue(fields, props, "minimum_outside_air_wetbulb_temperature_curve_name");
    1158            3 :                 spmCET->minOAWetBulbCurveNum = GetCurveIndex(state, minOAWetBulbCurveName);
    1159              : 
    1160              :                 std::string optCondenserEnteringTempCurveName =
    1161            6 :                     ip->getAlphaFieldValue(fields, props, "optimized_cond_entering_water_temperature_curve_name");
    1162              : 
    1163            3 :                 spmCET->optCondenserEnteringTempCurveNum = GetCurveIndex(state, optCondenserEnteringTempCurveName);
    1164            6 :                 spmCET->minLift = ip->getRealFieldValue(fields, props, "minimum_lift");
    1165              : 
    1166            6 :                 spmCET->maxCondenserEnteringTemp = ip->getRealFieldValue(fields, props, "maximum_condenser_entering_water_temperature");
    1167            6 :                 spmCET->towerDesignInletAirWetBulbTemp = ip->getRealFieldValue(fields, props, "cooling_tower_design_inlet_air_wet_bulb_temperature");
    1168              : 
    1169            3 :                 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            3 :             } break;
    1179              : 
    1180              :             // SetpointManager:CondenserEnteringReset:Ideal
    1181            2 :             case SPMType::IdealCondenserEnteringTemp: {
    1182            2 :                 auto *spmIdealCET = dynamic_cast<SPMIdealCondenserEnteringTemp *>(spm);
    1183            2 :                 assert(spmIdealCET != nullptr);
    1184              : 
    1185            2 :                 if (spmIdealCET->ctrlVar != HVAC::CtrlVarType::Temp) {
    1186            0 :                     ShowSevereInvalidKey(state, eoh, "control_variable", ctrlVarName);
    1187            0 :                     ErrorsFound = true;
    1188              :                 }
    1189              : 
    1190            4 :                 spmIdealCET->minLift = ip->getRealFieldValue(fields, props, "minimum_lift");
    1191            4 :                 spmIdealCET->maxCondenserEnteringTemp = ip->getRealFieldValue(fields, props, "maximum_condenser_entering_water_temperature");
    1192              : 
    1193            2 :             } break;
    1194              : 
    1195              :             // SetpointManager:SingleZone:OneStageCooling
    1196            4 :             case SPMType::SZOneStageCooling: {
    1197            4 :                 auto *spmSZOSC = dynamic_cast<SPMSingleZoneOneStageCooling *>(spm);
    1198            4 :                 assert(spmSZOSC != nullptr);
    1199              : 
    1200            8 :                 spmSZOSC->coolingOnSetPt = ip->getRealFieldValue(fields, props, "cooling_stage_on_supply_air_setpoint_temperature");
    1201            8 :                 spmSZOSC->coolingOffSetPt = ip->getRealFieldValue(fields, props, "cooling_stage_off_supply_air_setpoint_temperature");
    1202              : 
    1203            4 :                 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            8 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
    1214              :                 // get the actual zone number of the control zone
    1215            4 :                 spmSZOSC->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
    1216            4 :                 if (spmSZOSC->ctrlZoneNum == 0) {
    1217            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
    1218            0 :                     ErrorsFound = true;
    1219              :                 } else {
    1220            4 :                     spmSZOSC->zoneNodeNum = GetSystemNodeNumberForZone(state, spmSZOSC->ctrlZoneNum);
    1221            4 :                     if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
    1222            4 :                         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            4 :             } break;
    1231              : 
    1232              :             // SetpointManager:SingleZone:OneStageHeating
    1233            4 :             case SPMType::SZOneStageHeating: {
    1234            4 :                 auto *spmSZOSH = dynamic_cast<SPMSingleZoneOneStageHeating *>(spm);
    1235            4 :                 assert(spmSZOSH != nullptr);
    1236              : 
    1237            8 :                 spmSZOSH->heatingOnSetPt = ip->getRealFieldValue(fields, props, "heating_stage_on_supply_air_setpoint_temperature");
    1238            8 :                 spmSZOSH->heatingOffSetPt = ip->getRealFieldValue(fields, props, "heating_stage_off_supply_air_setpoint_temperature");
    1239              : 
    1240            4 :                 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            8 :                 std::string ctrlZoneName = ip->getAlphaFieldValue(fields, props, "control_zone_name");
    1251              :                 // get the actual zone number of the control zone
    1252            4 :                 spmSZOSH->ctrlZoneNum = Util::FindItemInList(ctrlZoneName, state.dataHeatBal->Zone);
    1253            4 :                 if (spmSZOSH->ctrlZoneNum == 0) {
    1254            0 :                     ShowSevereItemNotFound(state, eoh, "control_zone_name", ctrlZoneName);
    1255            0 :                     ErrorsFound = true;
    1256              :                 } else {
    1257            4 :                     spmSZOSH->zoneNodeNum = GetSystemNodeNumberForZone(state, spmSZOSH->ctrlZoneNum);
    1258            4 :                     if (allocated(state.dataZoneCtrls->StageZoneLogic)) {
    1259            4 :                         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            4 :             } break;
    1268              : 
    1269              :             // SetpointManager:ReturnTemperature:ChilledWater
    1270              :             // SetpointManager:ReturnTemperature:HotWater
    1271            4 :             case SPMType::ChilledWaterReturnTemp:
    1272              :             case SPMType::HotWaterReturnTemp: {
    1273            4 :                 auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    1274            4 :                 assert(spmRWT != nullptr);
    1275              : 
    1276            4 :                 bool errFlag = false;
    1277            8 :                 spmRWT->supplyNodeNum = GetOnlySingleNode(state,
    1278           12 :                                                           ip->getAlphaFieldValue(fields, props, "plant_loop_supply_outlet_node"),
    1279              :                                                           errFlag,
    1280            4 :                                                           spmNodeObjectTypes[(int)spm->type],
    1281            4 :                                                           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            8 :                 spmRWT->returnNodeNum = GetOnlySingleNode(state,
    1288           12 :                                                           ip->getAlphaFieldValue(fields, props, "plant_loop_supply_inlet_node"),
    1289              :                                                           errFlag,
    1290            4 :                                                           spmNodeObjectTypes[(int)spm->type],
    1291            4 :                                                           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            8 :                 spmRWT->minSetTemp = ip->getRealFieldValue(fields, props, "minimum_supply_temperature_setpoint");
    1300            8 :                 spmRWT->maxSetTemp = ip->getRealFieldValue(fields, props, "maximum_supply_temperature_setpoint");
    1301              : 
    1302            4 :                 spmRWT->returnTempType = static_cast<ReturnTempType>(
    1303            8 :                     getEnumValue(returnTempTypeNamesUC, ip->getAlphaFieldValue(fields, props, "return_temperature_setpoint_input_type")));
    1304              : 
    1305            4 :                 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            4 :                 } else if (spmRWT->returnTempType == ReturnTempType::Constant) {
    1312            9 :                     spmRWT->returnTempConstantTarget = ip->getRealFieldValue(fields, props, "return_temperature_setpoint_constant_value");
    1313              :                 }
    1314            4 :             } break;
    1315              : 
    1316              :             // SetpointManager:SystemNodeReset:Temperature
    1317            3 :             case SPMType::SystemNodeTemp: {
    1318            3 :                 auto *spmSNRTemp = dynamic_cast<SPMSystemNode *>(spm);
    1319            3 :                 assert(spmSNRTemp != nullptr);
    1320              : 
    1321            3 :                 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            6 :                 spmSNRTemp->lowRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_low_reference_temperature");
    1328            6 :                 spmSNRTemp->highRefSetPt = ip->getRealFieldValue(fields, props, "setpoint_at_high_reference_temperature");
    1329            6 :                 spmSNRTemp->lowRef = ip->getRealFieldValue(fields, props, "low_reference_temperature");
    1330            6 :                 spmSNRTemp->highRef = ip->getRealFieldValue(fields, props, "high_reference_temperature");
    1331              : 
    1332            6 :                 spmSNRTemp->refNodeNum = GetOnlySingleNode(state,
    1333            9 :                                                            ip->getAlphaFieldValue(fields, props, "reference_node_name"),
    1334              :                                                            ErrorsFound,
    1335            3 :                                                            spmNodeObjectTypes[(int)spm->type],
    1336            3 :                                                            spmSNRTemp->Name,
    1337              :                                                            DataLoopNode::NodeFluidType::Blank,
    1338              :                                                            DataLoopNode::ConnectionType::Sensor,
    1339              :                                                            NodeInputManager::CompFluidStream::Primary,
    1340              :                                                            ObjectIsNotParent);
    1341            3 :             } 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           26 :             default:
    1378           26 :                 break;
    1379              :             } // switch (spm->type)
    1380              : 
    1381              :             // Load control node list
    1382              :             // Do this at the end to preserve node order
    1383         4779 :             if (spm->type != SPMType::ReturnAirBypass && spm->type != SPMType::ChilledWaterReturnTemp && spm->type != SPMType::HotWaterReturnTemp) {
    1384         9548 :                 std::string ctrlNodeListName = ip->getAlphaFieldValue(fields, props, "setpoint_node_or_nodelist_name");
    1385         4774 :                 NodeListError = false;
    1386         9548 :                 GetNodeNums(state,
    1387              :                             ctrlNodeListName,
    1388              :                             NumNodes,
    1389              :                             NodeNums,
    1390              :                             NodeListError,
    1391              :                             DataLoopNode::NodeFluidType::Blank,
    1392         4774 :                             spmNodeObjectTypes[iSPM],
    1393              :                             name,
    1394              :                             DataLoopNode::ConnectionType::SetPoint,
    1395              :                             NodeInputManager::CompFluidStream::Primary,
    1396              :                             ObjectIsNotParent,
    1397              :                             false,
    1398              :                             "setpoint_node_or_nodelist_name");
    1399              : 
    1400         4774 :                 if (!NodeListError) {
    1401         9946 :                     for (int iNode = 1; iNode <= NumNodes; ++iNode) {
    1402         5172 :                         spm->ctrlNodeNums.push_back(NodeNums(iNode));
    1403              :                     }
    1404              :                 } else {
    1405            0 :                     ErrorsFound = true;
    1406              :                 }
    1407         4774 :             }
    1408              : 
    1409              :             // Now load all of the optional fields
    1410         4779 :             switch (spm->type) {
    1411         1710 :             case SPMType::MixedAir: {
    1412         1710 :                 auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
    1413         1710 :                 assert(spmMA != nullptr);
    1414         3420 :                 if (auto found = fields.find("cooling_coil_inlet_node_name"); found != fields.end()) {
    1415            2 :                     spmMA->coolCoilInNodeNum = GetOnlySingleNode(state,
    1416            2 :                                                                  Util::makeUPPER(found.value().get<std::string>()),
    1417              :                                                                  ErrorsFound,
    1418            1 :                                                                  spmNodeObjectTypes[(int)spm->type],
    1419            1 :                                                                  spmMA->Name,
    1420              :                                                                  DataLoopNode::NodeFluidType::Air,
    1421              :                                                                  DataLoopNode::ConnectionType::Sensor,
    1422              :                                                                  NodeInputManager::CompFluidStream::Primary,
    1423              :                                                                  ObjectIsNotParent);
    1424         1710 :                 }
    1425              : 
    1426         3420 :                 if (auto found = fields.find("cooling_coil_outlet_node_name"); found != fields.end()) {
    1427            2 :                     spmMA->coolCoilOutNodeNum = GetOnlySingleNode(state,
    1428            2 :                                                                   Util::makeUPPER(found.value().get<std::string>()),
    1429              :                                                                   ErrorsFound,
    1430            1 :                                                                   spmNodeObjectTypes[(int)spm->type],
    1431            1 :                                                                   spmMA->Name,
    1432              :                                                                   DataLoopNode::NodeFluidType::Air,
    1433              :                                                                   DataLoopNode::ConnectionType::Sensor,
    1434              :                                                                   NodeInputManager::CompFluidStream::Primary,
    1435              :                                                                   ObjectIsNotParent);
    1436         1710 :                 }
    1437              : 
    1438         3420 :                 if (auto found = fields.find("minimum_temperature_at_cooling_coil_outlet_node"); found != fields.end()) {
    1439            1 :                     spmMA->minCoolCoilOutTemp = found.value().get<Real64>();
    1440         1710 :                 }
    1441              : 
    1442              :                 // Also, do this check now that we have both RefNodeNum and ctrlNodeNums
    1443         1710 :                 if (std::find(spmMA->ctrlNodeNums.begin(), spmMA->ctrlNodeNums.end(), spmMA->refNodeNum) != spmMA->ctrlNodeNums.end()) {
    1444            0 :                     ShowSevereError(state, format("{}: {}=\"{}\", reference node.", routineName, cCurrentModuleObject, spmMA->Name));
    1445            0 :                     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            0 :                         ShowContinueError(state, "..Reference Node is the same as the SetPoint Node");
    1449              :                     }
    1450            0 :                     ShowContinueError(state, format("Reference Node Name=\"{}\".", state.dataLoopNodes->NodeID(spmMA->refNodeNum)));
    1451            0 :                     ErrorsFound = true;
    1452              :                 }
    1453         1710 :             } break;
    1454              : 
    1455         3069 :             default:
    1456         3069 :                 break;
    1457              :             } // switch (spm->type)
    1458              : 
    1459         6097 :         } // for (instance)
    1460        25632 :     } // for (iSPM)
    1461              : 
    1462          801 : } // GetSetPointManagerInputData()
    1463              : 
    1464          802 : 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         5577 :     for (int iSPM = 1; iSPM <= state.dataSetPointManager->spms.isize(); ++iSPM) {
    1493         4775 :         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         5177 :         for (int iNode = 0; iNode < (int)spm->ctrlNodeNums.size() - 1; ++iNode) {
    1499          971 :             for (int jNode = iNode + 1; jNode < (int)spm->ctrlNodeNums.size(); ++jNode) {
    1500          569 :                 if (spm->ctrlNodeNums[iNode] != spm->ctrlNodeNums[jNode]) {
    1501          569 :                     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        48157 :         for (int jSPM = iSPM + 1; jSPM <= (int)state.dataSetPointManager->spms.size(); ++jSPM) {
    1511        43382 :             auto const *spm2 = state.dataSetPointManager->spms(jSPM);
    1512              : 
    1513        43382 :             if (spm == spm2) {
    1514            0 :                 continue;
    1515              :             }
    1516              : 
    1517        43382 :             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        43382 :                 if (spm->ctrlVar != spm2->ctrlVar) {
    1551         3945 :                     continue;
    1552              :                 }
    1553              : 
    1554        79411 :                 for (int iNode = 0; iNode < (int)spm->ctrlNodeNums.size(); ++iNode) {
    1555        81672 :                     for (int jNode = 0; jNode < (int)spm2->ctrlNodeNums.size(); ++jNode) {
    1556              : 
    1557        41698 :                         if (spm->ctrlNodeNums[iNode] != spm2->ctrlNodeNums[jNode]) {
    1558        41697 :                             continue;
    1559              :                         }
    1560              : 
    1561              :                         //         only warn if scheduled setpoint manager is setting mass flow rate on the same node used by RAB
    1562            1 :                         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            1 :                             ShowWarningError(state, format("{}=\"{}\"", spmTypeNames[(int)spm->type], spm->Name));
    1572            2 :                             ShowContinueError(state, "...setpoint node conflicts with another setpoint manager.");
    1573            2 :                             ShowContinueError(state,
    1574            2 :                                               format("...conflicting setpoint manager = {}:\"{}\"", spmTypeNames[(int)spm2->type], spm2->Name));
    1575            1 :                             ShowContinueError(state, format("...conflicting node name = {}", state.dataLoopNodes->NodeID(spm->ctrlNodeNums[iNode])));
    1576            1 :                             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          802 : } // VerifySetPointManager()
    1590              : 
    1591      2855467 : 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      2855467 :     constexpr std::string_view routineName = "InitSetPointManagers";
    1633              : 
    1634      2855467 :     bool ErrorsFound(false);
    1635              : 
    1636      2855467 :     state.dataSetPointManager->ManagerOn = true;
    1637              : 
    1638              :     // One time initializations
    1639              : 
    1640      5710934 :     if (state.dataZoneEquip->ZoneEquipInputsFilled &&
    1641      2855467 :         state.dataAirLoop->AirLoopInputsFilled) { // check that the zone equipment and air loop data has been read in
    1642              : 
    1643      2853866 :         if (state.dataSetPointManager->InitSetPointManagersOneTimeFlag) {
    1644              : 
    1645         5560 :             for (auto *spm : state.dataSetPointManager->spms) {
    1646         4760 :                 std::string_view spmName = spm->Name;
    1647         4760 :                 std::string_view spmTypeName = spmTypeNames[(int)spm->type];
    1648              : 
    1649         4760 :                 ErrorObjectHeader eoh{routineName, spmTypeName, spmName};
    1650              : 
    1651         4760 :                 switch (spm->type) {
    1652              : 
    1653          294 :                 case SPMType::SZHeating:
    1654              :                 case SPMType::SZCooling: {
    1655          294 :                     auto *spmSZT = dynamic_cast<SPMSingleZoneTemp *>(spm);
    1656          294 :                     assert(spmSZT != nullptr);
    1657              :                     // find the index in the ZoneEquipConfig array of the control zone (the one with the main or only thermostat)
    1658          294 :                     int ConZoneNum = 0;
    1659         4918 :                     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1660         4624 :                         if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode == spmSZT->zoneNodeNum) {
    1661          294 :                             ConZoneNum = ZoneNum;
    1662              :                         }
    1663              :                     }
    1664          294 :                     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          294 :                         auto &zoneEquip = state.dataZoneEquip->ZoneEquipConfig(ConZoneNum);
    1671          294 :                         bool found = false;
    1672          634 :                         for (int zoneInNode = 1; zoneInNode <= zoneEquip.NumInletNodes; ++zoneInNode) {
    1673          340 :                             if (spmSZT->zoneInletNodeNum == zoneEquip.InletNode(zoneInNode)) {
    1674          294 :                                 found = true;
    1675              :                             }
    1676              :                         }
    1677          294 :                         if (!found) {
    1678            0 :                             ShowSevereError(state,
    1679            0 :                                             format("{}=\"{}\", The zone inlet node of {}",
    1680              :                                                    spmTypeName,
    1681              :                                                    spmName,
    1682            0 :                                                    state.dataLoopNodes->NodeID(spmSZT->zoneInletNodeNum)));
    1683            0 :                             ShowContinueError(state, format("is not found in Zone = {}. Please check inputs.", zoneEquip.ZoneName));
    1684            0 :                             ErrorsFound = true;
    1685              :                         }
    1686              :                     }
    1687          294 :                 } break;
    1688              : 
    1689           89 :                 case SPMType::SZMinHum:
    1690              :                 case SPMType::SZMaxHum: {
    1691           89 :                     auto *spmSZH = dynamic_cast<SPMSingleZoneHum *>(spm);
    1692           89 :                     assert(spmSZH != nullptr);
    1693              : 
    1694              :                     // set the actual and controlled zone numbers
    1695         3467 :                     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1696         3467 :                         if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode == spmSZH->zoneNodeNum) {
    1697           89 :                             spmSZH->ctrlZoneNum = ZoneNum;
    1698           89 :                             break;
    1699              :                         }
    1700              :                     }
    1701              :                     // still need to validate...
    1702           89 :                     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           89 :                         bool HstatZoneFound = false;
    1708          185 :                         for (int iZone = 1; iZone <= state.dataZoneCtrls->NumHumidityControlZones; ++iZone) {
    1709          185 :                             if (state.dataZoneCtrls->HumidityControlZone(iZone).ActualZoneNum == spmSZH->ctrlZoneNum) {
    1710           89 :                                 HstatZoneFound = true;
    1711           89 :                                 break;
    1712              :                             }
    1713              :                         }
    1714           89 :                         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           89 :                 } break;
    1722              : 
    1723          286 :                 case SPMType::SZReheat: {
    1724          286 :                     auto *spmSZR = dynamic_cast<SPMSingleZoneReheat *>(spm);
    1725          286 :                     assert(spmSZR != nullptr);
    1726              : 
    1727          286 :                     int FanNodeIn = 0;
    1728          286 :                     int FanNodeOut = 0;
    1729          286 :                     int MixedAirNode = 0;
    1730          286 :                     int InletBranchNum = 0;
    1731          286 :                     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          286 :                     int ConZoneNum = 0;
    1735         4752 :                     for (int ZoneNum = 1; ZoneNum <= state.dataGlobal->NumOfZones; ++ZoneNum) {
    1736         4466 :                         if (state.dataZoneEquip->ZoneEquipConfig(ZoneNum).ZoneNode == spmSZR->zoneNodeNum) {
    1737          286 :                             ConZoneNum = ZoneNum;
    1738              :                         }
    1739              :                     }
    1740              : 
    1741          286 :                     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          286 :                         bool found = false;
    1748          286 :                         auto const &zoneEquip = state.dataZoneEquip->ZoneEquipConfig(ConZoneNum);
    1749          576 :                         for (int zoneInNode = 1; zoneInNode <= zoneEquip.NumInletNodes; ++zoneInNode) {
    1750          290 :                             if (spmSZR->zoneInletNodeNum == zoneEquip.InletNode(zoneInNode)) {
    1751          286 :                                 spmSZR->airLoopNum = zoneEquip.InletNodeAirLoopNum(zoneInNode);
    1752          286 :                                 found = true;
    1753              :                             }
    1754              :                         }
    1755          286 :                         if (!found) {
    1756            0 :                             ShowSevereError(state,
    1757            0 :                                             format("{}=\"{}\", The zone inlet node of {}",
    1758              :                                                    spmTypeName,
    1759              :                                                    spmName,
    1760            0 :                                                    state.dataLoopNodes->NodeID(spmSZR->zoneInletNodeNum)));
    1761            0 :                             ShowContinueError(state, format("is not found in Zone = {}. Please check inputs.", zoneEquip.ZoneName));
    1762            0 :                             ErrorsFound = true;
    1763              :                         }
    1764          286 :                         if (spmSZR->airLoopNum == 0) {
    1765            0 :                             ShowSevereError(state, format("{}=\"{}\", The zone inlet node is not connected to an air loop.", spmTypeName, spmName));
    1766            0 :                             ErrorsFound = true;
    1767            0 :                             continue;
    1768              :                         }
    1769              :                     }
    1770              : 
    1771          286 :                     auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmSZR->airLoopNum);
    1772          286 :                     MixedAirNode = primaryAirSystem.OASysOutletNodeNum;
    1773          286 :                     InletBranchNum = primaryAirSystem.InletBranchNum[0];
    1774          286 :                     LoopInNode = primaryAirSystem.Branch(InletBranchNum).NodeNumIn;
    1775              :                     // get the supply fan inlet and outlet nodes
    1776          286 :                     if (MixedAirNode > 0) {
    1777          284 :                         bool LookForFan = false;
    1778          568 :                         for (auto const &branch : primaryAirSystem.Branch) {
    1779         1052 :                             for (auto const &comp : branch.Comp) {
    1780          984 :                                 if (MixedAirNode == comp.NodeNumIn) {
    1781          284 :                                     LookForFan = true;
    1782              :                                 }
    1783          984 :                                 if (LookForFan) {
    1784         1668 :                                     if (Util::SameString(comp.TypeOf, "Fan:ConstantVolume") || Util::SameString(comp.TypeOf, "Fan:VariableVolume") ||
    1785         1668 :                                         Util::SameString(comp.TypeOf, "Fan:OnOff") || Util::SameString(comp.TypeOf, "Fan:ComponentModel")) {
    1786          216 :                                         FanNodeIn = comp.NodeNumIn;
    1787          216 :                                         FanNodeOut = comp.NodeNumOut;
    1788          216 :                                         break;
    1789              :                                     }
    1790              :                                 }
    1791              :                             }
    1792              :                         } // for (BranchNum)
    1793              :                     } else {
    1794            4 :                         for (auto const &branch : primaryAirSystem.Branch) {
    1795            8 :                             for (auto const &comp : branch.Comp) {
    1796           14 :                                 if (Util::SameString(comp.TypeOf, "Fan:ConstantVolume") || Util::SameString(comp.TypeOf, "Fan:VariableVolume") ||
    1797           14 :                                     Util::SameString(comp.TypeOf, "Fan:OnOff") || Util::SameString(comp.TypeOf, "Fan:ComponentModel")) {
    1798            2 :                                     FanNodeIn = comp.NodeNumIn;
    1799            2 :                                     FanNodeOut = comp.NodeNumOut;
    1800              :                                 }
    1801              :                             }
    1802              :                         }
    1803              :                     }
    1804              : 
    1805          286 :                     spmSZR->fanInNodeNum = FanNodeIn;
    1806          286 :                     spmSZR->fanOutNodeNum = FanNodeOut;
    1807          286 :                     spmSZR->mixedAirNodeNum = MixedAirNode;
    1808          286 :                     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          286 :                     spmSZR->retNodeNum = primaryAirSystem.OASysInletNodeNum;
    1812          286 :                     spmSZR->loopInNodeNum = LoopInNode;
    1813              : 
    1814          286 :                 } break;
    1815              : 
    1816           23 :                 case SPMType::Warmest:
    1817              :                 case SPMType::Coldest: {
    1818           23 :                     auto *spmT = dynamic_cast<SPMTempest *>(spm);
    1819           23 :                     assert(spmT != nullptr);
    1820           23 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1821           23 :                         spmT->airLoopNum =
    1822           23 :                             Util::FindItemInList(spmT->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1823           23 :                         if (spmT->airLoopNum == 0) {
    1824            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmT->airLoopName);
    1825            0 :                             ErrorsFound = true;
    1826           23 :                         } 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           23 :                 } break;
    1837              : 
    1838            4 :                 case SPMType::WarmestTempFlow: {
    1839            4 :                     auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    1840            4 :                     assert(spmWTF != nullptr);
    1841              : 
    1842            4 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1843            4 :                         spmWTF->airLoopNum = Util::FindItemInList(
    1844            4 :                             spmWTF->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1845            4 :                         if (spmWTF->airLoopNum == 0) {
    1846            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmWTF->airLoopName);
    1847            0 :                             ErrorsFound = true;
    1848              :                         } else {
    1849            4 :                             spmWTF->simReady = true;
    1850              :                         }
    1851            4 :                         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            4 :                 } break;
    1862              : 
    1863            1 :                 case SPMType::ReturnAirBypass: {
    1864            1 :                     auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    1865            1 :                     assert(spmRAB != nullptr);
    1866              : 
    1867            1 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1868            1 :                         spmRAB->airLoopNum = Util::FindItemInList(
    1869            1 :                             spmRAB->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1870            1 :                         if (spmRAB->airLoopNum == 0) {
    1871            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmRAB->airLoopName);
    1872            0 :                             ErrorsFound = true;
    1873              :                         }
    1874              : 
    1875            1 :                         auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmRAB->airLoopNum);
    1876            1 :                         if (primaryAirSystem.RABExists) {
    1877            1 :                             spmRAB->rabMixInNodeNum = primaryAirSystem.RABMixInNode;
    1878            1 :                             spmRAB->supMixInNodeNum = primaryAirSystem.SupMixInNode;
    1879            1 :                             spmRAB->mixOutNodeNum = primaryAirSystem.MixOutNode;
    1880            1 :                             spmRAB->rabSplitOutNodeNum = primaryAirSystem.RABSplitOutNode;
    1881            1 :                             spmRAB->sysOutNodeNum = state.dataAirLoop->AirToZoneNodeInfo(spmRAB->airLoopNum).AirLoopSupplyNodeNum(1);
    1882            1 :                             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            1 :                 } break;
    1894              : 
    1895            2 :                 case SPMType::MZCoolingAverage:
    1896              :                 case SPMType::MZHeatingAverage: {
    1897            2 :                     auto *spmMZTemp = dynamic_cast<SPMMultiZoneTemp *>(spm);
    1898            2 :                     assert(spmMZTemp != nullptr);
    1899              : 
    1900            2 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1901            2 :                         spmMZTemp->airLoopNum = Util::FindItemInList(
    1902            2 :                             spmMZTemp->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1903            2 :                         if (spmMZTemp->airLoopNum == 0) {
    1904            0 :                             ShowSevereItemNotFound(state, eoh, "hvac_air_loop_name", spmMZTemp->airLoopName);
    1905            0 :                             ErrorsFound = true;
    1906              :                         }
    1907              : 
    1908            2 :                         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            2 :                 } break;
    1919              : 
    1920           24 :                 case SPMType::MZMinHumAverage:
    1921              :                 case SPMType::MZMaxHumAverage:
    1922              :                 case SPMType::MZMinHum:
    1923              :                 case SPMType::MZMaxHum: {
    1924           24 :                     auto *spmMZHum = dynamic_cast<SPMMultiZoneHum *>(spm);
    1925           24 :                     assert(spmMZHum != nullptr);
    1926              : 
    1927           24 :                     if (state.dataHVACGlobal->NumPrimaryAirSys > 0) {
    1928           24 :                         spmMZHum->airLoopNum = Util::FindItemInList(
    1929           24 :                             spmMZHum->airLoopName, state.dataAirLoop->AirToZoneNodeInfo, &AirLoopZoneEquipConnectData::AirLoopName);
    1930           24 :                         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           24 :                             auto const &primaryAirSystem = state.dataAirSystemsData->PrimaryAirSystems(spmMZHum->airLoopNum);
    1936           24 :                             auto const &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(spmMZHum->airLoopNum);
    1937           24 :                             bool HstatZoneFound = false;
    1938          136 :                             for (int iZone = 1; iZone <= state.dataZoneCtrls->NumHumidityControlZones; ++iZone) {
    1939          574 :                                 for (int jZone = 1; jZone <= airToZoneNode.NumZonesCooled; ++jZone) {
    1940          534 :                                     if (state.dataZoneCtrls->HumidityControlZone(iZone).ActualZoneNum == airToZoneNode.CoolCtrlZoneNums(jZone)) {
    1941           72 :                                         HstatZoneFound = true;
    1942           72 :                                         break;
    1943              :                                     }
    1944              :                                 }
    1945              :                             }
    1946              : 
    1947           24 :                             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           24 :                 } break;
    1961              : 
    1962            3 :                 case SPMType::CondenserEnteringTemp: {
    1963            3 :                     auto *spmCET = dynamic_cast<SPMCondenserEnteringTemp *>(spm);
    1964            3 :                     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           12 :                     for (int LoopNum = 1; LoopNum <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops; ++LoopNum) {
    1969            9 :                         auto &plantLoop = state.dataPlnt->PlantLoop(LoopNum);
    1970           18 :                         for (int ctrlNodeNum : spmCET->ctrlNodeNums) {
    1971            9 :                             if (plantLoop.TempSetPointNodeNum != ctrlNodeNum) {
    1972            6 :                                 continue;
    1973              :                             }
    1974              : 
    1975           16 :                             for (auto const &branch : plantLoop.LoopSide(LoopSideLocation::Supply).Branch) {
    1976           26 :                                 for (auto const &comp : branch.Comp) {
    1977           13 :                                     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           16 :                             for (int BranchNum = 1; BranchNum <= plantLoop.LoopSide(LoopSideLocation::Demand).TotalBranches; ++BranchNum) {
    1988           13 :                                 auto &branch = plantLoop.LoopSide(LoopSideLocation::Demand).Branch(BranchNum);
    1989              : 
    1990           26 :                                 for (int CompNum = 1; CompNum <= branch.TotalComponents; ++CompNum) {
    1991           13 :                                     auto const &comp = branch.Comp(CompNum);
    1992           13 :                                     switch (comp.Type) {
    1993              : 
    1994            4 :                                     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            4 :                                         DataPlant::PlantEquipmentType ChillerType = comp.Type;
    2005           16 :                                         for (int LoopNum2 = 1; LoopNum2 <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops;
    2006              :                                              ++LoopNum2) {
    2007           12 :                                             auto &plantLoop2 = state.dataPlnt->PlantLoop(LoopNum2);
    2008           12 :                                             auto &loopSide2 = plantLoop2.LoopSide(LoopSideLocation::Supply);
    2009           65 :                                             for (int BranchNum2 = 1; BranchNum2 <= loopSide2.TotalBranches; ++BranchNum2) {
    2010           53 :                                                 auto const &branch2 = loopSide2.Branch(BranchNum2);
    2011              : 
    2012          102 :                                                 for (int CompNum2 = 1; CompNum2 <= branch2.TotalComponents; ++CompNum2) {
    2013           53 :                                                     auto const &comp2 = branch2.Comp(CompNum2);
    2014           53 :                                                     if (comp2.Type == ChillerType) {
    2015            4 :                                                         spmCET->plantPloc = {LoopNum2, LoopSideLocation::Supply, BranchNum2, CompNum2};
    2016            4 :                                                         break;
    2017              :                                                     }
    2018              :                                                 }
    2019              :                                             }
    2020              :                                         }
    2021            4 :                                         spmCET->chillerType = ChillerType;
    2022            4 :                                         spmCET->demandPloc = {LoopNum, LoopSideLocation::Demand, BranchNum, CompNum};
    2023            4 :                                     } break;
    2024              : 
    2025            9 :                                     default:
    2026            9 :                                         break;
    2027              :                                     }
    2028              :                                 } // for (comp)
    2029              :                             } // for (branch)
    2030            9 :                         } // if (
    2031              :                     } // for (LoopNum)
    2032            3 :                 } break;
    2033              : 
    2034            2 :                 case SPMType::IdealCondenserEnteringTemp: {
    2035            2 :                     auto *spmIdealCET = dynamic_cast<SPMIdealCondenserEnteringTemp *>(spm);
    2036            2 :                     assert(spmIdealCET != nullptr);
    2037              : 
    2038            2 :                     PlantEquipmentType InitType = PlantEquipmentType::Invalid;
    2039            2 :                     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            8 :                     for (int LoopNum = 1; LoopNum <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops; ++LoopNum) {
    2044            6 :                         auto &plantLoop = state.dataPlnt->PlantLoop(LoopNum);
    2045            6 :                         auto &supplySide = plantLoop.LoopSide(LoopSideLocation::Supply);
    2046           15 :                         for (int ctrlNodeNum : spmIdealCET->ctrlNodeNums) {
    2047            9 :                             if (plantLoop.TempSetPointNodeNum != ctrlNodeNum) {
    2048            7 :                                 continue;
    2049              :                             }
    2050              : 
    2051           11 :                             for (int BranchNum = 1; BranchNum <= supplySide.TotalBranches; ++BranchNum) {
    2052            9 :                                 auto &branch = supplySide.Branch(BranchNum);
    2053           18 :                                 for (int CompNum = 1; CompNum <= branch.TotalComponents; ++CompNum) {
    2054            9 :                                     auto &comp = branch.Comp(CompNum);
    2055              :                                     // Check if cooling tower is single speed and generate and error
    2056            9 :                                     InitType = comp.Type;
    2057            9 :                                     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            9 :                                     } else if (InitType == PlantEquipmentType::CoolingTower_TwoSpd ||
    2063              :                                                InitType == PlantEquipmentType::CoolingTower_VarSpd) {
    2064            3 :                                         spmIdealCET->towerPlocs.push_back(PlantLocation(LoopNum, LoopSideLocation::Supply, BranchNum, CompNum));
    2065            3 :                                         spmIdealCET->numTowers++;
    2066              :                                     }
    2067              :                                     // Scan the pump on the condenser water loop
    2068            9 :                                     if (InitType == PlantEquipmentType::PumpVariableSpeed || InitType == PlantEquipmentType::PumpConstantSpeed) {
    2069            2 :                                         spmIdealCET->condenserPumpPloc = {LoopNum, LoopSideLocation::Supply, BranchNum, CompNum};
    2070              :                                     }
    2071              :                                 }
    2072              :                             }
    2073              : 
    2074            2 :                             auto &demandSide = plantLoop.LoopSide(LoopSideLocation::Demand);
    2075              :                             // Scan all attached chillers in the condenser loop index found to find the chiller index
    2076           10 :                             for (int BranchNum = 1; BranchNum <= demandSide.TotalBranches; ++BranchNum) {
    2077            8 :                                 auto &branch = demandSide.Branch(BranchNum);
    2078           16 :                                 for (int CompNum = 1; CompNum <= branch.TotalComponents; ++CompNum) {
    2079            8 :                                     auto &comp = branch.Comp(CompNum);
    2080            8 :                                     InitType = comp.Type;
    2081              : 
    2082            8 :                                     switch (InitType) {
    2083            2 :                                     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            2 :                                         DataPlant::PlantEquipmentType ChillerType = comp.Type;
    2094            8 :                                         for (int LoopNum2 = 1; LoopNum2 <= state.dataHVACGlobal->NumCondLoops + state.dataHVACGlobal->NumPlantLoops;
    2095              :                                              ++LoopNum2) {
    2096            6 :                                             auto &plantLoop2 = state.dataPlnt->PlantLoop(LoopNum2);
    2097            6 :                                             auto &supplySide2 = plantLoop2.LoopSide(LoopSideLocation::Supply);
    2098           31 :                                             for (int BranchNum2 = 1; BranchNum2 <= supplySide2.TotalBranches; ++BranchNum2) {
    2099           25 :                                                 auto &branch2 = supplySide2.Branch(BranchNum2);
    2100           50 :                                                 for (int CompNum2 = 1; CompNum2 <= branch2.TotalComponents; ++CompNum2) {
    2101           25 :                                                     auto const &comp2 = branch2.Comp(CompNum2);
    2102           25 :                                                     InitType = comp2.Type;
    2103           25 :                                                     if (InitType == ChillerType) {
    2104            2 :                                                         ++NumChiller;
    2105            2 :                                                         spmIdealCET->chillerPloc = {LoopNum2, LoopSideLocation::Supply, BranchNum2, CompNum2};
    2106              :                                                         // Scan the pump on the chilled water loop
    2107           10 :                                                         for (int BranchNum3 = 1; BranchNum3 <= supplySide2.TotalBranches; ++BranchNum3) {
    2108            8 :                                                             auto &branch3 = supplySide2.Branch(BranchNum3);
    2109           16 :                                                             for (int CompNum3 = 1; CompNum3 <= branch3.TotalComponents; ++CompNum3) {
    2110            8 :                                                                 auto const &comp3 = branch3.Comp(CompNum3);
    2111            8 :                                                                 InitType = comp3.Type;
    2112            8 :                                                                 if (InitType == PlantEquipmentType::PumpVariableSpeed ||
    2113              :                                                                     InitType == PlantEquipmentType::PumpConstantSpeed) {
    2114            2 :                                                                     spmIdealCET->chilledWaterPumpPloc = {
    2115              :                                                                         LoopNum2, LoopSideLocation::Supply, BranchNum3, CompNum3};
    2116              :                                                                 }
    2117              :                                                             }
    2118              :                                                         }
    2119              :                                                     }
    2120              :                                                 }
    2121              :                                             }
    2122              :                                         }
    2123            2 :                                         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            2 :                                         spmIdealCET->chillerType = ChillerType;
    2130            2 :                                         spmIdealCET->condenserPumpPloc.loopNum = LoopNum;
    2131            2 :                                     } break;
    2132              : 
    2133            6 :                                     default:
    2134            6 :                                         break;
    2135              :                                     } // switch (InitType)
    2136              :                                 } // for (CompNum)
    2137              :                             } // for (BranchNum)
    2138            2 :                             NumChiller = 0;
    2139            6 :                         } // for (iNode)
    2140              :                     } // for (LoopNum)
    2141            2 :                 } break;
    2142              : 
    2143         4032 :                 default:
    2144         4032 :                     break;
    2145              :                 } // switch (spm->type)
    2146              :             } // for (spm)
    2147              : 
    2148          800 :             VerifySetPointManagers(state, ErrorsFound);
    2149              : 
    2150          800 :             state.dataSetPointManager->InitSetPointManagersOneTimeFlag = false;
    2151              :         } // if (InitSetPointManagersOneTimeFlag)
    2152              : 
    2153      2853866 :         if (ErrorsFound) {
    2154            0 :             ShowFatalError(state, "InitSetPointManagers: Errors found in getting SetPointManager input.");
    2155              :         }
    2156              :     } // if (AirLoopInputsFilled)
    2157              : 
    2158      5706263 :     if ((state.dataGlobal->BeginEnvrnFlag && state.dataSetPointManager->InitSetPointManagersMyEnvrnFlag) ||
    2159      2850796 :         state.dataSetPointManager->InitSetPointManagersOneTimeFlag2) {
    2160              : 
    2161         6271 :         state.dataSetPointManager->ManagerOn = false;
    2162              : 
    2163        45901 :         for (auto *spm : state.dataSetPointManager->spms) {
    2164              : 
    2165        39630 :             switch (spm->type) {
    2166        16199 :             case SPMType::Scheduled: {
    2167        16199 :                 auto *spmS = dynamic_cast<SPMScheduled *>(spm);
    2168        16199 :                 assert(spmS != nullptr);
    2169              : 
    2170        32728 :                 for (int ctrlNodeNum : spmS->ctrlNodeNums) {
    2171        16529 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2172        16529 :                     Real64 SchedValue = spmS->sched->getCurrentVal();
    2173              :                     // Initialize scheduled setpoints
    2174        16529 :                     switch (spmS->ctrlVar) {
    2175        16450 :                     case HVAC::CtrlVarType::Temp: {
    2176        16450 :                         node.TempSetPoint = SchedValue;
    2177        16450 :                     } 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           71 :                     case HVAC::CtrlVarType::MaxHumRat: {
    2188           71 :                         node.HumRatMax = SchedValue;
    2189           71 :                     } break;
    2190            8 :                     case HVAC::CtrlVarType::MinHumRat: {
    2191            8 :                         node.HumRatMin = SchedValue;
    2192            8 :                     } 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        16199 :                 }
    2206        16199 :             } break;
    2207              : 
    2208          179 :             case SPMType::ScheduledDual: {
    2209          179 :                 auto *spmSD = dynamic_cast<SPMScheduledDual *>(spm);
    2210          179 :                 assert(spmSD != nullptr);
    2211          420 :                 for (int ctrlNodeNum : spmSD->ctrlNodeNums) {
    2212          241 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2213          241 :                     if (spmSD->ctrlVar == HVAC::CtrlVarType::Temp) {
    2214          241 :                         node.TempSetPointHi = spmSD->hiSched->getCurrentVal();
    2215          241 :                         node.TempSetPointLo = spmSD->loSched->getCurrentVal();
    2216          241 :                         node.TempSetPoint = (node.TempSetPointHi + node.TempSetPointLo) / 2.0;
    2217              :                     }
    2218          179 :                 }
    2219          179 :             } break;
    2220              : 
    2221          974 :             case SPMType::OutsideAir: {
    2222          974 :                 auto *spmOA = dynamic_cast<SPMOutsideAir *>(spm);
    2223          974 :                 assert(spmOA != nullptr);
    2224              : 
    2225         2178 :                 for (int NodeNum : spmOA->ctrlNodeNums) {
    2226         1204 :                     spmOA->calculate(state); // Why is this calculated for every node?
    2227              : 
    2228         1204 :                     auto &node = state.dataLoopNodes->Node(NodeNum);
    2229         1204 :                     if (spmOA->ctrlVar == HVAC::CtrlVarType::Temp) {
    2230         1204 :                         node.TempSetPoint = spmOA->setPt;
    2231            0 :                     } else if (spmOA->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    2232            0 :                         node.TempSetPointHi = spmOA->setPt;
    2233            0 :                     } else if (spmOA->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    2234            0 :                         node.TempSetPointLo = spmOA->setPt;
    2235              :                     }
    2236          974 :                 }
    2237          974 :             } break;
    2238              : 
    2239          275 :             case SPMType::SZMinHum: {
    2240          275 :                 auto *spmSZH = dynamic_cast<SPMSingleZoneHum *>(spm);
    2241          275 :                 assert(spmSZH != nullptr);
    2242              : 
    2243          275 :                 state.dataLoopNodes->Node(spmSZH->zoneNodeNum).MassFlowRate = 0.0;
    2244          550 :                 for (int ctrlNodeNum : spmSZH->ctrlNodeNums) {
    2245          275 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMin = 0.007;
    2246          275 :                 }
    2247          275 :             } break;
    2248              : 
    2249          470 :             case SPMType::SZMaxHum: {
    2250          470 :                 auto *spmSZH = dynamic_cast<SPMSingleZoneHum *>(spm);
    2251          470 :                 assert(spmSZH != nullptr);
    2252              : 
    2253          470 :                 state.dataLoopNodes->Node(spmSZH->zoneNodeNum).MassFlowRate = 0.0;
    2254          940 :                 for (int ctrlNodeNum : spmSZH->ctrlNodeNums) {
    2255          470 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMax = 0.011;
    2256          470 :                 }
    2257          470 :             } break;
    2258              : 
    2259         2116 :             case SPMType::SZReheat: {
    2260         2116 :                 auto *spmSZR = dynamic_cast<SPMSingleZoneReheat *>(spm);
    2261         2116 :                 assert(spmSZR != nullptr);
    2262              : 
    2263         2116 :                 state.dataLoopNodes->Node(spmSZR->zoneInletNodeNum).MassFlowRate = 0.0;
    2264         2116 :                 state.dataLoopNodes->Node(spmSZR->zoneNodeNum).MassFlowRate = 0.0;
    2265         2116 :                 if (spmSZR->ctrlVar == HVAC::CtrlVarType::Temp) {
    2266         4413 :                     for (int ctrlNodeNum : spmSZR->ctrlNodeNums) {
    2267         2297 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2268         2116 :                     }
    2269              :                 }
    2270              : 
    2271         2116 :             } break;
    2272              : 
    2273         2470 :             case SPMType::SZHeating:
    2274              :             case SPMType::SZCooling: {
    2275         2470 :                 auto *spmSZT = dynamic_cast<SPMSingleZoneTemp *>(spm);
    2276         2470 :                 assert(spmSZT != nullptr);
    2277              : 
    2278         2470 :                 state.dataLoopNodes->Node(spmSZT->zoneInletNodeNum).MassFlowRate = 0.0;
    2279         2470 :                 state.dataLoopNodes->Node(spmSZT->zoneNodeNum).MassFlowRate = 0.0;
    2280              : 
    2281         2470 :                 if (spmSZT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2282         5068 :                     for (int ctrlNodeNum : spmSZT->ctrlNodeNums) {
    2283         2598 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2284         2470 :                     }
    2285              :                 }
    2286         2470 :             } break;
    2287              : 
    2288        14365 :             case SPMType::MixedAir: {
    2289        14365 :                 auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
    2290        14365 :                 assert(spmMA != nullptr);
    2291              : 
    2292        14365 :                 auto &refNode = state.dataLoopNodes->Node(spmMA->refNodeNum);
    2293        14365 :                 auto &fanInNode = state.dataLoopNodes->Node(spmMA->fanInNodeNum);
    2294        14365 :                 auto &fanOutNode = state.dataLoopNodes->Node(spmMA->fanOutNodeNum);
    2295              : 
    2296        14365 :                 refNode.MassFlowRate = fanInNode.MassFlowRate = fanOutNode.MassFlowRate = 0.0;
    2297        14365 :                 refNode.Temp = fanInNode.Temp = fanOutNode.Temp = 20.0;
    2298        14365 :                 refNode.HumRat = fanInNode.HumRat = fanOutNode.HumRat = state.dataEnvrn->OutHumRat;
    2299        14365 :                 refNode.Quality = fanInNode.Quality = fanOutNode.Quality = 1.0;
    2300        14365 :                 refNode.Press = fanInNode.Press = fanOutNode.Press = state.dataEnvrn->OutBaroPress;
    2301        14365 :                 refNode.Enthalpy = fanInNode.Enthalpy = fanOutNode.Enthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
    2302              : 
    2303        14365 :                 if (spmMA->ctrlVar == HVAC::CtrlVarType::Temp) {
    2304        30912 :                     for (int ctrlNodeNum : spmMA->ctrlNodeNums) {
    2305        16547 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2306        14365 :                     }
    2307              :                 }
    2308              : 
    2309        14365 :             } break;
    2310              : 
    2311           75 :             case SPMType::OutsideAirPretreat: {
    2312           75 :                 auto *spmOAP = dynamic_cast<SPMOutsideAirPretreat *>(spm);
    2313           75 :                 assert(spmOAP != nullptr);
    2314              : 
    2315           75 :                 auto &refNode = state.dataLoopNodes->Node(spmOAP->refNodeNum);
    2316           75 :                 auto &mixedOutNode = state.dataLoopNodes->Node(spmOAP->mixedOutNodeNum);
    2317           75 :                 auto &oaInNode = state.dataLoopNodes->Node(spmOAP->oaInNodeNum);
    2318           75 :                 auto &returnInNode = state.dataLoopNodes->Node(spmOAP->returnInNodeNum);
    2319              : 
    2320           75 :                 refNode.MassFlowRate = mixedOutNode.MassFlowRate = oaInNode.MassFlowRate = returnInNode.MassFlowRate = 0.0;
    2321           75 :                 refNode.Temp = mixedOutNode.Temp = oaInNode.Temp = returnInNode.Temp = 20.0;
    2322           75 :                 refNode.HumRat = mixedOutNode.HumRat = oaInNode.HumRat = returnInNode.HumRat = state.dataEnvrn->OutHumRat;
    2323           75 :                 refNode.Quality = mixedOutNode.Quality = oaInNode.Quality = returnInNode.Quality = 1.0;
    2324           75 :                 refNode.Press = mixedOutNode.Press = oaInNode.Press = returnInNode.Press = state.dataEnvrn->OutBaroPress;
    2325           75 :                 refNode.Enthalpy = mixedOutNode.Enthalpy = oaInNode.Enthalpy = returnInNode.Enthalpy = PsyHFnTdbW(20.0, state.dataEnvrn->OutHumRat);
    2326              : 
    2327          150 :                 for (int ctrlNodeNum : spmOAP->ctrlNodeNums) {
    2328           75 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2329           75 :                     if (spmOAP->ctrlVar == HVAC::CtrlVarType::Temp) {
    2330           45 :                         node.TempSetPoint = 20.0; // Set the setpoint
    2331           30 :                     } else if (spmOAP->ctrlVar == HVAC::CtrlVarType::MaxHumRat) {
    2332           30 :                         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           75 :                 }
    2339           75 :             } break;
    2340              : 
    2341          198 :             case SPMType::Warmest:
    2342              :             case SPMType::Coldest: {
    2343              : 
    2344          396 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2345          198 :                     if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    2346          198 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2347              :                     }
    2348          198 :                 }
    2349              : 
    2350          198 :             } break;
    2351              : 
    2352           29 :             case SPMType::WarmestTempFlow: {
    2353           29 :                 auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    2354           29 :                 assert(spmWTF != nullptr);
    2355              : 
    2356           29 :                 if (spmWTF->ctrlVar == HVAC::CtrlVarType::Temp) {
    2357           58 :                     for (int ctrlNodeNum : spmWTF->ctrlNodeNums) {
    2358           29 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the temperature setpoint
    2359           29 :                         if (spmWTF->airLoopNum != 0) {
    2360           21 :                             state.dataAirLoop->AirLoopFlow(spmWTF->airLoopNum).ReqSupplyFrac = 1.0;           // PH 10/09/04 Set the flow
    2361           21 :                             state.dataAirLoop->AirLoopControlInfo(spmWTF->airLoopNum).LoopFlowRateSet = true; // PH 10/09/04 Set the flag
    2362              :                         }
    2363           29 :                     }
    2364              :                 }
    2365           29 :             } break;
    2366              : 
    2367            8 :             case SPMType::ReturnAirBypass: {
    2368            8 :                 if (state.dataZoneEquip->ZoneEquipInputsFilled && state.dataAirLoop->AirLoopInputsFilled) {
    2369              : 
    2370            6 :                     auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    2371            6 :                     assert(spmRAB != nullptr);
    2372              : 
    2373            6 :                     if (spmRAB->ctrlVar == HVAC::CtrlVarType::MassFlowRate) {
    2374            6 :                         state.dataLoopNodes->Node(spmRAB->rabSplitOutNodeNum).MassFlowRateSetPoint = 0.0;
    2375              :                     }
    2376              :                 }
    2377            8 :             } break;
    2378              : 
    2379           16 :             case SPMType::MZCoolingAverage:
    2380              :             case SPMType::MZHeatingAverage: {
    2381           16 :                 if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    2382           32 :                     for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2383           16 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = 20.0; // Set the setpoint
    2384           16 :                     }
    2385              :                 }
    2386           16 :             } break;
    2387              : 
    2388           78 :             case SPMType::MZMinHumAverage:
    2389              :             case SPMType::MZMinHum: {
    2390          156 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2391           78 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMin = 0.007; // Set the setpoint
    2392           78 :                 }
    2393           78 :             } break;
    2394              : 
    2395          129 :             case SPMType::MZMaxHumAverage:
    2396              :             case SPMType::MZMaxHum: {
    2397          298 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2398          169 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMax = 0.011; // Set the setpoint
    2399          129 :                 }
    2400          129 :             } break;
    2401              : 
    2402         1700 :             case SPMType::FollowOutsideAirTemp: {
    2403         1700 :                 auto *spmFOAT = dynamic_cast<SPMFollowOutsideAirTemp *>(spm);
    2404         1700 :                 assert(spmFOAT != nullptr);
    2405         1700 :                 bool isWetBulb = spmFOAT->refTempType == AirTempType::WetBulb;
    2406              : 
    2407         3400 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2408         1700 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2409         1700 :                     if (spmFOAT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2410         1700 :                         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         1700 :                 }
    2417         1700 :             } break;
    2418              : 
    2419            8 :             case SPMType::FollowSystemNodeTemp: {
    2420            8 :                 auto *spmFSNT = dynamic_cast<SPMFollowSysNodeTemp *>(spm);
    2421            8 :                 assert(spmFSNT != nullptr);
    2422              : 
    2423            8 :                 bool isWetBulb = spmFSNT->refTempType == AirTempType::WetBulb;
    2424            8 :                 auto &refNode = state.dataLoopNodes->Node(spmFSNT->refNodeNum);
    2425           16 :                 for (int ctrlNodeNum : spmFSNT->ctrlNodeNums) {
    2426            8 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2427            8 :                     if (CheckOutAirNodeNumber(state, spmFSNT->refNodeNum)) {
    2428            8 :                         refNode.SPMNodeWetBulbRepReq = isWetBulb;
    2429            8 :                         if (spmFSNT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2430            8 :                             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            8 :                 }
    2454            8 :             } break;
    2455              : 
    2456          150 :             case SPMType::FollowGroundTemp: {
    2457          150 :                 auto *spmFGT = dynamic_cast<SPMFollowGroundTemp *>(spm);
    2458          150 :                 assert(spmFGT != nullptr);
    2459              : 
    2460          150 :                 Real64 GroundTemp = state.dataEnvrn->GroundTemp[(int)spmFGT->refTempType];
    2461              : 
    2462          300 :                 for (int ctrlNodeNum : spmFGT->ctrlNodeNums) {
    2463          150 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2464          150 :                     if (spmFGT->ctrlVar == HVAC::CtrlVarType::Temp) {
    2465          150 :                         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          150 :                 }
    2472          150 :             } break;
    2473              : 
    2474           24 :             case SPMType::CondenserEnteringTemp: {
    2475           24 :                 auto *spmCER = dynamic_cast<SPMCondenserEnteringTemp *>(spm);
    2476           24 :                 assert(spmCER != nullptr);
    2477           24 :                 Real64 SchedValue = spmCER->condenserEnteringTempSched->getCurrentVal();
    2478           48 :                 for (int ctrlNodeNum : spmCER->ctrlNodeNums) {
    2479           24 :                     if (spmCER->ctrlVar == HVAC::CtrlVarType::Temp) {
    2480           24 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = SchedValue;
    2481              :                     }
    2482           24 :                 }
    2483           24 :             } break;
    2484              : 
    2485           15 :             case SPMType::IdealCondenserEnteringTemp: {
    2486           15 :                 auto const *spmICER = dynamic_cast<SPMIdealCondenserEnteringTemp *>(spm);
    2487           15 :                 assert(spmICER != nullptr);
    2488              : 
    2489           15 :                 if (spmICER->ctrlVar == HVAC::CtrlVarType::Temp) {
    2490           37 :                     for (int ctrlNodeNum : spmICER->ctrlNodeNums) {
    2491           22 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmICER->maxCondenserEnteringTemp;
    2492           15 :                     }
    2493              :                 }
    2494           15 :             } break;
    2495              : 
    2496           28 :             case SPMType::SZOneStageCooling: {
    2497           28 :                 auto const *spmSZOSC = dynamic_cast<SPMSingleZoneOneStageCooling *>(spm);
    2498           28 :                 assert(spmSZOSC != nullptr);
    2499              : 
    2500           28 :                 if (spmSZOSC->ctrlVar == HVAC::CtrlVarType::Temp) {
    2501           56 :                     for (int ctrlNodeNum : spmSZOSC->ctrlNodeNums) {
    2502           28 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmSZOSC->coolingOffSetPt;
    2503           28 :                     }
    2504              :                 }
    2505           28 :             } break;
    2506              : 
    2507           28 :             case SPMType::SZOneStageHeating: {
    2508           28 :                 auto const *spmSZOSH = dynamic_cast<SPMSingleZoneOneStageHeating *>(spm);
    2509           28 :                 assert(spmSZOSH != nullptr);
    2510              : 
    2511           28 :                 if (spmSZOSH->ctrlVar == HVAC::CtrlVarType::Temp) {
    2512           56 :                     for (int ctrlNodeNum : spmSZOSH->ctrlNodeNums) {
    2513           28 :                         state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmSZOSH->heatingOffSetPt;
    2514           28 :                     }
    2515              :                 }
    2516              : 
    2517           28 :             } break;
    2518              : 
    2519           37 :             case SPMType::ChilledWaterReturnTemp: {
    2520           37 :                 auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    2521           37 :                 assert(spmRWT != nullptr);
    2522              : 
    2523           37 :                 state.dataLoopNodes->Node(spmRWT->supplyNodeNum).TempSetPoint = spmRWT->minSetTemp;
    2524              : 
    2525           37 :             } break;
    2526              : 
    2527           23 :             case SPMType::HotWaterReturnTemp: {
    2528           23 :                 auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    2529           23 :                 assert(spmRWT != nullptr);
    2530              : 
    2531           23 :                 state.dataLoopNodes->Node(spmRWT->supplyNodeNum).TempSetPoint = spmRWT->maxSetTemp;
    2532           23 :             } break;
    2533              : 
    2534           24 :             case SPMType::SystemNodeTemp:
    2535              :             case SPMType::SystemNodeHum: {
    2536           48 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    2537           24 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    2538           24 :                     spm->calculate(state);
    2539           24 :                     switch (spm->ctrlVar) {
    2540           18 :                     case HVAC::CtrlVarType::Temp: {
    2541           18 :                         node.TempSetPoint = spm->setPt;
    2542           18 :                     } 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            0 :                     case HVAC::CtrlVarType::HumRat: {
    2550            0 :                         node.HumRatSetPoint = spm->setPt;
    2551            0 :                     } break;
    2552            6 :                     case HVAC::CtrlVarType::MaxHumRat: {
    2553            6 :                         node.HumRatMax = spm->setPt;
    2554            6 :                     } break;
    2555            0 :                     case HVAC::CtrlVarType::MinHumRat: {
    2556            0 :                         node.HumRatMin = spm->setPt;
    2557            0 :                     } break;
    2558            0 :                     default:
    2559            0 :                         break;
    2560              :                     }
    2561           24 :                 }
    2562           24 :             } break;
    2563              : 
    2564           12 :             default:
    2565           12 :                 break;
    2566              :             } // switch (spm->type)
    2567              :         } // for (spm)
    2568              : 
    2569         6271 :         state.dataSetPointManager->InitSetPointManagersMyEnvrnFlag = false;
    2570         6271 :         if (!state.dataSetPointManager->InitSetPointManagersOneTimeFlag) {
    2571         4670 :             state.dataSetPointManager->InitSetPointManagersOneTimeFlag2 = false;
    2572              :         }
    2573              : 
    2574         6271 :         if (ErrorsFound) {
    2575            0 :             ShowFatalError(state, "InitSetPointManagers: Errors found. Program Terminates.");
    2576              :         }
    2577              : 
    2578              :     } // end begin environment inits
    2579              : 
    2580      2855467 :     if (!state.dataGlobal->BeginEnvrnFlag) {
    2581      2843779 :         state.dataSetPointManager->InitSetPointManagersMyEnvrnFlag = true;
    2582              :     }
    2583      2855467 : } // InitSetPointManagers()
    2584              : 
    2585      2849196 : 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     21297181 :     for (auto *spm : state.dataSetPointManager->spms) {
    2619     18447985 :         if (spm->type != SPMType::MixedAir && spm->type != SPMType::OutsideAirPretreat) {
    2620     11038684 :             spm->calculate(state);
    2621              :         }
    2622              :     }
    2623      2849196 : } // SimSetPointManagers()
    2624              : 
    2625      7111050 : 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      7111050 :     this->setPt = this->sched->getCurrentVal();
    2634      7111050 : } // SPMScheduled::calculate()
    2635              : 
    2636         3422 : 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         3422 :     Real64 constexpr OnVal(0.5);
    2650              : 
    2651         3422 :     Real64 CurSchValOnPeak = this->sched->getCurrentVal();
    2652         3422 :     Real64 CurSchValCharge = this->chargeSched->getCurrentVal();
    2653              : 
    2654              :     // CtrlType bug
    2655              :     //        if (this->CompOpType == DataPlant::CtrlType::CoolingOp) { // this is some sort of chiller
    2656         3422 :     if (this->compOpType == DataPlant::CtrlType::HeatingOp) { // this is some sort of chiller
    2657         1711 :         if (CurSchValOnPeak >= OnVal) {
    2658          476 :             this->setPt = this->nonChargeCHWTemp;
    2659         1235 :         } else if (CurSchValCharge < OnVal) {
    2660          693 :             this->setPt = this->nonChargeCHWTemp;
    2661              :         } else {
    2662          542 :             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         1711 :     } else if (this->compOpType == DataPlant::CtrlType::CoolingOp) { // this is some sort of ice storage system
    2667         1711 :         this->setPt = this->nonChargeCHWTemp;
    2668              :     }
    2669         3422 : } // SPMTESSScheduled::calculate()
    2670              : 
    2671        32881 : 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        32881 :     this->setPtHi = this->hiSched->getCurrentVal();
    2680        32881 :     this->setPtLo = this->loSched->getCurrentVal();
    2681        32881 : } // SPMScheduledDual::calculate()
    2682              : 
    2683       514329 : void SPMOutsideAir::calculate(EnergyPlusData &state)
    2684              : {
    2685       514329 :     Real64 SchedVal = (this->sched != nullptr) ? this->sched->getCurrentVal() : 0.0;
    2686              : 
    2687       514329 :     if (SchedVal == 2.0) {
    2688            0 :         this->setPt = interpSetPoint(this->low2, this->high2, state.dataEnvrn->OutDryBulbTemp, this->lowSetPt2, this->highSetPt2);
    2689              :     } else {
    2690       514329 :         if ((this->sched != nullptr) && (SchedVal != 1.0)) { // Since schedule is optional, only check this if the user entered a schedule
    2691            0 :             ++this->setPtErrorCount;
    2692            0 :             if (this->setPtErrorCount <= 10) {
    2693            0 :                 ShowSevereError(state,
    2694            0 :                                 format("Schedule Values for the Outside Air Setpoint Manager = {} are something other than 1 or 2.", this->Name));
    2695            0 :                 ShowContinueError(state, format("...the value for the schedule currently is {}", SchedVal));
    2696            0 :                 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       514329 :         this->setPt = interpSetPoint(this->low1, this->high1, state.dataEnvrn->OutDryBulbTemp, this->lowSetPt1, this->highSetPt1);
    2705              :     }
    2706              : 
    2707       514329 : } // SPMOutsideAir::calculate()
    2708              : 
    2709      1168575 : 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      1168575 :     auto const &zoneInletNode = state.dataLoopNodes->Node(this->zoneInletNodeNum);
    2726              : 
    2727              :     // changed from MinOAFrac, now updates to current oa fraction for improve deadband control
    2728      1168575 :     Real64 OAFrac = state.dataAirLoop->AirLoopFlow(this->airLoopNum).OAFrac;
    2729      1168575 :     Real64 ZoneMassFlow = zoneInletNode.MassFlowRate;
    2730              : 
    2731      1168575 :     auto const &zoneSysEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum);
    2732      1168575 :     Real64 ZoneLoad = zoneSysEnergyDemand.TotalOutputRequired;
    2733      1168575 :     Real64 ZoneLoadToCoolSetPt = zoneSysEnergyDemand.OutputRequiredToCoolingSP;
    2734      1168575 :     Real64 ZoneLoadToHeatSetPt = zoneSysEnergyDemand.OutputRequiredToHeatingSP;
    2735      1168575 :     bool DeadBand = state.dataZoneEnergyDemand->DeadBandOrSetback(this->ctrlZoneNum);
    2736      1168575 :     Real64 ZoneTemp = state.dataLoopNodes->Node(this->zoneNodeNum).Temp;
    2737              : 
    2738              :     Real64 TMixAtMinOA;
    2739      1168575 :     if (this->oaInNodeNum > 0) {
    2740      1161103 :         auto const &oaInNode = state.dataLoopNodes->Node(this->oaInNodeNum);
    2741      1161103 :         auto const &retNode = state.dataLoopNodes->Node(this->retNodeNum);
    2742      1161103 :         Real64 HumRatMixAtMinOA = (1.0 - OAFrac) * retNode.HumRat + OAFrac * oaInNode.HumRat;
    2743      1161103 :         Real64 EnthMixAtMinOA = (1.0 - OAFrac) * retNode.Enthalpy + OAFrac * oaInNode.Enthalpy;
    2744      1161103 :         TMixAtMinOA = PsyTdbFnHW(EnthMixAtMinOA, HumRatMixAtMinOA);
    2745              :     } else {
    2746         7472 :         TMixAtMinOA = state.dataLoopNodes->Node(this->loopInNodeNum).Temp;
    2747              :     }
    2748              : 
    2749              :     Real64 FanDeltaT;
    2750      1168575 :     if (this->fanOutNodeNum > 0 && this->fanInNodeNum > 0) {
    2751       947788 :         FanDeltaT = state.dataLoopNodes->Node(this->fanOutNodeNum).Temp - state.dataLoopNodes->Node(this->fanInNodeNum).Temp;
    2752              :     } else {
    2753       220787 :         FanDeltaT = 0.0;
    2754              :     }
    2755              : 
    2756      1168575 :     Real64 TSupNoHC = TMixAtMinOA + FanDeltaT;
    2757      1168575 :     Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    2758      1168575 :     Real64 ExtrRateNoHC = CpAir * ZoneMassFlow * (TSupNoHC - ZoneTemp);
    2759      1168575 :     if (ZoneMassFlow <= HVAC::SmallMassFlow) {
    2760       318676 :         TSetPt = TSupNoHC;
    2761              : 
    2762       849899 :     } else if (DeadBand || std::abs(ZoneLoad) < HVAC::SmallLoad) {
    2763              :         // if air with no active heating or cooling provides cooling
    2764        64803 :         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        26881 :             TSetPt = (ExtrRateNoHC >= ZoneLoadToHeatSetPt) ? TSupNoHC : (ZoneTemp + ZoneLoadToHeatSetPt / (CpAir * ZoneMassFlow));
    2768              : 
    2769              :             // if air with no active heating or cooling provides heating
    2770        37922 :         } 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        37922 :             TSetPt = (ExtrRateNoHC <= ZoneLoadToCoolSetPt) ? TSupNoHC : (ZoneTemp + ZoneLoadToCoolSetPt / (CpAir * ZoneMassFlow));
    2774              : 
    2775              :         } else {
    2776            0 :             TSetPt = TSupNoHC;
    2777              :         }
    2778              : 
    2779       785096 :     } else if (ZoneLoad < (-1.0 * HVAC::SmallLoad)) {
    2780       353227 :         Real64 TSetPt1 = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlow);
    2781       353227 :         Real64 TSetPt2 = ZoneTemp + ZoneLoadToHeatSetPt / (CpAir * ZoneMassFlow);
    2782       353227 :         TSetPt = (TSetPt1 <= TSupNoHC) ? TSetPt1 : ((TSetPt2 > TSupNoHC) ? TSetPt2 : TSupNoHC);
    2783              : 
    2784       431869 :     } else if (ZoneLoad > HVAC::SmallLoad) {
    2785       431869 :         Real64 TSetPt1 = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlow);
    2786       431869 :         Real64 TSetPt2 = ZoneTemp + ZoneLoadToCoolSetPt / (CpAir * ZoneMassFlow);
    2787       431869 :         TSetPt = (TSetPt1 >= TSupNoHC) ? TSetPt1 : ((TSetPt2 < TSupNoHC) ? TSetPt2 : TSupNoHC);
    2788              : 
    2789              :     } else {
    2790            0 :         TSetPt = TSupNoHC;
    2791              :     }
    2792              : 
    2793      1168575 :     this->setPt = std::clamp(TSetPt, this->minSetTemp, this->maxSetTemp);
    2794      1168575 : } // SPMSZReheat::calculate()
    2795              : 
    2796       821402 : 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       821402 :     auto const &zoneInletNode = state.dataLoopNodes->Node(this->zoneInletNodeNum);
    2807              : 
    2808              :     // This function handles both heating and cooling
    2809       821402 :     auto const &zoneEnergyDemand = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum);
    2810       821402 :     Real64 ZoneLoadToSP =
    2811       821402 :         (this->type == SPMType::SZHeating) ? zoneEnergyDemand.OutputRequiredToHeatingSP : zoneEnergyDemand.OutputRequiredToCoolingSP;
    2812              : 
    2813       821402 :     Real64 ZoneTemp = state.dataLoopNodes->Node(this->zoneNodeNum).Temp;
    2814       821402 :     if (zoneInletNode.MassFlowRate <= HVAC::SmallMassFlow) {
    2815       201366 :         this->setPt = (this->type == SPMType::SZHeating) ? this->minSetTemp : this->maxSetTemp;
    2816              :     } else {
    2817       620036 :         Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    2818       620036 :         this->setPt = ZoneTemp + ZoneLoadToSP / (CpAir * zoneInletNode.MassFlowRate);
    2819       620036 :         this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    2820              :     }
    2821       821402 : } // SPMSZTemp::calculate()
    2822              : 
    2823        86412 : 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        86412 :     this->setPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum).StageNum >= 0) ? this->coolingOffSetPt : this->coolingOnSetPt;
    2836              :     // negative so a cooling stage is set
    2837        86412 : } // SPMSingleZoneOneStageCooling::calculate()
    2838              : 
    2839        86412 : 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        86412 :     this->setPt = (state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->ctrlZoneNum).StageNum <= 0) ? this->heatingOffSetPt : this->heatingOnSetPt;
    2852        86412 : } // SPMSingleZoneOneStageHeating::calculate()
    2853              : 
    2854       326728 : 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       326728 :     auto &zoneNode = state.dataLoopNodes->Node(this->zoneNodeNum);
    2876              : 
    2877       326728 :     Real64 ZoneMassFlow = zoneNode.MassFlowRate;
    2878       326728 :     if (ZoneMassFlow > HVAC::SmallMassFlow) {
    2879       324213 :         auto const &zoneMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(this->ctrlZoneNum);
    2880       324213 :         Real64 MoistureLoad =
    2881       324213 :             (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       324213 :         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       324213 :         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         2515 :         this->setPt = 0.0;
    2895              :     }
    2896       326728 : } // SPMSingleZoneHum::calculate()
    2897              : 
    2898      7388026 : 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      7388026 :     auto &fanInNode = state.dataLoopNodes->Node(this->fanInNodeNum);
    2912      7388026 :     auto &fanOutNode = state.dataLoopNodes->Node(this->fanOutNodeNum);
    2913      7388026 :     auto &refNode = state.dataLoopNodes->Node(this->refNodeNum);
    2914              : 
    2915      7388026 :     this->freezeCheckEnable = false;
    2916              : 
    2917      7388026 :     if (!state.dataGlobal->SysSizingCalc && this->mySetPointCheckFlag) {
    2918              : 
    2919         1695 :         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         1695 :         this->mySetPointCheckFlag = false;
    2942              :     }
    2943              : 
    2944      7388026 :     this->setPt = refNode.TempSetPoint - (fanOutNode.Temp - fanInNode.Temp);
    2945      7388026 :     if (this->coolCoilInNodeNum > 0 && this->coolCoilOutNodeNum > 0) {
    2946         2057 :         auto const &coolCoilInNode = state.dataLoopNodes->Node(this->coolCoilInNodeNum);
    2947         2057 :         auto const &coolCoilOutNode = state.dataLoopNodes->Node(this->coolCoilOutNodeNum);
    2948         2057 :         Real64 dtFan = fanOutNode.Temp - fanInNode.Temp;
    2949         2057 :         Real64 dtCoolCoil = coolCoilInNode.Temp - coolCoilOutNode.Temp;
    2950         2057 :         if (dtCoolCoil > 0.0 && this->minCoolCoilOutTemp > state.dataEnvrn->OutDryBulbTemp) {
    2951            0 :             this->freezeCheckEnable = true;
    2952            0 :             if (refNode.Temp == coolCoilOutNode.Temp) { // blow through
    2953            0 :                 this->setPt = max(refNode.TempSetPoint, this->minCoolCoilOutTemp) - dtFan + dtCoolCoil;
    2954            0 :             } else if (this->refNodeNum != this->coolCoilOutNodeNum) { // // draw through Ref node is outlet node
    2955            0 :                 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      7388026 : } // SPMMixedAir::calculate()
    2962              : 
    2963        21275 : 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        21275 :     Real64 ReturnInValue = 0;   // return air inlet node mass flow rate
    2983        21275 :     Real64 RefNodeSetPoint = 0; // setpoint at reference node
    2984        21275 :     Real64 MinSetPoint = 0;     // minimum allowed setpoint
    2985        21275 :     Real64 MaxSetPoint = 0;     // maximum allowed setpoint
    2986              : 
    2987        21275 :     auto &refNode = state.dataLoopNodes->Node(this->refNodeNum);
    2988        21275 :     auto &mixedOutNode = state.dataLoopNodes->Node(this->mixedOutNodeNum);
    2989        21275 :     auto &oaInNode = state.dataLoopNodes->Node(this->oaInNodeNum);
    2990        21275 :     auto &returnInNode = state.dataLoopNodes->Node(this->returnInNodeNum);
    2991              : 
    2992        21275 :     bool isHumiditySetPoint = false;
    2993              : 
    2994        21275 :     switch (this->ctrlVar) {
    2995        10595 :     case HVAC::CtrlVarType::Temp: { // 'Temperature'
    2996        10595 :         RefNodeSetPoint = refNode.TempSetPoint;
    2997        10595 :         ReturnInValue = returnInNode.Temp;
    2998        10595 :         MinSetPoint = this->minSetTemp;
    2999        10595 :         MaxSetPoint = this->maxSetTemp;
    3000        10595 :     } break;
    3001        10680 :     case HVAC::CtrlVarType::MaxHumRat: { // 'HUMRATMAX'
    3002        10680 :         RefNodeSetPoint = refNode.HumRatMax;
    3003        10680 :         ReturnInValue = returnInNode.HumRat;
    3004        10680 :         MinSetPoint = this->minSetHum;
    3005        10680 :         MaxSetPoint = this->maxSetHum;
    3006        10680 :         isHumiditySetPoint = true;
    3007        10680 :     } 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        21275 :     if (!state.dataGlobal->SysSizingCalc && this->mySetPointCheckFlag) {
    3027            9 :         this->mySetPointCheckFlag = false;
    3028            9 :         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        21275 :     if ((mixedOutNode.MassFlowRate <= 0.0) || (oaInNode.MassFlowRate <= 0.0)) {
    3059          110 :         this->setPt = RefNodeSetPoint;
    3060        21165 :     } 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        21165 :         Real64 OAFraction = oaInNode.MassFlowRate / mixedOutNode.MassFlowRate;
    3066        21165 :         this->setPt = ReturnInValue + (RefNodeSetPoint - ReturnInValue) / OAFraction;
    3067              :         // Apply maximum and minimum values
    3068        21165 :         this->setPt = std::clamp(this->setPt, MinSetPoint, MaxSetPoint);
    3069              :     }
    3070        21275 : } // SPMOutsideAirPretreat::calculate()
    3071              : 
    3072        52472 : 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        52472 :     Real64 SetPointTemp = 0.0;
    3087              : 
    3088        52472 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3089              : 
    3090        52472 :     if (this->type == SPMType::Warmest) {
    3091              : 
    3092        49782 :         Real64 TotCoolLoad = 0.0;
    3093        49782 :         SetPointTemp = this->maxSetTemp;
    3094              : 
    3095       490567 :         for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3096       440785 :             int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3097       440785 :             auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3098       440785 :             auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3099              : 
    3100       440785 :             Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3101       440785 :             Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3102       440785 :             Real64 ZoneTemp = zoneNode.Temp;
    3103       440785 :             Real64 ZoneSetPointTemp = this->maxSetTemp;
    3104       440785 :             if (ZoneLoad < 0.0) {
    3105       101209 :                 TotCoolLoad += std::abs(ZoneLoad);
    3106       101209 :                 Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3107       101209 :                 if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3108       101209 :                     ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3109              :                 }
    3110              :             }
    3111       440785 :             SetPointTemp = min(SetPointTemp, ZoneSetPointTemp);
    3112              :         }
    3113              : 
    3114        49782 :         SetPointTemp = std::clamp(SetPointTemp, this->minSetTemp, this->maxSetTemp);
    3115        49782 :         if (TotCoolLoad < HVAC::SmallLoad) {
    3116        27506 :             SetPointTemp = this->maxSetTemp;
    3117              :         }
    3118              : 
    3119              :     } else { // (spm->type == SPMType::Coldest)
    3120         2690 :         Real64 TotHeatLoad = 0.0;
    3121         2690 :         SetPointTemp = this->minSetTemp;
    3122              : 
    3123         2690 :         if (airToZoneNode.NumZonesHeated > 0) {
    3124              :             // dual-duct heated only zones
    3125        10760 :             for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesHeated; ++iZoneNum) {
    3126         8070 :                 int CtrlZoneNum = airToZoneNode.HeatCtrlZoneNums(iZoneNum);
    3127         8070 :                 auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.HeatZoneInletNodes(iZoneNum));
    3128         8070 :                 auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3129         8070 :                 Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3130         8070 :                 Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3131         8070 :                 Real64 ZoneTemp = zoneNode.Temp;
    3132         8070 :                 Real64 ZoneSetPointTemp = this->minSetTemp;
    3133         8070 :                 if (ZoneLoad > 0.0) {
    3134         4059 :                     TotHeatLoad += ZoneLoad;
    3135         4059 :                     Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3136         4059 :                     if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3137         4059 :                         ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3138              :                     }
    3139              :                 }
    3140         8070 :                 SetPointTemp = max(SetPointTemp, ZoneSetPointTemp);
    3141              :             }
    3142              :         } else {
    3143              :             // single-duct or central heated and cooled zones
    3144            0 :             for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3145            0 :                 int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3146            0 :                 auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3147            0 :                 auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3148            0 :                 Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3149            0 :                 Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3150            0 :                 Real64 ZoneTemp = zoneNode.Temp;
    3151            0 :                 Real64 ZoneSetPointTemp = this->minSetTemp;
    3152            0 :                 if (ZoneLoad > 0.0) {
    3153            0 :                     TotHeatLoad += ZoneLoad;
    3154            0 :                     Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3155            0 :                     if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3156            0 :                         ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax);
    3157              :                     }
    3158              :                 }
    3159            0 :                 SetPointTemp = max(SetPointTemp, ZoneSetPointTemp);
    3160              :             }
    3161              :         }
    3162              : 
    3163         2690 :         SetPointTemp = std::clamp(SetPointTemp, this->minSetTemp, this->maxSetTemp);
    3164         2690 :         if (TotHeatLoad < HVAC::SmallLoad) {
    3165         1287 :             SetPointTemp = this->minSetTemp;
    3166              :         }
    3167              :     }
    3168              : 
    3169        52472 :     this->setPt = SetPointTemp;
    3170        52472 : } // SMPTempest::calculate()
    3171              : 
    3172         6620 : 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         6620 :     if (!this->simReady) {
    3189            0 :         return;
    3190              :     }
    3191         6620 :     Real64 TotCoolLoad = 0.0;
    3192         6620 :     Real64 MaxSetPointTemp = this->maxSetTemp;
    3193         6620 :     Real64 SetPointTemp = MaxSetPointTemp;
    3194         6620 :     Real64 MinSetPointTemp = this->minSetTemp;
    3195         6620 :     Real64 MinFracFlow = this->minTurndown;
    3196         6620 :     Real64 FracFlow = MinFracFlow;
    3197         6620 :     int CritZoneNumTemp = 0;
    3198         6620 :     int CritZoneNumFlow = 0;
    3199              : 
    3200         6620 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3201              : 
    3202        33104 :     for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3203        26484 :         int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3204        26484 :         auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3205        26484 :         auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3206              : 
    3207        26484 :         Real64 ZoneMassFlowMax = zoneInletNode.MassFlowRateMax;
    3208        26484 :         Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3209        26484 :         Real64 ZoneTemp = zoneNode.Temp;
    3210        26484 :         Real64 ZoneSetPointTemp = MaxSetPointTemp;
    3211        26484 :         Real64 ZoneFracFlow = MinFracFlow;
    3212              : 
    3213        26484 :         if (ZoneLoad < 0.0) {
    3214         5253 :             TotCoolLoad += std::abs(ZoneLoad);
    3215         5253 :             Real64 CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3216         5253 :             if (ZoneMassFlowMax > HVAC::SmallMassFlow) {
    3217         5253 :                 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         5253 :                     ZoneSetPointTemp = ZoneTemp + ZoneLoad / (CpAir * ZoneMassFlowMax * MinFracFlow);
    3222         5253 :                     if (ZoneSetPointTemp < MinSetPointTemp) {
    3223         3746 :                         ZoneFracFlow = (ZoneLoad / (CpAir * (MinSetPointTemp - ZoneTemp))) / ZoneMassFlowMax;
    3224              :                     } else {
    3225         1507 :                         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        26484 :         if (ZoneSetPointTemp < SetPointTemp) {
    3241         2444 :             SetPointTemp = ZoneSetPointTemp;
    3242         2444 :             CritZoneNumTemp = CtrlZoneNum;
    3243              :         }
    3244        26484 :         if (ZoneFracFlow > FracFlow) {
    3245         2159 :             FracFlow = ZoneFracFlow;
    3246         2159 :             CritZoneNumFlow = CtrlZoneNum;
    3247              :         }
    3248              :     }
    3249              : 
    3250         6620 :     SetPointTemp = std::clamp(SetPointTemp, MinSetPointTemp, MaxSetPointTemp);
    3251         6620 :     FracFlow = std::clamp(FracFlow, MinFracFlow, 1.0);
    3252         6620 :     if (TotCoolLoad < HVAC::SmallLoad) {
    3253         4595 :         SetPointTemp = MaxSetPointTemp;
    3254         4595 :         FracFlow = MinFracFlow;
    3255              :     }
    3256              : 
    3257         6620 :     this->setPt = SetPointTemp;
    3258         6620 :     this->turndown = FracFlow;
    3259         6620 :     if (this->strategy == ControlStrategy::TempFirst) {
    3260         6620 :         this->critZoneNum = (CritZoneNumFlow != 0) ? CritZoneNumFlow : CritZoneNumTemp;
    3261              :     } else { // ControlStrategy = FlowFirst
    3262            0 :         this->critZoneNum = (CritZoneNumTemp != 0) ? CritZoneNumTemp : CritZoneNumFlow;
    3263              :     }
    3264              : } // SPMWarmestTempFlow::calculate()
    3265              : 
    3266         2005 : 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         2005 :     auto &mixerRABInNode = state.dataLoopNodes->Node(this->rabMixInNodeNum);
    3278         2005 :     auto &mixerSupInNode = state.dataLoopNodes->Node(this->supMixInNodeNum);
    3279         2005 :     auto &mixerOutNode = state.dataLoopNodes->Node(this->mixOutNodeNum);
    3280         2005 :     auto &loopOutNode = state.dataLoopNodes->Node(this->sysOutNodeNum);
    3281              : 
    3282         2005 :     Real64 TempSetPt = this->sched->getCurrentVal();
    3283         2005 :     Real64 TempSetPtMod = TempSetPt - (loopOutNode.Temp - mixerOutNode.Temp);
    3284         2005 :     Real64 SupFlow = mixerSupInNode.MassFlowRate;
    3285         2005 :     Real64 TempSup = mixerSupInNode.Temp;
    3286         2005 :     Real64 TotSupFlow = mixerOutNode.MassFlowRate;
    3287         2005 :     Real64 TempRAB = mixerRABInNode.Temp;
    3288         2005 :     Real64 RABFlow = (TotSupFlow * TempSetPtMod - SupFlow * TempSup) / max(TempRAB, 1.0);
    3289         2005 :     RABFlow = std::clamp(RABFlow, 0.0, TotSupFlow);
    3290         2005 :     this->FlowSetPt = RABFlow;
    3291         2005 : }
    3292              : 
    3293         5354 : 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         5354 :     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         5354 :     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         5354 :     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         5354 :     Real64 SumProductMdotCpTZoneTot = 0.0;
    3320              : 
    3321         5354 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3322        21416 :     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        16062 :         int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3333        16062 :         auto &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3334        16062 :         auto &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3335        16062 :         Real64 ZoneMassFlowRate = zoneInletNode.MassFlowRate;
    3336        16062 :         Real64 ZoneLoad = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(CtrlZoneNum).TotalOutputRequired;
    3337        16062 :         Real64 ZoneTemp = zoneNode.Temp;
    3338        16062 :         Real64 CpAir = PsyCpAirFnW(zoneNode.HumRat);
    3339        16062 :         SumProductMdotCpTot += ZoneMassFlowRate * CpAir;
    3340        16062 :         SumProductMdotCpTZoneTot += ZoneMassFlowRate * CpAir * ZoneTemp;
    3341        16062 :         if ((this->type == SPMType::MZHeatingAverage && ZoneLoad > 0.0) || (this->type == SPMType::MZCoolingAverage && ZoneLoad < 0.0)) {
    3342         8031 :             CpAir = PsyCpAirFnW(zoneInletNode.HumRat);
    3343         8031 :             SumLoad += ZoneLoad;
    3344         8031 :             SumProductMdotCp += ZoneMassFlowRate * CpAir;
    3345              :         }
    3346              :     }
    3347         5354 :     Real64 ZoneAverageTemp = (SumProductMdotCpTot > 0.0) ? (SumProductMdotCpTZoneTot / SumProductMdotCpTot) : 0.0;
    3348         8987 :     Real64 SetPointTemp = (SumProductMdotCp > 0.0) ? (ZoneAverageTemp + SumLoad / SumProductMdotCp)
    3349         3633 :                                                    : ((this->type == SPMType::MZHeatingAverage) ? this->minSetTemp : this->maxSetTemp);
    3350              : 
    3351         5354 :     SetPointTemp = std::clamp(SetPointTemp, this->minSetTemp, this->maxSetTemp);
    3352         5354 :     if (std::abs(SumLoad) < HVAC::SmallLoad) {
    3353         2564 :         SetPointTemp = (this->type == SPMType::MZHeatingAverage) ? this->minSetTemp : this->maxSetTemp;
    3354              :     }
    3355         5354 :     this->setPt = SetPointTemp;
    3356         5354 : } // SPMMultiZoneTemp::calculate()
    3357              : 
    3358        46732 : 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        46732 :     Real64 constexpr SmallMoistureLoad(0.00001); // small moisture load [kgWater/s]
    3374              : 
    3375              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3376        46732 :     Real64 SumMdot = 0.0;         // sum of the actual mass flow rate for controlled zones in the air loop [kg/s]
    3377        46732 :     Real64 SumMdotTot = 0.0;      // sum of the actual mass flow rate for this air loop [kg/s]
    3378        46732 :     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        46732 :     Real64 SumProductMdotHumTot = 0.0;
    3382              : 
    3383        46732 :     auto &airToZoneNode = state.dataAirLoop->AirToZoneNodeInfo(this->airLoopNum);
    3384              : 
    3385        46732 :     Real64 SetPointHum = (this->type == SPMType::MZMinHum || this->type == SPMType::MZMinHumAverage) ? this->minSetHum : this->maxSetHum;
    3386              : 
    3387       525016 :     for (int iZoneNum = 1; iZoneNum <= airToZoneNode.NumZonesCooled; ++iZoneNum) {
    3388       478284 :         int CtrlZoneNum = airToZoneNode.CoolCtrlZoneNums(iZoneNum);
    3389       478284 :         auto const &zoneInletNode = state.dataLoopNodes->Node(airToZoneNode.CoolZoneInletNodes(iZoneNum));
    3390       478284 :         auto const &zoneNode = state.dataLoopNodes->Node(state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneNode);
    3391       478284 :         auto const &zoneMoistureDemand = state.dataZoneEnergyDemand->ZoneSysMoistureDemand(CtrlZoneNum);
    3392       478284 :         Real64 ZoneMassFlowRate = zoneInletNode.MassFlowRate;
    3393       280782 :         Real64 MoistureLoad = (this->type == SPMType::MZMinHum || this->type == SPMType::MZMinHumAverage)
    3394       759066 :                                   ? zoneMoistureDemand.OutputRequiredToHumidifyingSP
    3395              :                                   : zoneMoistureDemand.OutputRequiredToDehumidifyingSP;
    3396              : 
    3397       478284 :         Real64 ZoneHum = zoneNode.HumRat;
    3398              :         // For humidification the moisture load is positive
    3399              : 
    3400       478284 :         switch (this->type) {
    3401         7935 :         case SPMType::MZMinHumAverage: {
    3402         7935 :             SumMdotTot += ZoneMassFlowRate;
    3403         7935 :             SumProductMdotHumTot += ZoneMassFlowRate * ZoneHum;
    3404         7935 :             if (MoistureLoad > 0.0) {
    3405         2464 :                 SumMdot += ZoneMassFlowRate;
    3406         2464 :                 SumMoistureLoad += MoistureLoad;
    3407              :             }
    3408         7935 :         } break;
    3409              : 
    3410         7935 :         case SPMType::MZMaxHumAverage: {
    3411         7935 :             SumMdotTot += ZoneMassFlowRate;
    3412         7935 :             SumProductMdotHumTot += ZoneMassFlowRate * ZoneHum;
    3413         7935 :             if (MoistureLoad < 0.0) {
    3414          521 :                 SumMdot += ZoneMassFlowRate;
    3415          521 :                 SumMoistureLoad += MoistureLoad;
    3416              :             }
    3417         7935 :         } break;
    3418              : 
    3419       197502 :         case SPMType::MZMinHum: {
    3420       197502 :             Real64 ZoneSetPointHum = this->minSetHum;
    3421       197502 :             if (MoistureLoad > 0.0) {
    3422        11423 :                 SumMoistureLoad += MoistureLoad;
    3423        11423 :                 if (ZoneMassFlowRate > HVAC::SmallMassFlow) {
    3424        11423 :                     ZoneSetPointHum = max(0.0, ZoneHum + MoistureLoad / ZoneMassFlowRate);
    3425              :                 }
    3426              :             }
    3427       197502 :             SetPointHum = max(SetPointHum, ZoneSetPointHum);
    3428       197502 :         } break;
    3429              : 
    3430       264912 :         case SPMType::MZMaxHum: {
    3431       264912 :             Real64 ZoneSetPointHum = this->maxSetHum;
    3432       264912 :             if (MoistureLoad < 0.0) {
    3433        34341 :                 SumMoistureLoad += MoistureLoad;
    3434        34341 :                 if (ZoneMassFlowRate > HVAC::SmallMassFlow) {
    3435        29374 :                     ZoneSetPointHum = max(0.0, ZoneHum + MoistureLoad / ZoneMassFlowRate);
    3436              :                 }
    3437              :             }
    3438       264912 :             SetPointHum = min(SetPointHum, ZoneSetPointHum);
    3439       264912 :         } break;
    3440              : 
    3441            0 :         default:
    3442            0 :             break;
    3443              :         } // switch (this->type)
    3444              :     }
    3445              : 
    3446        46732 :     if (this->type == SPMType::MZMinHumAverage || this->type == SPMType::MZMaxHumAverage) {
    3447         3174 :         Real64 AverageZoneHum = (SumMdotTot > HVAC::SmallMassFlow) ? (SumProductMdotHumTot / SumMdotTot) : 0.0;
    3448         3174 :         if (SumMdot > HVAC::SmallMassFlow) {
    3449         1039 :             SetPointHum = max(0.0, AverageZoneHum + SumMoistureLoad / SumMdot);
    3450              :         }
    3451         3174 :     } else {
    3452        43558 :         if (std::abs(SumMoistureLoad) < SmallMoistureLoad) {
    3453        28071 :             SetPointHum = (this->type == SPMType::MZMinHum) ? this->minSetHum : this->maxSetHum;
    3454              :         }
    3455              :     }
    3456              : 
    3457        46732 :     this->setPt = std::clamp(SetPointHum, this->minSetHum, this->maxSetHum);
    3458        46732 : } // SPMMultiZoneHum::calculate()
    3459              : 
    3460       685502 : 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       685502 :     this->setPt = ((this->refTempType == AirTempType::WetBulb) ? state.dataEnvrn->OutWetBulbTemp : state.dataEnvrn->OutDryBulbTemp) + this->offset;
    3475              : 
    3476              :     // Apply maximum and minimum values
    3477       685502 :     this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    3478       685502 : } // SPMFollowOutsideAirTemp::calculate()
    3479              : 
    3480         2860 : 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         2860 :     Real64 RefNodeTemp = (this->refTempType == AirTempType::DryBulb)
    3503         5720 :                              ? state.dataLoopNodes->Node(this->refNodeNum).Temp
    3504         2860 :                              : (allocated(state.dataLoopNodes->MoreNodeInfo) ? state.dataLoopNodes->MoreNodeInfo(this->refNodeNum).WetBulbTemp : 0.0);
    3505              : 
    3506         2860 :     this->setPt = RefNodeTemp + this->offset;
    3507              : 
    3508              :     // Apply maximum and minimum values
    3509         2860 :     this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    3510         2860 : } // SPMFollowSysNodeTemp::calculate()
    3511              : 
    3512        37652 : 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        37652 :     this->setPt = state.dataEnvrn->GroundTemp[(int)this->refTempType] + this->offset;
    3527              : 
    3528              :     // Apply maximum and minimum values
    3529        37652 :     this->setPt = std::clamp(this->setPt, this->minSetTemp, this->maxSetTemp);
    3530        37652 : } // SPMFollowGrounTemp::calculate()
    3531              : 
    3532         5842 : 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         5842 :     auto &dspm = state.dataSetPointManager;
    3551              : 
    3552              :     // Current timestep's condenser water entering setpoint
    3553         5842 :     Real64 CondenserEnteringTempSetPoint = this->condenserEnteringTempSched->getCurrentVal();
    3554              : 
    3555         5842 :     auto &supplyLoop = state.dataPlnt->PlantLoop(this->plantPloc.loopNum).LoopSide(LoopSideLocation::Supply);
    3556         5842 :     auto &supplyComp = supplyLoop.Branch(this->plantPloc.branchNum).Comp(this->plantPloc.compNum);
    3557              : 
    3558         5842 :     auto &demandLoop = state.dataPlnt->PlantLoop(this->demandPloc.loopNum).LoopSide(LoopSideLocation::Demand);
    3559         5842 :     auto &demandComp = demandLoop.Branch(this->demandPloc.branchNum).Comp(this->demandPloc.compNum);
    3560              : 
    3561              :     // If chiller is on
    3562         5842 :     Real64 CurLoad = std::abs(supplyComp.MyLoad);
    3563         5842 :     if (CurLoad > 0) {
    3564              : 
    3565         2425 :         Real64 CondInletTemp = 0.0;
    3566         2425 :         Real64 EvapOutletTemp = 0.0;
    3567              : 
    3568         2425 :         Real64 DesignLoad = 0.0;            // array of chiller design loads
    3569         2425 :         Real64 ActualLoad = 0.0;            // array of chiller actual loads
    3570         2425 :         Real64 DesignCondenserInTemp = 0.0; // Design condenser inlet temp. C , or 25.d0
    3571         2425 :         Real64 DesignEvapOutTemp = 0.0;     // design evaporator outlet temperature, water side
    3572              : 
    3573              :         // Get from tower design values
    3574         2425 :         constexpr Real64 NormDesignCondenserFlow = 5.38e-8; // m3/s per watt (typically 3 gpm/ton)=(Volume of condenser fluid)/(ton of heat rejection)
    3575              : 
    3576         2425 :         if (this->chillerType == PlantEquipmentType::Chiller_Absorption || this->chillerType == PlantEquipmentType::Chiller_CombTurbine ||
    3577         2425 :             this->chillerType == PlantEquipmentType::Chiller_Electric || this->chillerType == PlantEquipmentType::Chiller_ElectricReformEIR ||
    3578            0 :             this->chillerType == PlantEquipmentType::Chiller_EngineDriven) {
    3579         2425 :             DesignCondenserInTemp = supplyComp.TempDesCondIn;
    3580         2425 :             CondInletTemp = state.dataLoopNodes->Node(demandComp.NodeNumIn).Temp;
    3581         2425 :             EvapOutletTemp = state.dataLoopNodes->Node(supplyComp.NodeNumOut).Temp;
    3582         2425 :             DesignEvapOutTemp = supplyComp.TempDesEvapOut;
    3583         2425 :             DesignLoad = supplyComp.MaxLoad;
    3584         2425 :             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         2425 :         dspm->CET_DesignMinCondenserSetPt = 999.0;
    3596         2425 :         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         2425 :         Real64 DesignMinCondenserEnteringTempThisChiller = DesignEvapOutTemp + (this->minLift);
    3601         2425 :         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         2425 :         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         2425 :         dspm->CET_ActualLoadSum += ActualLoad;
    3611         2425 :         dspm->CET_DesignLoadSum += DesignLoad;
    3612              : 
    3613              :         // Exit if the chillers are all off this hour
    3614         2425 :         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         2425 :         Real64 WeightedActualLoad = 0.0; // Actual load weighting of each chiller, W
    3624         2425 :         Real64 WeightedDesignLoad = 0.0; // Design capacity of each chiller, W
    3625         2425 :         if (dspm->CET_ActualLoadSum != 0 && dspm->CET_DesignLoadSum != 0) {
    3626         2425 :             WeightedActualLoad = ((ActualLoad / dspm->CET_ActualLoadSum) * ActualLoad);
    3627         2425 :             WeightedDesignLoad = ((DesignLoad / dspm->CET_DesignLoadSum) * DesignLoad);
    3628              :         }
    3629              : 
    3630         2425 :         dspm->CET_WeightedActualLoadSum += WeightedActualLoad;
    3631         2425 :         dspm->CET_WeightedDesignLoadSum += WeightedDesignLoad;
    3632         2425 :         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         2425 :         dspm->CET_DesignMinWetBulbTemp = EnergyPlus::Curve::CurveValue(state,
    3639              :                                                                        this->minTowerDesignWetBulbCurveNum,
    3640         2425 :                                                                        state.dataEnvrn->OutWetBulbTemp,
    3641         2425 :                                                                        dspm->CET_WeightedLoadRatio,
    3642              :                                                                        this->towerDesignInletAirWetBulbTemp,
    3643              :                                                                        NormDesignCondenserFlow);
    3644              : 
    3645              :         // Min_ActualWb = BCoef1 + BCoef2*MinDsnWB + BCoef3*WPLR + BCoef4*TwrDsnWB + BCoef5*NF
    3646         2425 :         dspm->CET_MinActualWetBulbTemp = EnergyPlus::Curve::CurveValue(state,
    3647              :                                                                        this->minOAWetBulbCurveNum,
    3648         2425 :                                                                        dspm->CET_DesignMinWetBulbTemp,
    3649         2425 :                                                                        dspm->CET_WeightedLoadRatio,
    3650              :                                                                        this->towerDesignInletAirWetBulbTemp,
    3651              :                                                                        NormDesignCondenserFlow);
    3652              : 
    3653              :         // Opt_CondEntTemp = CCoef1 + CCoef2*OaWb + CCoef3*WPLR + CCoef4*TwrDsnWB + CCoef5*NF
    3654         2425 :         dspm->CET_OptCondenserEnteringTemp = EnergyPlus::Curve::CurveValue(state,
    3655              :                                                                            this->optCondenserEnteringTempCurveNum,
    3656         2425 :                                                                            state.dataEnvrn->OutWetBulbTemp,
    3657         2425 :                                                                            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         2425 :         dspm->CET_CurMinLift = 9999.0;
    3665              :         // temp_MinLiftTD = 20.0 / 1.8;
    3666         2425 :         Real64 TempMinLift = CondInletTemp - EvapOutletTemp;
    3667         2425 :         dspm->CET_CurMinLift = min(dspm->CET_CurMinLift, TempMinLift);
    3668              :     }
    3669              : 
    3670         5842 :     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         5842 :     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            0 :         SetPoint = dspm->CET_DesignEnteringCondenserTemp + 1.0;
    3678         5842 :     } else if ((state.dataEnvrn->OutWetBulbTemp >= dspm->CET_MinActualWetBulbTemp) &&
    3679         5842 :                (this->towerDesignInletAirWetBulbTemp >= dspm->CET_DesignMinWetBulbTemp) && (dspm->CET_CurMinLift > this->minLift)) {
    3680              :         // Boundaries are satisfied; use optimized condenser entering water temp
    3681         3198 :         SetPoint = dspm->CET_OptCondenserEnteringTemp;
    3682              :     } else {
    3683              :         // Boundaries violated; Reset to scheduled value of condenser water entering setpoint
    3684         2644 :         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         5842 :     this->setPt = max(SetPoint, dspm->CET_DesignMinCondenserSetPt);
    3690              : } // SPMCondenserEneteringTemp::calculate()
    3691              : 
    3692         5378 : 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         5378 :     auto &dspm = state.dataSetPointManager;
    3715              : 
    3716              :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    3717         5378 :     auto &supplyLoop = state.dataPlnt->PlantLoop(this->chillerPloc.loopNum).LoopSide(LoopSideLocation::Supply);
    3718         5378 :     auto &supplyComp = supplyLoop.Branch(this->chillerPloc.branchNum).Comp(this->chillerPloc.compNum);
    3719              : 
    3720         5378 :     if (state.dataGlobal->MetersHaveBeenInitialized) {
    3721              :         // Setup meter vars
    3722         5366 :         if (this->setupIdealCondEntSetPtVars) {
    3723            2 :             this->SetupMeteredVarsForSetPt(state);
    3724            2 :             this->setupIdealCondEntSetPtVars = false;
    3725              :         }
    3726              :     }
    3727              : 
    3728         5378 :     if (state.dataGlobal->MetersHaveBeenInitialized && state.dataGlobal->RunOptCondEntTemp) {
    3729              : 
    3730              :         // If chiller is on
    3731         2114 :         Real64 CurLoad = std::abs(supplyComp.MyLoad);
    3732              : 
    3733         2114 :         if (CurLoad > 0) {
    3734              : 
    3735              :             Real64 EvapOutletTemp =
    3736         1922 :                 (this->chillerType == PlantEquipmentType::Chiller_Absorption || this->chillerType == PlantEquipmentType::Chiller_CombTurbine ||
    3737         1922 :                  this->chillerType == PlantEquipmentType::Chiller_Electric || this->chillerType == PlantEquipmentType::Chiller_ElectricReformEIR ||
    3738            0 :                  this->chillerType == PlantEquipmentType::Chiller_EngineDriven)
    3739         3844 :                     ? state.dataLoopNodes->Node(supplyComp.NodeNumOut).Temp
    3740         1922 :                     : 6.666;
    3741              : 
    3742         1922 :             Real64 CondTempLimit = this->minLift + EvapOutletTemp;
    3743              : 
    3744         1922 :             Real64 TotEnergy = this->calculateCurrentEnergyUsage(state);
    3745              : 
    3746         1922 :             this->setupSetPointAndFlags(TotEnergy,
    3747         1922 :                                         dspm->ICET_TotEnergyPre,
    3748         1922 :                                         dspm->ICET_CondenserWaterSetPt,
    3749              :                                         CondTempLimit,
    3750         1922 :                                         state.dataGlobal->RunOptCondEntTemp,
    3751         1922 :                                         dspm->ICET_RunSubOptCondEntTemp,
    3752         1922 :                                         dspm->ICET_RunFinalOptCondEntTemp);
    3753              : 
    3754              :         } else {
    3755          192 :             dspm->ICET_CondenserWaterSetPt = this->maxCondenserEnteringTemp;
    3756          192 :             dspm->ICET_TotEnergyPre = 0.0;
    3757          192 :             state.dataGlobal->RunOptCondEntTemp = false;
    3758          192 :             dspm->ICET_RunSubOptCondEntTemp = false;
    3759              :         }
    3760              :     } else {
    3761         3264 :         dspm->ICET_CondenserWaterSetPt = this->maxCondenserEnteringTemp;
    3762         3264 :         state.dataGlobal->RunOptCondEntTemp = false;
    3763         3264 :         dspm->ICET_RunSubOptCondEntTemp = false;
    3764              :     }
    3765              : 
    3766         5378 :     this->setPt = dspm->ICET_CondenserWaterSetPt;
    3767         5378 : } // SPMIdealCondenserEnteringTemp::calculate()
    3768              : 
    3769         1922 : 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         1922 :     if (TotEnergyPre != 0.0) {
    3779              :         // Calculate the total energy consumption difference
    3780         1654 :         DeltaTotEnergy = TotEnergyPre - TotEnergy;
    3781              :         // Search for the minimum total energy consumption
    3782         1654 :         if ((DeltaTotEnergy > 0) && (CondWaterSetPoint >= CondTempLimit) && (!RunFinalOptCondEntTemp)) {
    3783          851 :             if (!RunSubOptCondEntTemp) {
    3784          596 :                 --CondWaterSetPoint;
    3785          596 :                 RunOptCondEntTemp = true;
    3786              :             } else {
    3787          255 :                 CondWaterSetPoint -= 0.2;
    3788          255 :                 RunOptCondEntTemp = true;
    3789              :             }
    3790          851 :             TotEnergyPre = TotEnergy;
    3791              :             // Set smaller set point (0.2 degC) decrease
    3792          803 :         } else if ((DeltaTotEnergy < 0) && (!RunSubOptCondEntTemp) && (CondWaterSetPoint > CondTempLimit) && (!RunFinalOptCondEntTemp)) {
    3793          267 :             CondWaterSetPoint += 0.8;
    3794          267 :             RunOptCondEntTemp = true;
    3795          267 :             RunSubOptCondEntTemp = true;
    3796              :         } else {
    3797          536 :             if (!RunFinalOptCondEntTemp) {
    3798          268 :                 CondWaterSetPoint += 0.2;
    3799          268 :                 RunOptCondEntTemp = true;
    3800          268 :                 RunSubOptCondEntTemp = false;
    3801          268 :                 RunFinalOptCondEntTemp = true;
    3802              :             } else {
    3803              :                 // CondWaterSetPoint = CondWaterSetPoint; // Self-assignment commented out
    3804          268 :                 TotEnergyPre = 0.0;
    3805          268 :                 RunOptCondEntTemp = false;
    3806          268 :                 RunSubOptCondEntTemp = false;
    3807          268 :                 RunFinalOptCondEntTemp = false;
    3808              :             }
    3809              :         }
    3810              :     } else {
    3811          268 :         CondWaterSetPoint = this->maxCondenserEnteringTemp - 1.0;
    3812          268 :         TotEnergyPre = TotEnergy;
    3813          268 :         RunOptCondEntTemp = true;
    3814          268 :         RunSubOptCondEntTemp = false;
    3815              :     }
    3816         1922 : } // SPMIdealCondenserEneteringTemp::()
    3817              : 
    3818         1922 : Real64 SPMIdealCondenserEnteringTemp::calculateCurrentEnergyUsage(EnergyPlusData &state)
    3819              : {
    3820         1922 :     Real64 ChillerEnergy = GetInternalVariableValue(state, this->chillerVar.Type, this->chillerVar.Num);
    3821         1922 :     Real64 ChilledPumpEnergy = GetInternalVariableValue(state, this->chilledWaterPumpVar.Type, this->chilledWaterPumpVar.Num);
    3822         1922 :     Real64 TowerFanEnergy = 0;
    3823         4768 :     for (int i = 1; i <= this->numTowers; i++) {
    3824         2846 :         TowerFanEnergy += GetInternalVariableValue(state, this->towerVars(i).Type, this->towerVars(i).Num);
    3825              :     }
    3826         1922 :     Real64 CondPumpEnergy = GetInternalVariableValue(state, this->condenserPumpVar.Type, this->condenserPumpVar.Num);
    3827         1922 :     return (ChillerEnergy + ChilledPumpEnergy + TowerFanEnergy + CondPumpEnergy);
    3828              : } // SPMIdealCondenserEnteringTemp::calculateCurrentEnergyUsage()
    3829              : 
    3830        31366 : 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        31366 :     auto &supplyNode = state.dataLoopNodes->Node(this->supplyNodeNum);
    3862        31366 :     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        31366 :     if (this->plantLoopNum == 0) {
    3868           14 :         for (int LoopNum = 1; LoopNum <= state.dataPlnt->TotNumLoops; ++LoopNum) {
    3869           10 :             auto &plantLoop = state.dataPlnt->PlantLoop(LoopNum);
    3870           10 :             if (this->supplyNodeNum == plantLoop.LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumOut) {
    3871            4 :                 this->plantLoopNum = LoopNum;
    3872            4 :                 this->plantSetPtNodeNum = plantLoop.TempSetPointNodeNum;
    3873              :                 // now that we've found the plant populated, let's verify that the nodes match
    3874            4 :                 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        31366 :     Real64 const mdot = supplyNode.MassFlowRate;
    3885        31366 :     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        31366 :     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        31366 :     Real64 T_return_target = this->returnTempConstantTarget;
    3905        31366 :     if (this->returnTempSched != nullptr) {
    3906            0 :         T_return_target = this->returnTempSched->getCurrentVal();
    3907        31366 :     } else if (this->returnTempType == ReturnTempType::Setpoint) {
    3908          963 :         if (returnNode.TempSetPoint != SensedNodeFlagValue) {
    3909          963 :             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        31366 :     Real64 T_supply_setpoint = (this->type == SPMType::ChilledWaterReturnTemp) ? this->minSetTemp : this->maxSetTemp;
    3925        31366 :     if (mdot > DataConvergParams::PlantFlowRateToler) {
    3926        13366 :         T_supply_setpoint = T_return_target + ((this->type == SPMType::ChilledWaterReturnTemp) ? -deltaT : deltaT);
    3927              :     }
    3928              : 
    3929        31366 :     this->currentSupplySetPt = std::clamp(T_supply_setpoint, this->minSetTemp, this->maxSetTemp);
    3930              : } // SPMReturnWaterTemp::calculate()
    3931              : 
    3932            2 : 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            2 :     Array1D<OutputProcessor::MeteredVar> meteredVars;
    3947              : 
    3948            2 :     auto &plantLoop = state.dataPlnt->PlantLoop(this->chillerPloc.loopNum);
    3949            2 :     auto &supplySide = plantLoop.LoopSide(this->chillerPloc.loopSideNum);
    3950            2 :     auto &chillerBranch = supplySide.Branch(this->chillerPloc.branchNum);
    3951            2 :     auto &chillerComp = chillerBranch.Comp(this->chillerPloc.compNum);
    3952              : 
    3953            2 :     int NumVariables = GetNumMeteredVariables(state, chillerComp.TypeOf, chillerComp.Name);
    3954            2 :     meteredVars.allocate(NumVariables);
    3955              : 
    3956            2 :     GetMeteredVariables(state, chillerComp.Name, meteredVars);
    3957            2 :     this->chillerVar.Type = meteredVars(1).varType;
    3958            2 :     this->chillerVar.Num = meteredVars(1).num;
    3959              : 
    3960            2 :     auto &chilledWaterPumpBranch = supplySide.Branch(this->chilledWaterPumpPloc.branchNum);
    3961            2 :     auto &chilledWaterPumpComp = chilledWaterPumpBranch.Comp(this->chilledWaterPumpPloc.compNum);
    3962              : 
    3963            2 :     NumVariables = GetNumMeteredVariables(state, chilledWaterPumpComp.TypeOf, chilledWaterPumpComp.Name);
    3964            2 :     meteredVars.allocate(NumVariables);
    3965              : 
    3966            2 :     GetMeteredVariables(state, chilledWaterPumpComp.Name, meteredVars);
    3967            2 :     this->chilledWaterPumpVar.Type = meteredVars(1).varType;
    3968            2 :     this->chilledWaterPumpVar.Num = meteredVars(1).num;
    3969              : 
    3970            2 :     auto &towerLoopSide = state.dataPlnt->PlantLoop(this->towerPlocs(1).loopNum).LoopSide(this->towerPlocs(1).loopSideNum);
    3971              : 
    3972            5 :     for (int i = 1; i <= this->numTowers; i++) {
    3973            3 :         auto &towerComp = towerLoopSide.Branch(this->towerPlocs(i).branchNum).Comp(this->towerPlocs(i).compNum);
    3974            3 :         NumVariables = GetNumMeteredVariables(state, towerComp.TypeOf, towerComp.Name);
    3975            3 :         meteredVars.allocate(NumVariables);
    3976              : 
    3977            3 :         GetMeteredVariables(state, towerComp.Name, meteredVars);
    3978            3 :         this->towerVars.push_back({meteredVars(1).varType, meteredVars(1).num});
    3979              :     }
    3980              : 
    3981            2 :     auto &condenserPumpComp = towerLoopSide.Branch(this->condenserPumpPloc.branchNum).Comp(this->condenserPumpPloc.compNum);
    3982            2 :     NumVariables = GetNumMeteredVariables(state, condenserPumpComp.TypeOf, condenserPumpComp.Name);
    3983            2 :     meteredVars.allocate(NumVariables);
    3984              : 
    3985            2 :     GetMeteredVariables(state, condenserPumpComp.Name, meteredVars);
    3986            2 :     this->condenserPumpVar = {meteredVars(1).varType, meteredVars(1).num};
    3987            2 : } // SPMIdealCondenserEnteringTemp::SetupMeteredVarsForSetPt()
    3988              : 
    3989         6920 : void SPMSystemNode::calculate(EnergyPlusData &state)
    3990              : {
    3991         6920 :     Real64 RefValue = 0; // Reference value from the Reference node
    3992              : 
    3993         6920 :     auto &refNode = state.dataLoopNodes->Node(this->refNodeNum);
    3994              : 
    3995         6920 :     switch (this->ctrlVar) {
    3996         5190 :     case HVAC::CtrlVarType::Temp:
    3997              :     case HVAC::CtrlVarType::MaxTemp:
    3998              :     case HVAC::CtrlVarType::MinTemp: {
    3999         5190 :         RefValue = refNode.Temp;
    4000         5190 :     } break;
    4001         1730 :     case HVAC::CtrlVarType::HumRat:
    4002              :     case HVAC::CtrlVarType::MaxHumRat:
    4003              :     case HVAC::CtrlVarType::MinHumRat: {
    4004         1730 :         RefValue = refNode.HumRat;
    4005         1730 :     } break;
    4006            0 :     default:
    4007            0 :         break;
    4008              :     }
    4009              : 
    4010         6920 :     this->setPt = interpSetPoint(this->lowRef, this->highRef, RefValue, this->lowRefSetPt, this->highRefSetPt);
    4011         6920 : } // SPMSystemNode::calculate()
    4012              : 
    4013       521249 : Real64 interpSetPoint(Real64 const LowVal, Real64 const HighVal, Real64 const RefVal, Real64 const SetptAtLowVal, Real64 const SetptAtHighVal)
    4014              : {
    4015       521249 :     if (LowVal >= HighVal) {
    4016            0 :         return 0.5 * (SetptAtLowVal + SetptAtHighVal);
    4017       521249 :     } else if (RefVal <= LowVal) {
    4018       134749 :         return SetptAtLowVal;
    4019       386500 :     } else if (RefVal >= HighVal) {
    4020        94847 :         return SetptAtHighVal;
    4021              :     } else {
    4022       291653 :         return SetptAtLowVal - ((RefVal - LowVal) / (HighVal - LowVal)) * (SetptAtLowVal - SetptAtHighVal);
    4023              :     }
    4024              : }
    4025              : 
    4026      2849196 : 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     21297181 :     for (auto *spm : state.dataSetPointManager->spms) {
    4073              : 
    4074     18447985 :         switch (spm->type) {
    4075              : 
    4076      7117946 :         case SPMType::Scheduled:
    4077              :         case SPMType::SystemNodeTemp:
    4078              :         case SPMType::SystemNodeHum: {
    4079     14330674 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4080      7212728 :                 auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4081      7212728 :                 switch (spm->ctrlVar) {
    4082              :                 // set the setpoint depending on the type of variable being controlled
    4083      7191240 :                 case HVAC::CtrlVarType::Temp: {
    4084      7191240 :                     node.TempSetPoint = spm->setPt;
    4085      7191240 :                 } 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            0 :                 case HVAC::CtrlVarType::HumRat: {
    4093            0 :                     node.HumRatSetPoint = spm->setPt;
    4094            0 :                 } break;
    4095        19462 :                 case HVAC::CtrlVarType::MaxHumRat: {
    4096        19462 :                     node.HumRatMax = spm->setPt;
    4097        19462 :                 } break;
    4098         2026 :                 case HVAC::CtrlVarType::MinHumRat: {
    4099         2026 :                     node.HumRatMin = spm->setPt;
    4100         2026 :                 } 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      7117946 :             } // for (CtrlNodeNum)
    4114      7117946 :         } break;
    4115              : 
    4116         3420 :         case SPMType::TESScheduled: {
    4117         3420 :             auto *spmTESS = dynamic_cast<SPMTESScheduled *>(spm);
    4118         3420 :             assert(spmTESS != nullptr);
    4119              : 
    4120         3420 :             state.dataLoopNodes->Node(spmTESS->ctrlNodeNum).TempSetPoint = spm->setPt;
    4121         3420 :         } break;
    4122              : 
    4123        32881 :         case SPMType::ScheduledDual: {
    4124        32881 :             auto *spmSD = dynamic_cast<SPMScheduledDual *>(spm);
    4125        32881 :             assert(spmSD != nullptr);
    4126              : 
    4127        32881 :             if (spmSD->ctrlVar == HVAC::CtrlVarType::Temp) {
    4128        79612 :                 for (int ctrlNodeNum : spmSD->ctrlNodeNums) {
    4129        46731 :                     auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4130              : 
    4131        46731 :                     node.TempSetPointHi = spmSD->setPtHi;                                  // Set the setpoint High
    4132        46731 :                     node.TempSetPointLo = spmSD->setPtLo;                                  // Set the setpoint Low
    4133        46731 :                     node.TempSetPoint = (node.TempSetPointHi + node.TempSetPointLo) / 2.0; // average of the high and low
    4134        32881 :                 }
    4135              :             }
    4136        32881 :         } break;
    4137              : 
    4138      1239139 :         case SPMType::OutsideAir:
    4139              :         case SPMType::FollowOutsideAirTemp:
    4140              :         case SPMType::FollowSystemNodeTemp:
    4141              :         case SPMType::FollowGroundTemp: {
    4142      2555008 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4143      1315869 :                 auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4144      1315869 :                 if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    4145      1315869 :                     node.TempSetPoint = spm->setPt;
    4146            0 :                 } else if (spm->ctrlVar == HVAC::CtrlVarType::MaxTemp) {
    4147            0 :                     node.TempSetPointHi = spm->setPt;
    4148            0 :                 } else if (spm->ctrlVar == HVAC::CtrlVarType::MinTemp) {
    4149            0 :                     node.TempSetPointLo = spm->setPt;
    4150              :                 }
    4151      1239139 :             }
    4152              : 
    4153      1239139 :         } break;
    4154              : 
    4155      2231847 :         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      2231847 :             if (spm->ctrlVar == HVAC::CtrlVarType::Temp) {
    4167      4581288 :                 for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4168      2349441 :                     state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spm->setPt; // Set the setpoint
    4169      2231847 :                 }
    4170              :             }
    4171      2231847 :         } break;
    4172              : 
    4173       130814 :         case SPMType::SZMinHum:
    4174              :         case SPMType::MZMinHumAverage:
    4175              :         case SPMType::MZMinHum: {
    4176       261628 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4177       130814 :                 if (spm->type == SPMType::SZMinHum || spm->ctrlVar == HVAC::CtrlVarType::MinHumRat) { // Why is SZMinHum not tested for this?
    4178       130814 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMin = spm->setPt;
    4179              :                 }
    4180       130814 :             }
    4181       130814 :         } break;
    4182              : 
    4183       242646 :         case SPMType::SZMaxHum:
    4184              :         case SPMType::MZMaxHumAverage:
    4185              :         case SPMType::MZMaxHum: {
    4186       495680 :             for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4187       253034 :                 if (spm->type == SPMType::SZMaxHum || spm->ctrlVar == HVAC::CtrlVarType::MaxHumRat) { // Why is SZMaxHum not tested for this?
    4188       253034 :                     state.dataLoopNodes->Node(ctrlNodeNum).HumRatMax = spm->setPt;
    4189              :                 }
    4190       242646 :             }
    4191       242646 :         } break;
    4192              : 
    4193         6620 :         case SPMType::WarmestTempFlow: {
    4194         6620 :             auto *spmWTF = dynamic_cast<SPMWarmestTempFlow *>(spm);
    4195         6620 :             assert(spmWTF != nullptr);
    4196              : 
    4197         6620 :             if (spmWTF->ctrlVar == HVAC::CtrlVarType::Temp) {
    4198        13240 :                 for (int ctrlNodeNum : spmWTF->ctrlNodeNums) {
    4199         6620 :                     state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spmWTF->setPt; // Set the supply air temperature setpoint
    4200         6620 :                 }
    4201              : 
    4202         6620 :                 state.dataAirLoop->AirLoopFlow(spmWTF->airLoopNum).ReqSupplyFrac = spmWTF->turndown; // Set the supply air flow rate
    4203         6620 :                 state.dataAirLoop->AirLoopControlInfo(spmWTF->airLoopNum).LoopFlowRateSet = true;    // PH 8/17/07
    4204              :             }
    4205         6620 :         } break;
    4206              : 
    4207         2005 :         case SPMType::ReturnAirBypass: {
    4208         2005 :             auto *spmRAB = dynamic_cast<SPMReturnAirBypassFlow *>(spm);
    4209         2005 :             assert(spmRAB != nullptr);
    4210              : 
    4211         2005 :             if (spmRAB->ctrlVar == HVAC::CtrlVarType::MassFlowRate) {
    4212         2005 :                 state.dataLoopNodes->Node(spmRAB->rabSplitOutNodeNum).MassFlowRateSetPoint = spmRAB->FlowSetPt; // Set the flow setpoint
    4213              :             }
    4214         2005 :         } break;
    4215              : 
    4216        31366 :         case SPMType::ChilledWaterReturnTemp:
    4217              :         case SPMType::HotWaterReturnTemp: {
    4218        31366 :             auto *spmRWT = dynamic_cast<SPMReturnWaterTemp *>(spm);
    4219        31366 :             assert(spmRWT != nullptr);
    4220        31366 :             if (spmRWT->plantSetPtNodeNum > 0) {
    4221        31366 :                 state.dataLoopNodes->Node(spmRWT->plantSetPtNodeNum).TempSetPoint = spmRWT->currentSupplySetPt;
    4222              :             }
    4223        31366 :         } break;
    4224              : 
    4225              :         // MixedAir and OutsideAirPretreat SPMs have to be handled separately because they depend on other SPMs
    4226      7409301 :         case SPMType::MixedAir:
    4227              :         case SPMType::OutsideAirPretreat: {
    4228      7409301 :         } break;
    4229              : 
    4230            0 :         default:
    4231            0 :             break;
    4232              :         } // switch (sys->type)
    4233              :     } // for (spm)
    4234      2849196 : } // UpdateSetPointManagers()
    4235              : 
    4236      2849196 : 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     21297181 :     for (auto *spm : state.dataSetPointManager->spms) {
    4247     18447985 :         if (spm->type != SPMType::MixedAir) {
    4248     11059959 :             continue;
    4249              :         }
    4250      7388026 :         if (spm->ctrlVar != HVAC::CtrlVarType::Temp) {
    4251            0 :             continue;
    4252              :         }
    4253     15548056 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4254      8160030 :             state.dataLoopNodes->Node(ctrlNodeNum).TempSetPoint = spm->setPt; // Set the setpoint
    4255      7388026 :         }
    4256              :     }
    4257      2849196 : } // UpdateMixedAirSetPoints()
    4258              : 
    4259      2849196 : 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     21297181 :     for (auto *spm : state.dataSetPointManager->spms) {
    4271     18447985 :         if (spm->type != SPMType::OutsideAirPretreat) {
    4272     18426710 :             continue;
    4273              :         }
    4274        42550 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4275        21275 :             auto &node = state.dataLoopNodes->Node(ctrlNodeNum);
    4276        21275 :             switch (spm->ctrlVar) {
    4277        10595 :             case HVAC::CtrlVarType::Temp: {
    4278        10595 :                 node.TempSetPoint = spm->setPt;
    4279        10595 :             } break;
    4280        10680 :             case HVAC::CtrlVarType::MaxHumRat: {
    4281        10680 :                 node.HumRatMax = spm->setPt;
    4282        10680 :             } 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        21275 :         }
    4293              :     }
    4294      2849196 : } // 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            0 :         GetSetPointManagerInputs(state);
    4301            0 :         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         4632 : 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         4632 :     if (state.dataSetPointManager->GetInputFlag) {
    4345            0 :         GetSetPointManagerInputs(state);
    4346            0 :         state.dataSetPointManager->GetInputFlag = false;
    4347              :     }
    4348              : 
    4349        44637 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4350        41153 :         if (spm->ctrlVar != ctrlVar) {
    4351         1470 :             continue;
    4352              :         }
    4353        80928 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4354        42393 :             if (NodeNum == ctrlNodeNum) {
    4355         1148 :                 return true;
    4356              :             }
    4357        40831 :         }
    4358              :     }
    4359              : 
    4360         3484 :     return false;
    4361              : } // IsNodeOnSetPointManager()
    4362              : 
    4363         5376 : 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         5376 :     if (state.dataSetPointManager->GetInputFlag) {
    4377            0 :         GetSetPointManagerInputs(state);
    4378            0 :         state.dataSetPointManager->GetInputFlag = false;
    4379              :     }
    4380              : 
    4381       125396 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4382       122310 :         if (spm->ctrlVar != ctrlVar) {
    4383        13578 :             continue;
    4384              :         }
    4385       216944 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4386       110502 :             if (NodeNum == ctrlNodeNum) {
    4387         2290 :                 return true;
    4388              :             }
    4389       111022 :         }
    4390              :     }
    4391              : 
    4392         3086 :     return false;
    4393              : } // NodeHasSPMCtrlVarType()
    4394              : 
    4395           55 : 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           55 :     if (state.dataSetPointManager->GetInputFlag) {
    4412            0 :         GetSetPointManagerInputs(state);
    4413            0 :         state.dataSetPointManager->GetInputFlag = false;
    4414              :     }
    4415              : 
    4416         2732 :     for (auto *spm : state.dataSetPointManager->spms) {
    4417         2677 :         if (spm->ctrlVar != HVAC::CtrlVarType::HumRat) {
    4418         2677 :             continue;
    4419              :         }
    4420            0 :         for (int ctrlNodeNum : spm->ctrlNodeNums) {
    4421            0 :             if (NodeNum != ctrlNodeNum) {
    4422            0 :                 continue;
    4423              :             }
    4424              : 
    4425            0 :             spm->ctrlVar = HVAC::CtrlVarType::MaxHumRat;
    4426            0 :             ShowWarningError(state, format("ResetHumidityRatioCtrlVarType: {}=\"{}\". ", spmTypeNames[(int)spm->type], spm->Name));
    4427            0 :             ShowContinueError(state, " ..Humidity ratio control variable type specified is = HumidityRatio");
    4428            0 :             ShowContinueError(state, " ..Humidity ratio control variable type allowed with water coils is = MaximumHumidityRatio");
    4429            0 :             ShowContinueError(state, " ..Setpointmanager control variable type is reset to = MaximumHumidityRatio");
    4430            0 :             ShowContinueError(state, " ..Simulation continues. ");
    4431            0 :             return;
    4432            0 :         }
    4433              :     }
    4434              : } // ResetHumidityRatioCtrlVarType()
    4435              : 
    4436          801 : 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         1602 :     state.dataGlobal->AnyIdealCondEntSetPointInModel =
    4446          801 :         (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "SetpointManager:CondenserEnteringReset:Ideal") > 0);
    4447          801 : } // CheckIfAnyIdealCondEntSetPoint()
    4448              : 
    4449            0 : 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            0 :     if (state.dataSetPointManager->GetInputFlag) {
    4460            0 :         GetSetPointManagerInputs(state);
    4461            0 :         state.dataSetPointManager->GetInputFlag = false;
    4462              :     }
    4463              : 
    4464            0 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4465            0 :         if (spm->type != SPMType::SZMaxHum && spm->type != SPMType::MZMaxHum && spm->type != SPMType::MZMaxHumAverage) {
    4466            0 :             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            0 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4474            0 :         if (spm->type != SPMType::SZMinHum && spm->type != SPMType::MZMinHum && spm->type != SPMType::MZMinHumAverage) {
    4475            0 :             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            0 :     for (auto const *spm : state.dataSetPointManager->spms) {
    4483            0 :         if (spm->type != SPMType::Scheduled) {
    4484            0 :             continue;
    4485              :         }
    4486            0 :         if (std::find(spm->ctrlNodeNums.begin(), spm->ctrlNodeNums.end(), NodeNum) != spm->ctrlNodeNums.end()) {
    4487            0 :             if (spm->ctrlVar == HVAC::CtrlVarType::HumRat || spm->ctrlVar == HVAC::CtrlVarType::MaxHumRat) {
    4488            0 :                 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        10151 : 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        10151 :     if (state.dataSetPointManager->GetInputFlag) {
    4560            0 :         GetSetPointManagerInputs(state);
    4561            0 :         state.dataSetPointManager->GetInputFlag = false;
    4562              :     }
    4563              : 
    4564        10151 :     auto const *spmMA = dynamic_cast<SPMMixedAir *>(state.dataSetPointManager->spms(spmNum));
    4565        10151 :     assert(spmMA != nullptr);
    4566        10151 :     return spmMA->freezeCheckEnable;
    4567              : } // GetCoilFreezingCheckFlag()
    4568              : 
    4569         1067 : 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         1067 :     if (state.dataSetPointManager->GetInputFlag) {
    4579            0 :         GetSetPointManagerInputs(state);
    4580            0 :         state.dataSetPointManager->GetInputFlag = false;
    4581              :     }
    4582              : 
    4583        19932 :     for (int iSPM = 1; iSPM <= state.dataSetPointManager->spms.isize(); ++iSPM) {
    4584        18866 :         auto *const spm = state.dataSetPointManager->spms(iSPM);
    4585        18866 :         if (spm->type != SPMType::MixedAir) {
    4586         9443 :             continue;
    4587              :         }
    4588              : 
    4589         9423 :         auto *spmMA = dynamic_cast<SPMMixedAir *>(spm);
    4590         9423 :         assert(spmMA != nullptr);
    4591              : 
    4592        18846 :         if (std::find(spmMA->ctrlNodeNums.begin(), spmMA->ctrlNodeNums.end(), MixedAirNode) != spmMA->ctrlNodeNums.end() &&
    4593        18846 :             spmMA->coolCoilInNodeNum > 0 && spmMA->coolCoilOutNodeNum > 0) {
    4594            1 :             return iSPM; // Is this really thing we are returning? Not the number of the SPM?  Why?
    4595              :         }
    4596              :     }
    4597              : 
    4598         1066 :     return 0;
    4599              : } // End of GetMixedAirNumWithCoilFreezingCheck()
    4600              : 
    4601              : } // namespace EnergyPlus::SetPointManager
        

Generated by: LCOV version 2.0-1