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