LCOV - code coverage report
Current view: top level - EnergyPlus - SetPointManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1762 2308 76.3 %
Date: 2024-08-24 18:31:18 Functions: 44 46 95.7 %

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

Generated by: LCOV version 1.14