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