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